blob: ec7fd50e5a6e0db91a84b4d675aa7b7ca7c1a3df [file] [log] [blame]
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.stk;
18
19import android.app.Notification;
20import android.app.NotificationManager;
21import android.app.PendingIntent;
22import android.app.Service;
23import android.content.Context;
24import android.content.Intent;
25import android.net.Uri;
26import android.os.Bundle;
27import android.os.Handler;
28import android.os.IBinder;
29import android.os.Looper;
30import android.os.Message;
Wink Saville56469d52009-04-02 01:37:03 -070031import android.telephony.TelephonyManager;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080032import android.view.Gravity;
33import android.view.LayoutInflater;
34import android.view.View;
35import android.widget.ImageView;
36import android.widget.RemoteViews;
37import android.widget.TextView;
38import android.widget.Toast;
39
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070040import com.android.internal.telephony.cat.AppInterface;
41import com.android.internal.telephony.cat.Menu;
42import com.android.internal.telephony.cat.Item;
43import com.android.internal.telephony.cat.ResultCode;
44import com.android.internal.telephony.cat.CatCmdMessage;
45import com.android.internal.telephony.cat.CatCmdMessage.BrowserSettings;
46import com.android.internal.telephony.cat.CatLog;
47import com.android.internal.telephony.cat.CatResponseMessage;
48import com.android.internal.telephony.cat.TextMessage;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080049
50import java.util.LinkedList;
51
52/**
53 * SIM toolkit application level service. Interacts with Telephopny messages,
54 * application's launch and user input from STK UI elements.
Wink Saville79085fc2009-06-09 10:27:23 -070055 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080056 */
57public class StkAppService extends Service implements Runnable {
58
59 // members
60 private volatile Looper mServiceLooper;
61 private volatile ServiceHandler mServiceHandler;
62 private AppInterface mStkService;
63 private Context mContext = null;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070064 private CatCmdMessage mMainCmd = null;
65 private CatCmdMessage mCurrentCmd = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080066 private Menu mCurrentMenu = null;
67 private String lastSelectedItem = null;
68 private boolean mMenuIsVisibile = false;
69 private boolean responseNeeded = true;
70 private boolean mCmdInProgress = false;
71 private NotificationManager mNotificationManager = null;
72 private LinkedList<DelayedCmd> mCmdsQ = null;
73 private boolean launchBrowser = false;
74 private BrowserSettings mBrowserSettings = null;
75 static StkAppService sInstance = null;
76
77 // Used for setting FLAG_ACTIVITY_NO_USER_ACTION when
78 // creating an intent.
79 private enum InitiatedByUserAction {
80 yes, // The action was started via a user initiated action
81 unknown, // Not known for sure if user initated the action
82 }
83
84 // constants
85 static final String OPCODE = "op";
86 static final String CMD_MSG = "cmd message";
87 static final String RES_ID = "response id";
88 static final String MENU_SELECTION = "menu selection";
89 static final String INPUT = "input";
90 static final String HELP = "help";
91 static final String CONFIRMATION = "confirm";
92
93 // operations ids for different service functionality.
94 static final int OP_CMD = 1;
95 static final int OP_RESPONSE = 2;
96 static final int OP_LAUNCH_APP = 3;
97 static final int OP_END_SESSION = 4;
98 static final int OP_BOOT_COMPLETED = 5;
99 private static final int OP_DELAYED_MSG = 6;
100
101 // Response ids
102 static final int RES_ID_MENU_SELECTION = 11;
103 static final int RES_ID_INPUT = 12;
104 static final int RES_ID_CONFIRM = 13;
105 static final int RES_ID_DONE = 14;
106
107 static final int RES_ID_TIMEOUT = 20;
108 static final int RES_ID_BACKWARD = 21;
109 static final int RES_ID_END_SESSION = 22;
110 static final int RES_ID_EXIT = 23;
111
112 private static final String PACKAGE_NAME = "com.android.stk";
Wink Saville79085fc2009-06-09 10:27:23 -0700113 private static final String MENU_ACTIVITY_NAME =
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800114 PACKAGE_NAME + ".StkMenuActivity";
Wink Saville79085fc2009-06-09 10:27:23 -0700115 private static final String INPUT_ACTIVITY_NAME =
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800116 PACKAGE_NAME + ".StkInputActivity";
Wink Saville79085fc2009-06-09 10:27:23 -0700117
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800118 // Notification id used to display Idle Mode text in NotificationManager.
119 private static final int STK_NOTIFICATION_ID = 333;
Wink Saville79085fc2009-06-09 10:27:23 -0700120
121 // Inner class used for queuing telephony messages (proactive commands,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800122 // session end) while the service is busy processing a previous message.
123 private class DelayedCmd {
124 // members
125 int id;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700126 CatCmdMessage msg;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800127
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700128 DelayedCmd(int id, CatCmdMessage msg) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800129 this.id = id;
130 this.msg = msg;
131 }
132 }
133
134 @Override
135 public void onCreate() {
136 // Initialize members
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700137 mStkService = com.android.internal.telephony.cat.CatService
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800138 .getInstance();
Wink Saville36eddd52009-05-29 13:56:28 -0700139
140 // NOTE mStkService is a singleton and continues to exist even if the GSMPhone is disposed
141 // after the radio technology change from GSM to CDMA so the PHONE_TYPE_CDMA check is
142 // needed. In case of switching back from CDMA to GSM the GSMPhone constructor updates
143 // the instance. (TODO: test).
Wink Saville56469d52009-04-02 01:37:03 -0700144 if ((mStkService == null)
145 && (TelephonyManager.getDefault().getPhoneType()
146 != TelephonyManager.PHONE_TYPE_CDMA)) {
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700147 CatLog.d(this, " Unable to get Service handle");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800148 return;
149 }
150
151 mCmdsQ = new LinkedList<DelayedCmd>();
152 Thread serviceThread = new Thread(null, this, "Stk App Service");
153 serviceThread.start();
154 mContext = getBaseContext();
155 mNotificationManager = (NotificationManager) mContext
156 .getSystemService(Context.NOTIFICATION_SERVICE);
157 sInstance = this;
158 }
159
160 @Override
161 public void onStart(Intent intent, int startId) {
162 waitForLooper();
163
John Wang62acae42009-10-08 11:20:23 -0700164 // onStart() method can be passed a null intent
165 // TODO: replace onStart() with onStartCommand()
166 if (intent == null) {
167 return;
168 }
169
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800170 Bundle args = intent.getExtras();
John Wang62acae42009-10-08 11:20:23 -0700171
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800172 if (args == null) {
173 return;
174 }
175
176 Message msg = mServiceHandler.obtainMessage();
177 msg.arg1 = args.getInt(OPCODE);
178 switch(msg.arg1) {
179 case OP_CMD:
180 msg.obj = args.getParcelable(CMD_MSG);
181 break;
182 case OP_RESPONSE:
183 msg.obj = args;
184 /* falls through */
185 case OP_LAUNCH_APP:
186 case OP_END_SESSION:
187 case OP_BOOT_COMPLETED:
188 break;
189 default:
190 return;
191 }
192 mServiceHandler.sendMessage(msg);
193 }
194
195 @Override
196 public void onDestroy() {
197 waitForLooper();
198 mServiceLooper.quit();
199 }
200
201 @Override
202 public IBinder onBind(Intent intent) {
203 return null;
204 }
205
206 public void run() {
207 Looper.prepare();
208
209 mServiceLooper = Looper.myLooper();
210 mServiceHandler = new ServiceHandler();
211
212 Looper.loop();
213 }
214
215 /*
216 * Package api used by StkMenuActivity to indicate if its on the foreground.
217 */
218 void indicateMenuVisibility(boolean visibility) {
219 mMenuIsVisibile = visibility;
220 }
221
222 /*
223 * Package api used by StkMenuActivity to get its Menu parameter.
224 */
225 Menu getMenu() {
226 return mCurrentMenu;
227 }
228
229 /*
230 * Package api used by UI Activities and Dialogs to communicate directly
231 * with the service to deliver state information and parameters.
232 */
233 static StkAppService getInstance() {
234 return sInstance;
235 }
236
237 private void waitForLooper() {
238 while (mServiceHandler == null) {
239 synchronized (this) {
240 try {
241 wait(100);
242 } catch (InterruptedException e) {
243 }
244 }
245 }
246 }
247
248 private final class ServiceHandler extends Handler {
249 @Override
250 public void handleMessage(Message msg) {
251 int opcode = msg.arg1;
252
253 switch (opcode) {
254 case OP_LAUNCH_APP:
255 if (mMainCmd == null) {
256 // nothing todo when no SET UP MENU command didn't arrive.
257 return;
258 }
259 launchMenuActivity(null);
260 break;
261 case OP_CMD:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700262 CatCmdMessage cmdMsg = (CatCmdMessage) msg.obj;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800263 // There are two types of commands:
264 // 1. Interactive - user's response is required.
265 // 2. Informative - display a message, no interaction with the user.
266 //
Wink Saville79085fc2009-06-09 10:27:23 -0700267 // Informative commands can be handled immediately without any delay.
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800268 // Interactive commands can't override each other. So if a command
269 // is already in progress, we need to queue the next command until
270 // the user has responded or a timeout expired.
271 if (!isCmdInteractive(cmdMsg)) {
272 handleCmd(cmdMsg);
273 } else {
274 if (!mCmdInProgress) {
275 mCmdInProgress = true;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700276 handleCmd((CatCmdMessage) msg.obj);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800277 } else {
278 mCmdsQ.addLast(new DelayedCmd(OP_CMD,
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700279 (CatCmdMessage) msg.obj));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800280 }
281 }
282 break;
283 case OP_RESPONSE:
284 if (responseNeeded) {
285 handleCmdResponse((Bundle) msg.obj);
286 }
287 // call delayed commands if needed.
288 if (mCmdsQ.size() != 0) {
289 callDelayedMsg();
290 } else {
291 mCmdInProgress = false;
292 }
293 // reset response needed state var to its original value.
294 responseNeeded = true;
295 break;
296 case OP_END_SESSION:
297 if (!mCmdInProgress) {
298 mCmdInProgress = true;
299 handleSessionEnd();
300 } else {
301 mCmdsQ.addLast(new DelayedCmd(OP_END_SESSION, null));
302 }
303 break;
304 case OP_BOOT_COMPLETED:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700305 CatLog.d(this, "OP_BOOT_COMPLETED");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800306 if (mMainCmd == null) {
307 StkAppInstaller.unInstall(mContext);
308 }
309 break;
310 case OP_DELAYED_MSG:
311 handleDelayedCmd();
312 break;
313 }
314 }
315 }
316
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700317 private boolean isCmdInteractive(CatCmdMessage cmd) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800318 switch (cmd.getCmdType()) {
319 case SEND_DTMF:
320 case SEND_SMS:
321 case SEND_SS:
322 case SEND_USSD:
323 case SET_UP_IDLE_MODE_TEXT:
324 case SET_UP_MENU:
325 return false;
326 }
327
328 return true;
329 }
330
331 private void handleDelayedCmd() {
332 if (mCmdsQ.size() != 0) {
333 DelayedCmd cmd = mCmdsQ.poll();
334 switch (cmd.id) {
335 case OP_CMD:
336 handleCmd(cmd.msg);
337 break;
338 case OP_END_SESSION:
339 handleSessionEnd();
340 break;
341 }
342 }
343 }
344
345 private void callDelayedMsg() {
346 Message msg = mServiceHandler.obtainMessage();
347 msg.arg1 = OP_DELAYED_MSG;
348 mServiceHandler.sendMessage(msg);
349 }
350
351 private void handleSessionEnd() {
352 mCurrentCmd = mMainCmd;
353 lastSelectedItem = null;
Wink Saville79085fc2009-06-09 10:27:23 -0700354 // In case of SET UP MENU command which removed the app, don't
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800355 // update the current menu member.
356 if (mCurrentMenu != null && mMainCmd != null) {
357 mCurrentMenu = mMainCmd.getMenu();
358 }
359 if (mMenuIsVisibile) {
360 launchMenuActivity(null);
361 }
362 if (mCmdsQ.size() != 0) {
363 callDelayedMsg();
364 } else {
365 mCmdInProgress = false;
366 }
367 // In case a launch browser command was just confirmed, launch that url.
368 if (launchBrowser) {
369 launchBrowser = false;
370 launchBrowser(mBrowserSettings);
371 }
372 }
373
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700374 private void handleCmd(CatCmdMessage cmdMsg) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800375 if (cmdMsg == null) {
376 return;
377 }
378 // save local reference for state tracking.
379 mCurrentCmd = cmdMsg;
380 boolean waitForUsersResponse = true;
381
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700382 CatLog.d(this, cmdMsg.getCmdType().name());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800383 switch (cmdMsg.getCmdType()) {
384 case DISPLAY_TEXT:
385 TextMessage msg = cmdMsg.geTextMessage();
386 responseNeeded = msg.responseNeeded;
387 if (lastSelectedItem != null) {
388 msg.title = lastSelectedItem;
389 } else if (mMainCmd != null){
390 msg.title = mMainCmd.getMenu().title;
391 } else {
392 // TODO: get the carrier name from the SIM
393 msg.title = "";
394 }
395 launchTextDialog();
396 break;
397 case SELECT_ITEM:
398 mCurrentMenu = cmdMsg.getMenu();
399 launchMenuActivity(cmdMsg.getMenu());
400 break;
401 case SET_UP_MENU:
402 mMainCmd = mCurrentCmd;
403 mCurrentMenu = cmdMsg.getMenu();
404 if (removeMenu()) {
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700405 CatLog.d(this, "Uninstall App");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800406 mCurrentMenu = null;
407 StkAppInstaller.unInstall(mContext);
408 } else {
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700409 CatLog.d(this, "Install App");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800410 StkAppInstaller.install(mContext);
411 }
412 if (mMenuIsVisibile) {
413 launchMenuActivity(null);
414 }
415 break;
416 case GET_INPUT:
417 case GET_INKEY:
418 launchInputActivity();
419 break;
420 case SET_UP_IDLE_MODE_TEXT:
421 waitForUsersResponse = false;
422 launchIdleText();
423 break;
424 case SEND_DTMF:
425 case SEND_SMS:
426 case SEND_SS:
427 case SEND_USSD:
428 waitForUsersResponse = false;
429 launchEventMessage();
430 break;
431 case LAUNCH_BROWSER:
432 launchConfirmationDialog(mCurrentCmd.geTextMessage());
433 break;
434 case SET_UP_CALL:
435 launchConfirmationDialog(mCurrentCmd.getCallSettings().confirmMsg);
436 break;
437 case PLAY_TONE:
438 launchToneDialog();
439 break;
440 }
441
442 if (!waitForUsersResponse) {
443 if (mCmdsQ.size() != 0) {
444 callDelayedMsg();
445 } else {
446 mCmdInProgress = false;
447 }
448 }
449 }
450
451 private void handleCmdResponse(Bundle args) {
452 if (mCurrentCmd == null) {
453 return;
454 }
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700455 CatResponseMessage resMsg = new CatResponseMessage(mCurrentCmd);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800456
457 // set result code
458 boolean helpRequired = args.getBoolean(HELP, false);
459
460 switch(args.getInt(RES_ID)) {
461 case RES_ID_MENU_SELECTION:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700462 CatLog.d(this, "RES_ID_MENU_SELECTION");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800463 int menuSelection = args.getInt(MENU_SELECTION);
464 switch(mCurrentCmd.getCmdType()) {
465 case SET_UP_MENU:
466 case SELECT_ITEM:
467 lastSelectedItem = getItemName(menuSelection);
468 if (helpRequired) {
469 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
470 } else {
471 resMsg.setResultCode(ResultCode.OK);
472 }
473 resMsg.setMenuSelection(menuSelection);
474 break;
475 }
476 break;
477 case RES_ID_INPUT:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700478 CatLog.d(this, "RES_ID_INPUT");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800479 String input = args.getString(INPUT);
480 if (mCurrentCmd.geInput().yesNo) {
481 boolean yesNoSelection = input
482 .equals(StkInputActivity.YES_STR_RESPONSE);
483 resMsg.setYesNo(yesNoSelection);
484 } else {
485 if (helpRequired) {
486 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
487 } else {
488 resMsg.setResultCode(ResultCode.OK);
489 resMsg.setInput(input);
490 }
491 }
492 break;
493 case RES_ID_CONFIRM:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700494 CatLog.d(this, "RES_ID_CONFIRM");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800495 boolean confirmed = args.getBoolean(CONFIRMATION);
496 switch (mCurrentCmd.getCmdType()) {
497 case DISPLAY_TEXT:
498 resMsg.setResultCode(confirmed ? ResultCode.OK
499 : ResultCode.UICC_SESSION_TERM_BY_USER);
500 break;
501 case LAUNCH_BROWSER:
502 resMsg.setResultCode(confirmed ? ResultCode.OK
503 : ResultCode.UICC_SESSION_TERM_BY_USER);
504 if (confirmed) {
505 launchBrowser = true;
506 mBrowserSettings = mCurrentCmd.getBrowserSettings();
507 }
508 break;
509 case SET_UP_CALL:
510 resMsg.setResultCode(ResultCode.OK);
511 resMsg.setConfirmation(confirmed);
512 if (confirmed) {
513 launchCallMsg();
514 }
515 break;
516 }
517 break;
518 case RES_ID_DONE:
519 resMsg.setResultCode(ResultCode.OK);
520 break;
521 case RES_ID_BACKWARD:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700522 CatLog.d(this, "RES_ID_BACKWARD");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800523 resMsg.setResultCode(ResultCode.BACKWARD_MOVE_BY_USER);
524 break;
525 case RES_ID_END_SESSION:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700526 CatLog.d(this, "RES_ID_END_SESSION");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800527 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
528 break;
529 case RES_ID_TIMEOUT:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700530 CatLog.d(this, "RES_ID_TIMEOUT");
Naveen Kallad5176892009-11-30 12:45:29 -0800531 // GCF test-case 27.22.4.1.1 Expected Sequence 1.5 (DISPLAY TEXT,
532 // Clear message after delay, successful) expects result code OK.
533 // If the command qualifier specifies no user response is required
534 // then send OK instead of NO_RESPONSE_FROM_USER
535 if ((mCurrentCmd.getCmdType().value() == AppInterface.CommandType.DISPLAY_TEXT
536 .value())
537 && (mCurrentCmd.geTextMessage().userClear == false)) {
538 resMsg.setResultCode(ResultCode.OK);
539 } else {
540 resMsg.setResultCode(ResultCode.NO_RESPONSE_FROM_USER);
541 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800542 break;
543 default:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700544 CatLog.d(this, "Unknown result id");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800545 return;
546 }
547 mStkService.onCmdResponse(resMsg);
548 }
549
550 /**
551 * Returns 0 or FLAG_ACTIVITY_NO_USER_ACTION, 0 means the user initiated the action.
552 *
553 * @param userAction If the userAction is yes then we always return 0 otherwise
554 * mMenuIsVisible is used to determine what to return. If mMenuIsVisible is true
555 * then we are the foreground app and we'll return 0 as from our perspective a
556 * user action did cause. If it's false than we aren't the foreground app and
557 * FLAG_ACTIVITY_NO_USER_ACTION is returned.
Wink Saville79085fc2009-06-09 10:27:23 -0700558 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800559 * @return 0 or FLAG_ACTIVITY_NO_USER_ACTION
560 */
561 private int getFlagActivityNoUserAction(InitiatedByUserAction userAction) {
562 return ((userAction == InitiatedByUserAction.yes) | mMenuIsVisibile) ?
563 0 : Intent.FLAG_ACTIVITY_NO_USER_ACTION;
564 }
565
566 private void launchMenuActivity(Menu menu) {
567 Intent newIntent = new Intent(Intent.ACTION_VIEW);
568 newIntent.setClassName(PACKAGE_NAME, MENU_ACTIVITY_NAME);
569 int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK
570 | Intent.FLAG_ACTIVITY_CLEAR_TOP;
571 if (menu == null) {
572 // We assume this was initiated by the user pressing the tool kit icon
573 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.yes);
574
575 newIntent.putExtra("STATE", StkMenuActivity.STATE_MAIN);
576 } else {
577 // We don't know and we'll let getFlagActivityNoUserAction decide.
578 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.unknown);
579
580 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
581 }
582 newIntent.setFlags(intentFlags);
583 mContext.startActivity(newIntent);
584 }
585
586 private void launchInputActivity() {
587 Intent newIntent = new Intent(Intent.ACTION_VIEW);
588 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
589 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown));
590 newIntent.setClassName(PACKAGE_NAME, INPUT_ACTIVITY_NAME);
591 newIntent.putExtra("INPUT", mCurrentCmd.geInput());
592 mContext.startActivity(newIntent);
593 }
594
595 private void launchTextDialog() {
596 Intent newIntent = new Intent(this, StkDialogActivity.class);
597 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
598 | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
599 | Intent.FLAG_ACTIVITY_NO_HISTORY
600 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
601 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown));
602 newIntent.putExtra("TEXT", mCurrentCmd.geTextMessage());
603 startActivity(newIntent);
604 }
605
606 private void launchEventMessage() {
607 TextMessage msg = mCurrentCmd.geTextMessage();
John Josephb22e7d82009-12-15 14:53:17 -0800608 if (msg == null || msg.text == null) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800609 return;
610 }
611 Toast toast = new Toast(mContext.getApplicationContext());
612 LayoutInflater inflate = (LayoutInflater) mContext
613 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
614 View v = inflate.inflate(R.layout.stk_event_msg, null);
615 TextView tv = (TextView) v
616 .findViewById(com.android.internal.R.id.message);
617 ImageView iv = (ImageView) v
618 .findViewById(com.android.internal.R.id.icon);
619 if (msg.icon != null) {
620 iv.setImageBitmap(msg.icon);
621 } else {
622 iv.setVisibility(View.GONE);
623 }
624 if (!msg.iconSelfExplanatory) {
625 tv.setText(msg.text);
626 }
627
628 toast.setView(v);
629 toast.setDuration(Toast.LENGTH_LONG);
630 toast.setGravity(Gravity.BOTTOM, 0, 0);
631 toast.show();
632 }
633
634 private void launchConfirmationDialog(TextMessage msg) {
635 msg.title = lastSelectedItem;
636 Intent newIntent = new Intent(this, StkDialogActivity.class);
637 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
638 | Intent.FLAG_ACTIVITY_NO_HISTORY
639 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
640 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown));
641 newIntent.putExtra("TEXT", msg);
642 startActivity(newIntent);
643 }
644
645 private void launchBrowser(BrowserSettings settings) {
646 if (settings == null) {
647 return;
648 }
649 // Set browser launch mode
650 Intent intent = new Intent();
651 intent.setClassName("com.android.browser",
652 "com.android.browser.BrowserActivity");
653
Wink Saville79085fc2009-06-09 10:27:23 -0700654 // to launch home page, make sure that data Uri is null.
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800655 Uri data = null;
656 if (settings.url != null) {
657 data = Uri.parse(settings.url);
658 }
659 intent.setData(data);
660 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
661 switch (settings.mode) {
662 case USE_EXISTING_BROWSER:
663 intent.setAction(Intent.ACTION_VIEW);
664 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
665 break;
666 case LAUNCH_NEW_BROWSER:
667 intent.setAction(Intent.ACTION_VIEW);
668 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
669 break;
670 case LAUNCH_IF_NOT_ALREADY_LAUNCHED:
671 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
672 break;
673 }
674 // start browser activity
675 startActivity(intent);
676 // a small delay, let the browser start, before processing the next command.
Wink Saville79085fc2009-06-09 10:27:23 -0700677 // this is good for scenarios where a related DISPLAY TEXT command is
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800678 // followed immediately.
679 try {
680 Thread.sleep(10000);
681 } catch (InterruptedException e) {}
682 }
683
684 private void launchCallMsg() {
685 TextMessage msg = mCurrentCmd.getCallSettings().callMsg;
686 if (msg.text == null || msg.text.length() == 0) {
687 return;
688 }
689 msg.title = lastSelectedItem;
690
691 Toast toast = Toast.makeText(mContext.getApplicationContext(), msg.text,
692 Toast.LENGTH_LONG);
693 toast.setGravity(Gravity.BOTTOM, 0, 0);
694 toast.show();
695 }
696
697 private void launchIdleText() {
698 TextMessage msg = mCurrentCmd.geTextMessage();
699 if (msg.text == null) {
700 mNotificationManager.cancel(STK_NOTIFICATION_ID);
701 } else {
702 Notification notification = new Notification();
703 RemoteViews contentView = new RemoteViews(
704 PACKAGE_NAME,
705 com.android.internal.R.layout.status_bar_latest_event_content);
706
707 notification.flags |= Notification.FLAG_NO_CLEAR;
708 notification.icon = com.android.internal.R.drawable.stat_notify_sim_toolkit;
709 // Set text and icon for the status bar and notification body.
710 if (!msg.iconSelfExplanatory) {
711 notification.tickerText = msg.text;
712 contentView.setTextViewText(com.android.internal.R.id.text,
713 msg.text);
714 }
715 if (msg.icon != null) {
716 contentView.setImageViewBitmap(com.android.internal.R.id.icon,
717 msg.icon);
718 } else {
719 contentView
720 .setImageViewResource(
721 com.android.internal.R.id.icon,
722 com.android.internal.R.drawable.stat_notify_sim_toolkit);
723 }
724 notification.contentView = contentView;
725 notification.contentIntent = PendingIntent.getService(mContext, 0,
726 new Intent(mContext, StkAppService.class), 0);
727
728 mNotificationManager.notify(STK_NOTIFICATION_ID, notification);
729 }
730 }
731
732 private void launchToneDialog() {
733 Intent newIntent = new Intent(this, ToneDialog.class);
734 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
735 | Intent.FLAG_ACTIVITY_NO_HISTORY
736 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
737 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown));
738 newIntent.putExtra("TEXT", mCurrentCmd.geTextMessage());
739 newIntent.putExtra("TONE", mCurrentCmd.getToneSettings());
740 startActivity(newIntent);
741 }
742
743 private String getItemName(int itemId) {
744 Menu menu = mCurrentCmd.getMenu();
745 if (menu == null) {
746 return null;
747 }
748 for (Item item : menu.items) {
749 if (item.id == itemId) {
750 return item.text;
751 }
752 }
753 return null;
754 }
755
756 private boolean removeMenu() {
757 try {
Wink Saville79085fc2009-06-09 10:27:23 -0700758 if (mCurrentMenu.items.size() == 1 &&
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800759 mCurrentMenu.items.get(0) == null) {
760 return true;
761 }
762 } catch (NullPointerException e) {
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700763 CatLog.d(this, "Unable to get Menu's items size");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800764 return true;
765 }
766 return false;
767 }
768}