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.ComponentName; 31 import android.content.Context; 32 import android.content.DialogInterface; 33 import android.content.Intent; 34 import android.content.res.Configuration; 35 import android.graphics.Bitmap; 36 import android.graphics.BitmapFactory; 37 import android.net.Uri; 38 import android.os.Bundle; 39 import android.os.Handler; 40 import android.os.IBinder; 41 import android.os.Looper; 42 import android.os.Message; 43 import android.os.PowerManager; 44 import android.os.SystemProperties; 45 import android.provider.Settings; 46 import android.telephony.TelephonyManager; 47 import android.text.TextUtils; 48 import android.view.Gravity; 49 import android.view.LayoutInflater; 50 import android.view.View; 51 import android.view.Window; 52 import android.view.WindowManager; 53 import android.widget.ImageView; 54 import android.widget.RemoteViews; 55 import android.widget.TextView; 56 import android.widget.Toast; 57 import android.content.BroadcastReceiver; 58 import android.content.IntentFilter; 59 import android.content.pm.ApplicationInfo; 60 import android.content.pm.PackageManager.NameNotFoundException; 61 62 import com.android.internal.telephony.cat.AppInterface; 63 import com.android.internal.telephony.cat.LaunchBrowserMode; 64 import com.android.internal.telephony.cat.Menu; 65 import com.android.internal.telephony.cat.Item; 66 import com.android.internal.telephony.cat.Input; 67 import com.android.internal.telephony.cat.ResultCode; 68 import com.android.internal.telephony.cat.CatCmdMessage; 69 import com.android.internal.telephony.cat.CatCmdMessage.BrowserSettings; 70 import com.android.internal.telephony.cat.CatCmdMessage.SetupEventListSettings; 71 import com.android.internal.telephony.cat.CatLog; 72 import com.android.internal.telephony.cat.CatResponseMessage; 73 import com.android.internal.telephony.cat.TextMessage; 74 import com.android.internal.telephony.uicc.IccRefreshResponse; 75 import com.android.internal.telephony.uicc.IccCardStatus.CardState; 76 import com.android.internal.telephony.PhoneConstants; 77 import com.android.internal.telephony.TelephonyIntents; 78 import com.android.internal.telephony.IccCardConstants; 79 import com.android.internal.telephony.uicc.UiccController; 80 import com.android.internal.telephony.GsmAlphabet; 81 import com.android.internal.telephony.cat.CatService; 82 83 import java.util.Iterator; 84 import java.util.LinkedList; 85 import java.lang.System; 86 import java.util.List; 87 88 import static com.android.internal.telephony.cat.CatCmdMessage. 89 SetupEventListConstants.IDLE_SCREEN_AVAILABLE_EVENT; 90 import 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 */ 98 public 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 for (int slot = PhoneConstants.SIM_ID_1; slot < mSimCount; slot++) { 585 checkForSetupEvent(LANGUAGE_SELECTION_EVENT, (Bundle) msg.obj, slot); 586 } 587 break; 588 case OP_ALPHA_NOTIFY: 589 handleAlphaNotify((Bundle) msg.obj); 590 break; 591 case OP_IDLE_SCREEN: 592 for (int slot = 0; slot < mSimCount; slot++) { 593 if (mStkContext[slot] != null) { 594 handleIdleScreen(slot); 595 } 596 } 597 break; 598 } 599 } 600 601 private void handleCardStatusChangeAndIccRefresh(Bundle args, int slotId) { 602 boolean cardStatus = args.getBoolean(AppInterface.CARD_STATUS); 603 604 CatLog.d(LOG_TAG, "CardStatus: " + cardStatus); 605 if (cardStatus == false) { 606 CatLog.d(LOG_TAG, "CARD is ABSENT"); 607 // Uninstall STKAPP, Clear Idle text, Stop StkAppService 608 mNotificationManager.cancel(getNotificationId(slotId)); 609 if (isAllOtherCardsAbsent(slotId)) { 610 CatLog.d(LOG_TAG, "All CARDs are ABSENT"); 611 StkAppInstaller.unInstall(mContext); 612 stopSelf(); 613 } 614 } else { 615 IccRefreshResponse state = new IccRefreshResponse(); 616 state.refreshResult = args.getInt(AppInterface.REFRESH_RESULT); 617 618 CatLog.d(LOG_TAG, "Icc Refresh Result: "+ state.refreshResult); 619 if ((state.refreshResult == IccRefreshResponse.REFRESH_RESULT_INIT) || 620 (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET)) { 621 // Clear Idle Text 622 mNotificationManager.cancel(getNotificationId(slotId)); 623 } 624 625 if (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) { 626 // Uninstall STkmenu 627 if (isAllOtherCardsAbsent(slotId)) { 628 StkAppInstaller.unInstall(mContext); 629 } 630 mStkContext[slotId].mCurrentMenu = null; 631 mStkContext[slotId].mMainCmd = null; 632 } 633 } 634 } 635 } 636 /* 637 * Check if all SIMs are absent except the id of slot equals "slotId". 638 */ 639 private boolean isAllOtherCardsAbsent(int slotId) { 640 TelephonyManager mTm = (TelephonyManager) mContext.getSystemService( 641 Context.TELEPHONY_SERVICE); 642 int i = 0; 643 644 for (i = 0; i < mSimCount; i++) { 645 if (i != slotId && mTm.hasIccCard(i)) { 646 break; 647 } 648 } 649 if (i == mSimCount) { 650 return true; 651 } else { 652 return false; 653 } 654 } 655 656 /* 657 * If the device is not in an interactive state, we can assume 658 * that the screen is idle. 659 */ 660 private boolean isScreenIdle() { 661 return (!mPowerManager.isInteractive()); 662 } 663 664 private void handleIdleScreen(int slotId) { 665 666 // If the idle screen event is present in the list need to send the 667 // response to SIM. 668 CatLog.d(this, "Need to send IDLE SCREEN Available event to SIM"); 669 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId); 670 671 if (mStkContext[slotId].mIdleModeTextCmd != null) { 672 launchIdleText(slotId); 673 } 674 } 675 676 private void sendScreenBusyResponse(int slotId) { 677 if (mStkContext[slotId].mCurrentCmd == null) { 678 return; 679 } 680 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd); 681 CatLog.d(this, "SCREEN_BUSY"); 682 resMsg.setResultCode(ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS); 683 mStkService[slotId].onCmdResponse(resMsg); 684 if (mStkContext[slotId].mCmdsQ.size() != 0) { 685 callDelayedMsg(slotId); 686 } else { 687 mStkContext[slotId].mCmdInProgress = false; 688 } 689 } 690 691 private void sendResponse(int resId, int slotId, boolean confirm) { 692 Message msg = mServiceHandler.obtainMessage(); 693 msg.arg1 = OP_RESPONSE; 694 msg.arg2 = slotId; 695 Bundle args = new Bundle(); 696 args.putInt(StkAppService.RES_ID, resId); 697 args.putBoolean(StkAppService.CONFIRMATION, confirm); 698 msg.obj = args; 699 mServiceHandler.sendMessage(msg); 700 } 701 702 private boolean isCmdInteractive(CatCmdMessage cmd) { 703 switch (cmd.getCmdType()) { 704 case SEND_DTMF: 705 case SEND_SMS: 706 case SEND_SS: 707 case SEND_USSD: 708 case SET_UP_IDLE_MODE_TEXT: 709 case SET_UP_MENU: 710 case CLOSE_CHANNEL: 711 case RECEIVE_DATA: 712 case SEND_DATA: 713 case SET_UP_EVENT_LIST: 714 return false; 715 } 716 717 return true; 718 } 719 720 private void handleDelayedCmd(int slotId) { 721 CatLog.d(LOG_TAG, "handleDelayedCmd, slotId: " + slotId); 722 if (mStkContext[slotId].mCmdsQ.size() != 0) { 723 DelayedCmd cmd = mStkContext[slotId].mCmdsQ.poll(); 724 if (cmd != null) { 725 CatLog.d(LOG_TAG, "handleDelayedCmd - queue size: " + 726 mStkContext[slotId].mCmdsQ.size() + 727 " id: " + cmd.id + "sim id: " + cmd.slotId); 728 switch (cmd.id) { 729 case OP_CMD: 730 handleCmd(cmd.msg, cmd.slotId); 731 break; 732 case OP_END_SESSION: 733 handleSessionEnd(cmd.slotId); 734 break; 735 } 736 } 737 } 738 } 739 740 private void callDelayedMsg(int slotId) { 741 Message msg = mServiceHandler.obtainMessage(); 742 msg.arg1 = OP_DELAYED_MSG; 743 msg.arg2 = slotId; 744 mServiceHandler.sendMessage(msg); 745 } 746 747 private void callSetActivityInstMsg(int inst_type, int slotId, Object obj) { 748 Message msg = mServiceHandler.obtainMessage(); 749 msg.obj = obj; 750 msg.arg1 = inst_type; 751 msg.arg2 = slotId; 752 mServiceHandler.sendMessage(msg); 753 } 754 755 private void handleSessionEnd(int slotId) { 756 // We should finish all pending activity if receiving END SESSION command. 757 cleanUpInstanceStackBySlot(slotId); 758 759 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd; 760 CatLog.d(LOG_TAG, "[handleSessionEnd] - mCurrentCmd changed to mMainCmd!."); 761 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mMainCmd; 762 CatLog.d(LOG_TAG, "slotId: " + slotId + ", mMenuState: " + 763 mStkContext[slotId].mMenuState); 764 765 mStkContext[slotId].mIsInputPending = false; 766 mStkContext[slotId].mIsMenuPending = false; 767 mStkContext[slotId].mIsDialogPending = false; 768 769 if (mStkContext[slotId].mMainCmd == null) { 770 CatLog.d(LOG_TAG, "[handleSessionEnd][mMainCmd is null!]"); 771 } 772 mStkContext[slotId].lastSelectedItem = null; 773 // In case of SET UP MENU command which removed the app, don't 774 // update the current menu member. 775 if (mStkContext[slotId].mCurrentMenu != null && mStkContext[slotId].mMainCmd != null) { 776 mStkContext[slotId].mCurrentMenu = mStkContext[slotId].mMainCmd.getMenu(); 777 } 778 CatLog.d(LOG_TAG, "[handleSessionEnd][mMenuState]" + mStkContext[slotId].mMenuIsVisible); 779 // In mutiple instance architecture, the main menu for slotId will be finished when user 780 // goes to the Stk menu of the other SIM. So, we should launch a new instance for the 781 // main menu if the main menu instance has been finished. 782 // If the current menu is secondary menu, we should launch main menu. 783 if (StkMenuActivity.STATE_SECONDARY == mStkContext[slotId].mMenuState) { 784 launchMenuActivity(null, slotId); 785 } 786 if (mStkContext[slotId].mCmdsQ.size() != 0) { 787 callDelayedMsg(slotId); 788 } else { 789 mStkContext[slotId].mCmdInProgress = false; 790 } 791 // In case a launch browser command was just confirmed, launch that url. 792 if (mStkContext[slotId].launchBrowser) { 793 mStkContext[slotId].launchBrowser = false; 794 launchBrowser(mStkContext[slotId].mBrowserSettings); 795 } 796 } 797 798 // returns true if any Stk related activity already has focus on the screen 799 private boolean isTopOfStack() { 800 ActivityManager mAcivityManager = (ActivityManager) mContext 801 .getSystemService(ACTIVITY_SERVICE); 802 String currentPackageName = mAcivityManager.getRunningTasks(1).get(0).topActivity 803 .getPackageName(); 804 if (null != currentPackageName) { 805 return currentPackageName.equals(PACKAGE_NAME); 806 } 807 808 return false; 809 } 810 811 private void handleCmd(CatCmdMessage cmdMsg, int slotId) { 812 813 if (cmdMsg == null) { 814 return; 815 } 816 // save local reference for state tracking. 817 mStkContext[slotId].mCurrentCmd = cmdMsg; 818 boolean waitForUsersResponse = true; 819 820 mStkContext[slotId].mIsInputPending = false; 821 mStkContext[slotId].mIsMenuPending = false; 822 mStkContext[slotId].mIsDialogPending = false; 823 824 CatLog.d(LOG_TAG,"[handleCmd]" + cmdMsg.getCmdType().name()); 825 switch (cmdMsg.getCmdType()) { 826 case DISPLAY_TEXT: 827 TextMessage msg = cmdMsg.geTextMessage(); 828 waitForUsersResponse = msg.responseNeeded; 829 if (mStkContext[slotId].lastSelectedItem != null) { 830 msg.title = mStkContext[slotId].lastSelectedItem; 831 } else if (mStkContext[slotId].mMainCmd != null){ 832 msg.title = mStkContext[slotId].mMainCmd.getMenu().title; 833 } else { 834 // TODO: get the carrier name from the SIM 835 msg.title = ""; 836 } 837 //If we receive a low priority Display Text and the device is 838 // not displaying any STK related activity and the screen is not idle 839 // ( that is, device is in an interactive state), then send a screen busy 840 // terminal response. Otherwise display the message. The existing 841 // displayed message shall be updated with the new display text 842 // proactive command (Refer to ETSI TS 102 384 section 27.22.4.1.4.4.2). 843 if (!(msg.isHighPriority || mStkContext[slotId].mMenuIsVisible 844 || mStkContext[slotId].mDisplayTextDlgIsVisibile || isTopOfStack())) { 845 if(!isScreenIdle()) { 846 CatLog.d(LOG_TAG, "Screen is not idle"); 847 sendScreenBusyResponse(slotId); 848 } else { 849 launchTextDialog(slotId); 850 } 851 } else { 852 launchTextDialog(slotId); 853 } 854 break; 855 case SELECT_ITEM: 856 CatLog.d(LOG_TAG, "SELECT_ITEM +"); 857 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd; 858 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu(); 859 launchMenuActivity(cmdMsg.getMenu(), slotId); 860 break; 861 case SET_UP_MENU: 862 mStkContext[slotId].mCmdInProgress = false; 863 mStkContext[slotId].mMainCmd = mStkContext[slotId].mCurrentCmd; 864 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd; 865 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu(); 866 CatLog.d(LOG_TAG, "SET_UP_MENU [" + removeMenu(slotId) + "]"); 867 868 if (removeMenu(slotId)) { 869 int i = 0; 870 CatLog.d(LOG_TAG, "removeMenu() - Uninstall App"); 871 mStkContext[slotId].mCurrentMenu = null; 872 mStkContext[slotId].mMainCmd = null; 873 //Check other setup menu state. If all setup menu are removed, uninstall apk. 874 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) { 875 if (i != slotId 876 && (mStkContext[slotId].mSetupMenuState == STATE_UNKNOWN 877 || mStkContext[slotId].mSetupMenuState == STATE_EXIST)) { 878 CatLog.d(LOG_TAG, "Not Uninstall App:" + i + "," 879 + mStkContext[slotId].mSetupMenuState); 880 break; 881 } 882 } 883 if (i == mSimCount) { 884 StkAppInstaller.unInstall(mContext); 885 } 886 } else { 887 CatLog.d(LOG_TAG, "install App"); 888 StkAppInstaller.install(mContext); 889 } 890 if (mStkContext[slotId].mMenuIsVisible) { 891 launchMenuActivity(null, slotId); 892 } 893 break; 894 case GET_INPUT: 895 case GET_INKEY: 896 launchInputActivity(slotId); 897 break; 898 case SET_UP_IDLE_MODE_TEXT: 899 waitForUsersResponse = false; 900 mStkContext[slotId].mIdleModeTextCmd = mStkContext[slotId].mCurrentCmd; 901 TextMessage idleModeText = mStkContext[slotId].mCurrentCmd.geTextMessage(); 902 if (idleModeText == null) { 903 launchIdleText(slotId); 904 mStkContext[slotId].mIdleModeTextCmd = null; 905 } 906 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd; 907 if ((mStkContext[slotId].mIdleModeTextCmd != null) && isScreenIdle()) { 908 CatLog.d(this, "set up idle mode"); 909 launchIdleText(slotId); 910 } 911 break; 912 case SEND_DTMF: 913 case SEND_SMS: 914 case SEND_SS: 915 case SEND_USSD: 916 case GET_CHANNEL_STATUS: 917 waitForUsersResponse = false; 918 launchEventMessage(slotId); 919 break; 920 case LAUNCH_BROWSER: 921 TextMessage alphaId = mStkContext[slotId].mCurrentCmd.geTextMessage(); 922 if ((mStkContext[slotId].mCurrentCmd.getBrowserSettings().mode 923 == LaunchBrowserMode.LAUNCH_IF_NOT_ALREADY_LAUNCHED) && 924 ((alphaId == null) || TextUtils.isEmpty(alphaId.text))) { 925 // don't need user confirmation in this case 926 // just launch the browser or spawn a new tab 927 CatLog.d(this, "Browser mode is: launch if not already launched " + 928 "and user confirmation is not currently needed.\n" + 929 "supressing confirmation dialogue and confirming silently..."); 930 mStkContext[slotId].launchBrowser = true; 931 mStkContext[slotId].mBrowserSettings = 932 mStkContext[slotId].mCurrentCmd.getBrowserSettings(); 933 sendResponse(RES_ID_CONFIRM, slotId, true); 934 } else { 935 launchConfirmationDialog(alphaId, slotId); 936 } 937 break; 938 case SET_UP_CALL: 939 TextMessage mesg = mStkContext[slotId].mCurrentCmd.getCallSettings().confirmMsg; 940 if((mesg != null) && (mesg.text == null || mesg.text.length() == 0)) { 941 mesg.text = getResources().getString(R.string.default_setup_call_msg); 942 } 943 CatLog.d(this, "SET_UP_CALL mesg.text " + mesg.text); 944 launchConfirmationDialog(mesg, slotId); 945 break; 946 case PLAY_TONE: 947 launchToneDialog(slotId); 948 break; 949 case OPEN_CHANNEL: 950 launchOpenChannelDialog(slotId); 951 break; 952 case CLOSE_CHANNEL: 953 case RECEIVE_DATA: 954 case SEND_DATA: 955 TextMessage m = mStkContext[slotId].mCurrentCmd.geTextMessage(); 956 957 if ((m != null) && (m.text == null)) { 958 switch(cmdMsg.getCmdType()) { 959 case CLOSE_CHANNEL: 960 m.text = getResources().getString(R.string.default_close_channel_msg); 961 break; 962 case RECEIVE_DATA: 963 m.text = getResources().getString(R.string.default_receive_data_msg); 964 break; 965 case SEND_DATA: 966 m.text = getResources().getString(R.string.default_send_data_msg); 967 break; 968 } 969 } 970 /* 971 * Display indication in the form of a toast to the user if required. 972 */ 973 launchEventMessage(slotId); 974 break; 975 case SET_UP_EVENT_LIST: 976 mStkContext[slotId].mSetupEventListSettings = 977 mStkContext[slotId].mCurrentCmd.getSetEventList(); 978 mStkContext[slotId].mCurrentSetupEventCmd = mStkContext[slotId].mCurrentCmd; 979 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd; 980 if (isScreenIdle()) { 981 CatLog.d(this," Check if IDLE_SCREEN_AVAILABLE_EVENT is present in List"); 982 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId); 983 } 984 break; 985 } 986 987 if (!waitForUsersResponse) { 988 if (mStkContext[slotId].mCmdsQ.size() != 0) { 989 callDelayedMsg(slotId); 990 } else { 991 mStkContext[slotId].mCmdInProgress = false; 992 } 993 } 994 } 995 996 private void handleCmdResponse(Bundle args, int slotId) { 997 CatLog.d(LOG_TAG, "handleCmdResponse, sim id: " + slotId); 998 if (mStkContext[slotId].mCurrentCmd == null) { 999 return; 1000 } 1001 1002 if (mStkService[slotId] == null) { 1003 mStkService[slotId] = CatService.getInstance(slotId); 1004 if (mStkService[slotId] == null) { 1005 // This should never happen (we should be responding only to a message 1006 // that arrived from StkService). It has to exist by this time 1007 CatLog.d(LOG_TAG, "Exception! mStkService is null when we need to send response."); 1008 throw new RuntimeException("mStkService is null when we need to send response"); 1009 } 1010 } 1011 1012 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd); 1013 1014 // set result code 1015 boolean helpRequired = args.getBoolean(HELP, false); 1016 boolean confirmed = false; 1017 1018 switch(args.getInt(RES_ID)) { 1019 case RES_ID_MENU_SELECTION: 1020 CatLog.d(LOG_TAG, "MENU_SELECTION=" + mStkContext[slotId]. 1021 mCurrentMenuCmd.getCmdType()); 1022 int menuSelection = args.getInt(MENU_SELECTION); 1023 switch(mStkContext[slotId].mCurrentMenuCmd.getCmdType()) { 1024 case SET_UP_MENU: 1025 case SELECT_ITEM: 1026 mStkContext[slotId].lastSelectedItem = getItemName(menuSelection, slotId); 1027 if (helpRequired) { 1028 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED); 1029 } else { 1030 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ? 1031 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK); 1032 } 1033 resMsg.setMenuSelection(menuSelection); 1034 break; 1035 } 1036 break; 1037 case RES_ID_INPUT: 1038 CatLog.d(LOG_TAG, "RES_ID_INPUT"); 1039 String input = args.getString(INPUT); 1040 if (input != null && (null != mStkContext[slotId].mCurrentCmd.geInput()) && 1041 (mStkContext[slotId].mCurrentCmd.geInput().yesNo)) { 1042 boolean yesNoSelection = input 1043 .equals(StkInputActivity.YES_STR_RESPONSE); 1044 resMsg.setYesNo(yesNoSelection); 1045 } else { 1046 if (helpRequired) { 1047 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED); 1048 } else { 1049 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ? 1050 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK); 1051 resMsg.setInput(input); 1052 } 1053 } 1054 break; 1055 case RES_ID_CONFIRM: 1056 CatLog.d(this, "RES_ID_CONFIRM"); 1057 confirmed = args.getBoolean(CONFIRMATION); 1058 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) { 1059 case DISPLAY_TEXT: 1060 if (confirmed) { 1061 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ? 1062 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK); 1063 } else { 1064 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER); 1065 } 1066 break; 1067 case LAUNCH_BROWSER: 1068 resMsg.setResultCode(confirmed ? ResultCode.OK 1069 : ResultCode.UICC_SESSION_TERM_BY_USER); 1070 if (confirmed) { 1071 mStkContext[slotId].launchBrowser = true; 1072 mStkContext[slotId].mBrowserSettings = 1073 mStkContext[slotId].mCurrentCmd.getBrowserSettings(); 1074 } 1075 break; 1076 case SET_UP_CALL: 1077 resMsg.setResultCode(ResultCode.OK); 1078 resMsg.setConfirmation(confirmed); 1079 if (confirmed) { 1080 CatLog.d(this, "Going back to mainMenu before starting a call."); 1081 launchMenuActivity(null, slotId); 1082 launchEventMessage(slotId, 1083 mStkContext[slotId].mCurrentCmd.getCallSettings().callMsg); 1084 } 1085 break; 1086 } 1087 break; 1088 case RES_ID_DONE: 1089 resMsg.setResultCode(ResultCode.OK); 1090 break; 1091 case RES_ID_BACKWARD: 1092 CatLog.d(LOG_TAG, "RES_ID_BACKWARD"); 1093 resMsg.setResultCode(ResultCode.BACKWARD_MOVE_BY_USER); 1094 break; 1095 case RES_ID_END_SESSION: 1096 CatLog.d(LOG_TAG, "RES_ID_END_SESSION"); 1097 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER); 1098 break; 1099 case RES_ID_TIMEOUT: 1100 CatLog.d(LOG_TAG, "RES_ID_TIMEOUT"); 1101 // GCF test-case 27.22.4.1.1 Expected Sequence 1.5 (DISPLAY TEXT, 1102 // Clear message after delay, successful) expects result code OK. 1103 // If the command qualifier specifies no user response is required 1104 // then send OK instead of NO_RESPONSE_FROM_USER 1105 if ((mStkContext[slotId].mCurrentCmd.getCmdType().value() == 1106 AppInterface.CommandType.DISPLAY_TEXT.value()) 1107 && (mStkContext[slotId].mCurrentCmd.geTextMessage().userClear == false)) { 1108 resMsg.setResultCode(ResultCode.OK); 1109 } else { 1110 resMsg.setResultCode(ResultCode.NO_RESPONSE_FROM_USER); 1111 } 1112 break; 1113 case RES_ID_CHOICE: 1114 int choice = args.getInt(CHOICE); 1115 CatLog.d(this, "User Choice=" + choice); 1116 switch (choice) { 1117 case YES: 1118 resMsg.setResultCode(ResultCode.OK); 1119 confirmed = true; 1120 break; 1121 case NO: 1122 resMsg.setResultCode(ResultCode.USER_NOT_ACCEPT); 1123 break; 1124 } 1125 1126 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() == 1127 AppInterface.CommandType.OPEN_CHANNEL.value()) { 1128 resMsg.setConfirmation(confirmed); 1129 } 1130 break; 1131 1132 default: 1133 CatLog.d(LOG_TAG, "Unknown result id"); 1134 return; 1135 } 1136 1137 if (null != mStkContext[slotId].mCurrentCmd && 1138 null != mStkContext[slotId].mCurrentCmd.getCmdType()) { 1139 CatLog.d(LOG_TAG, "handleCmdResponse- cmdName[" + 1140 mStkContext[slotId].mCurrentCmd.getCmdType().name() + "]"); 1141 } 1142 mStkService[slotId].onCmdResponse(resMsg); 1143 } 1144 1145 /** 1146 * Returns 0 or FLAG_ACTIVITY_NO_USER_ACTION, 0 means the user initiated the action. 1147 * 1148 * @param userAction If the userAction is yes then we always return 0 otherwise 1149 * mMenuIsVisible is used to determine what to return. If mMenuIsVisible is true 1150 * then we are the foreground app and we'll return 0 as from our perspective a 1151 * user action did cause. If it's false than we aren't the foreground app and 1152 * FLAG_ACTIVITY_NO_USER_ACTION is returned. 1153 * 1154 * @return 0 or FLAG_ACTIVITY_NO_USER_ACTION 1155 */ 1156 private int getFlagActivityNoUserAction(InitiatedByUserAction userAction, int slotId) { 1157 return ((userAction == InitiatedByUserAction.yes) | mStkContext[slotId].mMenuIsVisible) 1158 ? 0 : Intent.FLAG_ACTIVITY_NO_USER_ACTION; 1159 } 1160 /** 1161 * This method is used for cleaning up pending instances in stack. 1162 */ 1163 private void cleanUpInstanceStackBySlot(int slotId) { 1164 Activity activity = mStkContext[slotId].getPendingActivityInstance(); 1165 Activity dialog = mStkContext[slotId].getPendingDialogInstance(); 1166 CatLog.d(LOG_TAG, "cleanUpInstanceStackBySlot slotId: " + slotId); 1167 if (mStkContext[slotId].mCurrentCmd == null) { 1168 CatLog.d(LOG_TAG, "current cmd is null."); 1169 return; 1170 } 1171 if (activity != null) { 1172 CatLog.d(LOG_TAG, "current cmd type: " + 1173 mStkContext[slotId].mCurrentCmd.getCmdType()); 1174 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() == 1175 AppInterface.CommandType.GET_INPUT.value() || 1176 mStkContext[slotId].mCurrentCmd.getCmdType().value() == 1177 AppInterface.CommandType.GET_INKEY.value()) { 1178 mStkContext[slotId].mIsInputPending = true; 1179 } else if (mStkContext[slotId].mCurrentCmd.getCmdType().value() == 1180 AppInterface.CommandType.SET_UP_MENU.value() || 1181 mStkContext[slotId].mCurrentCmd.getCmdType().value() == 1182 AppInterface.CommandType.SELECT_ITEM.value()) { 1183 mStkContext[slotId].mIsMenuPending = true; 1184 } else { 1185 } 1186 CatLog.d(LOG_TAG, "finish pending activity."); 1187 activity.finish(); 1188 mStkContext[slotId].mActivityInstance = null; 1189 } 1190 if (dialog != null) { 1191 CatLog.d(LOG_TAG, "finish pending dialog."); 1192 mStkContext[slotId].mIsDialogPending = true; 1193 dialog.finish(); 1194 mStkContext[slotId].mDialogInstance = null; 1195 } 1196 } 1197 /** 1198 * This method is used for restoring pending instances from stack. 1199 */ 1200 private void restoreInstanceFromStackBySlot(int slotId) { 1201 AppInterface.CommandType cmdType = mStkContext[slotId].mCurrentCmd.getCmdType(); 1202 1203 CatLog.d(LOG_TAG, "restoreInstanceFromStackBySlot cmdType : " + cmdType); 1204 switch(cmdType) { 1205 case GET_INPUT: 1206 case GET_INKEY: 1207 launchInputActivity(slotId); 1208 //Set mMenuIsVisible to true for showing main menu for 1209 //following session end command. 1210 mStkContext[slotId].mMenuIsVisible = true; 1211 break; 1212 case DISPLAY_TEXT: 1213 launchTextDialog(slotId); 1214 break; 1215 case LAUNCH_BROWSER: 1216 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.geTextMessage(), 1217 slotId); 1218 break; 1219 case OPEN_CHANNEL: 1220 launchOpenChannelDialog(slotId); 1221 break; 1222 case SET_UP_CALL: 1223 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.getCallSettings(). 1224 confirmMsg, slotId); 1225 break; 1226 case SET_UP_MENU: 1227 case SELECT_ITEM: 1228 launchMenuActivity(null, slotId); 1229 break; 1230 default: 1231 break; 1232 } 1233 } 1234 1235 private void launchMenuActivity(Menu menu, int slotId) { 1236 Intent newIntent = new Intent(Intent.ACTION_VIEW); 1237 String targetActivity = STK_MENU_ACTIVITY_NAME; 1238 String uriString = STK_MENU_URI + System.currentTimeMillis(); 1239 //Set unique URI to create a new instance of activity for different slotId. 1240 Uri uriData = Uri.parse(uriString); 1241 1242 CatLog.d(LOG_TAG, "launchMenuActivity, slotId: " + slotId + " , " + 1243 uriData.toString() + " , " + mStkContext[slotId].mOpCode + ", " 1244 + mStkContext[slotId].mMenuState); 1245 newIntent.setClassName(PACKAGE_NAME, targetActivity); 1246 int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK; 1247 1248 if (menu == null) { 1249 // We assume this was initiated by the user pressing the tool kit icon 1250 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.yes, slotId); 1251 if (mStkContext[slotId].mOpCode == OP_END_SESSION) { 1252 CatLog.d(LOG_TAG, "launchMenuActivity, return OP_END_SESSION"); 1253 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN; 1254 if (mStkContext[slotId].mMainActivityInstance != null) { 1255 CatLog.d(LOG_TAG, "launchMenuActivity, mMainActivityInstance is not null"); 1256 return; 1257 } 1258 } 1259 1260 //If the last pending menu is secondary menu, "STATE" should be "STATE_SECONDARY". 1261 //Otherwise, it should be "STATE_MAIN". 1262 if (mStkContext[slotId].mOpCode == OP_LAUNCH_APP && 1263 mStkContext[slotId].mMenuState == StkMenuActivity.STATE_SECONDARY) { 1264 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY); 1265 } else { 1266 newIntent.putExtra("STATE", StkMenuActivity.STATE_MAIN); 1267 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN; 1268 } 1269 } else { 1270 // We don't know and we'll let getFlagActivityNoUserAction decide. 1271 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId); 1272 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY); 1273 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_SECONDARY; 1274 } 1275 newIntent.putExtra(SLOT_ID, slotId); 1276 newIntent.setData(uriData); 1277 newIntent.setFlags(intentFlags); 1278 mContext.startActivity(newIntent); 1279 } 1280 1281 private void launchInputActivity(int slotId) { 1282 Intent newIntent = new Intent(Intent.ACTION_VIEW); 1283 String targetActivity = STK_INPUT_ACTIVITY_NAME; 1284 String uriString = STK_INPUT_URI + System.currentTimeMillis(); 1285 //Set unique URI to create a new instance of activity for different slotId. 1286 Uri uriData = Uri.parse(uriString); 1287 1288 CatLog.d(LOG_TAG, "launchInputActivity, slotId: " + slotId); 1289 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 1290 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId)); 1291 newIntent.setClassName(PACKAGE_NAME, targetActivity); 1292 newIntent.putExtra("INPUT", mStkContext[slotId].mCurrentCmd.geInput()); 1293 newIntent.putExtra(SLOT_ID, slotId); 1294 newIntent.setData(uriData); 1295 mContext.startActivity(newIntent); 1296 } 1297 1298 private void launchTextDialog(int slotId) { 1299 CatLog.d(LOG_TAG, "launchTextDialog, slotId: " + slotId); 1300 Intent newIntent = new Intent(); 1301 String targetActivity = STK_DIALOG_ACTIVITY_NAME; 1302 int action = getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId); 1303 String uriString = STK_DIALOG_URI + System.currentTimeMillis(); 1304 //Set unique URI to create a new instance of activity for different slotId. 1305 Uri uriData = Uri.parse(uriString); 1306 if (newIntent != null) { 1307 newIntent.setClassName(PACKAGE_NAME, targetActivity); 1308 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 1309 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 1310 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId)); 1311 newIntent.setData(uriData); 1312 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage()); 1313 newIntent.putExtra(SLOT_ID, slotId); 1314 startActivity(newIntent); 1315 // For display texts with immediate response, send the terminal response 1316 // immediately. responseNeeded will be false, if display text command has 1317 // the immediate response tlv. 1318 if (!mStkContext[slotId].mCurrentCmd.geTextMessage().responseNeeded) { 1319 sendResponse(RES_ID_CONFIRM, slotId, true); 1320 } 1321 } 1322 } 1323 1324 public boolean isStkDialogActivated(Context context) { 1325 String stkDialogActivity = "com.android.stk.StkDialogActivity"; 1326 boolean activated = false; 1327 final ActivityManager am = (ActivityManager) context.getSystemService( 1328 Context.ACTIVITY_SERVICE); 1329 String topActivity = am.getRunningTasks(1).get(0).topActivity.getClassName(); 1330 1331 CatLog.d(LOG_TAG, "isStkDialogActivated: " + topActivity); 1332 if (topActivity.equals(stkDialogActivity)) { 1333 activated = true; 1334 } 1335 CatLog.d(LOG_TAG, "activated : " + activated); 1336 return activated; 1337 } 1338 1339 private void sendSetUpEventResponse(int event, byte[] addedInfo, int slotId) { 1340 CatLog.d(this, "sendSetUpEventResponse: event : " + event + "slotId = " + slotId); 1341 1342 if (mStkContext[slotId].mCurrentSetupEventCmd == null){ 1343 CatLog.e(this, "mCurrentSetupEventCmd is null"); 1344 return; 1345 } 1346 1347 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentSetupEventCmd); 1348 1349 resMsg.setResultCode(ResultCode.OK); 1350 resMsg.setEventDownload(event, addedInfo); 1351 1352 mStkService[slotId].onCmdResponse(resMsg); 1353 } 1354 1355 private void checkForSetupEvent(int event, Bundle args, int slotId) { 1356 boolean eventPresent = false; 1357 byte[] addedInfo = null; 1358 CatLog.d(this, "Event :" + event); 1359 1360 if (mStkContext[slotId].mSetupEventListSettings != null) { 1361 /* Checks if the event is present in the EventList updated by last 1362 * SetupEventList Proactive Command */ 1363 for (int i : mStkContext[slotId].mSetupEventListSettings.eventList) { 1364 if (event == i) { 1365 eventPresent = true; 1366 break; 1367 } 1368 } 1369 1370 /* If Event is present send the response to ICC */ 1371 if (eventPresent == true) { 1372 CatLog.d(this, " Event " + event + "exists in the EventList"); 1373 1374 switch (event) { 1375 case IDLE_SCREEN_AVAILABLE_EVENT: 1376 sendSetUpEventResponse(event, addedInfo, slotId); 1377 removeSetUpEvent(event, slotId); 1378 break; 1379 case LANGUAGE_SELECTION_EVENT: 1380 String language = mContext 1381 .getResources().getConfiguration().locale.getLanguage(); 1382 CatLog.d(this, "language: " + language); 1383 // Each language code is a pair of alpha-numeric characters. 1384 // Each alpha-numeric character shall be coded on one byte 1385 // using the SMS default 7-bit coded alphabet 1386 addedInfo = GsmAlphabet.stringToGsm8BitPacked(language); 1387 sendSetUpEventResponse(event, addedInfo, slotId); 1388 break; 1389 default: 1390 break; 1391 } 1392 } else { 1393 CatLog.e(this, " Event does not exist in the EventList"); 1394 } 1395 } else { 1396 CatLog.e(this, "SetupEventList is not received. Ignoring the event: " + event); 1397 } 1398 } 1399 1400 private void removeSetUpEvent(int event, int slotId) { 1401 CatLog.d(this, "Remove Event :" + event); 1402 1403 if (mStkContext[slotId].mSetupEventListSettings != null) { 1404 /* 1405 * Make new Eventlist without the event 1406 */ 1407 for (int i = 0; i < mStkContext[slotId].mSetupEventListSettings.eventList.length; i++) { 1408 if (event == mStkContext[slotId].mSetupEventListSettings.eventList[i]) { 1409 mStkContext[slotId].mSetupEventListSettings.eventList[i] = INVALID_SETUP_EVENT; 1410 break; 1411 } 1412 } 1413 } 1414 } 1415 1416 private void launchEventMessage(int slotId) { 1417 launchEventMessage(slotId, mStkContext[slotId].mCurrentCmd.geTextMessage()); 1418 } 1419 1420 private void launchEventMessage(int slotId, TextMessage msg) { 1421 if (msg == null || (msg.text != null && msg.text.length() == 0)) { 1422 CatLog.d(LOG_TAG, "launchEventMessage return"); 1423 return; 1424 } 1425 1426 Toast toast = new Toast(mContext.getApplicationContext()); 1427 LayoutInflater inflate = (LayoutInflater) mContext 1428 .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 1429 View v = inflate.inflate(R.layout.stk_event_msg, null); 1430 TextView tv = (TextView) v 1431 .findViewById(com.android.internal.R.id.message); 1432 ImageView iv = (ImageView) v 1433 .findViewById(com.android.internal.R.id.icon); 1434 if (msg.icon != null) { 1435 iv.setImageBitmap(msg.icon); 1436 } else { 1437 iv.setVisibility(View.GONE); 1438 } 1439 /* In case of 'self explanatory' stkapp should display the specified 1440 * icon in proactive command (but not the alpha string). 1441 * If icon is non-self explanatory and if the icon could not be displayed 1442 * then alpha string or text data should be displayed 1443 * Ref: ETSI 102.223,section 6.5.4 1444 */ 1445 if (mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() || 1446 msg.icon == null || !msg.iconSelfExplanatory) { 1447 tv.setText(msg.text); 1448 } 1449 1450 toast.setView(v); 1451 toast.setDuration(Toast.LENGTH_LONG); 1452 toast.setGravity(Gravity.BOTTOM, 0, 0); 1453 toast.show(); 1454 } 1455 1456 private void launchConfirmationDialog(TextMessage msg, int slotId) { 1457 msg.title = mStkContext[slotId].lastSelectedItem; 1458 Intent newIntent = new Intent(); 1459 String targetActivity = STK_DIALOG_ACTIVITY_NAME; 1460 String uriString = STK_DIALOG_URI + System.currentTimeMillis(); 1461 //Set unique URI to create a new instance of activity for different slotId. 1462 Uri uriData = Uri.parse(uriString); 1463 1464 if (newIntent != null) { 1465 newIntent.setClassName(this, targetActivity); 1466 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 1467 | Intent.FLAG_ACTIVITY_NO_HISTORY 1468 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 1469 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId)); 1470 newIntent.putExtra("TEXT", msg); 1471 newIntent.putExtra(SLOT_ID, slotId); 1472 newIntent.setData(uriData); 1473 startActivity(newIntent); 1474 } 1475 } 1476 1477 private void launchBrowser(BrowserSettings settings) { 1478 if (settings == null) { 1479 return; 1480 } 1481 1482 Uri data = null; 1483 String url; 1484 if (settings.url == null) { 1485 // if the command did not contain a URL, 1486 // launch the browser to the default homepage. 1487 CatLog.d(this, "no url data provided by proactive command." + 1488 " launching browser with stk default URL ... "); 1489 url = SystemProperties.get(STK_BROWSER_DEFAULT_URL_SYSPROP, 1490 "http://www.google.com"); 1491 } else { 1492 CatLog.d(this, "launch browser command has attached url = " + settings.url); 1493 url = settings.url; 1494 } 1495 1496 if (url.startsWith("http://") || url.startsWith("https://")) { 1497 data = Uri.parse(url); 1498 CatLog.d(this, "launching browser with url = " + url); 1499 } else { 1500 String modifiedUrl = "http://" + url; 1501 data = Uri.parse(modifiedUrl); 1502 CatLog.d(this, "launching browser with modified url = " + modifiedUrl); 1503 } 1504 1505 Intent intent = new Intent(Intent.ACTION_VIEW); 1506 intent.setData(data); 1507 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1508 switch (settings.mode) { 1509 case USE_EXISTING_BROWSER: 1510 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 1511 break; 1512 case LAUNCH_NEW_BROWSER: 1513 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); 1514 break; 1515 case LAUNCH_IF_NOT_ALREADY_LAUNCHED: 1516 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 1517 break; 1518 } 1519 // start browser activity 1520 startActivity(intent); 1521 // a small delay, let the browser start, before processing the next command. 1522 // this is good for scenarios where a related DISPLAY TEXT command is 1523 // followed immediately. 1524 try { 1525 Thread.sleep(10000); 1526 } catch (InterruptedException e) {} 1527 } 1528 1529 private void launchIdleText(int slotId) { 1530 TextMessage msg = mStkContext[slotId].mIdleModeTextCmd.geTextMessage(); 1531 1532 if (msg == null || msg.text ==null) { 1533 CatLog.d(LOG_TAG, msg == null ? "mCurrent.getTextMessage is NULL" 1534 : "mCurrent.getTextMessage.text is NULL"); 1535 mNotificationManager.cancel(getNotificationId(slotId)); 1536 return; 1537 } else { 1538 CatLog.d(LOG_TAG, "launchIdleText - text[" + msg.text 1539 + "] iconSelfExplanatory[" + msg.iconSelfExplanatory 1540 + "] icon[" + msg.icon + "], sim id: " + slotId); 1541 CatLog.d(LOG_TAG, "Add IdleMode text"); 1542 PendingIntent pendingIntent = PendingIntent.getService(mContext, 0, 1543 new Intent(mContext, StkAppService.class), 0); 1544 1545 final Notification.Builder notificationBuilder = new Notification.Builder( 1546 StkAppService.this); 1547 if (mStkContext[slotId].mMainCmd != null && 1548 mStkContext[slotId].mMainCmd.getMenu() != null) { 1549 notificationBuilder.setContentTitle(mStkContext[slotId].mMainCmd.getMenu().title); 1550 } else { 1551 notificationBuilder.setContentTitle(""); 1552 } 1553 notificationBuilder 1554 .setSmallIcon(com.android.internal.R.drawable.stat_notify_sim_toolkit); 1555 notificationBuilder.setContentIntent(pendingIntent); 1556 notificationBuilder.setOngoing(true); 1557 // Set text and icon for the status bar and notification body. 1558 if (mStkContext[slotId].mIdleModeTextCmd.hasIconLoadFailed() || 1559 !msg.iconSelfExplanatory) { 1560 notificationBuilder.setContentText(msg.text); 1561 notificationBuilder.setTicker(msg.text); 1562 } 1563 if (msg.icon != null) { 1564 notificationBuilder.setLargeIcon(msg.icon); 1565 } else { 1566 Bitmap bitmapIcon = BitmapFactory.decodeResource(StkAppService.this 1567 .getResources().getSystem(), 1568 com.android.internal.R.drawable.stat_notify_sim_toolkit); 1569 notificationBuilder.setLargeIcon(bitmapIcon); 1570 } 1571 notificationBuilder.setColor(mContext.getResources().getColor( 1572 com.android.internal.R.color.system_notification_accent_color)); 1573 mNotificationManager.notify(getNotificationId(slotId), notificationBuilder.build()); 1574 } 1575 } 1576 1577 private void launchToneDialog(int slotId) { 1578 Intent newIntent = new Intent(this, ToneDialog.class); 1579 String uriString = STK_TONE_URI + slotId; 1580 Uri uriData = Uri.parse(uriString); 1581 //Set unique URI to create a new instance of activity for different slotId. 1582 CatLog.d(LOG_TAG, "launchToneDialog, slotId: " + slotId); 1583 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 1584 | Intent.FLAG_ACTIVITY_NO_HISTORY 1585 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 1586 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId)); 1587 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage()); 1588 newIntent.putExtra("TONE", mStkContext[slotId].mCurrentCmd.getToneSettings()); 1589 newIntent.putExtra(SLOT_ID, slotId); 1590 newIntent.setData(uriData); 1591 startActivity(newIntent); 1592 } 1593 1594 private void launchOpenChannelDialog(final int slotId) { 1595 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage(); 1596 if (msg == null) { 1597 CatLog.d(LOG_TAG, "msg is null, return here"); 1598 return; 1599 } 1600 1601 msg.title = getResources().getString(R.string.stk_dialog_title); 1602 if (msg.text == null) { 1603 msg.text = getResources().getString(R.string.default_open_channel_msg); 1604 } 1605 1606 final AlertDialog dialog = new AlertDialog.Builder(mContext) 1607 .setIconAttribute(android.R.attr.alertDialogIcon) 1608 .setTitle(msg.title) 1609 .setMessage(msg.text) 1610 .setCancelable(false) 1611 .setPositiveButton(getResources().getString(R.string.stk_dialog_accept), 1612 new DialogInterface.OnClickListener() { 1613 public void onClick(DialogInterface dialog, int which) { 1614 Bundle args = new Bundle(); 1615 args.putInt(RES_ID, RES_ID_CHOICE); 1616 args.putInt(CHOICE, YES); 1617 Message message = mServiceHandler.obtainMessage(); 1618 message.arg1 = OP_RESPONSE; 1619 message.arg2 = slotId; 1620 message.obj = args; 1621 mServiceHandler.sendMessage(message); 1622 } 1623 }) 1624 .setNegativeButton(getResources().getString(R.string.stk_dialog_reject), 1625 new DialogInterface.OnClickListener() { 1626 public void onClick(DialogInterface dialog, int which) { 1627 Bundle args = new Bundle(); 1628 args.putInt(RES_ID, RES_ID_CHOICE); 1629 args.putInt(CHOICE, NO); 1630 Message message = mServiceHandler.obtainMessage(); 1631 message.arg1 = OP_RESPONSE; 1632 message.arg2 = slotId; 1633 message.obj = args; 1634 mServiceHandler.sendMessage(message); 1635 } 1636 }) 1637 .create(); 1638 1639 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 1640 if (!mContext.getResources().getBoolean( 1641 com.android.internal.R.bool.config_sf_slowBlur)) { 1642 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 1643 } 1644 1645 dialog.show(); 1646 } 1647 1648 private void launchTransientEventMessage(int slotId) { 1649 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage(); 1650 if (msg == null) { 1651 CatLog.d(LOG_TAG, "msg is null, return here"); 1652 return; 1653 } 1654 1655 msg.title = getResources().getString(R.string.stk_dialog_title); 1656 1657 final AlertDialog dialog = new AlertDialog.Builder(mContext) 1658 .setIconAttribute(android.R.attr.alertDialogIcon) 1659 .setTitle(msg.title) 1660 .setMessage(msg.text) 1661 .setCancelable(false) 1662 .setPositiveButton(getResources().getString(android.R.string.ok), 1663 new DialogInterface.OnClickListener() { 1664 public void onClick(DialogInterface dialog, int which) { 1665 } 1666 }) 1667 .create(); 1668 1669 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 1670 if (!mContext.getResources().getBoolean( 1671 com.android.internal.R.bool.config_sf_slowBlur)) { 1672 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 1673 } 1674 1675 dialog.show(); 1676 } 1677 1678 private int getNotificationId(int slotId) { 1679 int notifyId = STK_NOTIFICATION_ID; 1680 if (slotId >= 0 && slotId < mSimCount) { 1681 notifyId += slotId; 1682 } else { 1683 CatLog.d(LOG_TAG, "invalid slotId: " + slotId); 1684 } 1685 CatLog.d(LOG_TAG, "getNotificationId, slotId: " + slotId + ", notifyId: " + notifyId); 1686 return notifyId; 1687 } 1688 1689 private String getItemName(int itemId, int slotId) { 1690 Menu menu = mStkContext[slotId].mCurrentCmd.getMenu(); 1691 if (menu == null) { 1692 return null; 1693 } 1694 for (Item item : menu.items) { 1695 if (item.id == itemId) { 1696 return item.text; 1697 } 1698 } 1699 return null; 1700 } 1701 1702 private boolean removeMenu(int slotId) { 1703 try { 1704 if (mStkContext[slotId].mCurrentMenu.items.size() == 1 && 1705 mStkContext[slotId].mCurrentMenu.items.get(0) == null) { 1706 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST; 1707 return true; 1708 } 1709 } catch (NullPointerException e) { 1710 CatLog.d(LOG_TAG, "Unable to get Menu's items size"); 1711 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST; 1712 return true; 1713 } 1714 mStkContext[slotId].mSetupMenuState = STATE_EXIST; 1715 return false; 1716 } 1717 1718 StkContext getStkContext(int slotId) { 1719 if (slotId >= 0 && slotId < mSimCount) { 1720 return mStkContext[slotId]; 1721 } else { 1722 CatLog.d(LOG_TAG, "invalid slotId: " + slotId); 1723 return null; 1724 } 1725 } 1726 1727 private void handleAlphaNotify(Bundle args) { 1728 String alphaString = args.getString(AppInterface.ALPHA_STRING); 1729 1730 CatLog.d(this, "Alpha string received from card: " + alphaString); 1731 Toast toast = Toast.makeText(sInstance, alphaString, Toast.LENGTH_LONG); 1732 toast.setGravity(Gravity.TOP, 0, 0); 1733 toast.show(); 1734 } 1735 } 1736