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