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