blob: 54698dce00ea33c5988a69f9e9bc36949ac3c3e3 [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;
Pierre Fröjd97503262010-11-08 13:59:36 +010043import com.android.internal.telephony.cat.Input;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070044import com.android.internal.telephony.cat.ResultCode;
45import com.android.internal.telephony.cat.CatCmdMessage;
46import com.android.internal.telephony.cat.CatCmdMessage.BrowserSettings;
47import com.android.internal.telephony.cat.CatLog;
48import com.android.internal.telephony.cat.CatResponseMessage;
49import com.android.internal.telephony.cat.TextMessage;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080050
51import java.util.LinkedList;
52
53/**
54 * SIM toolkit application level service. Interacts with Telephopny messages,
55 * application's launch and user input from STK UI elements.
Wink Saville79085fc2009-06-09 10:27:23 -070056 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080057 */
58public class StkAppService extends Service implements Runnable {
59
60 // members
61 private volatile Looper mServiceLooper;
62 private volatile ServiceHandler mServiceHandler;
63 private AppInterface mStkService;
64 private Context mContext = null;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070065 private CatCmdMessage mMainCmd = null;
66 private CatCmdMessage mCurrentCmd = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080067 private Menu mCurrentMenu = null;
68 private String lastSelectedItem = null;
69 private boolean mMenuIsVisibile = false;
70 private boolean responseNeeded = true;
71 private boolean mCmdInProgress = false;
72 private NotificationManager mNotificationManager = null;
73 private LinkedList<DelayedCmd> mCmdsQ = null;
74 private boolean launchBrowser = false;
75 private BrowserSettings mBrowserSettings = null;
76 static StkAppService sInstance = null;
77
78 // Used for setting FLAG_ACTIVITY_NO_USER_ACTION when
79 // creating an intent.
80 private enum InitiatedByUserAction {
81 yes, // The action was started via a user initiated action
82 unknown, // Not known for sure if user initated the action
83 }
84
85 // constants
86 static final String OPCODE = "op";
87 static final String CMD_MSG = "cmd message";
88 static final String RES_ID = "response id";
89 static final String MENU_SELECTION = "menu selection";
90 static final String INPUT = "input";
91 static final String HELP = "help";
92 static final String CONFIRMATION = "confirm";
93
94 // operations ids for different service functionality.
95 static final int OP_CMD = 1;
96 static final int OP_RESPONSE = 2;
97 static final int OP_LAUNCH_APP = 3;
98 static final int OP_END_SESSION = 4;
99 static final int OP_BOOT_COMPLETED = 5;
100 private static final int OP_DELAYED_MSG = 6;
101
102 // Response ids
103 static final int RES_ID_MENU_SELECTION = 11;
104 static final int RES_ID_INPUT = 12;
105 static final int RES_ID_CONFIRM = 13;
106 static final int RES_ID_DONE = 14;
107
108 static final int RES_ID_TIMEOUT = 20;
109 static final int RES_ID_BACKWARD = 21;
110 static final int RES_ID_END_SESSION = 22;
111 static final int RES_ID_EXIT = 23;
112
113 private static final String PACKAGE_NAME = "com.android.stk";
Wink Saville79085fc2009-06-09 10:27:23 -0700114 private static final String MENU_ACTIVITY_NAME =
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800115 PACKAGE_NAME + ".StkMenuActivity";
Wink Saville79085fc2009-06-09 10:27:23 -0700116 private static final String INPUT_ACTIVITY_NAME =
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800117 PACKAGE_NAME + ".StkInputActivity";
Wink Saville79085fc2009-06-09 10:27:23 -0700118
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800119 // Notification id used to display Idle Mode text in NotificationManager.
120 private static final int STK_NOTIFICATION_ID = 333;
Wink Saville79085fc2009-06-09 10:27:23 -0700121
122 // Inner class used for queuing telephony messages (proactive commands,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800123 // session end) while the service is busy processing a previous message.
124 private class DelayedCmd {
125 // members
126 int id;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700127 CatCmdMessage msg;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800128
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700129 DelayedCmd(int id, CatCmdMessage msg) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800130 this.id = id;
131 this.msg = msg;
132 }
133 }
134
135 @Override
136 public void onCreate() {
137 // Initialize members
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700138 mStkService = com.android.internal.telephony.cat.CatService
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800139 .getInstance();
Wink Saville36eddd52009-05-29 13:56:28 -0700140
141 // NOTE mStkService is a singleton and continues to exist even if the GSMPhone is disposed
142 // after the radio technology change from GSM to CDMA so the PHONE_TYPE_CDMA check is
143 // needed. In case of switching back from CDMA to GSM the GSMPhone constructor updates
144 // the instance. (TODO: test).
Wink Saville56469d52009-04-02 01:37:03 -0700145 if ((mStkService == null)
146 && (TelephonyManager.getDefault().getPhoneType()
147 != TelephonyManager.PHONE_TYPE_CDMA)) {
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700148 CatLog.d(this, " Unable to get Service handle");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800149 return;
150 }
151
152 mCmdsQ = new LinkedList<DelayedCmd>();
153 Thread serviceThread = new Thread(null, this, "Stk App Service");
154 serviceThread.start();
155 mContext = getBaseContext();
156 mNotificationManager = (NotificationManager) mContext
157 .getSystemService(Context.NOTIFICATION_SERVICE);
158 sInstance = this;
159 }
160
161 @Override
162 public void onStart(Intent intent, int startId) {
163 waitForLooper();
164
John Wang62acae42009-10-08 11:20:23 -0700165 // onStart() method can be passed a null intent
166 // TODO: replace onStart() with onStartCommand()
167 if (intent == null) {
168 return;
169 }
170
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800171 Bundle args = intent.getExtras();
John Wang62acae42009-10-08 11:20:23 -0700172
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800173 if (args == null) {
174 return;
175 }
176
177 Message msg = mServiceHandler.obtainMessage();
178 msg.arg1 = args.getInt(OPCODE);
179 switch(msg.arg1) {
180 case OP_CMD:
181 msg.obj = args.getParcelable(CMD_MSG);
182 break;
183 case OP_RESPONSE:
184 msg.obj = args;
185 /* falls through */
186 case OP_LAUNCH_APP:
187 case OP_END_SESSION:
188 case OP_BOOT_COMPLETED:
189 break;
190 default:
191 return;
192 }
193 mServiceHandler.sendMessage(msg);
194 }
195
196 @Override
197 public void onDestroy() {
198 waitForLooper();
199 mServiceLooper.quit();
200 }
201
202 @Override
203 public IBinder onBind(Intent intent) {
204 return null;
205 }
206
207 public void run() {
208 Looper.prepare();
209
210 mServiceLooper = Looper.myLooper();
211 mServiceHandler = new ServiceHandler();
212
213 Looper.loop();
214 }
215
216 /*
217 * Package api used by StkMenuActivity to indicate if its on the foreground.
218 */
219 void indicateMenuVisibility(boolean visibility) {
220 mMenuIsVisibile = visibility;
221 }
222
223 /*
224 * Package api used by StkMenuActivity to get its Menu parameter.
225 */
226 Menu getMenu() {
227 return mCurrentMenu;
228 }
229
230 /*
231 * Package api used by UI Activities and Dialogs to communicate directly
232 * with the service to deliver state information and parameters.
233 */
234 static StkAppService getInstance() {
235 return sInstance;
236 }
237
238 private void waitForLooper() {
239 while (mServiceHandler == null) {
240 synchronized (this) {
241 try {
242 wait(100);
243 } catch (InterruptedException e) {
244 }
245 }
246 }
247 }
248
249 private final class ServiceHandler extends Handler {
250 @Override
251 public void handleMessage(Message msg) {
252 int opcode = msg.arg1;
253
254 switch (opcode) {
255 case OP_LAUNCH_APP:
256 if (mMainCmd == null) {
257 // nothing todo when no SET UP MENU command didn't arrive.
258 return;
259 }
260 launchMenuActivity(null);
261 break;
262 case OP_CMD:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700263 CatCmdMessage cmdMsg = (CatCmdMessage) msg.obj;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800264 // There are two types of commands:
265 // 1. Interactive - user's response is required.
266 // 2. Informative - display a message, no interaction with the user.
267 //
Wink Saville79085fc2009-06-09 10:27:23 -0700268 // Informative commands can be handled immediately without any delay.
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800269 // Interactive commands can't override each other. So if a command
270 // is already in progress, we need to queue the next command until
271 // the user has responded or a timeout expired.
272 if (!isCmdInteractive(cmdMsg)) {
273 handleCmd(cmdMsg);
274 } else {
275 if (!mCmdInProgress) {
276 mCmdInProgress = true;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700277 handleCmd((CatCmdMessage) msg.obj);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800278 } else {
279 mCmdsQ.addLast(new DelayedCmd(OP_CMD,
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700280 (CatCmdMessage) msg.obj));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800281 }
282 }
283 break;
284 case OP_RESPONSE:
285 if (responseNeeded) {
286 handleCmdResponse((Bundle) msg.obj);
287 }
288 // call delayed commands if needed.
289 if (mCmdsQ.size() != 0) {
290 callDelayedMsg();
291 } else {
292 mCmdInProgress = false;
293 }
294 // reset response needed state var to its original value.
295 responseNeeded = true;
296 break;
297 case OP_END_SESSION:
298 if (!mCmdInProgress) {
299 mCmdInProgress = true;
300 handleSessionEnd();
301 } else {
302 mCmdsQ.addLast(new DelayedCmd(OP_END_SESSION, null));
303 }
304 break;
305 case OP_BOOT_COMPLETED:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700306 CatLog.d(this, "OP_BOOT_COMPLETED");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800307 if (mMainCmd == null) {
308 StkAppInstaller.unInstall(mContext);
309 }
310 break;
311 case OP_DELAYED_MSG:
312 handleDelayedCmd();
313 break;
314 }
315 }
316 }
317
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700318 private boolean isCmdInteractive(CatCmdMessage cmd) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800319 switch (cmd.getCmdType()) {
320 case SEND_DTMF:
321 case SEND_SMS:
322 case SEND_SS:
323 case SEND_USSD:
324 case SET_UP_IDLE_MODE_TEXT:
325 case SET_UP_MENU:
326 return false;
327 }
328
329 return true;
330 }
331
332 private void handleDelayedCmd() {
333 if (mCmdsQ.size() != 0) {
334 DelayedCmd cmd = mCmdsQ.poll();
335 switch (cmd.id) {
336 case OP_CMD:
337 handleCmd(cmd.msg);
338 break;
339 case OP_END_SESSION:
340 handleSessionEnd();
341 break;
342 }
343 }
344 }
345
346 private void callDelayedMsg() {
347 Message msg = mServiceHandler.obtainMessage();
348 msg.arg1 = OP_DELAYED_MSG;
349 mServiceHandler.sendMessage(msg);
350 }
351
352 private void handleSessionEnd() {
353 mCurrentCmd = mMainCmd;
354 lastSelectedItem = null;
Wink Saville79085fc2009-06-09 10:27:23 -0700355 // In case of SET UP MENU command which removed the app, don't
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800356 // update the current menu member.
357 if (mCurrentMenu != null && mMainCmd != null) {
358 mCurrentMenu = mMainCmd.getMenu();
359 }
360 if (mMenuIsVisibile) {
361 launchMenuActivity(null);
362 }
363 if (mCmdsQ.size() != 0) {
364 callDelayedMsg();
365 } else {
366 mCmdInProgress = false;
367 }
368 // In case a launch browser command was just confirmed, launch that url.
369 if (launchBrowser) {
370 launchBrowser = false;
371 launchBrowser(mBrowserSettings);
372 }
373 }
374
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700375 private void handleCmd(CatCmdMessage cmdMsg) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800376 if (cmdMsg == null) {
377 return;
378 }
379 // save local reference for state tracking.
380 mCurrentCmd = cmdMsg;
381 boolean waitForUsersResponse = true;
382
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700383 CatLog.d(this, cmdMsg.getCmdType().name());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800384 switch (cmdMsg.getCmdType()) {
385 case DISPLAY_TEXT:
386 TextMessage msg = cmdMsg.geTextMessage();
387 responseNeeded = msg.responseNeeded;
388 if (lastSelectedItem != null) {
389 msg.title = lastSelectedItem;
390 } else if (mMainCmd != null){
391 msg.title = mMainCmd.getMenu().title;
392 } else {
393 // TODO: get the carrier name from the SIM
394 msg.title = "";
395 }
396 launchTextDialog();
397 break;
398 case SELECT_ITEM:
399 mCurrentMenu = cmdMsg.getMenu();
400 launchMenuActivity(cmdMsg.getMenu());
401 break;
402 case SET_UP_MENU:
403 mMainCmd = mCurrentCmd;
404 mCurrentMenu = cmdMsg.getMenu();
405 if (removeMenu()) {
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700406 CatLog.d(this, "Uninstall App");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800407 mCurrentMenu = null;
408 StkAppInstaller.unInstall(mContext);
409 } else {
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700410 CatLog.d(this, "Install App");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800411 StkAppInstaller.install(mContext);
412 }
413 if (mMenuIsVisibile) {
414 launchMenuActivity(null);
415 }
416 break;
417 case GET_INPUT:
418 case GET_INKEY:
419 launchInputActivity();
420 break;
421 case SET_UP_IDLE_MODE_TEXT:
422 waitForUsersResponse = false;
423 launchIdleText();
424 break;
425 case SEND_DTMF:
426 case SEND_SMS:
427 case SEND_SS:
428 case SEND_USSD:
429 waitForUsersResponse = false;
430 launchEventMessage();
431 break;
432 case LAUNCH_BROWSER:
433 launchConfirmationDialog(mCurrentCmd.geTextMessage());
434 break;
435 case SET_UP_CALL:
436 launchConfirmationDialog(mCurrentCmd.getCallSettings().confirmMsg);
437 break;
438 case PLAY_TONE:
439 launchToneDialog();
440 break;
441 }
442
443 if (!waitForUsersResponse) {
444 if (mCmdsQ.size() != 0) {
445 callDelayedMsg();
446 } else {
447 mCmdInProgress = false;
448 }
449 }
450 }
451
452 private void handleCmdResponse(Bundle args) {
453 if (mCurrentCmd == null) {
454 return;
455 }
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700456 CatResponseMessage resMsg = new CatResponseMessage(mCurrentCmd);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800457
458 // set result code
459 boolean helpRequired = args.getBoolean(HELP, false);
460
461 switch(args.getInt(RES_ID)) {
462 case RES_ID_MENU_SELECTION:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700463 CatLog.d(this, "RES_ID_MENU_SELECTION");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800464 int menuSelection = args.getInt(MENU_SELECTION);
465 switch(mCurrentCmd.getCmdType()) {
466 case SET_UP_MENU:
467 case SELECT_ITEM:
468 lastSelectedItem = getItemName(menuSelection);
469 if (helpRequired) {
470 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
471 } else {
472 resMsg.setResultCode(ResultCode.OK);
473 }
474 resMsg.setMenuSelection(menuSelection);
475 break;
476 }
477 break;
478 case RES_ID_INPUT:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700479 CatLog.d(this, "RES_ID_INPUT");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800480 String input = args.getString(INPUT);
Pierre Fröjd97503262010-11-08 13:59:36 +0100481 Input cmdInput = mCurrentCmd.geInput();
482 if (cmdInput != null && cmdInput.yesNo) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800483 boolean yesNoSelection = input
484 .equals(StkInputActivity.YES_STR_RESPONSE);
485 resMsg.setYesNo(yesNoSelection);
486 } else {
487 if (helpRequired) {
488 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
489 } else {
490 resMsg.setResultCode(ResultCode.OK);
491 resMsg.setInput(input);
492 }
493 }
494 break;
495 case RES_ID_CONFIRM:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700496 CatLog.d(this, "RES_ID_CONFIRM");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800497 boolean confirmed = args.getBoolean(CONFIRMATION);
498 switch (mCurrentCmd.getCmdType()) {
499 case DISPLAY_TEXT:
500 resMsg.setResultCode(confirmed ? ResultCode.OK
501 : ResultCode.UICC_SESSION_TERM_BY_USER);
502 break;
503 case LAUNCH_BROWSER:
504 resMsg.setResultCode(confirmed ? ResultCode.OK
505 : ResultCode.UICC_SESSION_TERM_BY_USER);
506 if (confirmed) {
507 launchBrowser = true;
508 mBrowserSettings = mCurrentCmd.getBrowserSettings();
509 }
510 break;
511 case SET_UP_CALL:
512 resMsg.setResultCode(ResultCode.OK);
513 resMsg.setConfirmation(confirmed);
514 if (confirmed) {
515 launchCallMsg();
516 }
517 break;
518 }
519 break;
520 case RES_ID_DONE:
521 resMsg.setResultCode(ResultCode.OK);
522 break;
523 case RES_ID_BACKWARD:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700524 CatLog.d(this, "RES_ID_BACKWARD");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800525 resMsg.setResultCode(ResultCode.BACKWARD_MOVE_BY_USER);
526 break;
527 case RES_ID_END_SESSION:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700528 CatLog.d(this, "RES_ID_END_SESSION");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800529 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
530 break;
531 case RES_ID_TIMEOUT:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700532 CatLog.d(this, "RES_ID_TIMEOUT");
Naveen Kallad5176892009-11-30 12:45:29 -0800533 // GCF test-case 27.22.4.1.1 Expected Sequence 1.5 (DISPLAY TEXT,
534 // Clear message after delay, successful) expects result code OK.
535 // If the command qualifier specifies no user response is required
536 // then send OK instead of NO_RESPONSE_FROM_USER
537 if ((mCurrentCmd.getCmdType().value() == AppInterface.CommandType.DISPLAY_TEXT
538 .value())
539 && (mCurrentCmd.geTextMessage().userClear == false)) {
540 resMsg.setResultCode(ResultCode.OK);
541 } else {
542 resMsg.setResultCode(ResultCode.NO_RESPONSE_FROM_USER);
543 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800544 break;
545 default:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700546 CatLog.d(this, "Unknown result id");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800547 return;
548 }
549 mStkService.onCmdResponse(resMsg);
550 }
551
552 /**
553 * Returns 0 or FLAG_ACTIVITY_NO_USER_ACTION, 0 means the user initiated the action.
554 *
555 * @param userAction If the userAction is yes then we always return 0 otherwise
556 * mMenuIsVisible is used to determine what to return. If mMenuIsVisible is true
557 * then we are the foreground app and we'll return 0 as from our perspective a
558 * user action did cause. If it's false than we aren't the foreground app and
559 * FLAG_ACTIVITY_NO_USER_ACTION is returned.
Wink Saville79085fc2009-06-09 10:27:23 -0700560 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800561 * @return 0 or FLAG_ACTIVITY_NO_USER_ACTION
562 */
563 private int getFlagActivityNoUserAction(InitiatedByUserAction userAction) {
564 return ((userAction == InitiatedByUserAction.yes) | mMenuIsVisibile) ?
565 0 : Intent.FLAG_ACTIVITY_NO_USER_ACTION;
566 }
567
568 private void launchMenuActivity(Menu menu) {
569 Intent newIntent = new Intent(Intent.ACTION_VIEW);
570 newIntent.setClassName(PACKAGE_NAME, MENU_ACTIVITY_NAME);
571 int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK
572 | Intent.FLAG_ACTIVITY_CLEAR_TOP;
573 if (menu == null) {
574 // We assume this was initiated by the user pressing the tool kit icon
575 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.yes);
576
577 newIntent.putExtra("STATE", StkMenuActivity.STATE_MAIN);
578 } else {
579 // We don't know and we'll let getFlagActivityNoUserAction decide.
580 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.unknown);
581
582 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
583 }
584 newIntent.setFlags(intentFlags);
585 mContext.startActivity(newIntent);
586 }
587
588 private void launchInputActivity() {
589 Intent newIntent = new Intent(Intent.ACTION_VIEW);
590 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
591 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown));
592 newIntent.setClassName(PACKAGE_NAME, INPUT_ACTIVITY_NAME);
593 newIntent.putExtra("INPUT", mCurrentCmd.geInput());
594 mContext.startActivity(newIntent);
595 }
596
597 private void launchTextDialog() {
598 Intent newIntent = new Intent(this, StkDialogActivity.class);
599 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
600 | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
601 | Intent.FLAG_ACTIVITY_NO_HISTORY
602 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
603 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown));
604 newIntent.putExtra("TEXT", mCurrentCmd.geTextMessage());
605 startActivity(newIntent);
606 }
607
608 private void launchEventMessage() {
609 TextMessage msg = mCurrentCmd.geTextMessage();
John Josephb22e7d82009-12-15 14:53:17 -0800610 if (msg == null || msg.text == null) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800611 return;
612 }
613 Toast toast = new Toast(mContext.getApplicationContext());
614 LayoutInflater inflate = (LayoutInflater) mContext
615 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
616 View v = inflate.inflate(R.layout.stk_event_msg, null);
617 TextView tv = (TextView) v
618 .findViewById(com.android.internal.R.id.message);
619 ImageView iv = (ImageView) v
620 .findViewById(com.android.internal.R.id.icon);
621 if (msg.icon != null) {
622 iv.setImageBitmap(msg.icon);
623 } else {
624 iv.setVisibility(View.GONE);
625 }
626 if (!msg.iconSelfExplanatory) {
627 tv.setText(msg.text);
628 }
629
630 toast.setView(v);
631 toast.setDuration(Toast.LENGTH_LONG);
632 toast.setGravity(Gravity.BOTTOM, 0, 0);
633 toast.show();
634 }
635
636 private void launchConfirmationDialog(TextMessage msg) {
637 msg.title = lastSelectedItem;
638 Intent newIntent = new Intent(this, StkDialogActivity.class);
639 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
640 | Intent.FLAG_ACTIVITY_NO_HISTORY
641 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
642 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown));
643 newIntent.putExtra("TEXT", msg);
644 startActivity(newIntent);
645 }
646
647 private void launchBrowser(BrowserSettings settings) {
648 if (settings == null) {
649 return;
650 }
651 // Set browser launch mode
652 Intent intent = new Intent();
653 intent.setClassName("com.android.browser",
654 "com.android.browser.BrowserActivity");
655
Wink Saville79085fc2009-06-09 10:27:23 -0700656 // to launch home page, make sure that data Uri is null.
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800657 Uri data = null;
658 if (settings.url != null) {
dujin.cha486c1d02011-11-02 22:14:25 +0900659 CatLog.d(this, "settings.url = " + settings.url);
dujin.cha2a0eb2a2011-11-11 15:03:57 +0900660 if ((settings.url.startsWith("http://") || (settings.url.startsWith("https://")))) {
dujin.cha486c1d02011-11-02 22:14:25 +0900661 data = Uri.parse(settings.url);
662 } else {
663 String modifiedUrl = "http://" + settings.url;
664 CatLog.d(this, "modifiedUrl = " + modifiedUrl);
665 data = Uri.parse(modifiedUrl);
666 }
David Brown885adf32011-10-20 15:36:12 -0700667 } else {
668 // If no URL specified, just bring up the "home page".
669 //
670 // (Note we need to specify *something* in the intent's data field
671 // here, since if you fire off a VIEW intent with no data at all
672 // you'll get an activity chooser rather than the browser. There's
673 // no specific URI that means "use the default home page", so
674 // instead let's just explicitly bring up http://google.com.)
675 data = Uri.parse("http://google.com/");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800676 }
677 intent.setData(data);
678 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
679 switch (settings.mode) {
680 case USE_EXISTING_BROWSER:
681 intent.setAction(Intent.ACTION_VIEW);
682 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
683 break;
684 case LAUNCH_NEW_BROWSER:
685 intent.setAction(Intent.ACTION_VIEW);
686 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
687 break;
688 case LAUNCH_IF_NOT_ALREADY_LAUNCHED:
689 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
690 break;
691 }
692 // start browser activity
693 startActivity(intent);
694 // a small delay, let the browser start, before processing the next command.
Wink Saville79085fc2009-06-09 10:27:23 -0700695 // this is good for scenarios where a related DISPLAY TEXT command is
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800696 // followed immediately.
697 try {
698 Thread.sleep(10000);
699 } catch (InterruptedException e) {}
700 }
701
702 private void launchCallMsg() {
703 TextMessage msg = mCurrentCmd.getCallSettings().callMsg;
704 if (msg.text == null || msg.text.length() == 0) {
705 return;
706 }
707 msg.title = lastSelectedItem;
708
709 Toast toast = Toast.makeText(mContext.getApplicationContext(), msg.text,
710 Toast.LENGTH_LONG);
711 toast.setGravity(Gravity.BOTTOM, 0, 0);
712 toast.show();
713 }
714
715 private void launchIdleText() {
716 TextMessage msg = mCurrentCmd.geTextMessage();
dujin.cha2a0eb2a2011-11-11 15:03:57 +0900717
Wink Saville046db4b2011-11-01 20:42:54 -0700718 if (msg == null) {
dujin.cha2a0eb2a2011-11-11 15:03:57 +0900719 CatLog.d(this, "mCurrent.getTextMessage is NULL");
720 mNotificationManager.cancel(STK_NOTIFICATION_ID);
Wink Saville046db4b2011-11-01 20:42:54 -0700721 return;
722 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800723 if (msg.text == null) {
724 mNotificationManager.cancel(STK_NOTIFICATION_ID);
725 } else {
726 Notification notification = new Notification();
727 RemoteViews contentView = new RemoteViews(
728 PACKAGE_NAME,
729 com.android.internal.R.layout.status_bar_latest_event_content);
730
731 notification.flags |= Notification.FLAG_NO_CLEAR;
732 notification.icon = com.android.internal.R.drawable.stat_notify_sim_toolkit;
733 // Set text and icon for the status bar and notification body.
734 if (!msg.iconSelfExplanatory) {
735 notification.tickerText = msg.text;
736 contentView.setTextViewText(com.android.internal.R.id.text,
737 msg.text);
738 }
739 if (msg.icon != null) {
740 contentView.setImageViewBitmap(com.android.internal.R.id.icon,
741 msg.icon);
742 } else {
743 contentView
744 .setImageViewResource(
745 com.android.internal.R.id.icon,
746 com.android.internal.R.drawable.stat_notify_sim_toolkit);
747 }
748 notification.contentView = contentView;
749 notification.contentIntent = PendingIntent.getService(mContext, 0,
750 new Intent(mContext, StkAppService.class), 0);
751
752 mNotificationManager.notify(STK_NOTIFICATION_ID, notification);
753 }
754 }
755
756 private void launchToneDialog() {
757 Intent newIntent = new Intent(this, ToneDialog.class);
758 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
759 | Intent.FLAG_ACTIVITY_NO_HISTORY
760 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
761 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown));
762 newIntent.putExtra("TEXT", mCurrentCmd.geTextMessage());
763 newIntent.putExtra("TONE", mCurrentCmd.getToneSettings());
764 startActivity(newIntent);
765 }
766
767 private String getItemName(int itemId) {
768 Menu menu = mCurrentCmd.getMenu();
769 if (menu == null) {
770 return null;
771 }
772 for (Item item : menu.items) {
773 if (item.id == itemId) {
774 return item.text;
775 }
776 }
777 return null;
778 }
779
780 private boolean removeMenu() {
781 try {
Wink Saville79085fc2009-06-09 10:27:23 -0700782 if (mCurrentMenu.items.size() == 1 &&
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800783 mCurrentMenu.items.get(0) == null) {
784 return true;
785 }
786 } catch (NullPointerException e) {
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700787 CatLog.d(this, "Unable to get Menu's items size");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800788 return true;
789 }
790 return false;
791 }
792}