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