blob: fae072dac31b2b83c1b7aaacc18ed9b3b8cb0e60 [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
40import com.android.internal.telephony.gsm.stk.AppInterface;
41import com.android.internal.telephony.gsm.stk.Menu;
42import com.android.internal.telephony.gsm.stk.Item;
43import com.android.internal.telephony.gsm.stk.ResultCode;
44import com.android.internal.telephony.gsm.stk.StkCmdMessage;
45import com.android.internal.telephony.gsm.stk.StkCmdMessage.BrowserSettings;
46import com.android.internal.telephony.gsm.stk.StkLog;
47import com.android.internal.telephony.gsm.stk.StkResponseMessage;
48import com.android.internal.telephony.gsm.stk.TextMessage;
49
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.
55 *
56 */
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;
64 private StkCmdMessage mMainCmd = null;
65 private StkCmdMessage mCurrentCmd = null;
66 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";
113 private static final String MENU_ACTIVITY_NAME =
114 PACKAGE_NAME + ".StkMenuActivity";
115 private static final String INPUT_ACTIVITY_NAME =
116 PACKAGE_NAME + ".StkInputActivity";
117
118 // Notification id used to display Idle Mode text in NotificationManager.
119 private static final int STK_NOTIFICATION_ID = 333;
120
121 // Inner class used for queuing telephony messages (proactive commands,
122 // session end) while the service is busy processing a previous message.
123 private class DelayedCmd {
124 // members
125 int id;
126 StkCmdMessage msg;
127
128 DelayedCmd(int id, StkCmdMessage msg) {
129 this.id = id;
130 this.msg = msg;
131 }
132 }
133
134 @Override
135 public void onCreate() {
136 // Initialize members
137 mStkService = com.android.internal.telephony.gsm.stk.StkService
138 .getInstance();
Wink Saville56469d52009-04-02 01:37:03 -0700139
140 // WINK:TODO: Teleca, the test for PHONE_TYPE_CDMA is needed so the
141 // application will boot. This is probably a bug in
142 // and Wink has been assigned a bug to investigate.
143 //
144 if ((mStkService == null)
145 && (TelephonyManager.getDefault().getPhoneType()
146 != TelephonyManager.PHONE_TYPE_CDMA)) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800147 StkLog.d(this, " Unable to get Service handle");
148 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
164 Bundle args = intent.getExtras();
165 if (args == null) {
166 return;
167 }
168
169 Message msg = mServiceHandler.obtainMessage();
170 msg.arg1 = args.getInt(OPCODE);
171 switch(msg.arg1) {
172 case OP_CMD:
173 msg.obj = args.getParcelable(CMD_MSG);
174 break;
175 case OP_RESPONSE:
176 msg.obj = args;
177 /* falls through */
178 case OP_LAUNCH_APP:
179 case OP_END_SESSION:
180 case OP_BOOT_COMPLETED:
181 break;
182 default:
183 return;
184 }
185 mServiceHandler.sendMessage(msg);
186 }
187
188 @Override
189 public void onDestroy() {
190 waitForLooper();
191 mServiceLooper.quit();
192 }
193
194 @Override
195 public IBinder onBind(Intent intent) {
196 return null;
197 }
198
199 public void run() {
200 Looper.prepare();
201
202 mServiceLooper = Looper.myLooper();
203 mServiceHandler = new ServiceHandler();
204
205 Looper.loop();
206 }
207
208 /*
209 * Package api used by StkMenuActivity to indicate if its on the foreground.
210 */
211 void indicateMenuVisibility(boolean visibility) {
212 mMenuIsVisibile = visibility;
213 }
214
215 /*
216 * Package api used by StkMenuActivity to get its Menu parameter.
217 */
218 Menu getMenu() {
219 return mCurrentMenu;
220 }
221
222 /*
223 * Package api used by UI Activities and Dialogs to communicate directly
224 * with the service to deliver state information and parameters.
225 */
226 static StkAppService getInstance() {
227 return sInstance;
228 }
229
230 private void waitForLooper() {
231 while (mServiceHandler == null) {
232 synchronized (this) {
233 try {
234 wait(100);
235 } catch (InterruptedException e) {
236 }
237 }
238 }
239 }
240
241 private final class ServiceHandler extends Handler {
242 @Override
243 public void handleMessage(Message msg) {
244 int opcode = msg.arg1;
245
246 switch (opcode) {
247 case OP_LAUNCH_APP:
248 if (mMainCmd == null) {
249 // nothing todo when no SET UP MENU command didn't arrive.
250 return;
251 }
252 launchMenuActivity(null);
253 break;
254 case OP_CMD:
255 StkCmdMessage cmdMsg = (StkCmdMessage) msg.obj;
256 // There are two types of commands:
257 // 1. Interactive - user's response is required.
258 // 2. Informative - display a message, no interaction with the user.
259 //
260 // Informative commands can be handled immediately without any delay.
261 // Interactive commands can't override each other. So if a command
262 // is already in progress, we need to queue the next command until
263 // the user has responded or a timeout expired.
264 if (!isCmdInteractive(cmdMsg)) {
265 handleCmd(cmdMsg);
266 } else {
267 if (!mCmdInProgress) {
268 mCmdInProgress = true;
269 handleCmd((StkCmdMessage) msg.obj);
270 } else {
271 mCmdsQ.addLast(new DelayedCmd(OP_CMD,
272 (StkCmdMessage) msg.obj));
273 }
274 }
275 break;
276 case OP_RESPONSE:
277 if (responseNeeded) {
278 handleCmdResponse((Bundle) msg.obj);
279 }
280 // call delayed commands if needed.
281 if (mCmdsQ.size() != 0) {
282 callDelayedMsg();
283 } else {
284 mCmdInProgress = false;
285 }
286 // reset response needed state var to its original value.
287 responseNeeded = true;
288 break;
289 case OP_END_SESSION:
290 if (!mCmdInProgress) {
291 mCmdInProgress = true;
292 handleSessionEnd();
293 } else {
294 mCmdsQ.addLast(new DelayedCmd(OP_END_SESSION, null));
295 }
296 break;
297 case OP_BOOT_COMPLETED:
298 StkLog.d(this, "OP_BOOT_COMPLETED");
299 if (mMainCmd == null) {
300 StkAppInstaller.unInstall(mContext);
301 }
302 break;
303 case OP_DELAYED_MSG:
304 handleDelayedCmd();
305 break;
306 }
307 }
308 }
309
310 private boolean isCmdInteractive(StkCmdMessage cmd) {
311 switch (cmd.getCmdType()) {
312 case SEND_DTMF:
313 case SEND_SMS:
314 case SEND_SS:
315 case SEND_USSD:
316 case SET_UP_IDLE_MODE_TEXT:
317 case SET_UP_MENU:
318 return false;
319 }
320
321 return true;
322 }
323
324 private void handleDelayedCmd() {
325 if (mCmdsQ.size() != 0) {
326 DelayedCmd cmd = mCmdsQ.poll();
327 switch (cmd.id) {
328 case OP_CMD:
329 handleCmd(cmd.msg);
330 break;
331 case OP_END_SESSION:
332 handleSessionEnd();
333 break;
334 }
335 }
336 }
337
338 private void callDelayedMsg() {
339 Message msg = mServiceHandler.obtainMessage();
340 msg.arg1 = OP_DELAYED_MSG;
341 mServiceHandler.sendMessage(msg);
342 }
343
344 private void handleSessionEnd() {
345 mCurrentCmd = mMainCmd;
346 lastSelectedItem = null;
347 // In case of SET UP MENU command which removed the app, don't
348 // update the current menu member.
349 if (mCurrentMenu != null && mMainCmd != null) {
350 mCurrentMenu = mMainCmd.getMenu();
351 }
352 if (mMenuIsVisibile) {
353 launchMenuActivity(null);
354 }
355 if (mCmdsQ.size() != 0) {
356 callDelayedMsg();
357 } else {
358 mCmdInProgress = false;
359 }
360 // In case a launch browser command was just confirmed, launch that url.
361 if (launchBrowser) {
362 launchBrowser = false;
363 launchBrowser(mBrowserSettings);
364 }
365 }
366
367 private void handleCmd(StkCmdMessage cmdMsg) {
368 if (cmdMsg == null) {
369 return;
370 }
371 // save local reference for state tracking.
372 mCurrentCmd = cmdMsg;
373 boolean waitForUsersResponse = true;
374
375 StkLog.d(this, cmdMsg.getCmdType().name());
376 switch (cmdMsg.getCmdType()) {
377 case DISPLAY_TEXT:
378 TextMessage msg = cmdMsg.geTextMessage();
379 responseNeeded = msg.responseNeeded;
380 if (lastSelectedItem != null) {
381 msg.title = lastSelectedItem;
382 } else if (mMainCmd != null){
383 msg.title = mMainCmd.getMenu().title;
384 } else {
385 // TODO: get the carrier name from the SIM
386 msg.title = "";
387 }
388 launchTextDialog();
389 break;
390 case SELECT_ITEM:
391 mCurrentMenu = cmdMsg.getMenu();
392 launchMenuActivity(cmdMsg.getMenu());
393 break;
394 case SET_UP_MENU:
395 mMainCmd = mCurrentCmd;
396 mCurrentMenu = cmdMsg.getMenu();
397 if (removeMenu()) {
398 StkLog.d(this, "Uninstall App");
399 mCurrentMenu = null;
400 StkAppInstaller.unInstall(mContext);
401 } else {
402 StkLog.d(this, "Install App");
403 StkAppInstaller.install(mContext);
404 }
405 if (mMenuIsVisibile) {
406 launchMenuActivity(null);
407 }
408 break;
409 case GET_INPUT:
410 case GET_INKEY:
411 launchInputActivity();
412 break;
413 case SET_UP_IDLE_MODE_TEXT:
414 waitForUsersResponse = false;
415 launchIdleText();
416 break;
417 case SEND_DTMF:
418 case SEND_SMS:
419 case SEND_SS:
420 case SEND_USSD:
421 waitForUsersResponse = false;
422 launchEventMessage();
423 break;
424 case LAUNCH_BROWSER:
425 launchConfirmationDialog(mCurrentCmd.geTextMessage());
426 break;
427 case SET_UP_CALL:
428 launchConfirmationDialog(mCurrentCmd.getCallSettings().confirmMsg);
429 break;
430 case PLAY_TONE:
431 launchToneDialog();
432 break;
433 }
434
435 if (!waitForUsersResponse) {
436 if (mCmdsQ.size() != 0) {
437 callDelayedMsg();
438 } else {
439 mCmdInProgress = false;
440 }
441 }
442 }
443
444 private void handleCmdResponse(Bundle args) {
445 if (mCurrentCmd == null) {
446 return;
447 }
448 StkResponseMessage resMsg = new StkResponseMessage(mCurrentCmd);
449
450 // set result code
451 boolean helpRequired = args.getBoolean(HELP, false);
452
453 switch(args.getInt(RES_ID)) {
454 case RES_ID_MENU_SELECTION:
455 StkLog.d(this, "RES_ID_MENU_SELECTION");
456 int menuSelection = args.getInt(MENU_SELECTION);
457 switch(mCurrentCmd.getCmdType()) {
458 case SET_UP_MENU:
459 case SELECT_ITEM:
460 lastSelectedItem = getItemName(menuSelection);
461 if (helpRequired) {
462 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
463 } else {
464 resMsg.setResultCode(ResultCode.OK);
465 }
466 resMsg.setMenuSelection(menuSelection);
467 break;
468 }
469 break;
470 case RES_ID_INPUT:
471 StkLog.d(this, "RES_ID_INPUT");
472 String input = args.getString(INPUT);
473 if (mCurrentCmd.geInput().yesNo) {
474 boolean yesNoSelection = input
475 .equals(StkInputActivity.YES_STR_RESPONSE);
476 resMsg.setYesNo(yesNoSelection);
477 } else {
478 if (helpRequired) {
479 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
480 } else {
481 resMsg.setResultCode(ResultCode.OK);
482 resMsg.setInput(input);
483 }
484 }
485 break;
486 case RES_ID_CONFIRM:
487 StkLog.d(this, "RES_ID_CONFIRM");
488 boolean confirmed = args.getBoolean(CONFIRMATION);
489 switch (mCurrentCmd.getCmdType()) {
490 case DISPLAY_TEXT:
491 resMsg.setResultCode(confirmed ? ResultCode.OK
492 : ResultCode.UICC_SESSION_TERM_BY_USER);
493 break;
494 case LAUNCH_BROWSER:
495 resMsg.setResultCode(confirmed ? ResultCode.OK
496 : ResultCode.UICC_SESSION_TERM_BY_USER);
497 if (confirmed) {
498 launchBrowser = true;
499 mBrowserSettings = mCurrentCmd.getBrowserSettings();
500 }
501 break;
502 case SET_UP_CALL:
503 resMsg.setResultCode(ResultCode.OK);
504 resMsg.setConfirmation(confirmed);
505 if (confirmed) {
506 launchCallMsg();
507 }
508 break;
509 }
510 break;
511 case RES_ID_DONE:
512 resMsg.setResultCode(ResultCode.OK);
513 break;
514 case RES_ID_BACKWARD:
515 StkLog.d(this, "RES_ID_BACKWARD");
516 resMsg.setResultCode(ResultCode.BACKWARD_MOVE_BY_USER);
517 break;
518 case RES_ID_END_SESSION:
519 StkLog.d(this, "RES_ID_END_SESSION");
520 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
521 break;
522 case RES_ID_TIMEOUT:
523 StkLog.d(this, "RES_ID_TIMEOUT");
524 resMsg.setResultCode(ResultCode.NO_RESPONSE_FROM_USER);
525 break;
526 default:
527 StkLog.d(this, "Unknown result id");
528 return;
529 }
530 mStkService.onCmdResponse(resMsg);
531 }
532
533 /**
534 * Returns 0 or FLAG_ACTIVITY_NO_USER_ACTION, 0 means the user initiated the action.
535 *
536 * @param userAction If the userAction is yes then we always return 0 otherwise
537 * mMenuIsVisible is used to determine what to return. If mMenuIsVisible is true
538 * then we are the foreground app and we'll return 0 as from our perspective a
539 * user action did cause. If it's false than we aren't the foreground app and
540 * FLAG_ACTIVITY_NO_USER_ACTION is returned.
541 *
542 * @return 0 or FLAG_ACTIVITY_NO_USER_ACTION
543 */
544 private int getFlagActivityNoUserAction(InitiatedByUserAction userAction) {
545 return ((userAction == InitiatedByUserAction.yes) | mMenuIsVisibile) ?
546 0 : Intent.FLAG_ACTIVITY_NO_USER_ACTION;
547 }
548
549 private void launchMenuActivity(Menu menu) {
550 Intent newIntent = new Intent(Intent.ACTION_VIEW);
551 newIntent.setClassName(PACKAGE_NAME, MENU_ACTIVITY_NAME);
552 int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK
553 | Intent.FLAG_ACTIVITY_CLEAR_TOP;
554 if (menu == null) {
555 // We assume this was initiated by the user pressing the tool kit icon
556 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.yes);
557
558 newIntent.putExtra("STATE", StkMenuActivity.STATE_MAIN);
559 } else {
560 // We don't know and we'll let getFlagActivityNoUserAction decide.
561 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.unknown);
562
563 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
564 }
565 newIntent.setFlags(intentFlags);
566 mContext.startActivity(newIntent);
567 }
568
569 private void launchInputActivity() {
570 Intent newIntent = new Intent(Intent.ACTION_VIEW);
571 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
572 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown));
573 newIntent.setClassName(PACKAGE_NAME, INPUT_ACTIVITY_NAME);
574 newIntent.putExtra("INPUT", mCurrentCmd.geInput());
575 mContext.startActivity(newIntent);
576 }
577
578 private void launchTextDialog() {
579 Intent newIntent = new Intent(this, StkDialogActivity.class);
580 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
581 | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
582 | Intent.FLAG_ACTIVITY_NO_HISTORY
583 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
584 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown));
585 newIntent.putExtra("TEXT", mCurrentCmd.geTextMessage());
586 startActivity(newIntent);
587 }
588
589 private void launchEventMessage() {
590 TextMessage msg = mCurrentCmd.geTextMessage();
591 if (msg == null) {
592 return;
593 }
594 Toast toast = new Toast(mContext.getApplicationContext());
595 LayoutInflater inflate = (LayoutInflater) mContext
596 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
597 View v = inflate.inflate(R.layout.stk_event_msg, null);
598 TextView tv = (TextView) v
599 .findViewById(com.android.internal.R.id.message);
600 ImageView iv = (ImageView) v
601 .findViewById(com.android.internal.R.id.icon);
602 if (msg.icon != null) {
603 iv.setImageBitmap(msg.icon);
604 } else {
605 iv.setVisibility(View.GONE);
606 }
607 if (!msg.iconSelfExplanatory) {
608 tv.setText(msg.text);
609 }
610
611 toast.setView(v);
612 toast.setDuration(Toast.LENGTH_LONG);
613 toast.setGravity(Gravity.BOTTOM, 0, 0);
614 toast.show();
615 }
616
617 private void launchConfirmationDialog(TextMessage msg) {
618 msg.title = lastSelectedItem;
619 Intent newIntent = new Intent(this, StkDialogActivity.class);
620 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
621 | Intent.FLAG_ACTIVITY_NO_HISTORY
622 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
623 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown));
624 newIntent.putExtra("TEXT", msg);
625 startActivity(newIntent);
626 }
627
628 private void launchBrowser(BrowserSettings settings) {
629 if (settings == null) {
630 return;
631 }
632 // Set browser launch mode
633 Intent intent = new Intent();
634 intent.setClassName("com.android.browser",
635 "com.android.browser.BrowserActivity");
636
637 // to launch home page, make sure that data Uri is null.
638 Uri data = null;
639 if (settings.url != null) {
640 data = Uri.parse(settings.url);
641 }
642 intent.setData(data);
643 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
644 switch (settings.mode) {
645 case USE_EXISTING_BROWSER:
646 intent.setAction(Intent.ACTION_VIEW);
647 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
648 break;
649 case LAUNCH_NEW_BROWSER:
650 intent.setAction(Intent.ACTION_VIEW);
651 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
652 break;
653 case LAUNCH_IF_NOT_ALREADY_LAUNCHED:
654 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
655 break;
656 }
657 // start browser activity
658 startActivity(intent);
659 // a small delay, let the browser start, before processing the next command.
660 // this is good for scenarios where a related DISPLAY TEXT command is
661 // followed immediately.
662 try {
663 Thread.sleep(10000);
664 } catch (InterruptedException e) {}
665 }
666
667 private void launchCallMsg() {
668 TextMessage msg = mCurrentCmd.getCallSettings().callMsg;
669 if (msg.text == null || msg.text.length() == 0) {
670 return;
671 }
672 msg.title = lastSelectedItem;
673
674 Toast toast = Toast.makeText(mContext.getApplicationContext(), msg.text,
675 Toast.LENGTH_LONG);
676 toast.setGravity(Gravity.BOTTOM, 0, 0);
677 toast.show();
678 }
679
680 private void launchIdleText() {
681 TextMessage msg = mCurrentCmd.geTextMessage();
682 if (msg.text == null) {
683 mNotificationManager.cancel(STK_NOTIFICATION_ID);
684 } else {
685 Notification notification = new Notification();
686 RemoteViews contentView = new RemoteViews(
687 PACKAGE_NAME,
688 com.android.internal.R.layout.status_bar_latest_event_content);
689
690 notification.flags |= Notification.FLAG_NO_CLEAR;
691 notification.icon = com.android.internal.R.drawable.stat_notify_sim_toolkit;
692 // Set text and icon for the status bar and notification body.
693 if (!msg.iconSelfExplanatory) {
694 notification.tickerText = msg.text;
695 contentView.setTextViewText(com.android.internal.R.id.text,
696 msg.text);
697 }
698 if (msg.icon != null) {
699 contentView.setImageViewBitmap(com.android.internal.R.id.icon,
700 msg.icon);
701 } else {
702 contentView
703 .setImageViewResource(
704 com.android.internal.R.id.icon,
705 com.android.internal.R.drawable.stat_notify_sim_toolkit);
706 }
707 notification.contentView = contentView;
708 notification.contentIntent = PendingIntent.getService(mContext, 0,
709 new Intent(mContext, StkAppService.class), 0);
710
711 mNotificationManager.notify(STK_NOTIFICATION_ID, notification);
712 }
713 }
714
715 private void launchToneDialog() {
716 Intent newIntent = new Intent(this, ToneDialog.class);
717 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
718 | Intent.FLAG_ACTIVITY_NO_HISTORY
719 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
720 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown));
721 newIntent.putExtra("TEXT", mCurrentCmd.geTextMessage());
722 newIntent.putExtra("TONE", mCurrentCmd.getToneSettings());
723 startActivity(newIntent);
724 }
725
726 private String getItemName(int itemId) {
727 Menu menu = mCurrentCmd.getMenu();
728 if (menu == null) {
729 return null;
730 }
731 for (Item item : menu.items) {
732 if (item.id == itemId) {
733 return item.text;
734 }
735 }
736 return null;
737 }
738
739 private boolean removeMenu() {
740 try {
741 if (mCurrentMenu.items.size() == 1 &&
742 mCurrentMenu.items.get(0) == null) {
743 return true;
744 }
745 } catch (NullPointerException e) {
746 StkLog.d(this, "Unable to get Menu's items size");
747 return true;
748 }
749 return false;
750 }
751}
Wink Saville56469d52009-04-02 01:37:03 -0700752