1/* 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.ActivityManager; 20import android.app.ActivityManager.RunningTaskInfo; 21import android.app.AlertDialog; 22import android.app.Notification; 23import android.app.NotificationManager; 24import android.app.PendingIntent; 25import android.app.Service; 26import android.app.Activity; 27import android.app.ActivityManager; 28import android.app.ActivityManager.RecentTaskInfo; 29import android.app.ActivityManager.RunningAppProcessInfo; 30import android.content.ComponentName; 31import android.content.Context; 32import android.content.DialogInterface; 33import android.content.Intent; 34import android.content.res.Configuration; 35import android.graphics.Bitmap; 36import android.graphics.BitmapFactory; 37import android.net.Uri; 38import android.os.Bundle; 39import android.os.Handler; 40import android.os.IBinder; 41import android.os.Looper; 42import android.os.Message; 43import android.os.PowerManager; 44import android.os.SystemProperties; 45import android.provider.Settings; 46import android.telephony.TelephonyManager; 47import android.text.TextUtils; 48import android.view.Gravity; 49import android.view.LayoutInflater; 50import android.view.View; 51import android.view.Window; 52import android.view.WindowManager; 53import android.widget.ImageView; 54import android.widget.RemoteViews; 55import android.widget.TextView; 56import android.widget.Toast; 57import android.content.BroadcastReceiver; 58import android.content.IntentFilter; 59import android.content.pm.ApplicationInfo; 60import android.content.pm.PackageManager.NameNotFoundException; 61 62import com.android.internal.telephony.cat.AppInterface; 63import com.android.internal.telephony.cat.LaunchBrowserMode; 64import com.android.internal.telephony.cat.Menu; 65import com.android.internal.telephony.cat.Item; 66import com.android.internal.telephony.cat.Input; 67import com.android.internal.telephony.cat.ResultCode; 68import com.android.internal.telephony.cat.CatCmdMessage; 69import com.android.internal.telephony.cat.CatCmdMessage.BrowserSettings; 70import com.android.internal.telephony.cat.CatCmdMessage.SetupEventListSettings; 71import com.android.internal.telephony.cat.CatLog; 72import com.android.internal.telephony.cat.CatResponseMessage; 73import com.android.internal.telephony.cat.TextMessage; 74import com.android.internal.telephony.uicc.IccRefreshResponse; 75import com.android.internal.telephony.uicc.IccCardStatus.CardState; 76import com.android.internal.telephony.PhoneConstants; 77import com.android.internal.telephony.TelephonyIntents; 78import com.android.internal.telephony.IccCardConstants; 79import com.android.internal.telephony.uicc.UiccController; 80import com.android.internal.telephony.GsmAlphabet; 81import com.android.internal.telephony.cat.CatService; 82 83import java.util.Iterator; 84import java.util.LinkedList; 85import java.lang.System; 86import java.util.List; 87 88import static com.android.internal.telephony.cat.CatCmdMessage. 89 SetupEventListConstants.IDLE_SCREEN_AVAILABLE_EVENT; 90import static com.android.internal.telephony.cat.CatCmdMessage. 91 SetupEventListConstants.LANGUAGE_SELECTION_EVENT; 92 93/** 94 * SIM toolkit application level service. Interacts with Telephopny messages, 95 * application's launch and user input from STK UI elements. 96 * 97 */ 98public class StkAppService extends Service implements Runnable { 99 100 // members 101 protected class StkContext { 102 protected CatCmdMessage mMainCmd = null; 103 protected CatCmdMessage mCurrentCmd = null; 104 protected CatCmdMessage mCurrentMenuCmd = null; 105 protected Menu mCurrentMenu = null; 106 protected String lastSelectedItem = null; 107 protected boolean mMenuIsVisible = false; 108 protected boolean mIsInputPending = false; 109 protected boolean mIsMenuPending = false; 110 protected boolean mIsDialogPending = false; 111 protected boolean responseNeeded = true; 112 protected boolean launchBrowser = false; 113 protected BrowserSettings mBrowserSettings = null; 114 protected LinkedList<DelayedCmd> mCmdsQ = null; 115 protected boolean mCmdInProgress = false; 116 protected int mStkServiceState = STATE_UNKNOWN; 117 protected int mSetupMenuState = STATE_UNKNOWN; 118 protected int mMenuState = StkMenuActivity.STATE_INIT; 119 protected int mOpCode = -1; 120 private Activity mActivityInstance = null; 121 private Activity mDialogInstance = null; 122 private Activity mMainActivityInstance = null; 123 private int mSlotId = 0; 124 private SetupEventListSettings mSetupEventListSettings = null; 125 private boolean mClearSelectItem = false; 126 private boolean mDisplayTextDlgIsVisibile = false; 127 private CatCmdMessage mCurrentSetupEventCmd = null; 128 private CatCmdMessage mIdleModeTextCmd = null; 129 final synchronized void setPendingActivityInstance(Activity act) { 130 CatLog.d(this, "setPendingActivityInstance act : " + mSlotId + ", " + act); 131 callSetActivityInstMsg(OP_SET_ACT_INST, mSlotId, act); 132 } 133 final synchronized Activity getPendingActivityInstance() { 134 CatLog.d(this, "getPendingActivityInstance act : " + mSlotId + ", " + 135 mActivityInstance); 136 return mActivityInstance; 137 } 138 final synchronized void setPendingDialogInstance(Activity act) { 139 CatLog.d(this, "setPendingDialogInstance act : " + mSlotId + ", " + act); 140 callSetActivityInstMsg(OP_SET_DAL_INST, mSlotId, act); 141 } 142 final synchronized Activity getPendingDialogInstance() { 143 CatLog.d(this, "getPendingDialogInstance act : " + mSlotId + ", " + 144 mDialogInstance); 145 return mDialogInstance; 146 } 147 final synchronized void setMainActivityInstance(Activity act) { 148 CatLog.d(this, "setMainActivityInstance act : " + mSlotId + ", " + act); 149 callSetActivityInstMsg(OP_SET_MAINACT_INST, mSlotId, act); 150 } 151 final synchronized Activity getMainActivityInstance() { 152 CatLog.d(this, "getMainActivityInstance act : " + mSlotId + ", " + 153 mMainActivityInstance); 154 return mMainActivityInstance; 155 } 156 } 157 158 private volatile Looper mServiceLooper; 159 private volatile ServiceHandler mServiceHandler; 160 private Context mContext = null; 161 private NotificationManager mNotificationManager = null; 162 static StkAppService sInstance = null; 163 private AppInterface[] mStkService = null; 164 private StkContext[] mStkContext = null; 165 private int mSimCount = 0; 166 private PowerManager mPowerManager = null; 167 private StkCmdReceiver mStkCmdReceiver = null; 168 169 // Used for setting FLAG_ACTIVITY_NO_USER_ACTION when 170 // creating an intent. 171 private enum InitiatedByUserAction { 172 yes, // The action was started via a user initiated action 173 unknown, // Not known for sure if user initated the action 174 } 175 176 // constants 177 static final String OPCODE = "op"; 178 static final String CMD_MSG = "cmd message"; 179 static final String RES_ID = "response id"; 180 static final String MENU_SELECTION = "menu selection"; 181 static final String INPUT = "input"; 182 static final String HELP = "help"; 183 static final String CONFIRMATION = "confirm"; 184 static final String CHOICE = "choice"; 185 static final String SLOT_ID = "SLOT_ID"; 186 static final String STK_CMD = "STK CMD"; 187 static final String STK_DIALOG_URI = "stk://com.android.stk/dialog/"; 188 static final String STK_MENU_URI = "stk://com.android.stk/menu/"; 189 static final String STK_INPUT_URI = "stk://com.android.stk/input/"; 190 static final String STK_TONE_URI = "stk://com.android.stk/tone/"; 191 192 // These below constants are used for SETUP_EVENT_LIST 193 static final String SETUP_EVENT_TYPE = "event"; 194 static final String SETUP_EVENT_CAUSE = "cause"; 195 196 // operations ids for different service functionality. 197 static final int OP_CMD = 1; 198 static final int OP_RESPONSE = 2; 199 static final int OP_LAUNCH_APP = 3; 200 static final int OP_END_SESSION = 4; 201 static final int OP_BOOT_COMPLETED = 5; 202 private static final int OP_DELAYED_MSG = 6; 203 static final int OP_CARD_STATUS_CHANGED = 7; 204 static final int OP_SET_ACT_INST = 8; 205 static final int OP_SET_DAL_INST = 9; 206 static final int OP_SET_MAINACT_INST = 10; 207 static final int OP_LOCALE_CHANGED = 11; 208 static final int OP_ALPHA_NOTIFY = 12; 209 static final int OP_IDLE_SCREEN = 13; 210 211 //Invalid SetupEvent 212 static final int INVALID_SETUP_EVENT = 0xFF; 213 214 // Response ids 215 static final int RES_ID_MENU_SELECTION = 11; 216 static final int RES_ID_INPUT = 12; 217 static final int RES_ID_CONFIRM = 13; 218 static final int RES_ID_DONE = 14; 219 static final int RES_ID_CHOICE = 15; 220 221 static final int RES_ID_TIMEOUT = 20; 222 static final int RES_ID_BACKWARD = 21; 223 static final int RES_ID_END_SESSION = 22; 224 static final int RES_ID_EXIT = 23; 225 226 static final int YES = 1; 227 static final int NO = 0; 228 229 static final int STATE_UNKNOWN = -1; 230 static final int STATE_NOT_EXIST = 0; 231 static final int STATE_EXIST = 1; 232 233 private static final String PACKAGE_NAME = "com.android.stk"; 234 private static final String STK_MENU_ACTIVITY_NAME = PACKAGE_NAME + ".StkMenuActivity"; 235 private static final String STK_INPUT_ACTIVITY_NAME = PACKAGE_NAME + ".StkInputActivity"; 236 private static final String STK_DIALOG_ACTIVITY_NAME = PACKAGE_NAME + ".StkDialogActivity"; 237 // Notification id used to display Idle Mode text in NotificationManager. 238 private static final int STK_NOTIFICATION_ID = 333; 239 private static final String LOG_TAG = new Object(){}.getClass().getEnclosingClass().getName(); 240 241 // Inner class used for queuing telephony messages (proactive commands, 242 // session end) while the service is busy processing a previous message. 243 private class DelayedCmd { 244 // members 245 int id; 246 CatCmdMessage msg; 247 int slotId; 248 249 DelayedCmd(int id, CatCmdMessage msg, int slotId) { 250 this.id = id; 251 this.msg = msg; 252 this.slotId = slotId; 253 } 254 } 255 256 // system property to set the STK specific default url for launch browser proactive cmds 257 private static final String STK_BROWSER_DEFAULT_URL_SYSPROP = "persist.radio.stk.default_url"; 258 259 @Override 260 public void onCreate() { 261 CatLog.d(LOG_TAG, "onCreate()+"); 262 // Initialize members 263 int i = 0; 264 mContext = getBaseContext(); 265 mSimCount = TelephonyManager.from(mContext).getSimCount(); 266 CatLog.d(LOG_TAG, "simCount: " + mSimCount); 267 mStkService = new AppInterface[mSimCount]; 268 mStkContext = new StkContext[mSimCount]; 269 mPowerManager = (PowerManager)getSystemService(Context.POWER_SERVICE); 270 mStkCmdReceiver = new StkCmdReceiver(); 271 registerReceiver(mStkCmdReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF)); 272 for (i = 0; i < mSimCount; i++) { 273 CatLog.d(LOG_TAG, "slotId: " + i); 274 mStkService[i] = CatService.getInstance(i); 275 mStkContext[i] = new StkContext(); 276 mStkContext[i].mSlotId = i; 277 mStkContext[i].mCmdsQ = new LinkedList<DelayedCmd>(); 278 } 279 280 Thread serviceThread = new Thread(null, this, "Stk App Service"); 281 serviceThread.start(); 282 mNotificationManager = (NotificationManager) mContext 283 .getSystemService(Context.NOTIFICATION_SERVICE); 284 sInstance = this; 285 } 286 287 @Override 288 public void onStart(Intent intent, int startId) { 289 if (intent == null) { 290 CatLog.d(LOG_TAG, "StkAppService onStart intent is null so return"); 291 return; 292 } 293 294 Bundle args = intent.getExtras(); 295 if (args == null) { 296 CatLog.d(LOG_TAG, "StkAppService onStart args is null so return"); 297 return; 298 } 299 300 int op = args.getInt(OPCODE); 301 int slotId = 0; 302 int i = 0; 303 if (op != OP_BOOT_COMPLETED) { 304 slotId = args.getInt(SLOT_ID); 305 } 306 CatLog.d(LOG_TAG, "onStart sim id: " + slotId + ", op: " + op + ", *****"); 307 if ((slotId >= 0 && slotId < mSimCount) && mStkService[slotId] == null) { 308 mStkService[slotId] = CatService.getInstance(slotId); 309 if (mStkService[slotId] == null) { 310 CatLog.d(LOG_TAG, "mStkService is: " + mStkContext[slotId].mStkServiceState); 311 mStkContext[slotId].mStkServiceState = STATE_NOT_EXIST; 312 //Check other StkService state. 313 //If all StkServices are not available, stop itself and uninstall apk. 314 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) { 315 if (i != slotId 316 && (mStkContext[i].mStkServiceState == STATE_UNKNOWN 317 || mStkContext[i].mStkServiceState == STATE_EXIST)) { 318 break; 319 } 320 } 321 } else { 322 mStkContext[slotId].mStkServiceState = STATE_EXIST; 323 } 324 if (i == mSimCount) { 325 stopSelf(); 326 StkAppInstaller.unInstall(mContext); 327 return; 328 } 329 } 330 331 waitForLooper(); 332 333 Message msg = mServiceHandler.obtainMessage(); 334 msg.arg1 = op; 335 msg.arg2 = slotId; 336 switch(msg.arg1) { 337 case OP_CMD: 338 msg.obj = args.getParcelable(CMD_MSG); 339 break; 340 case OP_RESPONSE: 341 case OP_CARD_STATUS_CHANGED: 342 case OP_LOCALE_CHANGED: 343 case OP_ALPHA_NOTIFY: 344 case OP_IDLE_SCREEN: 345 msg.obj = args; 346 /* falls through */ 347 case OP_LAUNCH_APP: 348 case OP_END_SESSION: 349 case OP_BOOT_COMPLETED: 350 break; 351 default: 352 return; 353 } 354 mServiceHandler.sendMessage(msg); 355 } 356 357 @Override 358 public void onDestroy() { 359 CatLog.d(LOG_TAG, "onDestroy()"); 360 if (mStkCmdReceiver != null) { 361 unregisterReceiver(mStkCmdReceiver); 362 mStkCmdReceiver = null; 363 } 364 mPowerManager = null; 365 waitForLooper(); 366 mServiceLooper.quit(); 367 } 368 369 @Override 370 public IBinder onBind(Intent intent) { 371 return null; 372 } 373 374 public void run() { 375 Looper.prepare(); 376 377 mServiceLooper = Looper.myLooper(); 378 mServiceHandler = new ServiceHandler(); 379 380 Looper.loop(); 381 } 382 383 /* 384 * Package api used by StkMenuActivity to indicate if its on the foreground. 385 */ 386 void indicateMenuVisibility(boolean visibility, int slotId) { 387 if (slotId >= 0 && slotId < mSimCount) { 388 mStkContext[slotId].mMenuIsVisible = visibility; 389 } 390 } 391 392 /* 393 * Package api used by StkDialogActivity to indicate if its on the foreground. 394 */ 395 void setDisplayTextDlgVisibility(boolean visibility, int slotId) { 396 if (slotId >= 0 && slotId < mSimCount) { 397 mStkContext[slotId].mDisplayTextDlgIsVisibile = visibility; 398 } 399 } 400 401 boolean isInputPending(int slotId) { 402 if (slotId >= 0 && slotId < mSimCount) { 403 CatLog.d(LOG_TAG, "isInputFinishBySrv: " + mStkContext[slotId].mIsInputPending); 404 return mStkContext[slotId].mIsInputPending; 405 } 406 return false; 407 } 408 409 boolean isMenuPending(int slotId) { 410 if (slotId >= 0 && slotId < mSimCount) { 411 CatLog.d(LOG_TAG, "isMenuPending: " + mStkContext[slotId].mIsMenuPending); 412 return mStkContext[slotId].mIsMenuPending; 413 } 414 return false; 415 } 416 417 boolean isDialogPending(int slotId) { 418 if (slotId >= 0 && slotId < mSimCount) { 419 CatLog.d(LOG_TAG, "isDialogPending: " + mStkContext[slotId].mIsDialogPending); 420 return mStkContext[slotId].mIsDialogPending; 421 } 422 return false; 423 } 424 425 /* 426 * Package api used by StkMenuActivity to get its Menu parameter. 427 */ 428 Menu getMenu(int slotId) { 429 CatLog.d(LOG_TAG, "StkAppService, getMenu, sim id: " + slotId); 430 if (slotId >=0 && slotId < mSimCount) { 431 return mStkContext[slotId].mCurrentMenu; 432 } else { 433 return null; 434 } 435 } 436 437 /* 438 * Package api used by StkMenuActivity to get its Main Menu parameter. 439 */ 440 Menu getMainMenu(int slotId) { 441 CatLog.d(LOG_TAG, "StkAppService, getMainMenu, sim id: " + slotId); 442 if (slotId >=0 && slotId < mSimCount && (mStkContext[slotId].mMainCmd != null)) { 443 return mStkContext[slotId].mMainCmd.getMenu(); 444 } else { 445 return null; 446 } 447 } 448 449 /* 450 * Package api used by UI Activities and Dialogs to communicate directly 451 * with the service to deliver state information and parameters. 452 */ 453 static StkAppService getInstance() { 454 return sInstance; 455 } 456 457 private void waitForLooper() { 458 while (mServiceHandler == null) { 459 synchronized (this) { 460 try { 461 wait(100); 462 } catch (InterruptedException e) { 463 } 464 } 465 } 466 } 467 468 private final class ServiceHandler extends Handler { 469 @Override 470 public void handleMessage(Message msg) { 471 if(null == msg) { 472 CatLog.d(LOG_TAG, "ServiceHandler handleMessage msg is null"); 473 return; 474 } 475 int opcode = msg.arg1; 476 int slotId = msg.arg2; 477 478 CatLog.d(LOG_TAG, "handleMessage opcode[" + opcode + "], sim id[" + slotId + "]"); 479 if (opcode == OP_CMD && msg.obj != null && 480 ((CatCmdMessage)msg.obj).getCmdType()!= null) { 481 CatLog.d(LOG_TAG, "cmdName[" + ((CatCmdMessage)msg.obj).getCmdType().name() + "]"); 482 } 483 mStkContext[slotId].mOpCode = opcode; 484 switch (opcode) { 485 case OP_LAUNCH_APP: 486 if (mStkContext[slotId].mMainCmd == null) { 487 CatLog.d(LOG_TAG, "mMainCmd is null"); 488 // nothing todo when no SET UP MENU command didn't arrive. 489 return; 490 } 491 CatLog.d(LOG_TAG, "handleMessage OP_LAUNCH_APP - mCmdInProgress[" + 492 mStkContext[slotId].mCmdInProgress + "]"); 493 494 //If there is a pending activity for the slot id, 495 //just finish it and create a new one to handle the pending command. 496 cleanUpInstanceStackBySlot(slotId); 497 498 CatLog.d(LOG_TAG, "Current cmd type: " + 499 mStkContext[slotId].mCurrentCmd.getCmdType()); 500 //Restore the last command from stack by slot id. 501 restoreInstanceFromStackBySlot(slotId); 502 break; 503 case OP_CMD: 504 CatLog.d(LOG_TAG, "[OP_CMD]"); 505 CatCmdMessage cmdMsg = (CatCmdMessage) msg.obj; 506 // There are two types of commands: 507 // 1. Interactive - user's response is required. 508 // 2. Informative - display a message, no interaction with the user. 509 // 510 // Informative commands can be handled immediately without any delay. 511 // Interactive commands can't override each other. So if a command 512 // is already in progress, we need to queue the next command until 513 // the user has responded or a timeout expired. 514 if (!isCmdInteractive(cmdMsg)) { 515 handleCmd(cmdMsg, slotId); 516 } else { 517 if (!mStkContext[slotId].mCmdInProgress) { 518 mStkContext[slotId].mCmdInProgress = true; 519 handleCmd((CatCmdMessage) msg.obj, slotId); 520 } else { 521 CatLog.d(LOG_TAG, "[Interactive][in progress]"); 522 mStkContext[slotId].mCmdsQ.addLast(new DelayedCmd(OP_CMD, 523 (CatCmdMessage) msg.obj, slotId)); 524 } 525 } 526 break; 527 case OP_RESPONSE: 528 handleCmdResponse((Bundle) msg.obj, slotId); 529 // call delayed commands if needed. 530 if (mStkContext[slotId].mCmdsQ.size() != 0) { 531 callDelayedMsg(slotId); 532 } else { 533 mStkContext[slotId].mCmdInProgress = false; 534 } 535 break; 536 case OP_END_SESSION: 537 if (!mStkContext[slotId].mCmdInProgress) { 538 mStkContext[slotId].mCmdInProgress = true; 539 handleSessionEnd(slotId); 540 } else { 541 mStkContext[slotId].mCmdsQ.addLast( 542 new DelayedCmd(OP_END_SESSION, null, slotId)); 543 } 544 break; 545 case OP_BOOT_COMPLETED: 546 CatLog.d(LOG_TAG, " OP_BOOT_COMPLETED"); 547 int i = 0; 548 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) { 549 if (mStkContext[i].mMainCmd != null) { 550 break; 551 } 552 } 553 if (i == mSimCount) { 554 StkAppInstaller.unInstall(mContext); 555 } 556 break; 557 case OP_DELAYED_MSG: 558 handleDelayedCmd(slotId); 559 break; 560 case OP_CARD_STATUS_CHANGED: 561 CatLog.d(LOG_TAG, "Card/Icc Status change received"); 562 handleCardStatusChangeAndIccRefresh((Bundle) msg.obj, slotId); 563 break; 564 case OP_SET_ACT_INST: 565 Activity act = new Activity(); 566 act = (Activity) msg.obj; 567 CatLog.d(LOG_TAG, "Set activity instance. " + act); 568 mStkContext[slotId].mActivityInstance = act; 569 break; 570 case OP_SET_DAL_INST: 571 Activity dal = new Activity(); 572 CatLog.d(LOG_TAG, "Set dialog instance. " + dal); 573 dal = (Activity) msg.obj; 574 mStkContext[slotId].mDialogInstance = dal; 575 break; 576 case OP_SET_MAINACT_INST: 577 Activity mainAct = new Activity(); 578 mainAct = (Activity) msg.obj; 579 CatLog.d(LOG_TAG, "Set activity instance. " + mainAct); 580 mStkContext[slotId].mMainActivityInstance = mainAct; 581 break; 582 case OP_LOCALE_CHANGED: 583 CatLog.d(this, "Locale Changed"); 584 checkForSetupEvent(LANGUAGE_SELECTION_EVENT,(Bundle) msg.obj, slotId); 585 break; 586 case OP_ALPHA_NOTIFY: 587 handleAlphaNotify((Bundle) msg.obj); 588 break; 589 case OP_IDLE_SCREEN: 590 for (int slot = 0; slot < mSimCount; slot++) { 591 if (mStkContext[slot] != null) { 592 handleIdleScreen(slot); 593 } 594 } 595 break; 596 } 597 } 598 599 private void handleCardStatusChangeAndIccRefresh(Bundle args, int slotId) { 600 boolean cardStatus = args.getBoolean(AppInterface.CARD_STATUS); 601 602 CatLog.d(LOG_TAG, "CardStatus: " + cardStatus); 603 if (cardStatus == false) { 604 CatLog.d(LOG_TAG, "CARD is ABSENT"); 605 // Uninstall STKAPP, Clear Idle text, Stop StkAppService 606 mNotificationManager.cancel(getNotificationId(slotId)); 607 if (isAllOtherCardsAbsent(slotId)) { 608 CatLog.d(LOG_TAG, "All CARDs are ABSENT"); 609 StkAppInstaller.unInstall(mContext); 610 stopSelf(); 611 } 612 } else { 613 IccRefreshResponse state = new IccRefreshResponse(); 614 state.refreshResult = args.getInt(AppInterface.REFRESH_RESULT); 615 616 CatLog.d(LOG_TAG, "Icc Refresh Result: "+ state.refreshResult); 617 if ((state.refreshResult == IccRefreshResponse.REFRESH_RESULT_INIT) || 618 (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET)) { 619 // Clear Idle Text 620 mNotificationManager.cancel(getNotificationId(slotId)); 621 } 622 623 if (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) { 624 // Uninstall STkmenu 625 if (isAllOtherCardsAbsent(slotId)) { 626 StkAppInstaller.unInstall(mContext); 627 } 628 mStkContext[slotId].mCurrentMenu = null; 629 mStkContext[slotId].mMainCmd = null; 630 } 631 } 632 } 633 } 634 /* 635 * Check if all SIMs are absent except the id of slot equals "slotId". 636 */ 637 private boolean isAllOtherCardsAbsent(int slotId) { 638 TelephonyManager mTm = (TelephonyManager) mContext.getSystemService( 639 Context.TELEPHONY_SERVICE); 640 int i = 0; 641 642 for (i = 0; i < mSimCount; i++) { 643 if (i != slotId && mTm.hasIccCard(i)) { 644 break; 645 } 646 } 647 if (i == mSimCount) { 648 return true; 649 } else { 650 return false; 651 } 652 } 653 654 /* 655 * If the device is not in an interactive state, we can assume 656 * that the screen is idle. 657 */ 658 private boolean isScreenIdle() { 659 return (!mPowerManager.isInteractive()); 660 } 661 662 private void handleIdleScreen(int slotId) { 663 664 // If the idle screen event is present in the list need to send the 665 // response to SIM. 666 CatLog.d(this, "Need to send IDLE SCREEN Available event to SIM"); 667 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId); 668 669 if (mStkContext[slotId].mIdleModeTextCmd != null) { 670 launchIdleText(slotId); 671 } 672 } 673 674 private void sendScreenBusyResponse(int slotId) { 675 if (mStkContext[slotId].mCurrentCmd == null) { 676 return; 677 } 678 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd); 679 CatLog.d(this, "SCREEN_BUSY"); 680 resMsg.setResultCode(ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS); 681 mStkService[slotId].onCmdResponse(resMsg); 682 if (mStkContext[slotId].mCmdsQ.size() != 0) { 683 callDelayedMsg(slotId); 684 } else { 685 mStkContext[slotId].mCmdInProgress = false; 686 } 687 } 688 689 private void sendResponse(int resId, int slotId, boolean confirm) { 690 Message msg = mServiceHandler.obtainMessage(); 691 msg.arg1 = OP_RESPONSE; 692 Bundle args = new Bundle(); 693 args.putInt(StkAppService.RES_ID, resId); 694 args.putInt(SLOT_ID, slotId); 695 args.putBoolean(StkAppService.CONFIRMATION, confirm); 696 msg.obj = args; 697 mServiceHandler.sendMessage(msg); 698 } 699 700 private boolean isCmdInteractive(CatCmdMessage cmd) { 701 switch (cmd.getCmdType()) { 702 case SEND_DTMF: 703 case SEND_SMS: 704 case SEND_SS: 705 case SEND_USSD: 706 case SET_UP_IDLE_MODE_TEXT: 707 case SET_UP_MENU: 708 case CLOSE_CHANNEL: 709 case RECEIVE_DATA: 710 case SEND_DATA: 711 case SET_UP_EVENT_LIST: 712 return false; 713 } 714 715 return true; 716 } 717 718 private void handleDelayedCmd(int slotId) { 719 CatLog.d(LOG_TAG, "handleDelayedCmd, slotId: " + slotId); 720 if (mStkContext[slotId].mCmdsQ.size() != 0) { 721 DelayedCmd cmd = mStkContext[slotId].mCmdsQ.poll(); 722 if (cmd != null) { 723 CatLog.d(LOG_TAG, "handleDelayedCmd - queue size: " + 724 mStkContext[slotId].mCmdsQ.size() + 725 " id: " + cmd.id + "sim id: " + cmd.slotId); 726 switch (cmd.id) { 727 case OP_CMD: 728 handleCmd(cmd.msg, cmd.slotId); 729 break; 730 case OP_END_SESSION: 731 handleSessionEnd(cmd.slotId); 732 break; 733 } 734 } 735 } 736 } 737 738 private void callDelayedMsg(int slotId) { 739 Message msg = mServiceHandler.obtainMessage(); 740 msg.arg1 = OP_DELAYED_MSG; 741 msg.arg2 = slotId; 742 mServiceHandler.sendMessage(msg); 743 } 744 745 private void callSetActivityInstMsg(int inst_type, int slotId, Object obj) { 746 Message msg = mServiceHandler.obtainMessage(); 747 msg.obj = obj; 748 msg.arg1 = inst_type; 749 msg.arg2 = slotId; 750 mServiceHandler.sendMessage(msg); 751 } 752 753 private void handleSessionEnd(int slotId) { 754 // We should finish all pending activity if receiving END SESSION command. 755 cleanUpInstanceStackBySlot(slotId); 756 757 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd; 758 CatLog.d(LOG_TAG, "[handleSessionEnd] - mCurrentCmd changed to mMainCmd!."); 759 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mMainCmd; 760 CatLog.d(LOG_TAG, "slotId: " + slotId + ", mMenuState: " + 761 mStkContext[slotId].mMenuState); 762 763 mStkContext[slotId].mIsInputPending = false; 764 mStkContext[slotId].mIsMenuPending = false; 765 mStkContext[slotId].mIsDialogPending = false; 766 767 if (mStkContext[slotId].mMainCmd == null) { 768 CatLog.d(LOG_TAG, "[handleSessionEnd][mMainCmd is null!]"); 769 } 770 mStkContext[slotId].lastSelectedItem = null; 771 // In case of SET UP MENU command which removed the app, don't 772 // update the current menu member. 773 if (mStkContext[slotId].mCurrentMenu != null && mStkContext[slotId].mMainCmd != null) { 774 mStkContext[slotId].mCurrentMenu = mStkContext[slotId].mMainCmd.getMenu(); 775 } 776 CatLog.d(LOG_TAG, "[handleSessionEnd][mMenuState]" + mStkContext[slotId].mMenuIsVisible); 777 // In mutiple instance architecture, the main menu for slotId will be finished when user 778 // goes to the Stk menu of the other SIM. So, we should launch a new instance for the 779 // main menu if the main menu instance has been finished. 780 // If the current menu is secondary menu, we should launch main menu. 781 if (StkMenuActivity.STATE_SECONDARY == mStkContext[slotId].mMenuState) { 782 launchMenuActivity(null, slotId); 783 } 784 if (mStkContext[slotId].mCmdsQ.size() != 0) { 785 callDelayedMsg(slotId); 786 } else { 787 mStkContext[slotId].mCmdInProgress = false; 788 } 789 // In case a launch browser command was just confirmed, launch that url. 790 if (mStkContext[slotId].launchBrowser) { 791 mStkContext[slotId].launchBrowser = false; 792 launchBrowser(mStkContext[slotId].mBrowserSettings); 793 } 794 } 795 796 // returns true if any Stk related activity already has focus on the screen 797 private boolean isTopOfStack() { 798 ActivityManager mAcivityManager = (ActivityManager) mContext 799 .getSystemService(ACTIVITY_SERVICE); 800 String currentPackageName = mAcivityManager.getRunningTasks(1).get(0).topActivity 801 .getPackageName(); 802 if (null != currentPackageName) { 803 return currentPackageName.equals(PACKAGE_NAME); 804 } 805 806 return false; 807 } 808 809 private void handleCmd(CatCmdMessage cmdMsg, int slotId) { 810 811 if (cmdMsg == null) { 812 return; 813 } 814 // save local reference for state tracking. 815 mStkContext[slotId].mCurrentCmd = cmdMsg; 816 boolean waitForUsersResponse = true; 817 818 mStkContext[slotId].mIsInputPending = false; 819 mStkContext[slotId].mIsMenuPending = false; 820 mStkContext[slotId].mIsDialogPending = false; 821 822 CatLog.d(LOG_TAG,"[handleCmd]" + cmdMsg.getCmdType().name()); 823 switch (cmdMsg.getCmdType()) { 824 case DISPLAY_TEXT: 825 TextMessage msg = cmdMsg.geTextMessage(); 826 waitForUsersResponse = msg.responseNeeded; 827 if (mStkContext[slotId].lastSelectedItem != null) { 828 msg.title = mStkContext[slotId].lastSelectedItem; 829 } else if (mStkContext[slotId].mMainCmd != null){ 830 msg.title = mStkContext[slotId].mMainCmd.getMenu().title; 831 } else { 832 // TODO: get the carrier name from the SIM 833 msg.title = ""; 834 } 835 //If we receive a low priority Display Text and the device is 836 // not displaying any STK related activity and the screen is not idle 837 // ( that is, device is in an interactive state), then send a screen busy 838 // terminal response. Otherwise display the message. The existing 839 // displayed message shall be updated with the new display text 840 // proactive command (Refer to ETSI TS 102 384 section 27.22.4.1.4.4.2). 841 if (!(msg.isHighPriority || mStkContext[slotId].mMenuIsVisible 842 || mStkContext[slotId].mDisplayTextDlgIsVisibile || isTopOfStack())) { 843 if(!isScreenIdle()) { 844 CatLog.d(LOG_TAG, "Screen is not idle"); 845 sendScreenBusyResponse(slotId); 846 } else { 847 launchTextDialog(slotId); 848 } 849 } else { 850 launchTextDialog(slotId); 851 } 852 break; 853 case SELECT_ITEM: 854 CatLog.d(LOG_TAG, "SELECT_ITEM +"); 855 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd; 856 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu(); 857 launchMenuActivity(cmdMsg.getMenu(), slotId); 858 break; 859 case SET_UP_MENU: 860 mStkContext[slotId].mCmdInProgress = false; 861 mStkContext[slotId].mMainCmd = mStkContext[slotId].mCurrentCmd; 862 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd; 863 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu(); 864 CatLog.d(LOG_TAG, "SET_UP_MENU [" + removeMenu(slotId) + "]"); 865 866 if (removeMenu(slotId)) { 867 int i = 0; 868 CatLog.d(LOG_TAG, "removeMenu() - Uninstall App"); 869 mStkContext[slotId].mCurrentMenu = null; 870 mStkContext[slotId].mMainCmd = null; 871 //Check other setup menu state. If all setup menu are removed, uninstall apk. 872 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) { 873 if (i != slotId 874 && (mStkContext[slotId].mSetupMenuState == STATE_UNKNOWN 875 || mStkContext[slotId].mSetupMenuState == STATE_EXIST)) { 876 CatLog.d(LOG_TAG, "Not Uninstall App:" + i + "," 877 + mStkContext[slotId].mSetupMenuState); 878 break; 879 } 880 } 881 if (i == mSimCount) { 882 StkAppInstaller.unInstall(mContext); 883 } 884 } else { 885 CatLog.d(LOG_TAG, "install App"); 886 StkAppInstaller.install(mContext); 887 } 888 if (mStkContext[slotId].mMenuIsVisible) { 889 launchMenuActivity(null, slotId); 890 } 891 break; 892 case GET_INPUT: 893 case GET_INKEY: 894 launchInputActivity(slotId); 895 break; 896 case SET_UP_IDLE_MODE_TEXT: 897 waitForUsersResponse = false; 898 mStkContext[slotId].mIdleModeTextCmd = mStkContext[slotId].mCurrentCmd; 899 TextMessage idleModeText = mStkContext[slotId].mCurrentCmd.geTextMessage(); 900 if (idleModeText == null) { 901 launchIdleText(slotId); 902 mStkContext[slotId].mIdleModeTextCmd = null; 903 } 904 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd; 905 if ((mStkContext[slotId].mIdleModeTextCmd != null) && isScreenIdle()) { 906 CatLog.d(this, "set up idle mode"); 907 launchIdleText(slotId); 908 } 909 break; 910 case SEND_DTMF: 911 case SEND_SMS: 912 case SEND_SS: 913 case SEND_USSD: 914 case GET_CHANNEL_STATUS: 915 waitForUsersResponse = false; 916 launchEventMessage(slotId); 917 break; 918 case LAUNCH_BROWSER: 919 TextMessage alphaId = mStkContext[slotId].mCurrentCmd.geTextMessage(); 920 if ((mStkContext[slotId].mCurrentCmd.getBrowserSettings().mode 921 == LaunchBrowserMode.LAUNCH_IF_NOT_ALREADY_LAUNCHED) && 922 ((alphaId == null) || TextUtils.isEmpty(alphaId.text))) { 923 // don't need user confirmation in this case 924 // just launch the browser or spawn a new tab 925 CatLog.d(this, "Browser mode is: launch if not already launched " + 926 "and user confirmation is not currently needed.\n" + 927 "supressing confirmation dialogue and confirming silently..."); 928 mStkContext[slotId].launchBrowser = true; 929 mStkContext[slotId].mBrowserSettings = 930 mStkContext[slotId].mCurrentCmd.getBrowserSettings(); 931 sendResponse(RES_ID_CONFIRM, slotId, true); 932 } else { 933 launchConfirmationDialog(alphaId, slotId); 934 } 935 break; 936 case SET_UP_CALL: 937 TextMessage mesg = mStkContext[slotId].mCurrentCmd.getCallSettings().confirmMsg; 938 if((mesg != null) && (mesg.text == null || mesg.text.length() == 0)) { 939 mesg.text = getResources().getString(R.string.default_setup_call_msg); 940 } 941 CatLog.d(this, "SET_UP_CALL mesg.text " + mesg.text); 942 launchConfirmationDialog(mesg, slotId); 943 break; 944 case PLAY_TONE: 945 launchToneDialog(slotId); 946 break; 947 case OPEN_CHANNEL: 948 launchOpenChannelDialog(slotId); 949 break; 950 case CLOSE_CHANNEL: 951 case RECEIVE_DATA: 952 case SEND_DATA: 953 TextMessage m = mStkContext[slotId].mCurrentCmd.geTextMessage(); 954 955 if ((m != null) && (m.text == null)) { 956 switch(cmdMsg.getCmdType()) { 957 case CLOSE_CHANNEL: 958 m.text = getResources().getString(R.string.default_close_channel_msg); 959 break; 960 case RECEIVE_DATA: 961 m.text = getResources().getString(R.string.default_receive_data_msg); 962 break; 963 case SEND_DATA: 964 m.text = getResources().getString(R.string.default_send_data_msg); 965 break; 966 } 967 } 968 /* 969 * Display indication in the form of a toast to the user if required. 970 */ 971 launchEventMessage(slotId); 972 break; 973 case SET_UP_EVENT_LIST: 974 mStkContext[slotId].mSetupEventListSettings = 975 mStkContext[slotId].mCurrentCmd.getSetEventList(); 976 mStkContext[slotId].mCurrentSetupEventCmd = mStkContext[slotId].mCurrentCmd; 977 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd; 978 if (isScreenIdle()) { 979 CatLog.d(this," Check if IDLE_SCREEN_AVAILABLE_EVENT is present in List"); 980 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId); 981 } 982 break; 983 } 984 985 if (!waitForUsersResponse) { 986 if (mStkContext[slotId].mCmdsQ.size() != 0) { 987 callDelayedMsg(slotId); 988 } else { 989 mStkContext[slotId].mCmdInProgress = false; 990 } 991 } 992 } 993 994 private void handleCmdResponse(Bundle args, int slotId) { 995 CatLog.d(LOG_TAG, "handleCmdResponse, sim id: " + slotId); 996 if (mStkContext[slotId].mCurrentCmd == null) { 997 return; 998 } 999 1000 if (mStkService[slotId] == null) { 1001 mStkService[slotId] = CatService.getInstance(slotId); 1002 if (mStkService[slotId] == null) { 1003 // This should never happen (we should be responding only to a message 1004 // that arrived from StkService). It has to exist by this time 1005 CatLog.d(LOG_TAG, "Exception! mStkService is null when we need to send response."); 1006 throw new RuntimeException("mStkService is null when we need to send response"); 1007 } 1008 } 1009 1010 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd); 1011 1012 // set result code 1013 boolean helpRequired = args.getBoolean(HELP, false); 1014 boolean confirmed = false; 1015 1016 switch(args.getInt(RES_ID)) { 1017 case RES_ID_MENU_SELECTION: 1018 CatLog.d(LOG_TAG, "MENU_SELECTION=" + mStkContext[slotId]. 1019 mCurrentMenuCmd.getCmdType()); 1020 int menuSelection = args.getInt(MENU_SELECTION); 1021 switch(mStkContext[slotId].mCurrentMenuCmd.getCmdType()) { 1022 case SET_UP_MENU: 1023 case SELECT_ITEM: 1024 mStkContext[slotId].lastSelectedItem = getItemName(menuSelection, slotId); 1025 if (helpRequired) { 1026 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED); 1027 } else { 1028 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ? 1029 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK); 1030 } 1031 resMsg.setMenuSelection(menuSelection); 1032 break; 1033 } 1034 break; 1035 case RES_ID_INPUT: 1036 CatLog.d(LOG_TAG, "RES_ID_INPUT"); 1037 String input = args.getString(INPUT); 1038 if (input != null && (null != mStkContext[slotId].mCurrentCmd.geInput()) && 1039 (mStkContext[slotId].mCurrentCmd.geInput().yesNo)) { 1040 boolean yesNoSelection = input 1041 .equals(StkInputActivity.YES_STR_RESPONSE); 1042 resMsg.setYesNo(yesNoSelection); 1043 } else { 1044 if (helpRequired) { 1045 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED); 1046 } else { 1047 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ? 1048 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK); 1049 resMsg.setInput(input); 1050 } 1051 } 1052 break; 1053 case RES_ID_CONFIRM: 1054 CatLog.d(this, "RES_ID_CONFIRM"); 1055 confirmed = args.getBoolean(CONFIRMATION); 1056 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) { 1057 case DISPLAY_TEXT: 1058 if (confirmed) { 1059 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ? 1060 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK); 1061 } else { 1062 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER); 1063 } 1064 break; 1065 case LAUNCH_BROWSER: 1066 resMsg.setResultCode(confirmed ? ResultCode.OK 1067 : ResultCode.UICC_SESSION_TERM_BY_USER); 1068 if (confirmed) { 1069 mStkContext[slotId].launchBrowser = true; 1070 mStkContext[slotId].mBrowserSettings = 1071 mStkContext[slotId].mCurrentCmd.getBrowserSettings(); 1072 } 1073 break; 1074 case SET_UP_CALL: 1075 resMsg.setResultCode(ResultCode.OK); 1076 resMsg.setConfirmation(confirmed); 1077 if (confirmed) { 1078 CatLog.d(this, "Going back to mainMenu before starting a call."); 1079 launchMenuActivity(null, slotId); 1080 launchEventMessage(slotId, 1081 mStkContext[slotId].mCurrentCmd.getCallSettings().callMsg); 1082 } 1083 break; 1084 } 1085 break; 1086 case RES_ID_DONE: 1087 resMsg.setResultCode(ResultCode.OK); 1088 break; 1089 case RES_ID_BACKWARD: 1090 CatLog.d(LOG_TAG, "RES_ID_BACKWARD"); 1091 resMsg.setResultCode(ResultCode.BACKWARD_MOVE_BY_USER); 1092 break; 1093 case RES_ID_END_SESSION: 1094 CatLog.d(LOG_TAG, "RES_ID_END_SESSION"); 1095 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER); 1096 break; 1097 case RES_ID_TIMEOUT: 1098 CatLog.d(LOG_TAG, "RES_ID_TIMEOUT"); 1099 // GCF test-case 27.22.4.1.1 Expected Sequence 1.5 (DISPLAY TEXT, 1100 // Clear message after delay, successful) expects result code OK. 1101 // If the command qualifier specifies no user response is required 1102 // then send OK instead of NO_RESPONSE_FROM_USER 1103 if ((mStkContext[slotId].mCurrentCmd.getCmdType().value() == 1104 AppInterface.CommandType.DISPLAY_TEXT.value()) 1105 && (mStkContext[slotId].mCurrentCmd.geTextMessage().userClear == false)) { 1106 resMsg.setResultCode(ResultCode.OK); 1107 } else { 1108 resMsg.setResultCode(ResultCode.NO_RESPONSE_FROM_USER); 1109 } 1110 break; 1111 case RES_ID_CHOICE: 1112 int choice = args.getInt(CHOICE); 1113 CatLog.d(this, "User Choice=" + choice); 1114 switch (choice) { 1115 case YES: 1116 resMsg.setResultCode(ResultCode.OK); 1117 confirmed = true; 1118 break; 1119 case NO: 1120 resMsg.setResultCode(ResultCode.USER_NOT_ACCEPT); 1121 break; 1122 } 1123 1124 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() == 1125 AppInterface.CommandType.OPEN_CHANNEL.value()) { 1126 resMsg.setConfirmation(confirmed); 1127 } 1128 break; 1129 1130 default: 1131 CatLog.d(LOG_TAG, "Unknown result id"); 1132 return; 1133 } 1134 1135 if (null != mStkContext[slotId].mCurrentCmd && 1136 null != mStkContext[slotId].mCurrentCmd.getCmdType()) { 1137 CatLog.d(LOG_TAG, "handleCmdResponse- cmdName[" + 1138 mStkContext[slotId].mCurrentCmd.getCmdType().name() + "]"); 1139 } 1140 mStkService[slotId].onCmdResponse(resMsg); 1141 } 1142 1143 /** 1144 * Returns 0 or FLAG_ACTIVITY_NO_USER_ACTION, 0 means the user initiated the action. 1145 * 1146 * @param userAction If the userAction is yes then we always return 0 otherwise 1147 * mMenuIsVisible is used to determine what to return. If mMenuIsVisible is true 1148 * then we are the foreground app and we'll return 0 as from our perspective a 1149 * user action did cause. If it's false than we aren't the foreground app and 1150 * FLAG_ACTIVITY_NO_USER_ACTION is returned. 1151 * 1152 * @return 0 or FLAG_ACTIVITY_NO_USER_ACTION 1153 */ 1154 private int getFlagActivityNoUserAction(InitiatedByUserAction userAction, int slotId) { 1155 return ((userAction == InitiatedByUserAction.yes) | mStkContext[slotId].mMenuIsVisible) 1156 ? 0 : Intent.FLAG_ACTIVITY_NO_USER_ACTION; 1157 } 1158 /** 1159 * This method is used for cleaning up pending instances in stack. 1160 */ 1161 private void cleanUpInstanceStackBySlot(int slotId) { 1162 Activity activity = mStkContext[slotId].getPendingActivityInstance(); 1163 Activity dialog = mStkContext[slotId].getPendingDialogInstance(); 1164 CatLog.d(LOG_TAG, "cleanUpInstanceStackBySlot slotId: " + slotId); 1165 if (mStkContext[slotId].mCurrentCmd == null) { 1166 CatLog.d(LOG_TAG, "current cmd is null."); 1167 return; 1168 } 1169 if (activity != null) { 1170 CatLog.d(LOG_TAG, "current cmd type: " + 1171 mStkContext[slotId].mCurrentCmd.getCmdType()); 1172 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() == 1173 AppInterface.CommandType.GET_INPUT.value() || 1174 mStkContext[slotId].mCurrentCmd.getCmdType().value() == 1175 AppInterface.CommandType.GET_INKEY.value()) { 1176 mStkContext[slotId].mIsInputPending = true; 1177 } else if (mStkContext[slotId].mCurrentCmd.getCmdType().value() == 1178 AppInterface.CommandType.SET_UP_MENU.value() || 1179 mStkContext[slotId].mCurrentCmd.getCmdType().value() == 1180 AppInterface.CommandType.SELECT_ITEM.value()) { 1181 mStkContext[slotId].mIsMenuPending = true; 1182 } else { 1183 } 1184 CatLog.d(LOG_TAG, "finish pending activity."); 1185 activity.finish(); 1186 mStkContext[slotId].mActivityInstance = null; 1187 } 1188 if (dialog != null) { 1189 CatLog.d(LOG_TAG, "finish pending dialog."); 1190 mStkContext[slotId].mIsDialogPending = true; 1191 dialog.finish(); 1192 mStkContext[slotId].mDialogInstance = null; 1193 } 1194 } 1195 /** 1196 * This method is used for restoring pending instances from stack. 1197 */ 1198 private void restoreInstanceFromStackBySlot(int slotId) { 1199 AppInterface.CommandType cmdType = mStkContext[slotId].mCurrentCmd.getCmdType(); 1200 1201 CatLog.d(LOG_TAG, "restoreInstanceFromStackBySlot cmdType : " + cmdType); 1202 switch(cmdType) { 1203 case GET_INPUT: 1204 case GET_INKEY: 1205 launchInputActivity(slotId); 1206 //Set mMenuIsVisible to true for showing main menu for 1207 //following session end command. 1208 mStkContext[slotId].mMenuIsVisible = true; 1209 break; 1210 case DISPLAY_TEXT: 1211 launchTextDialog(slotId); 1212 break; 1213 case LAUNCH_BROWSER: 1214 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.geTextMessage(), 1215 slotId); 1216 break; 1217 case OPEN_CHANNEL: 1218 launchOpenChannelDialog(slotId); 1219 break; 1220 case SET_UP_CALL: 1221 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.getCallSettings(). 1222 confirmMsg, slotId); 1223 break; 1224 case SET_UP_MENU: 1225 case SELECT_ITEM: 1226 launchMenuActivity(null, slotId); 1227 break; 1228 default: 1229 break; 1230 } 1231 } 1232 1233 private void launchMenuActivity(Menu menu, int slotId) { 1234 Intent newIntent = new Intent(Intent.ACTION_VIEW); 1235 String targetActivity = STK_MENU_ACTIVITY_NAME; 1236 String uriString = STK_MENU_URI + System.currentTimeMillis(); 1237 //Set unique URI to create a new instance of activity for different slotId. 1238 Uri uriData = Uri.parse(uriString); 1239 1240 CatLog.d(LOG_TAG, "launchMenuActivity, slotId: " + slotId + " , " + 1241 uriData.toString() + " , " + mStkContext[slotId].mOpCode + ", " 1242 + mStkContext[slotId].mMenuState); 1243 newIntent.setClassName(PACKAGE_NAME, targetActivity); 1244 int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK; 1245 1246 if (menu == null) { 1247 // We assume this was initiated by the user pressing the tool kit icon 1248 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.yes, slotId); 1249 if (mStkContext[slotId].mOpCode == OP_END_SESSION) { 1250 CatLog.d(LOG_TAG, "launchMenuActivity, return OP_END_SESSION"); 1251 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN; 1252 if (mStkContext[slotId].mMainActivityInstance != null) { 1253 CatLog.d(LOG_TAG, "launchMenuActivity, mMainActivityInstance is not null"); 1254 return; 1255 } 1256 } 1257 1258 //If the last pending menu is secondary menu, "STATE" should be "STATE_SECONDARY". 1259 //Otherwise, it should be "STATE_MAIN". 1260 if (mStkContext[slotId].mOpCode == OP_LAUNCH_APP && 1261 mStkContext[slotId].mMenuState == StkMenuActivity.STATE_SECONDARY) { 1262 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY); 1263 } else { 1264 newIntent.putExtra("STATE", StkMenuActivity.STATE_MAIN); 1265 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN; 1266 } 1267 } else { 1268 // We don't know and we'll let getFlagActivityNoUserAction decide. 1269 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId); 1270 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY); 1271 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_SECONDARY; 1272 } 1273 newIntent.putExtra(SLOT_ID, slotId); 1274 newIntent.setData(uriData); 1275 newIntent.setFlags(intentFlags); 1276 mContext.startActivity(newIntent); 1277 } 1278 1279 private void launchInputActivity(int slotId) { 1280 Intent newIntent = new Intent(Intent.ACTION_VIEW); 1281 String targetActivity = STK_INPUT_ACTIVITY_NAME; 1282 String uriString = STK_INPUT_URI + System.currentTimeMillis(); 1283 //Set unique URI to create a new instance of activity for different slotId. 1284 Uri uriData = Uri.parse(uriString); 1285 1286 CatLog.d(LOG_TAG, "launchInputActivity, slotId: " + slotId); 1287 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 1288 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId)); 1289 newIntent.setClassName(PACKAGE_NAME, targetActivity); 1290 newIntent.putExtra("INPUT", mStkContext[slotId].mCurrentCmd.geInput()); 1291 newIntent.putExtra(SLOT_ID, slotId); 1292 newIntent.setData(uriData); 1293 mContext.startActivity(newIntent); 1294 } 1295 1296 private void launchTextDialog(int slotId) { 1297 CatLog.d(LOG_TAG, "launchTextDialog, slotId: " + slotId); 1298 Intent newIntent = new Intent(); 1299 String targetActivity = STK_DIALOG_ACTIVITY_NAME; 1300 int action = getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId); 1301 String uriString = STK_DIALOG_URI + System.currentTimeMillis(); 1302 //Set unique URI to create a new instance of activity for different slotId. 1303 Uri uriData = Uri.parse(uriString); 1304 if (newIntent != null) { 1305 newIntent.setClassName(PACKAGE_NAME, targetActivity); 1306 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 1307 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 1308 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId)); 1309 newIntent.setData(uriData); 1310 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage()); 1311 newIntent.putExtra(SLOT_ID, slotId); 1312 startActivity(newIntent); 1313 // For display texts with immediate response, send the terminal response 1314 // immediately. responseNeeded will be false, if display text command has 1315 // the immediate response tlv. 1316 if (!mStkContext[slotId].mCurrentCmd.geTextMessage().responseNeeded) { 1317 sendResponse(RES_ID_CONFIRM, slotId, true); 1318 } 1319 } 1320 } 1321 1322 public boolean isStkDialogActivated(Context context) { 1323 String stkDialogActivity = "com.android.stk.StkDialogActivity"; 1324 boolean activated = false; 1325 final ActivityManager am = (ActivityManager) context.getSystemService( 1326 Context.ACTIVITY_SERVICE); 1327 String topActivity = am.getRunningTasks(1).get(0).topActivity.getClassName(); 1328 1329 CatLog.d(LOG_TAG, "isStkDialogActivated: " + topActivity); 1330 if (topActivity.equals(stkDialogActivity)) { 1331 activated = true; 1332 } 1333 CatLog.d(LOG_TAG, "activated : " + activated); 1334 return activated; 1335 } 1336 1337 private void sendSetUpEventResponse(int event, byte[] addedInfo, int slotId) { 1338 CatLog.d(this, "sendSetUpEventResponse: event : " + event + "slotId = " + slotId); 1339 1340 if (mStkContext[slotId].mCurrentSetupEventCmd == null){ 1341 CatLog.e(this, "mCurrentSetupEventCmd is null"); 1342 return; 1343 } 1344 1345 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentSetupEventCmd); 1346 1347 resMsg.setResultCode(ResultCode.OK); 1348 resMsg.setEventDownload(event, addedInfo); 1349 1350 mStkService[slotId].onCmdResponse(resMsg); 1351 } 1352 1353 private void checkForSetupEvent(int event, Bundle args, int slotId) { 1354 boolean eventPresent = false; 1355 byte[] addedInfo = null; 1356 CatLog.d(this, "Event :" + event); 1357 1358 if (mStkContext[slotId].mSetupEventListSettings != null) { 1359 /* Checks if the event is present in the EventList updated by last 1360 * SetupEventList Proactive Command */ 1361 for (int i : mStkContext[slotId].mSetupEventListSettings.eventList) { 1362 if (event == i) { 1363 eventPresent = true; 1364 break; 1365 } 1366 } 1367 1368 /* If Event is present send the response to ICC */ 1369 if (eventPresent == true) { 1370 CatLog.d(this, " Event " + event + "exists in the EventList"); 1371 1372 switch (event) { 1373 case IDLE_SCREEN_AVAILABLE_EVENT: 1374 sendSetUpEventResponse(event, addedInfo, slotId); 1375 removeSetUpEvent(event, slotId); 1376 break; 1377 case LANGUAGE_SELECTION_EVENT: 1378 String language = mContext 1379 .getResources().getConfiguration().locale.getLanguage(); 1380 CatLog.d(this, "language: " + language); 1381 // Each language code is a pair of alpha-numeric characters. 1382 // Each alpha-numeric character shall be coded on one byte 1383 // using the SMS default 7-bit coded alphabet 1384 addedInfo = GsmAlphabet.stringToGsm8BitPacked(language); 1385 sendSetUpEventResponse(event, addedInfo, slotId); 1386 break; 1387 default: 1388 break; 1389 } 1390 } else { 1391 CatLog.e(this, " Event does not exist in the EventList"); 1392 } 1393 } else { 1394 CatLog.e(this, "SetupEventList is not received. Ignoring the event: " + event); 1395 } 1396 } 1397 1398 private void removeSetUpEvent(int event, int slotId) { 1399 CatLog.d(this, "Remove Event :" + event); 1400 1401 if (mStkContext[slotId].mSetupEventListSettings != null) { 1402 /* 1403 * Make new Eventlist without the event 1404 */ 1405 for (int i = 0; i < mStkContext[slotId].mSetupEventListSettings.eventList.length; i++) { 1406 if (event == mStkContext[slotId].mSetupEventListSettings.eventList[i]) { 1407 mStkContext[slotId].mSetupEventListSettings.eventList[i] = INVALID_SETUP_EVENT; 1408 break; 1409 } 1410 } 1411 } 1412 } 1413 1414 private void launchEventMessage(int slotId) { 1415 launchEventMessage(slotId, mStkContext[slotId].mCurrentCmd.geTextMessage()); 1416 } 1417 1418 private void launchEventMessage(int slotId, TextMessage msg) { 1419 if (msg == null || (msg.text != null && msg.text.length() == 0)) { 1420 CatLog.d(LOG_TAG, "launchEventMessage return"); 1421 return; 1422 } 1423 1424 Toast toast = new Toast(mContext.getApplicationContext()); 1425 LayoutInflater inflate = (LayoutInflater) mContext 1426 .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 1427 View v = inflate.inflate(R.layout.stk_event_msg, null); 1428 TextView tv = (TextView) v 1429 .findViewById(com.android.internal.R.id.message); 1430 ImageView iv = (ImageView) v 1431 .findViewById(com.android.internal.R.id.icon); 1432 if (msg.icon != null) { 1433 iv.setImageBitmap(msg.icon); 1434 } else { 1435 iv.setVisibility(View.GONE); 1436 } 1437 /* In case of 'self explanatory' stkapp should display the specified 1438 * icon in proactive command (but not the alpha string). 1439 * If icon is non-self explanatory and if the icon could not be displayed 1440 * then alpha string or text data should be displayed 1441 * Ref: ETSI 102.223,section 6.5.4 1442 */ 1443 if (mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() || 1444 msg.icon == null || !msg.iconSelfExplanatory) { 1445 tv.setText(msg.text); 1446 } 1447 1448 toast.setView(v); 1449 toast.setDuration(Toast.LENGTH_LONG); 1450 toast.setGravity(Gravity.BOTTOM, 0, 0); 1451 toast.show(); 1452 } 1453 1454 private void launchConfirmationDialog(TextMessage msg, int slotId) { 1455 msg.title = mStkContext[slotId].lastSelectedItem; 1456 Intent newIntent = new Intent(); 1457 String targetActivity = STK_DIALOG_ACTIVITY_NAME; 1458 String uriString = STK_DIALOG_URI + System.currentTimeMillis(); 1459 //Set unique URI to create a new instance of activity for different slotId. 1460 Uri uriData = Uri.parse(uriString); 1461 1462 if (newIntent != null) { 1463 newIntent.setClassName(this, targetActivity); 1464 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 1465 | Intent.FLAG_ACTIVITY_NO_HISTORY 1466 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 1467 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId)); 1468 newIntent.putExtra("TEXT", msg); 1469 newIntent.putExtra(SLOT_ID, slotId); 1470 newIntent.setData(uriData); 1471 startActivity(newIntent); 1472 } 1473 } 1474 1475 private void launchBrowser(BrowserSettings settings) { 1476 if (settings == null) { 1477 return; 1478 } 1479 1480 Uri data = null; 1481 String url; 1482 if (settings.url == null) { 1483 // if the command did not contain a URL, 1484 // launch the browser to the default homepage. 1485 CatLog.d(this, "no url data provided by proactive command." + 1486 " launching browser with stk default URL ... "); 1487 url = SystemProperties.get(STK_BROWSER_DEFAULT_URL_SYSPROP, 1488 "http://www.google.com"); 1489 } else { 1490 CatLog.d(this, "launch browser command has attached url = " + settings.url); 1491 url = settings.url; 1492 } 1493 1494 if (url.startsWith("http://") || url.startsWith("https://")) { 1495 data = Uri.parse(url); 1496 CatLog.d(this, "launching browser with url = " + url); 1497 } else { 1498 String modifiedUrl = "http://" + url; 1499 data = Uri.parse(modifiedUrl); 1500 CatLog.d(this, "launching browser with modified url = " + modifiedUrl); 1501 } 1502 1503 Intent intent = new Intent(Intent.ACTION_VIEW); 1504 intent.setData(data); 1505 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1506 switch (settings.mode) { 1507 case USE_EXISTING_BROWSER: 1508 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 1509 break; 1510 case LAUNCH_NEW_BROWSER: 1511 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); 1512 break; 1513 case LAUNCH_IF_NOT_ALREADY_LAUNCHED: 1514 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 1515 break; 1516 } 1517 // start browser activity 1518 startActivity(intent); 1519 // a small delay, let the browser start, before processing the next command. 1520 // this is good for scenarios where a related DISPLAY TEXT command is 1521 // followed immediately. 1522 try { 1523 Thread.sleep(10000); 1524 } catch (InterruptedException e) {} 1525 } 1526 1527 private void launchIdleText(int slotId) { 1528 TextMessage msg = mStkContext[slotId].mIdleModeTextCmd.geTextMessage(); 1529 1530 if (msg == null || msg.text ==null) { 1531 CatLog.d(LOG_TAG, msg == null ? "mCurrent.getTextMessage is NULL" 1532 : "mCurrent.getTextMessage.text is NULL"); 1533 mNotificationManager.cancel(getNotificationId(slotId)); 1534 return; 1535 } else { 1536 CatLog.d(LOG_TAG, "launchIdleText - text[" + msg.text 1537 + "] iconSelfExplanatory[" + msg.iconSelfExplanatory 1538 + "] icon[" + msg.icon + "], sim id: " + slotId); 1539 CatLog.d(LOG_TAG, "Add IdleMode text"); 1540 PendingIntent pendingIntent = PendingIntent.getService(mContext, 0, 1541 new Intent(mContext, StkAppService.class), 0); 1542 1543 final Notification.Builder notificationBuilder = new Notification.Builder( 1544 StkAppService.this); 1545 if (mStkContext[slotId].mMainCmd != null && 1546 mStkContext[slotId].mMainCmd.getMenu() != null) { 1547 notificationBuilder.setContentTitle(mStkContext[slotId].mMainCmd.getMenu().title); 1548 } else { 1549 notificationBuilder.setContentTitle(""); 1550 } 1551 notificationBuilder 1552 .setSmallIcon(com.android.internal.R.drawable.stat_notify_sim_toolkit); 1553 notificationBuilder.setContentIntent(pendingIntent); 1554 notificationBuilder.setOngoing(true); 1555 // Set text and icon for the status bar and notification body. 1556 if (mStkContext[slotId].mIdleModeTextCmd.hasIconLoadFailed() || 1557 !msg.iconSelfExplanatory) { 1558 notificationBuilder.setContentText(msg.text); 1559 notificationBuilder.setTicker(msg.text); 1560 } 1561 if (msg.icon != null) { 1562 notificationBuilder.setLargeIcon(msg.icon); 1563 } else { 1564 Bitmap bitmapIcon = BitmapFactory.decodeResource(StkAppService.this 1565 .getResources().getSystem(), 1566 com.android.internal.R.drawable.stat_notify_sim_toolkit); 1567 notificationBuilder.setLargeIcon(bitmapIcon); 1568 } 1569 notificationBuilder.setColor(mContext.getResources().getColor( 1570 com.android.internal.R.color.system_notification_accent_color)); 1571 mNotificationManager.notify(getNotificationId(slotId), notificationBuilder.build()); 1572 } 1573 } 1574 1575 private void launchToneDialog(int slotId) { 1576 Intent newIntent = new Intent(this, ToneDialog.class); 1577 String uriString = STK_TONE_URI + slotId; 1578 Uri uriData = Uri.parse(uriString); 1579 //Set unique URI to create a new instance of activity for different slotId. 1580 CatLog.d(LOG_TAG, "launchToneDialog, slotId: " + slotId); 1581 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 1582 | Intent.FLAG_ACTIVITY_NO_HISTORY 1583 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 1584 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId)); 1585 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage()); 1586 newIntent.putExtra("TONE", mStkContext[slotId].mCurrentCmd.getToneSettings()); 1587 newIntent.putExtra(SLOT_ID, slotId); 1588 newIntent.setData(uriData); 1589 startActivity(newIntent); 1590 } 1591 1592 private void launchOpenChannelDialog(int slotId) { 1593 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage(); 1594 if (msg == null) { 1595 CatLog.d(LOG_TAG, "msg is null, return here"); 1596 return; 1597 } 1598 1599 msg.title = getResources().getString(R.string.stk_dialog_title); 1600 if (msg.text == null) { 1601 msg.text = getResources().getString(R.string.default_open_channel_msg); 1602 } 1603 1604 final AlertDialog dialog = new AlertDialog.Builder(mContext) 1605 .setIconAttribute(android.R.attr.alertDialogIcon) 1606 .setTitle(msg.title) 1607 .setMessage(msg.text) 1608 .setCancelable(false) 1609 .setPositiveButton(getResources().getString(R.string.stk_dialog_accept), 1610 new DialogInterface.OnClickListener() { 1611 public void onClick(DialogInterface dialog, int which) { 1612 Bundle args = new Bundle(); 1613 args.putInt(RES_ID, RES_ID_CHOICE); 1614 args.putInt(CHOICE, YES); 1615 Message message = mServiceHandler.obtainMessage(); 1616 message.arg1 = OP_RESPONSE; 1617 message.obj = args; 1618 mServiceHandler.sendMessage(message); 1619 } 1620 }) 1621 .setNegativeButton(getResources().getString(R.string.stk_dialog_reject), 1622 new DialogInterface.OnClickListener() { 1623 public void onClick(DialogInterface dialog, int which) { 1624 Bundle args = new Bundle(); 1625 args.putInt(RES_ID, RES_ID_CHOICE); 1626 args.putInt(CHOICE, NO); 1627 Message message = mServiceHandler.obtainMessage(); 1628 message.arg1 = OP_RESPONSE; 1629 message.obj = args; 1630 mServiceHandler.sendMessage(message); 1631 } 1632 }) 1633 .create(); 1634 1635 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 1636 if (!mContext.getResources().getBoolean( 1637 com.android.internal.R.bool.config_sf_slowBlur)) { 1638 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 1639 } 1640 1641 dialog.show(); 1642 } 1643 1644 private void launchTransientEventMessage(int slotId) { 1645 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage(); 1646 if (msg == null) { 1647 CatLog.d(LOG_TAG, "msg is null, return here"); 1648 return; 1649 } 1650 1651 msg.title = getResources().getString(R.string.stk_dialog_title); 1652 1653 final AlertDialog dialog = new AlertDialog.Builder(mContext) 1654 .setIconAttribute(android.R.attr.alertDialogIcon) 1655 .setTitle(msg.title) 1656 .setMessage(msg.text) 1657 .setCancelable(false) 1658 .setPositiveButton(getResources().getString(android.R.string.ok), 1659 new DialogInterface.OnClickListener() { 1660 public void onClick(DialogInterface dialog, int which) { 1661 } 1662 }) 1663 .create(); 1664 1665 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 1666 if (!mContext.getResources().getBoolean( 1667 com.android.internal.R.bool.config_sf_slowBlur)) { 1668 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 1669 } 1670 1671 dialog.show(); 1672 } 1673 1674 private int getNotificationId(int slotId) { 1675 int notifyId = STK_NOTIFICATION_ID; 1676 if (slotId >= 0 && slotId < mSimCount) { 1677 notifyId += slotId; 1678 } else { 1679 CatLog.d(LOG_TAG, "invalid slotId: " + slotId); 1680 } 1681 CatLog.d(LOG_TAG, "getNotificationId, slotId: " + slotId + ", notifyId: " + notifyId); 1682 return notifyId; 1683 } 1684 1685 private String getItemName(int itemId, int slotId) { 1686 Menu menu = mStkContext[slotId].mCurrentCmd.getMenu(); 1687 if (menu == null) { 1688 return null; 1689 } 1690 for (Item item : menu.items) { 1691 if (item.id == itemId) { 1692 return item.text; 1693 } 1694 } 1695 return null; 1696 } 1697 1698 private boolean removeMenu(int slotId) { 1699 try { 1700 if (mStkContext[slotId].mCurrentMenu.items.size() == 1 && 1701 mStkContext[slotId].mCurrentMenu.items.get(0) == null) { 1702 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST; 1703 return true; 1704 } 1705 } catch (NullPointerException e) { 1706 CatLog.d(LOG_TAG, "Unable to get Menu's items size"); 1707 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST; 1708 return true; 1709 } 1710 mStkContext[slotId].mSetupMenuState = STATE_EXIST; 1711 return false; 1712 } 1713 1714 StkContext getStkContext(int slotId) { 1715 if (slotId >= 0 && slotId < mSimCount) { 1716 return mStkContext[slotId]; 1717 } else { 1718 CatLog.d(LOG_TAG, "invalid slotId: " + slotId); 1719 return null; 1720 } 1721 } 1722 1723 private void handleAlphaNotify(Bundle args) { 1724 String alphaString = args.getString(AppInterface.ALPHA_STRING); 1725 1726 CatLog.d(this, "Alpha string received from card: " + alphaString); 1727 Toast toast = Toast.makeText(sInstance, alphaString, Toast.LENGTH_LONG); 1728 toast.setGravity(Gravity.TOP, 0, 0); 1729 toast.show(); 1730 } 1731} 1732