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