STK App DSDS support

Change-Id: I8d0a9ac406327fa91d78119df2953a417b4e4cb6
diff --git a/src/com/android/stk/BootCompletedReceiver.java b/src/com/android/stk/BootCompletedReceiver.java
index 12cb32e..f11c4f3 100644
--- a/src/com/android/stk/BootCompletedReceiver.java
+++ b/src/com/android/stk/BootCompletedReceiver.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
+import com.android.internal.telephony.cat.CatLog;
 
 /**
  * Boot completed receiver. used to reset the app install state every time the
@@ -27,6 +28,8 @@
  *
  */
 public class BootCompletedReceiver extends BroadcastReceiver {
+    private static final String LOG_TAG = new Object(){}.getClass().getEnclosingClass().getName();
+
     @Override
     public void onReceive(Context context, Intent intent) {
         String action = intent.getAction();
@@ -37,6 +40,7 @@
             args.putInt(StkAppService.OPCODE, StkAppService.OP_BOOT_COMPLETED);
             context.startService(new Intent(context, StkAppService.class)
                     .putExtras(args));
+            CatLog.d(LOG_TAG, "[ACTION_BOOT_COMPLETED]");
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/stk/StkAppInstaller.java b/src/com/android/stk/StkAppInstaller.java
index d9e96e9..3208ba8 100644
--- a/src/com/android/stk/StkAppInstaller.java
+++ b/src/com/android/stk/StkAppInstaller.java
@@ -17,45 +17,65 @@
 package com.android.stk;
 
 import com.android.internal.telephony.cat.CatLog;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.TelephonyProperties;
 
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.telephony.TelephonyManager;
+import android.os.SystemProperties;
 
 /**
  * Application installer for SIM Toolkit.
  *
  */
 abstract class StkAppInstaller {
-    private StkAppInstaller() {}
+    private static final String STK_LAUNCHER_ACTIVITY = "com.android.stk.StkLauncherActivity";
+    private static final String LOG_TAG = "StkAppInstaller";
 
-    static void install(Context context) {
+    private StkAppInstaller() {
+        CatLog.d(LOG_TAG, "init");
+    }
+
+    public static void install(Context context) {
         setAppState(context, true);
     }
 
-    static void unInstall(Context context) {
+    public static void unInstall(Context context) {
         setAppState(context, false);
     }
 
     private static void setAppState(Context context, boolean install) {
+        CatLog.d(LOG_TAG, "[setAppState]+");
         if (context == null) {
+            CatLog.d(LOG_TAG, "[setAppState]- no context, just return.");
             return;
         }
         PackageManager pm = context.getPackageManager();
         if (pm == null) {
+            CatLog.d(LOG_TAG, "[setAppState]- no package manager, just return.");
             return;
         }
-        // check that STK app package is known to the PackageManager
-        ComponentName cName = new ComponentName("com.android.stk",
-                "com.android.stk.StkLauncherActivity");
+        ComponentName cName = new ComponentName("com.android.stk", STK_LAUNCHER_ACTIVITY);
         int state = install ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                 : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 
-        try {
-            pm.setComponentEnabledSetting(cName, state,
-                    PackageManager.DONT_KILL_APP);
-        } catch (Exception e) {
-            CatLog.d("StkAppInstaller", "Could not change STK app state");
+        if (((PackageManager.COMPONENT_ENABLED_STATE_ENABLED == state) &&
+                (PackageManager.COMPONENT_ENABLED_STATE_ENABLED ==
+                pm.getComponentEnabledSetting(cName))) ||
+                ((PackageManager.COMPONENT_ENABLED_STATE_DISABLED == state) &&
+                (PackageManager.COMPONENT_ENABLED_STATE_DISABLED ==
+                pm.getComponentEnabledSetting(cName)))) {
+            CatLog.d(LOG_TAG, "Need not change app state!!");
+        } else {
+            CatLog.d(LOG_TAG, "Change app state[" + install + "]");
+            try {
+                pm.setComponentEnabledSetting(cName, state, PackageManager.DONT_KILL_APP);
+            } catch (Exception e) {
+                CatLog.d(LOG_TAG, "Could not change STK app state");
+            }
         }
+        CatLog.d(LOG_TAG, "[setAppState]-");
     }
 }
diff --git a/src/com/android/stk/StkAppService.java b/src/com/android/stk/StkAppService.java
old mode 100644
new mode 100755
index 24d5b89..1220741
--- a/src/com/android/stk/StkAppService.java
+++ b/src/com/android/stk/StkAppService.java
@@ -21,6 +21,10 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RecentTaskInfo;
+import android.app.ActivityManager.RunningAppProcessInfo;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -42,6 +46,10 @@
 import android.widget.RemoteViews;
 import android.widget.TextView;
 import android.widget.Toast;
+import android.content.BroadcastReceiver;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
 
 import com.android.internal.telephony.cat.AppInterface;
 import com.android.internal.telephony.cat.Menu;
@@ -55,8 +63,14 @@
 import com.android.internal.telephony.cat.TextMessage;
 import com.android.internal.telephony.uicc.IccRefreshResponse;
 import com.android.internal.telephony.uicc.IccCardStatus.CardState;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.uicc.UiccController;
 
 import java.util.LinkedList;
+import java.lang.System;
+import java.util.List;
 
 /**
  * SIM toolkit application level service. Interacts with Telephopny messages,
@@ -66,23 +80,67 @@
 public class StkAppService extends Service implements Runnable {
 
     // members
+    protected class StkContext {
+        protected CatCmdMessage mMainCmd = null;
+        protected CatCmdMessage mCurrentCmd = null;
+        protected CatCmdMessage mCurrentMenuCmd = null;
+        protected Menu mCurrentMenu = null;
+        protected String lastSelectedItem = null;
+        protected boolean mMenuIsVisible = false;
+        protected boolean mIsInputPending = false;
+        protected boolean mIsMenuPending = false;
+        protected boolean mIsDialogPending = false;
+        protected boolean responseNeeded = true;
+        protected boolean launchBrowser = false;
+        protected BrowserSettings mBrowserSettings = null;
+        protected LinkedList<DelayedCmd> mCmdsQ = null;
+        protected boolean mCmdInProgress = false;
+        protected int mStkServiceState = STATE_UNKNOWN;
+        protected int mSetupMenuState = STATE_UNKNOWN;
+        protected int mMenuState = StkMenuActivity.STATE_INIT;
+        protected int mOpCode = -1;
+        private Activity mActivityInstance = null;
+        private Activity mDialogInstance = null;
+        private Activity mMainActivityInstance = null;
+        private boolean mBackGroundTRSent = false;
+        private int mSlotId = 0;
+        final synchronized void setPendingActivityInstance(Activity act) {
+            CatLog.d(this, "setPendingActivityInstance act : " + mSlotId + ", " + act);
+            callSetActivityInstMsg(OP_SET_ACT_INST, mSlotId, act);
+        }
+        final synchronized Activity getPendingActivityInstance() {
+            CatLog.d(this, "getPendingActivityInstance act : " + mSlotId + ", " +
+                    mActivityInstance);
+            return mActivityInstance;
+        }
+        final synchronized void setPendingDialogInstance(Activity act) {
+            CatLog.d(this, "setPendingDialogInstance act : " + mSlotId + ", " + act);
+            callSetActivityInstMsg(OP_SET_DAL_INST, mSlotId, act);
+        }
+        final synchronized Activity getPendingDialogInstance() {
+            CatLog.d(this, "getPendingDialogInstance act : " + mSlotId + ", " +
+                    mDialogInstance);
+            return mDialogInstance;
+        }
+        final synchronized void setMainActivityInstance(Activity act) {
+            CatLog.d(this, "setMainActivityInstance act : " + mSlotId + ", " + act);
+            callSetActivityInstMsg(OP_SET_MAINACT_INST, mSlotId, act);
+        }
+        final synchronized Activity getMainActivityInstance() {
+            CatLog.d(this, "getMainActivityInstance act : " + mSlotId + ", " +
+                    mMainActivityInstance);
+            return mMainActivityInstance;
+        }
+    }
+
     private volatile Looper mServiceLooper;
     private volatile ServiceHandler mServiceHandler;
-    private AppInterface mStkService;
     private Context mContext = null;
-    private CatCmdMessage mMainCmd = null;
-    private CatCmdMessage mCurrentCmd = null;
-    private Menu mCurrentMenu = null;
-    private String lastSelectedItem = null;
-    private boolean mMenuIsVisibile = false;
-    private boolean responseNeeded = true;
-    private boolean mCmdInProgress = false;
     private NotificationManager mNotificationManager = null;
-    private LinkedList<DelayedCmd> mCmdsQ = null;
-    private boolean launchBrowser = false;
-    private BrowserSettings mBrowserSettings = null;
     static StkAppService sInstance = null;
-
+    private AppInterface[] mStkService = null;
+    private StkContext[] mStkContext = null;
+    private int mSimCount = 0;
     // Used for setting FLAG_ACTIVITY_NO_USER_ACTION when
     // creating an intent.
     private enum InitiatedByUserAction {
@@ -99,7 +157,12 @@
     static final String HELP = "help";
     static final String CONFIRMATION = "confirm";
     static final String CHOICE = "choice";
-
+    static final String SLOT_ID = "SLOT_ID";
+    static final String STK_CMD = "STK CMD";
+    static final String STK_DIALOG_URI = "stk://com.android.stk/dialog/";
+    static final String STK_MENU_URI = "stk://com.android.stk/menu/";
+    static final String STK_INPUT_URI = "stk://com.android.stk/input/";
+    static final String STK_TONE_URI = "stk://com.android.stk/tone/";
     // operations ids for different service functionality.
     static final int OP_CMD = 1;
     static final int OP_RESPONSE = 2;
@@ -108,6 +171,9 @@
     static final int OP_BOOT_COMPLETED = 5;
     private static final int OP_DELAYED_MSG = 6;
     static final int OP_CARD_STATUS_CHANGED = 7;
+    static final int OP_SET_ACT_INST = 8;
+    static final int OP_SET_DAL_INST = 9;
+    static final int OP_SET_MAINACT_INST = 10;
 
     // Response ids
     static final int RES_ID_MENU_SELECTION = 11;
@@ -124,14 +190,17 @@
     static final int YES = 1;
     static final int NO = 0;
 
-    private static final String PACKAGE_NAME = "com.android.stk";
-    private static final String MENU_ACTIVITY_NAME =
-                                        PACKAGE_NAME + ".StkMenuActivity";
-    private static final String INPUT_ACTIVITY_NAME =
-                                        PACKAGE_NAME + ".StkInputActivity";
+    static final int STATE_UNKNOWN = -1;
+    static final int STATE_NOT_EXIST = 0;
+    static final int STATE_EXIST = 1;
 
+    private static final String PACKAGE_NAME = "com.android.stk";
+    private static final String STK_MENU_ACTIVITY_NAME = PACKAGE_NAME + ".StkMenuActivity";
+    private static final String STK_INPUT_ACTIVITY_NAME = PACKAGE_NAME + ".StkInputActivity";
+    private static final String STK_DIALOG_ACTIVITY_NAME = PACKAGE_NAME + ".StkDialogActivity";
     // Notification id used to display Idle Mode text in NotificationManager.
     private static final int STK_NOTIFICATION_ID = 333;
+    private static final String LOG_TAG = new Object(){}.getClass().getEnclosingClass().getName();
 
     // Inner class used for queuing telephony messages (proactive commands,
     // session end) while the service is busy processing a previous message.
@@ -139,20 +208,41 @@
         // members
         int id;
         CatCmdMessage msg;
+        int slotId;
 
-        DelayedCmd(int id, CatCmdMessage msg) {
+        DelayedCmd(int id, CatCmdMessage msg, int slotId) {
             this.id = id;
             this.msg = msg;
+            this.slotId = slotId;
         }
     }
 
     @Override
     public void onCreate() {
+        CatLog.d(LOG_TAG, "onCreate()+");
         // Initialize members
-        mCmdsQ = new LinkedList<DelayedCmd>();
+        int i = 0;
+        mContext = getBaseContext();
+        mSimCount = TelephonyManager.from(mContext).getSimCount();
+        CatLog.d(LOG_TAG, "simCount: " + mSimCount);
+        mStkService = new AppInterface[mSimCount];
+        mStkContext = new StkContext[mSimCount];
+        for (i = 0; i < mSimCount; i++) {
+            CatLog.d(LOG_TAG, "slotId: " + i);
+            if (null != UiccController.getInstance() && null != UiccController.getInstance()
+                    .getUiccCard(i)) {
+                mStkService[i] = UiccController.getInstance().getUiccCard(i).getCatService();
+            } else {
+                CatLog.d(LOG_TAG, "Null instance: [" + UiccController.getInstance() + "],[" +
+                        UiccController.getInstance().getUiccCard(i) + "]");
+            }
+            mStkContext[i] = new StkContext();
+            mStkContext[i].mSlotId = i;
+            mStkContext[i].mCmdsQ = new LinkedList<DelayedCmd>();
+        }
+
         Thread serviceThread = new Thread(null, this, "Stk App Service");
         serviceThread.start();
-        mContext = getBaseContext();
         mNotificationManager = (NotificationManager) mContext
                 .getSystemService(Context.NOTIFICATION_SERVICE);
         sInstance = this;
@@ -160,17 +250,55 @@
 
     @Override
     public void onStart(Intent intent, int startId) {
-
-        mStkService = com.android.internal.telephony.cat.CatService
-                .getInstance();
-
-        if (mStkService == null) {
-            stopSelf();
-            CatLog.d(this, " Unable to get Service handle");
-            StkAppInstaller.unInstall(mContext);
+        if (intent == null) {
+            CatLog.d(LOG_TAG, "StkAppService onStart intent is null so return");
             return;
         }
 
+        Bundle args = intent.getExtras();
+        if (args == null) {
+            CatLog.d(LOG_TAG, "StkAppService onStart args is null so return");
+            return;
+        }
+
+        int op = args.getInt(OPCODE);
+        int slotId = 0;
+        int i = 0;
+        if (op != OP_BOOT_COMPLETED) {
+            slotId = args.getInt(SLOT_ID);
+        }
+        CatLog.d(LOG_TAG, "onStart sim id: " + slotId + ", op: " + op + ", " + args);
+        if ((slotId >= 0 && slotId < mSimCount) && mStkService[slotId] == null) {
+            if (null != UiccController.getInstance() && null != UiccController.getInstance()
+                    .getUiccCard(slotId)) {
+                mStkService[slotId] = UiccController.getInstance().getUiccCard(slotId)
+                        .getCatService();
+            } else {
+                CatLog.d(LOG_TAG, "Null instance: [" + UiccController.getInstance() + "],[" +
+                        UiccController.getInstance().getUiccCard(slotId)+"]");
+            }
+            if (mStkService[slotId] == null) {
+                CatLog.d(LOG_TAG, "mStkService is: " + mStkContext[slotId].mStkServiceState);
+                mStkContext[slotId].mStkServiceState = STATE_NOT_EXIST;
+                //Check other StkService state.
+                //If all StkServices are not available, stop itself and uninstall apk.
+                for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
+                    if (i != slotId
+                            && (mStkContext[i].mStkServiceState == STATE_UNKNOWN
+                            || mStkContext[i].mStkServiceState == STATE_EXIST)) {
+                       break;
+                   }
+                }
+            } else {
+                mStkContext[slotId].mStkServiceState = STATE_EXIST;
+            }
+            if (i == mSimCount) {
+                stopSelf();
+                StkAppInstaller.unInstall(mContext);
+                return;
+            }
+        }
+
         waitForLooper();
         // onStart() method can be passed a null intent
         // TODO: replace onStart() with onStartCommand()
@@ -178,14 +306,9 @@
             return;
         }
 
-        Bundle args = intent.getExtras();
-
-        if (args == null) {
-            return;
-        }
-
         Message msg = mServiceHandler.obtainMessage();
-        msg.arg1 = args.getInt(OPCODE);
+        msg.arg1 = op;
+        msg.arg2 = slotId;
         switch(msg.arg1) {
         case OP_CMD:
             msg.obj = args.getParcelable(CMD_MSG);
@@ -206,6 +329,7 @@
 
     @Override
     public void onDestroy() {
+        CatLog.d(LOG_TAG, "onDestroy()");
         waitForLooper();
         mServiceLooper.quit();
     }
@@ -227,15 +351,58 @@
     /*
      * Package api used by StkMenuActivity to indicate if its on the foreground.
      */
-    void indicateMenuVisibility(boolean visibility) {
-        mMenuIsVisibile = visibility;
+    void indicateMenuVisibility(boolean visibility, int slotId) {
+        if (slotId >= 0 && slotId < mSimCount) {
+            mStkContext[slotId].mMenuIsVisible = visibility;
+        }
+    }
+
+    boolean isInputPending(int slotId) {
+        if (slotId >= 0 && slotId < mSimCount) {
+            CatLog.d(LOG_TAG, "isInputFinishBySrv: " + mStkContext[slotId].mIsInputPending);
+            return mStkContext[slotId].mIsInputPending;
+        }
+        return false;
+    }
+
+    boolean isMenuPending(int slotId) {
+        if (slotId >= 0 && slotId < mSimCount) {
+            CatLog.d(LOG_TAG, "isMenuPending: " + mStkContext[slotId].mIsMenuPending);
+            return mStkContext[slotId].mIsMenuPending;
+        }
+        return false;
+    }
+
+    boolean isDialogPending(int slotId) {
+        if (slotId >= 0 && slotId < mSimCount) {
+            CatLog.d(LOG_TAG, "isDialogPending: " + mStkContext[slotId].mIsDialogPending);
+            return mStkContext[slotId].mIsDialogPending;
+        }
+        return false;
     }
 
     /*
      * Package api used by StkMenuActivity to get its Menu parameter.
      */
-    Menu getMenu() {
-        return mCurrentMenu;
+    Menu getMenu(int slotId) {
+        CatLog.d(LOG_TAG, "StkAppService, getMenu, sim id: " + slotId);
+        if (slotId >=0 && slotId < mSimCount) {
+            return mStkContext[slotId].mCurrentMenu;
+        } else {
+            return null;
+        }
+    }
+
+    /*
+     * Package api used by StkMenuActivity to get its Main Menu parameter.
+     */
+    Menu getMainMenu(int slotId) {
+        CatLog.d(LOG_TAG, "StkAppService, getMainMenu, sim id: " + slotId);
+        if (slotId >=0 && slotId < mSimCount) {
+            return mStkContext[slotId].mMainCmd.getMenu();
+        } else {
+            return null;
+        }
     }
 
     /*
@@ -260,17 +427,69 @@
     private final class ServiceHandler extends Handler {
         @Override
         public void handleMessage(Message msg) {
+            if(null == msg) {
+                CatLog.d(LOG_TAG, "ServiceHandler handleMessage msg is null");
+                return;
+            }
             int opcode = msg.arg1;
+            int slotId = msg.arg2;
 
+            CatLog.d(LOG_TAG, "handleMessage opcode[" + opcode + "], sim id[" + slotId + "]");
+            if (opcode == OP_CMD && msg.obj != null &&
+                    ((CatCmdMessage)msg.obj).getCmdType()!= null) {
+                CatLog.d(LOG_TAG, "cmdName[" + ((CatCmdMessage)msg.obj).getCmdType().name() + "]");
+            }
+            mStkContext[slotId].mOpCode = opcode;
             switch (opcode) {
             case OP_LAUNCH_APP:
-                if (mMainCmd == null) {
+                if (mStkContext[slotId].mMainCmd == null) {
+                    CatLog.d(LOG_TAG, "mMainCmd is null");
                     // nothing todo when no SET UP MENU command didn't arrive.
                     return;
                 }
-                launchMenuActivity(null);
+                CatLog.d(LOG_TAG, "handleMessage OP_LAUNCH_APP - mCmdInProgress[" +
+                        mStkContext[slotId].mCmdInProgress + "]");
+
+                //If there is a pending activity for the slot id,
+                //just finish it and create a new one to handle the pending command.
+                cleanUpInstanceStackBySlot(slotId);
+
+                //Clean up all other activities in stack.
+                for (int i = 0; i < mSimCount; i++) {
+                    if (i != slotId && mStkContext[i].mCurrentCmd != null) {
+                        Activity otherAct = mStkContext[i].getPendingActivityInstance();
+                        Activity otherDal = mStkContext[i].getPendingDialogInstance();
+                        Activity otherMainMenu = mStkContext[i].getMainActivityInstance();
+                        if (otherAct != null) {
+                            CatLog.d(LOG_TAG, "finish pending otherAct and send SE. slot: " + i);
+                            // Send end session for the pending proactive command of slot i in
+                            // onDestroy of the activity.
+                            // Set mBackGroundTRSent to true for ignoring to show the main menu
+                            // for the following end session event.
+                            mStkContext[i].mBackGroundTRSent = true;
+                            otherAct.finish();
+                            mStkContext[i].mActivityInstance = null;
+                        }
+                        if (otherDal != null) {
+                            CatLog.d(LOG_TAG, "finish pending otherDal and send TR for the dialog");
+                            mStkContext[i].mBackGroundTRSent = true;
+                            otherDal.finish();
+                            mStkContext[i].mDialogInstance = null;
+                        }
+                        if (otherMainMenu != null) {
+                            CatLog.d(LOG_TAG, "finish pending otherMainMenu.");
+                            otherMainMenu.finish();
+                            mStkContext[i].mMainActivityInstance = null;
+                        }
+                    }
+                }
+                CatLog.d(LOG_TAG, "Current cmd type: " +
+                        mStkContext[slotId].mCurrentCmd.getCmdType());
+                //Restore the last command from stack by slot id.
+                restoreInstanceFromStackBySlot(slotId);
                 break;
             case OP_CMD:
+                CatLog.d(LOG_TAG, "[OP_CMD]");
                 CatCmdMessage cmdMsg = (CatCmdMessage) msg.obj;
                 // There are two types of commands:
                 // 1. Interactive - user's response is required.
@@ -281,85 +500,134 @@
                 // is already in progress, we need to queue the next command until
                 // the user has responded or a timeout expired.
                 if (!isCmdInteractive(cmdMsg)) {
-                    handleCmd(cmdMsg);
+                    handleCmd(cmdMsg, slotId);
                 } else {
-                    if (!mCmdInProgress) {
-                        mCmdInProgress = true;
-                        handleCmd((CatCmdMessage) msg.obj);
+                    if (!mStkContext[slotId].mCmdInProgress) {
+                        mStkContext[slotId].mCmdInProgress = true;
+                        handleCmd((CatCmdMessage) msg.obj, slotId);
                     } else {
-                        mCmdsQ.addLast(new DelayedCmd(OP_CMD,
-                                (CatCmdMessage) msg.obj));
+                        CatLog.d(LOG_TAG, "[Interactive][in progress]");
+                        mStkContext[slotId].mCmdsQ.addLast(new DelayedCmd(OP_CMD,
+                                (CatCmdMessage) msg.obj, slotId));
                     }
                 }
                 break;
             case OP_RESPONSE:
-                if (responseNeeded) {
-                    handleCmdResponse((Bundle) msg.obj);
+                if (mStkContext[slotId].responseNeeded) {
+                    handleCmdResponse((Bundle) msg.obj, slotId);
                 }
                 // call delayed commands if needed.
-                if (mCmdsQ.size() != 0) {
-                    callDelayedMsg();
+                if (mStkContext[slotId].mCmdsQ.size() != 0) {
+                    callDelayedMsg(slotId);
                 } else {
-                    mCmdInProgress = false;
+                    mStkContext[slotId].mCmdInProgress = false;
                 }
                 // reset response needed state var to its original value.
-                responseNeeded = true;
+                mStkContext[slotId].responseNeeded = true;
                 break;
             case OP_END_SESSION:
-                if (!mCmdInProgress) {
-                    mCmdInProgress = true;
-                    handleSessionEnd();
+                if (!mStkContext[slotId].mCmdInProgress) {
+                    mStkContext[slotId].mCmdInProgress = true;
+                    handleSessionEnd(slotId);
                 } else {
-                    mCmdsQ.addLast(new DelayedCmd(OP_END_SESSION, null));
+                    mStkContext[slotId].mCmdsQ.addLast(
+                            new DelayedCmd(OP_END_SESSION, null, slotId));
                 }
                 break;
             case OP_BOOT_COMPLETED:
-                CatLog.d(this, "OP_BOOT_COMPLETED");
-                if (mMainCmd == null) {
+                CatLog.d(LOG_TAG, " OP_BOOT_COMPLETED");
+                int i = 0;
+                for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
+                    if (mStkContext[i].mMainCmd != null) {
+                        break;
+                    }
+                }
+                if (i == mSimCount) {
                     StkAppInstaller.unInstall(mContext);
                 }
                 break;
             case OP_DELAYED_MSG:
-                handleDelayedCmd();
+                handleDelayedCmd(slotId);
                 break;
             case OP_CARD_STATUS_CHANGED:
-                CatLog.d(this, "Card/Icc Status change received");
-                handleCardStatusChangeAndIccRefresh((Bundle) msg.obj);
+                CatLog.d(LOG_TAG, "Card/Icc Status change received");
+                handleCardStatusChangeAndIccRefresh((Bundle) msg.obj, slotId);
+                break;
+            case OP_SET_ACT_INST:
+                Activity act = new Activity();
+                act = (Activity) msg.obj;
+                CatLog.d(LOG_TAG, "Set activity instance. " + act);
+                mStkContext[slotId].mActivityInstance = act;
+                break;
+            case OP_SET_DAL_INST:
+                Activity dal = new Activity();
+                CatLog.d(LOG_TAG, "Set dialog instance. " + dal);
+                dal = (Activity) msg.obj;
+                mStkContext[slotId].mDialogInstance = dal;
+                break;
+            case OP_SET_MAINACT_INST:
+                Activity mainAct = new Activity();
+                mainAct = (Activity) msg.obj;
+                CatLog.d(LOG_TAG, "Set activity instance. " + mainAct);
+                mStkContext[slotId].mMainActivityInstance = mainAct;
                 break;
             }
         }
 
-        private void handleCardStatusChangeAndIccRefresh(Bundle args) {
+        private void handleCardStatusChangeAndIccRefresh(Bundle args, int slotId) {
             boolean cardStatus = args.getBoolean(AppInterface.CARD_STATUS);
 
-            CatLog.d(this, "CardStatus: " + cardStatus);
+            CatLog.d(LOG_TAG, "CardStatus: " + cardStatus);
             if (cardStatus == false) {
-                CatLog.d(this, "CARD is ABSENT");
+                CatLog.d(LOG_TAG, "CARD is ABSENT");
                 // Uninstall STKAPP, Clear Idle text, Stop StkAppService
-                StkAppInstaller.unInstall(mContext);
-                mNotificationManager.cancel(STK_NOTIFICATION_ID);
-                stopSelf();
+                mNotificationManager.cancel(getNotificationId(slotId));
+                if (isAllOtherCardsAbsent(slotId)) {
+                    CatLog.d(LOG_TAG, "All CARDs are ABSENT");
+                    StkAppInstaller.unInstall(mContext);
+                    stopSelf();
+                }
             } else {
                 IccRefreshResponse state = new IccRefreshResponse();
                 state.refreshResult = args.getInt(AppInterface.REFRESH_RESULT);
 
-                CatLog.d(this, "Icc Refresh Result: "+ state.refreshResult);
+                CatLog.d(LOG_TAG, "Icc Refresh Result: "+ state.refreshResult);
                 if ((state.refreshResult == IccRefreshResponse.REFRESH_RESULT_INIT) ||
                     (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET)) {
                     // Clear Idle Text
-                    mNotificationManager.cancel(STK_NOTIFICATION_ID);
+                    mNotificationManager.cancel(getNotificationId(slotId));
                 }
 
                 if (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) {
                     // Uninstall STkmenu
-                    StkAppInstaller.unInstall(mContext);
-                    mCurrentMenu = null;
-                    mMainCmd = null;
+                    if (isAllOtherCardsAbsent(slotId)) {
+                        StkAppInstaller.unInstall(mContext);
+                    }
+                    mStkContext[slotId].mCurrentMenu = null;
+                    mStkContext[slotId].mMainCmd = null;
                 }
             }
         }
     }
+    /*
+     * Check if all SIMs are absent except the id of slot equals "slotId".
+     */
+    private boolean isAllOtherCardsAbsent(int slotId) {
+        TelephonyManager mTm = (TelephonyManager) mContext.getSystemService(
+                Context.TELEPHONY_SERVICE);
+        int i = 0;
 
+        for (i = 0; i < mSimCount; i++) {
+            if (i != slotId && mTm.hasIccCard(i)) {
+                break;
+            }
+        }
+        if (i == mSimCount) {
+            return true;
+        } else {
+            return false;
+        }
+    }
     private boolean isCmdInteractive(CatCmdMessage cmd) {
         switch (cmd.getCmdType()) {
         case SEND_DTMF:
@@ -377,123 +645,182 @@
         return true;
     }
 
-    private void handleDelayedCmd() {
-        if (mCmdsQ.size() != 0) {
-            DelayedCmd cmd = mCmdsQ.poll();
-            switch (cmd.id) {
-            case OP_CMD:
-                handleCmd(cmd.msg);
-                break;
-            case OP_END_SESSION:
-                handleSessionEnd();
-                break;
+    private void handleDelayedCmd(int slotId) {
+        CatLog.d(LOG_TAG, "handleDelayedCmd, slotId: " + slotId);
+        if (mStkContext[slotId].mCmdsQ.size() != 0) {
+            DelayedCmd cmd = mStkContext[slotId].mCmdsQ.poll();
+            if (cmd != null) {
+                CatLog.d(LOG_TAG, "handleDelayedCmd - queue size: " +
+                        mStkContext[slotId].mCmdsQ.size() +
+                        " id: " + cmd.id + "sim id: " + cmd.slotId);
+                switch (cmd.id) {
+                case OP_CMD:
+                    handleCmd(cmd.msg, cmd.slotId);
+                    break;
+                case OP_END_SESSION:
+                    handleSessionEnd(cmd.slotId);
+                    break;
+                }
             }
         }
     }
 
-    private void callDelayedMsg() {
+    private void callDelayedMsg(int slotId) {
         Message msg = mServiceHandler.obtainMessage();
         msg.arg1 = OP_DELAYED_MSG;
+        msg.arg2 = slotId;
         mServiceHandler.sendMessage(msg);
     }
 
-    private void handleSessionEnd() {
-        mCurrentCmd = mMainCmd;
-        lastSelectedItem = null;
+    private void callSetActivityInstMsg(int inst_type, int slotId, Object obj) {
+        Message msg = mServiceHandler.obtainMessage();
+        msg.obj = obj;
+        msg.arg1 = inst_type;
+        msg.arg2 = slotId;
+        mServiceHandler.sendMessage(msg);
+    }
+
+    private void handleSessionEnd(int slotId) {
+        mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
+        CatLog.d(LOG_TAG, "[handleSessionEnd] - mCurrentCmd changed to mMainCmd!.");
+        mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mMainCmd;
+        CatLog.d(LOG_TAG, "slotId: " + slotId + ", mMenuState: " +
+                mStkContext[slotId].mMenuState);
+
+        mStkContext[slotId].mIsInputPending = false;
+        mStkContext[slotId].mIsMenuPending = false;
+        mStkContext[slotId].mIsDialogPending = false;
+
+        // We should finish all pending activity if receiving END SESSION command.
+        cleanUpInstanceStackBySlot(slotId);
+
+        if (mStkContext[slotId].mMainCmd == null) {
+            CatLog.d(LOG_TAG, "[handleSessionEnd][mMainCmd is null!]");
+        }
+        mStkContext[slotId].lastSelectedItem = null;
         // In case of SET UP MENU command which removed the app, don't
         // update the current menu member.
-        if (mCurrentMenu != null && mMainCmd != null) {
-            mCurrentMenu = mMainCmd.getMenu();
+        if (mStkContext[slotId].mCurrentMenu != null && mStkContext[slotId].mMainCmd != null) {
+            mStkContext[slotId].mCurrentMenu = mStkContext[slotId].mMainCmd.getMenu();
         }
-        if (mMenuIsVisibile) {
-            launchMenuActivity(null);
+        CatLog.d(LOG_TAG, "[handleSessionEnd][mMenuState]" + mStkContext[slotId].mMenuIsVisible);
+        // In mutiple instance architecture, the main menu for slotId will be finished when user
+        // goes to the Stk menu of the other SIM. So, we should launch a new instance for the
+        // main menu if the main menu instance has been finished.
+        // If the current menu is secondary menu, we should launch main menu.
+        if (StkMenuActivity.STATE_SECONDARY == mStkContext[slotId].mMenuState) {
+            launchMenuActivity(null, slotId);
         }
-        if (mCmdsQ.size() != 0) {
-            callDelayedMsg();
+        if (mStkContext[slotId].mCmdsQ.size() != 0) {
+            callDelayedMsg(slotId);
         } else {
-            mCmdInProgress = false;
+            mStkContext[slotId].mCmdInProgress = false;
         }
         // In case a launch browser command was just confirmed, launch that url.
-        if (launchBrowser) {
-            launchBrowser = false;
-            launchBrowser(mBrowserSettings);
+        if (mStkContext[slotId].launchBrowser) {
+            mStkContext[slotId].launchBrowser = false;
+            launchBrowser(mStkContext[slotId].mBrowserSettings);
         }
     }
 
-    private void handleCmd(CatCmdMessage cmdMsg) {
+    private void handleCmd(CatCmdMessage cmdMsg, int slotId) {
         if (cmdMsg == null) {
             return;
         }
         // save local reference for state tracking.
-        mCurrentCmd = cmdMsg;
+        mStkContext[slotId].mCurrentCmd = cmdMsg;
         boolean waitForUsersResponse = true;
 
-        CatLog.d(this, cmdMsg.getCmdType().name());
+        mStkContext[slotId].mIsInputPending = false;
+        mStkContext[slotId].mIsMenuPending = false;
+        mStkContext[slotId].mIsDialogPending = false;
+
+        CatLog.d(LOG_TAG,"[handleCmd]" + cmdMsg.getCmdType().name());
         switch (cmdMsg.getCmdType()) {
         case DISPLAY_TEXT:
             TextMessage msg = cmdMsg.geTextMessage();
-            responseNeeded = msg.responseNeeded;
+            mStkContext[slotId].responseNeeded = msg.responseNeeded;
             waitForUsersResponse = msg.responseNeeded;
-            if (lastSelectedItem != null) {
-                msg.title = lastSelectedItem;
-            } else if (mMainCmd != null){
-                msg.title = mMainCmd.getMenu().title;
+            if (mStkContext[slotId].lastSelectedItem != null) {
+                msg.title = mStkContext[slotId].lastSelectedItem;
+            } else if (mStkContext[slotId].mMainCmd != null){
+                msg.title = mStkContext[slotId].mMainCmd.getMenu().title;
             } else {
                 // TODO: get the carrier name from the SIM
                 msg.title = "";
             }
-            launchTextDialog();
+            launchTextDialog(slotId);
             break;
         case SELECT_ITEM:
-            mCurrentMenu = cmdMsg.getMenu();
-            launchMenuActivity(cmdMsg.getMenu());
+            CatLog.d(LOG_TAG, "SELECT_ITEM +");
+            mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
+            mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
+            launchMenuActivity(cmdMsg.getMenu(), slotId);
             break;
         case SET_UP_MENU:
-            mMainCmd = mCurrentCmd;
-            mCurrentMenu = cmdMsg.getMenu();
-            if (removeMenu()) {
-                CatLog.d(this, "Uninstall App");
-                mCurrentMenu = null;
-                StkAppInstaller.unInstall(mContext);
+            mStkContext[slotId].mCmdInProgress = false;
+            mStkContext[slotId].mMainCmd = mStkContext[slotId].mCurrentCmd;
+            mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
+            mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
+            CatLog.d(LOG_TAG, "SET_UP_MENU [" + removeMenu(slotId) + "]");
+
+            if (removeMenu(slotId)) {
+                int i = 0;
+                CatLog.d(LOG_TAG, "removeMenu() - Uninstall App");
+                mStkContext[slotId].mCurrentMenu = null;
+                //Check other setup menu state. If all setup menu are removed, uninstall apk.
+                for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
+                    if (i != slotId
+                            && (mStkContext[slotId].mSetupMenuState == STATE_UNKNOWN
+                            || mStkContext[slotId].mSetupMenuState == STATE_EXIST)) {
+                        CatLog.d(LOG_TAG, "Not Uninstall App:" + i + ","
+                                + mStkContext[slotId].mSetupMenuState);
+                        break;
+                    }
+                }
+                if (i == mSimCount) {
+                    StkAppInstaller.unInstall(mContext);
+                }
             } else {
-                CatLog.d(this, "Install App");
+                CatLog.d(LOG_TAG, "install App");
                 StkAppInstaller.install(mContext);
             }
-            if (mMenuIsVisibile) {
-                launchMenuActivity(null);
+            if (mStkContext[slotId].mMenuIsVisible) {
+                launchMenuActivity(null, slotId);
             }
             break;
         case GET_INPUT:
         case GET_INKEY:
-            launchInputActivity();
+            launchInputActivity(slotId);
             break;
         case SET_UP_IDLE_MODE_TEXT:
             waitForUsersResponse = false;
-            launchIdleText();
+            launchIdleText(slotId);
             break;
         case SEND_DTMF:
         case SEND_SMS:
         case SEND_SS:
         case SEND_USSD:
             waitForUsersResponse = false;
-            launchEventMessage();
+            launchEventMessage(slotId);
             break;
         case LAUNCH_BROWSER:
-            launchConfirmationDialog(mCurrentCmd.geTextMessage());
+            launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.geTextMessage(), slotId);
             break;
         case SET_UP_CALL:
-            launchConfirmationDialog(mCurrentCmd.getCallSettings().confirmMsg);
+            launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.getCallSettings()
+                    .confirmMsg, slotId);
             break;
         case PLAY_TONE:
-            launchToneDialog();
+            launchToneDialog(slotId);
             break;
         case OPEN_CHANNEL:
-            launchOpenChannelDialog();
+            launchOpenChannelDialog(slotId);
             break;
         case CLOSE_CHANNEL:
         case RECEIVE_DATA:
         case SEND_DATA:
-            TextMessage m = mCurrentCmd.geTextMessage();
+            TextMessage m = mStkContext[slotId].mCurrentCmd.geTextMessage();
 
             if ((m != null) && (m.text == null)) {
                 switch(cmdMsg.getCmdType()) {
@@ -511,33 +838,43 @@
             /*
              * Display indication in the form of a toast to the user if required.
              */
-            launchEventMessage();
+            launchEventMessage(slotId);
             break;
         }
 
         if (!waitForUsersResponse) {
-            if (mCmdsQ.size() != 0) {
-                callDelayedMsg();
+            if (mStkContext[slotId].mCmdsQ.size() != 0) {
+                callDelayedMsg(slotId);
             } else {
-                mCmdInProgress = false;
+                mStkContext[slotId].mCmdInProgress = false;
             }
         }
     }
 
-    private void handleCmdResponse(Bundle args) {
-        if (mCurrentCmd == null) {
+    private void handleCmdResponse(Bundle args, int slotId) {
+        CatLog.d(LOG_TAG, "handleCmdResponse, sim id: " + slotId);
+        if (mStkContext[slotId].mCurrentCmd == null) {
             return;
         }
-        if (mStkService == null) {
-            mStkService = com.android.internal.telephony.cat.CatService.getInstance();
-            if (mStkService == null) {
+
+        if (mStkService[slotId] == null) {
+            if(null != UiccController.getInstance() &&
+                    null != UiccController.getInstance().getUiccCard(slotId)) {
+                mStkService[slotId] = UiccController.getInstance().getUiccCard(slotId)
+                        .getCatService();
+            } else {
+                CatLog.d(LOG_TAG, "Null instance: [" + UiccController.getInstance() +
+                        "],["+UiccController.getInstance().getUiccCard(slotId)+"]");
+            }
+            if (mStkService[slotId] == null) {
                 // This should never happen (we should be responding only to a message
                 // that arrived from StkService). It has to exist by this time
+                CatLog.d(LOG_TAG, "Exception! mStkService is null when we need to send response.");
                 throw new RuntimeException("mStkService is null when we need to send response");
             }
         }
 
-        CatResponseMessage resMsg = new CatResponseMessage(mCurrentCmd);
+        CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
 
         // set result code
         boolean helpRequired = args.getBoolean(HELP, false);
@@ -545,12 +882,13 @@
 
         switch(args.getInt(RES_ID)) {
         case RES_ID_MENU_SELECTION:
-            CatLog.d(this, "RES_ID_MENU_SELECTION");
+            CatLog.d(LOG_TAG, "MENU_SELECTION=" + mStkContext[slotId].
+                    mCurrentMenuCmd.getCmdType());
             int menuSelection = args.getInt(MENU_SELECTION);
-            switch(mCurrentCmd.getCmdType()) {
+            switch(mStkContext[slotId].mCurrentMenuCmd.getCmdType()) {
             case SET_UP_MENU:
             case SELECT_ITEM:
-                lastSelectedItem = getItemName(menuSelection);
+                mStkContext[slotId].lastSelectedItem = getItemName(menuSelection, slotId);
                 if (helpRequired) {
                     resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
                 } else {
@@ -561,10 +899,10 @@
             }
             break;
         case RES_ID_INPUT:
-            CatLog.d(this, "RES_ID_INPUT");
+            CatLog.d(LOG_TAG, "RES_ID_INPUT");
             String input = args.getString(INPUT);
-            Input cmdInput = mCurrentCmd.geInput();
-            if (cmdInput != null && cmdInput.yesNo) {
+            if (input != null && (null != mStkContext[slotId].mCurrentCmd.geInput()) &&
+                    (mStkContext[slotId].mCurrentCmd.geInput().yesNo)) {
                 boolean yesNoSelection = input
                         .equals(StkInputActivity.YES_STR_RESPONSE);
                 resMsg.setYesNo(yesNoSelection);
@@ -580,7 +918,7 @@
         case RES_ID_CONFIRM:
             CatLog.d(this, "RES_ID_CONFIRM");
             confirmed = args.getBoolean(CONFIRMATION);
-            switch (mCurrentCmd.getCmdType()) {
+            switch (mStkContext[slotId].mCurrentCmd.getCmdType()) {
             case DISPLAY_TEXT:
                 resMsg.setResultCode(confirmed ? ResultCode.OK
                         : ResultCode.UICC_SESSION_TERM_BY_USER);
@@ -589,15 +927,17 @@
                 resMsg.setResultCode(confirmed ? ResultCode.OK
                         : ResultCode.UICC_SESSION_TERM_BY_USER);
                 if (confirmed) {
-                    launchBrowser = true;
-                    mBrowserSettings = mCurrentCmd.getBrowserSettings();
+                    mStkContext[slotId].launchBrowser = true;
+                    mStkContext[slotId].mBrowserSettings =
+                            mStkContext[slotId].mCurrentCmd.getBrowserSettings();
                 }
                 break;
             case SET_UP_CALL:
                 resMsg.setResultCode(ResultCode.OK);
                 resMsg.setConfirmation(confirmed);
                 if (confirmed) {
-                    launchEventMessage(mCurrentCmd.getCallSettings().callMsg);
+                    launchEventMessage(slotId,
+                            mStkContext[slotId].mCurrentCmd.getCallSettings().callMsg);
                 }
                 break;
             }
@@ -606,22 +946,22 @@
             resMsg.setResultCode(ResultCode.OK);
             break;
         case RES_ID_BACKWARD:
-            CatLog.d(this, "RES_ID_BACKWARD");
+            CatLog.d(LOG_TAG, "RES_ID_BACKWARD");
             resMsg.setResultCode(ResultCode.BACKWARD_MOVE_BY_USER);
             break;
         case RES_ID_END_SESSION:
-            CatLog.d(this, "RES_ID_END_SESSION");
+            CatLog.d(LOG_TAG, "RES_ID_END_SESSION");
             resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
             break;
         case RES_ID_TIMEOUT:
-            CatLog.d(this, "RES_ID_TIMEOUT");
+            CatLog.d(LOG_TAG, "RES_ID_TIMEOUT");
             // GCF test-case 27.22.4.1.1 Expected Sequence 1.5 (DISPLAY TEXT,
             // Clear message after delay, successful) expects result code OK.
             // If the command qualifier specifies no user response is required
             // then send OK instead of NO_RESPONSE_FROM_USER
-            if ((mCurrentCmd.getCmdType().value() == AppInterface.CommandType.DISPLAY_TEXT
-                    .value())
-                    && (mCurrentCmd.geTextMessage().userClear == false)) {
+            if ((mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
+                    AppInterface.CommandType.DISPLAY_TEXT.value())
+                    && (mStkContext[slotId].mCurrentCmd.geTextMessage().userClear == false)) {
                 resMsg.setResultCode(ResultCode.OK);
             } else {
                 resMsg.setResultCode(ResultCode.NO_RESPONSE_FROM_USER);
@@ -640,17 +980,23 @@
                     break;
             }
 
-            if (mCurrentCmd.getCmdType().value() == AppInterface.CommandType.OPEN_CHANNEL
-                    .value()) {
+            if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
+                    AppInterface.CommandType.OPEN_CHANNEL.value()) {
                 resMsg.setConfirmation(confirmed);
             }
             break;
 
         default:
-            CatLog.d(this, "Unknown result id");
+            CatLog.d(LOG_TAG, "Unknown result id");
             return;
         }
-        mStkService.onCmdResponse(resMsg);
+
+        if (null != mStkContext[slotId].mCurrentCmd &&
+                null != mStkContext[slotId].mCurrentCmd.getCmdType()) {
+            CatLog.d(LOG_TAG, "handleCmdResponse- cmdName[" +
+                    mStkContext[slotId].mCurrentCmd.getCmdType().name() + "]");
+        }
+        mStkService[slotId].onCmdResponse(resMsg);
     }
 
     /**
@@ -664,59 +1010,193 @@
      *
      * @return 0 or FLAG_ACTIVITY_NO_USER_ACTION
      */
-    private int getFlagActivityNoUserAction(InitiatedByUserAction userAction) {
-        return ((userAction == InitiatedByUserAction.yes) | mMenuIsVisibile) ?
-                                                    0 : Intent.FLAG_ACTIVITY_NO_USER_ACTION;
+    private int getFlagActivityNoUserAction(InitiatedByUserAction userAction, int slotId) {
+        return ((userAction == InitiatedByUserAction.yes) | mStkContext[slotId].mMenuIsVisible)
+                ? 0 : Intent.FLAG_ACTIVITY_NO_USER_ACTION;
+    }
+    /**
+     * This method is used for cleaning up pending instances in stack.
+     */
+    private void cleanUpInstanceStackBySlot(int slotId) {
+        Activity activity = mStkContext[slotId].getPendingActivityInstance();
+        Activity dialog = mStkContext[slotId].getPendingDialogInstance();
+        CatLog.d(LOG_TAG, "cleanUpInstanceStackBySlot slotId: " + slotId);
+        if (activity != null) {
+            CatLog.d(LOG_TAG, "current cmd type: " +
+                    mStkContext[slotId].mCurrentCmd.getCmdType());
+            if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
+                    AppInterface.CommandType.GET_INPUT.value() ||
+                    mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
+                    AppInterface.CommandType.GET_INKEY.value()) {
+                mStkContext[slotId].mIsInputPending = true;
+            } else if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
+                    AppInterface.CommandType.SET_UP_MENU.value() ||
+                    mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
+                    AppInterface.CommandType.SELECT_ITEM.value()) {
+                mStkContext[slotId].mIsMenuPending = true;
+            } else {
+            }
+            CatLog.d(LOG_TAG, "finish pending activity.");
+            activity.finish();
+            mStkContext[slotId].mActivityInstance = null;
+        }
+        if (dialog != null) {
+            CatLog.d(LOG_TAG, "finish pending dialog.");
+            mStkContext[slotId].mIsDialogPending = true;
+            dialog.finish();
+            mStkContext[slotId].mDialogInstance = null;
+        }
+    }
+    /**
+     * This method is used for restoring pending instances from stack.
+     */
+    private void restoreInstanceFromStackBySlot(int slotId) {
+        AppInterface.CommandType cmdType = mStkContext[slotId].mCurrentCmd.getCmdType();
+
+        CatLog.d(LOG_TAG, "restoreInstanceFromStackBySlot cmdType : " + cmdType);
+        switch(cmdType) {
+            case GET_INPUT:
+            case GET_INKEY:
+                launchInputActivity(slotId);
+                //Set mMenuIsVisible to true for showing main menu for
+                //following session end command.
+                mStkContext[slotId].mMenuIsVisible = true;
+            break;
+            case DISPLAY_TEXT:
+                launchTextDialog(slotId);
+            break;
+            case LAUNCH_BROWSER:
+                launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.geTextMessage(),
+                        slotId);
+            break;
+            case OPEN_CHANNEL:
+                launchOpenChannelDialog(slotId);
+            break;
+            case SET_UP_CALL:
+                launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.getCallSettings().
+                        confirmMsg, slotId);
+            break;
+            case SET_UP_MENU:
+            case SELECT_ITEM:
+                launchMenuActivity(null, slotId);
+            break;
+        default:
+            break;
+        }
     }
 
-    private void launchMenuActivity(Menu menu) {
+    private void launchMenuActivity(Menu menu, int slotId) {
         Intent newIntent = new Intent(Intent.ACTION_VIEW);
-        newIntent.setClassName(PACKAGE_NAME, MENU_ACTIVITY_NAME);
-        int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK
-                | Intent.FLAG_ACTIVITY_CLEAR_TOP;
+        String targetActivity = STK_MENU_ACTIVITY_NAME;
+        String uriString = STK_MENU_URI + System.currentTimeMillis();
+        //Set unique URI to create a new instance of activity for different slotId.
+        Uri uriData = Uri.parse(uriString);
+
+        CatLog.d(LOG_TAG, "launchMenuActivity, slotId: " + slotId + " , " +
+                uriData.toString() + " , " + mStkContext[slotId].mOpCode + ", "
+                + mStkContext[slotId].mMenuState);
+        newIntent.setClassName(PACKAGE_NAME, targetActivity);
+        int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK;
+
         if (menu == null) {
             // We assume this was initiated by the user pressing the tool kit icon
-            intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.yes);
+            intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.yes, slotId);
+            if (mStkContext[slotId].mOpCode == OP_END_SESSION) {
+                CatLog.d(LOG_TAG, "launchMenuActivity, return OP_END_SESSION");
+                mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
+                if (mStkContext[slotId].mMainActivityInstance != null) {
+                    CatLog.d(LOG_TAG, "launchMenuActivity, mMainActivityInstance is not null");
+                    return;
+                }
+                // If END SESSION is sent that results from the activity is finished by
+                // stkappservice (line 457), we should igonore to display the stk main menu
+                // of slot id.
+                if (mStkContext[slotId].mBackGroundTRSent) {
+                    CatLog.d(LOG_TAG, "launchMenuActivity, ES is triggered by BG.");
+                    mStkContext[slotId].mBackGroundTRSent = false;
+                    return;
+                }
+            }
 
-            newIntent.putExtra("STATE", StkMenuActivity.STATE_MAIN);
+            //If the last pending menu is secondary menu, "STATE" should be "STATE_SECONDARY".
+            //Otherwise, it should be "STATE_MAIN".
+            if (mStkContext[slotId].mOpCode == OP_LAUNCH_APP &&
+                    mStkContext[slotId].mMenuState == StkMenuActivity.STATE_SECONDARY) {
+                newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
+            } else {
+                newIntent.putExtra("STATE", StkMenuActivity.STATE_MAIN);
+                mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
+            }
         } else {
             // We don't know and we'll let getFlagActivityNoUserAction decide.
-            intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.unknown);
-
+            intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
             newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
+            mStkContext[slotId].mMenuState = StkMenuActivity.STATE_SECONDARY;
         }
+        newIntent.putExtra(SLOT_ID, slotId);
+        newIntent.setData(uriData);
         newIntent.setFlags(intentFlags);
         mContext.startActivity(newIntent);
     }
 
-    private void launchInputActivity() {
+    private void launchInputActivity(int slotId) {
         Intent newIntent = new Intent(Intent.ACTION_VIEW);
+        String targetActivity = STK_INPUT_ACTIVITY_NAME;
+        String uriString = STK_INPUT_URI + System.currentTimeMillis();
+        //Set unique URI to create a new instance of activity for different slotId.
+        Uri uriData = Uri.parse(uriString);
+
+        CatLog.d(LOG_TAG, "launchInputActivity, slotId: " + slotId);
         newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                            | getFlagActivityNoUserAction(InitiatedByUserAction.unknown));
-        newIntent.setClassName(PACKAGE_NAME, INPUT_ACTIVITY_NAME);
-        newIntent.putExtra("INPUT", mCurrentCmd.geInput());
+                            | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
+        newIntent.setClassName(PACKAGE_NAME, targetActivity);
+        newIntent.putExtra("INPUT", mStkContext[slotId].mCurrentCmd.geInput());
+        newIntent.putExtra(SLOT_ID, slotId);
+        newIntent.setData(uriData);
         mContext.startActivity(newIntent);
     }
 
-    private void launchTextDialog() {
-        Intent newIntent = new Intent(this, StkDialogActivity.class);
-        newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                | Intent.FLAG_ACTIVITY_CLEAR_TOP
-                | Intent.FLAG_ACTIVITY_NO_HISTORY
-                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
-                | getFlagActivityNoUserAction(InitiatedByUserAction.unknown));
-        newIntent.putExtra("TEXT", mCurrentCmd.geTextMessage());
-        startActivity(newIntent);
+    private void launchTextDialog(int slotId) {
+        CatLog.d(LOG_TAG, "launchTextDialog, slotId: " + slotId);
+        Intent newIntent = new Intent();
+        String targetActivity = STK_DIALOG_ACTIVITY_NAME;
+        int action = getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
+        String uriString = STK_DIALOG_URI + System.currentTimeMillis();
+        //Set unique URI to create a new instance of activity for different slotId.
+        Uri uriData = Uri.parse(uriString);
+        if (newIntent != null) {
+            newIntent.setClassName(PACKAGE_NAME, targetActivity);
+            newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+                    | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
+            newIntent.setData(uriData);
+            newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
+            newIntent.putExtra(SLOT_ID, slotId);
+            startActivity(newIntent);
+        }
     }
 
-    private void launchEventMessage() {
-        launchEventMessage(mCurrentCmd.geTextMessage());
+    public boolean isStkDialogActivated(Context context) {
+        String stkDialogActivity = "com.android.stk.StkDialogActivity";
+        boolean activated = false;
+        final ActivityManager am = (ActivityManager) context.getSystemService(
+                Context.ACTIVITY_SERVICE);
+        String topActivity = am.getRunningTasks(1).get(0).topActivity.getClassName();
+
+        CatLog.d(LOG_TAG, "isStkDialogActivated: " + topActivity);
+        if (topActivity.equals(stkDialogActivity)) {
+            activated = true;
+        }
+        CatLog.d(LOG_TAG, "activated : " + activated);
+        return activated;
     }
 
-    private void launchEventMessage(TextMessage msg) {
-        if (msg == null || msg.text == null) {
+    private void launchEventMessage(int slotId, TextMessage msg) {
+        if (msg == null || (msg.text != null && msg.text.length() == 0)) {
+            CatLog.d(LOG_TAG, "launchEventMessage return");
             return;
         }
+
         Toast toast = new Toast(mContext.getApplicationContext());
         LayoutInflater inflate = (LayoutInflater) mContext
                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -740,15 +1220,29 @@
         toast.show();
     }
 
-    private void launchConfirmationDialog(TextMessage msg) {
-        msg.title = lastSelectedItem;
-        Intent newIntent = new Intent(this, StkDialogActivity.class);
-        newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                | Intent.FLAG_ACTIVITY_NO_HISTORY
-                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
-                | getFlagActivityNoUserAction(InitiatedByUserAction.unknown));
-        newIntent.putExtra("TEXT", msg);
-        startActivity(newIntent);
+    private void launchEventMessage(int slotId) {
+        launchEventMessage(slotId, mStkContext[slotId].mCurrentCmd.geTextMessage());
+    }
+
+    private void launchConfirmationDialog(TextMessage msg, int slotId) {
+        msg.title = mStkContext[slotId].lastSelectedItem;
+        Intent newIntent = new Intent();
+        String targetActivity = STK_DIALOG_ACTIVITY_NAME;
+        String uriString = STK_DIALOG_URI + System.currentTimeMillis();
+        //Set unique URI to create a new instance of activity for different slotId.
+        Uri uriData = Uri.parse(uriString);
+
+        if (newIntent != null) {
+            newIntent.setClassName(this, targetActivity);
+            newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_NO_HISTORY
+                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+                    | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
+            newIntent.putExtra("TEXT", msg);
+            newIntent.putExtra(SLOT_ID, slotId);
+            newIntent.setData(uriData);
+            startActivity(newIntent);
+        }
     }
 
     private void launchBrowser(BrowserSettings settings) {
@@ -760,12 +1254,12 @@
         Uri data = null;
 
         if (settings.url != null) {
-            CatLog.d(this, "settings.url = " + settings.url);
+            CatLog.d(LOG_TAG, "settings.url = " + settings.url);
             if ((settings.url.startsWith("http://") || (settings.url.startsWith("https://")))) {
                 data = Uri.parse(settings.url);
             } else {
                 String modifiedUrl = "http://" + settings.url;
-                CatLog.d(this, "modifiedUrl = " + modifiedUrl);
+                CatLog.d(LOG_TAG, "modifiedUrl = " + modifiedUrl);
                 data = Uri.parse(modifiedUrl);
             }
         }
@@ -775,7 +1269,7 @@
         } else {
             // if the command did not contain a URL,
             // launch the browser to the default homepage.
-            CatLog.d(this, "launch browser with default URL ");
+            CatLog.d(LOG_TAG, "launch browser with default URL ");
             intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN,
                     Intent.CATEGORY_APP_BROWSER);
         }
@@ -802,24 +1296,31 @@
         } catch (InterruptedException e) {}
     }
 
-    private void launchIdleText() {
-        TextMessage msg = mCurrentCmd.geTextMessage();
+    private void launchIdleText(int slotId) {
+        TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
 
         if (msg == null) {
-            CatLog.d(this, "mCurrent.getTextMessage is NULL");
-            mNotificationManager.cancel(STK_NOTIFICATION_ID);
+            CatLog.d(LOG_TAG, "mCurrent.getTextMessage is NULL");
+            mNotificationManager.cancel(getNotificationId(slotId));
             return;
         }
+        CatLog.d(LOG_TAG, "launchIdleText - text[" + msg.text
+                         + "] iconSelfExplanatory[" + msg.iconSelfExplanatory
+                         + "] icon[" + msg.icon + "], sim id: " + slotId);
+
         if (msg.text == null) {
-            mNotificationManager.cancel(STK_NOTIFICATION_ID);
+            CatLog.d(LOG_TAG, "cancel IdleMode text");
+            mNotificationManager.cancel(getNotificationId(slotId));
         } else {
+            CatLog.d(LOG_TAG, "Add IdleMode text");
             PendingIntent pendingIntent = PendingIntent.getService(mContext, 0,
                     new Intent(mContext, StkAppService.class), 0);
 
             final Notification.Builder notificationBuilder = new Notification.Builder(
                     StkAppService.this);
-            if (mMainCmd != null && mMainCmd.getMenu() != null) {
-                notificationBuilder.setContentTitle(mMainCmd.getMenu().title);
+            if (mStkContext[slotId].mMainCmd != null &&
+                    mStkContext[slotId].mMainCmd.getMenu() != null) {
+                notificationBuilder.setContentTitle(mStkContext[slotId].mMainCmd.getMenu().title);
             } else {
                 notificationBuilder.setContentTitle("");
             }
@@ -842,25 +1343,31 @@
             }
             notificationBuilder.setColor(mContext.getResources().getColor(
                     com.android.internal.R.color.system_notification_accent_color));
-            mNotificationManager.notify(STK_NOTIFICATION_ID, notificationBuilder.build());
+            mNotificationManager.notify(getNotificationId(slotId), notificationBuilder.build());
         }
     }
 
-    private void launchToneDialog() {
+    private void launchToneDialog(int slotId) {
         Intent newIntent = new Intent(this, ToneDialog.class);
+        String uriString = STK_TONE_URI + slotId;
+        Uri uriData = Uri.parse(uriString);
+        //Set unique URI to create a new instance of activity for different slotId.
+        CatLog.d(LOG_TAG, "launchToneDialog, slotId: " + slotId);
         newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                 | Intent.FLAG_ACTIVITY_NO_HISTORY
                 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
-                | getFlagActivityNoUserAction(InitiatedByUserAction.unknown));
-        newIntent.putExtra("TEXT", mCurrentCmd.geTextMessage());
-        newIntent.putExtra("TONE", mCurrentCmd.getToneSettings());
+                | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
+        newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
+        newIntent.putExtra("TONE", mStkContext[slotId].mCurrentCmd.getToneSettings());
+        newIntent.putExtra(SLOT_ID, slotId);
+        newIntent.setData(uriData);
         startActivity(newIntent);
     }
 
-    private void launchOpenChannelDialog() {
-        TextMessage msg = mCurrentCmd.geTextMessage();
+    private void launchOpenChannelDialog(int slotId) {
+        TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
         if (msg == null) {
-            CatLog.d(this, "msg is null, return here");
+            CatLog.d(LOG_TAG, "msg is null, return here");
             return;
         }
 
@@ -909,10 +1416,10 @@
         dialog.show();
     }
 
-    private void launchTransientEventMessage() {
-        TextMessage msg = mCurrentCmd.geTextMessage();
+    private void launchTransientEventMessage(int slotId) {
+        TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
         if (msg == null) {
-            CatLog.d(this, "msg is null, return here");
+            CatLog.d(LOG_TAG, "msg is null, return here");
             return;
         }
 
@@ -939,8 +1446,19 @@
         dialog.show();
     }
 
-    private String getItemName(int itemId) {
-        Menu menu = mCurrentCmd.getMenu();
+    private int getNotificationId(int slotId) {
+        int notifyId = STK_NOTIFICATION_ID;
+        if (slotId >= 0 && slotId < mSimCount) {
+            notifyId += slotId;
+        } else {
+            CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
+        }
+        CatLog.d(LOG_TAG, "getNotificationId, slotId: " + slotId + ", notifyId: " + notifyId);
+        return notifyId;
+    }
+
+    private String getItemName(int itemId, int slotId) {
+        Menu menu = mStkContext[slotId].mCurrentCmd.getMenu();
         if (menu == null) {
             return null;
         }
@@ -952,16 +1470,27 @@
         return null;
     }
 
-    private boolean removeMenu() {
+    private boolean removeMenu(int slotId) {
         try {
-            if (mCurrentMenu.items.size() == 1 &&
-                mCurrentMenu.items.get(0) == null) {
+            if (mStkContext[slotId].mCurrentMenu.items.size() == 1 &&
+                mStkContext[slotId].mCurrentMenu.items.get(0) == null) {
+                mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
                 return true;
             }
         } catch (NullPointerException e) {
-            CatLog.d(this, "Unable to get Menu's items size");
+            CatLog.d(LOG_TAG, "Unable to get Menu's items size");
+            mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
             return true;
         }
+        mStkContext[slotId].mSetupMenuState = STATE_EXIST;
         return false;
     }
+    StkContext getStkContext(int slotId) {
+        if (slotId >= 0 && slotId < mSimCount) {
+            return mStkContext[slotId];
+        } else {
+            CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
+            return null;
+        }
+    }
 }
diff --git a/src/com/android/stk/StkCmdReceiver.java b/src/com/android/stk/StkCmdReceiver.java
index 8e9aae7..254c7fb 100644
--- a/src/com/android/stk/StkCmdReceiver.java
+++ b/src/com/android/stk/StkCmdReceiver.java
@@ -18,12 +18,14 @@
 
 import com.android.internal.telephony.cat.AppInterface;
 import com.android.internal.telephony.uicc.IccRefreshResponse;
-
+import com.android.internal.telephony.cat.CatLog;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 
+import com.android.internal.telephony.cat.AppInterface;
+
 /**
  * Receiver class to get STK intents, broadcasted by telephony layer.
  *
@@ -35,45 +37,42 @@
         String action = intent.getAction();
 
         if (action.equals(AppInterface.CAT_CMD_ACTION)) {
-            handleCommandMessage(context, intent);
+            handleAction(context, intent, StkAppService.OP_CMD);
         } else if (action.equals(AppInterface.CAT_SESSION_END_ACTION)) {
-            handleSessionEnd(context, intent);
+            handleAction(context, intent, StkAppService.OP_END_SESSION);
         } else if (action.equals(AppInterface.CAT_ICC_STATUS_CHANGE)) {
-            handleCardStatusChange(context, intent);
+            handleAction(context, intent, StkAppService.OP_CARD_STATUS_CHANGED);
         }
     }
 
-    private void handleCommandMessage(Context context, Intent intent) {
+    private void handleAction(Context context, Intent intent, int op) {
         Bundle args = new Bundle();
-        args.putInt(StkAppService.OPCODE, StkAppService.OP_CMD);
-        args.putParcelable(StkAppService.CMD_MSG, intent
-                .getParcelableExtra("STK CMD"));
-        context.startService(new Intent(context, StkAppService.class)
-                .putExtras(args));
-    }
+        int slot_id = intent.getIntExtra(StkAppService.SLOT_ID,0);
 
-    private void handleSessionEnd(Context context, Intent intent) {
-        Bundle args = new Bundle();
-        args.putInt(StkAppService.OPCODE, StkAppService.OP_END_SESSION);
-        context.startService(new Intent(context, StkAppService.class)
-                .putExtras(args));
-    }
+        args.putInt(StkAppService.OPCODE, op);
+        args.putInt(StkAppService.SLOT_ID, slot_id);
 
-    private void handleCardStatusChange(Context context, Intent intent) {
-        // If the Card is absent then check if the StkAppService is even
-        // running before starting it to stop it right away
-        if ((intent.getBooleanExtra(AppInterface.CARD_STATUS, false) == false)
-                && StkAppService.getInstance() == null) {
-            return;
+        if (StkAppService.OP_CMD == op) {
+            args.putParcelable(StkAppService.CMD_MSG, intent
+                    .getParcelableExtra(StkAppService.STK_CMD));
+        } else if (StkAppService.OP_CARD_STATUS_CHANGED == op) {
+            // If the Card is absent then check if the StkAppService is even
+            // running before starting it to stop it right away
+            if ((intent.getBooleanExtra(AppInterface.CARD_STATUS, false) == false)
+                    && StkAppService.getInstance() == null) {
+                return;
+            }
+
+            args.putBoolean(AppInterface.CARD_STATUS,
+                    intent.getBooleanExtra(AppInterface.CARD_STATUS, true));
+            args.putInt(AppInterface.REFRESH_RESULT,
+                    intent.getIntExtra(AppInterface.REFRESH_RESULT,
+                    IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE));
         }
-        Bundle args = new Bundle();
-        args.putInt(StkAppService.OPCODE, StkAppService.OP_CARD_STATUS_CHANGED);
-        args.putBoolean(AppInterface.CARD_STATUS,
-                intent.getBooleanExtra(AppInterface.CARD_STATUS, true));
-        args.putInt(AppInterface.REFRESH_RESULT,
-                intent.getIntExtra(AppInterface.REFRESH_RESULT,
-                IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE));
-        context.startService(new Intent(context, StkAppService.class)
-                .putExtras(args));
+        CatLog.d("StkCmdReceiver", "handleAction, op: " + op +
+                "args: " + args + ", slot id: " + slot_id);
+        Intent toService = new Intent(context, StkAppService.class);
+        toService.putExtras(args);
+        context.startService(toService);
     }
 }
diff --git a/src/com/android/stk/StkDialogActivity.java b/src/com/android/stk/StkDialogActivity.java
old mode 100644
new mode 100755
index cf81f03..b09aa40
--- a/src/com/android/stk/StkDialogActivity.java
+++ b/src/com/android/stk/StkDialogActivity.java
@@ -37,14 +37,19 @@
  */
 public class StkDialogActivity extends Activity implements View.OnClickListener {
     // members
-    TextMessage mTextMsg;
-
+    private static final String className = new Object(){}.getClass().getEnclosingClass().getName();
+    private static final String LOG_TAG = className.substring(className.lastIndexOf('.') + 1);
+    TextMessage mTextMsg = null;
+    private int mSlotId = -1;
+    private StkAppService appService = StkAppService.getInstance();
     private boolean mIsResponseSent = false;
+
     Handler mTimeoutHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             switch(msg.what) {
             case MSG_ID_TIMEOUT:
+                CatLog.d(LOG_TAG, "MSG_ID_TIMEOUT finish.");
                 sendResponse(StkAppService.RES_ID_TIMEOUT);
                 finish();
                 break;
@@ -66,6 +71,7 @@
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
+        CatLog.d(LOG_TAG, "onCreate");
         initFromIntent(getIntent());
         if (mTextMsg == null) {
             finish();
@@ -91,6 +97,7 @@
         }
 
         if (mTextMsg.icon == null) {
+            CatLog.d(LOG_TAG, "onCreate icon is null");
             window.setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
                     com.android.internal.R.drawable.stat_notify_sim_toolkit);
         } else {
@@ -104,11 +111,15 @@
 
         switch (v.getId()) {
         case OK_BUTTON:
+            CatLog.d(LOG_TAG, "OK Clicked!, mSlotId: " + mSlotId);
             sendResponse(StkAppService.RES_ID_CONFIRM, true);
+            cancelTimeOut();
             finish();
             break;
         case CANCEL_BUTTON:
+            CatLog.d(LOG_TAG, "Cancel Clicked!, mSlotId: " + mSlotId);
             sendResponse(StkAppService.RES_ID_CONFIRM, false);
+            cancelTimeOut();
             finish();
             break;
         }
@@ -118,6 +129,8 @@
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         switch (keyCode) {
         case KeyEvent.KEYCODE_BACK:
+            CatLog.d(LOG_TAG, "onKeyDown - KEYCODE_BACK");
+            cancelTimeOut();
             sendResponse(StkAppService.RES_ID_BACKWARD);
             finish();
             break;
@@ -128,7 +141,8 @@
     @Override
     public void onResume() {
         super.onResume();
-
+        CatLog.d(LOG_TAG, "onResume - mIsResponseSent[" + mIsResponseSent +
+                "], sim id: " + mSlotId);
         /*
          * The user should be shown the message forever or until some high
          * priority event occurs (such as incoming call, MMI code execution
@@ -151,7 +165,7 @@
     @Override
     public void onPause() {
         super.onPause();
-
+        CatLog.d(LOG_TAG, "onPause, sim id: " + mSlotId);
         cancelTimeOut();
     }
 
@@ -164,13 +178,37 @@
     @Override
     public void onStop() {
         super.onStop();
+        CatLog.d(LOG_TAG, "onStop - before Send CONFIRM false mIsResponseSent[" +
+                mIsResponseSent + "], sim id: " + mSlotId);
         if (!mIsResponseSent) {
-            sendResponse(StkAppService.RES_ID_TIMEOUT);
+            appService.getStkContext(mSlotId).setPendingDialogInstance(this);
+        } else {
+            CatLog.d(LOG_TAG, "finish.");
+            appService.getStkContext(mSlotId).setPendingDialogInstance(null);
+            cancelTimeOut();
+            finish();
+            CatLog.d(LOG_TAG, "finish.");
         }
     }
 
     @Override
+    public void onDestroy() {
+        super.onDestroy();
+        CatLog.d(LOG_TAG, "onDestroy - mIsResponseSent[" + mIsResponseSent +
+                "], sim id: " + mSlotId);
+        // if dialog activity is finished by stkappservice
+        // when receiving OP_LAUNCH_APP from the other SIM, we can not send TR here
+        // , since the dialog cmd is waiting user to process.
+        if (!mIsResponseSent && !appService.isDialogPending(mSlotId)) {
+            sendResponse(StkAppService.RES_ID_CONFIRM, false);
+        }
+        cancelTimeOut();
+    }
+
+    @Override
     public void onSaveInstanceState(Bundle outState) {
+        CatLog.d(LOG_TAG, "onSaveInstanceState");
+
         super.onSaveInstanceState(outState);
 
         outState.putParcelable(TEXT, mTextMsg);
@@ -181,11 +219,25 @@
         super.onRestoreInstanceState(savedInstanceState);
 
         mTextMsg = savedInstanceState.getParcelable(TEXT);
+        CatLog.d(LOG_TAG, "onRestoreInstanceState - [" + mTextMsg + "]");
     }
 
     private void sendResponse(int resId, boolean confirmed) {
+        if (mSlotId == -1) {
+            CatLog.d(LOG_TAG, "sim id is invalid");
+            return;
+        }
+
+        if (StkAppService.getInstance() == null) {
+            CatLog.d(LOG_TAG, "Ignore response: id is " + resId);
+            return;
+        }
+
+        CatLog.d(LOG_TAG, "sendResponse resID[" + resId + "] confirmed[" + confirmed + "]");
+
         Bundle args = new Bundle();
         args.putInt(StkAppService.OPCODE, StkAppService.OP_RESPONSE);
+        args.putInt(StkAppService.SLOT_ID, mSlotId);
         args.putInt(StkAppService.RES_ID, resId);
         args.putBoolean(StkAppService.CONFIRMATION, confirmed);
         startService(new Intent(this, StkAppService.class).putExtras(args));
@@ -200,12 +252,16 @@
 
         if (intent != null) {
             mTextMsg = intent.getParcelableExtra("TEXT");
+            mSlotId = intent.getIntExtra(StkAppService.SLOT_ID, -1);
         } else {
             finish();
         }
+
+        CatLog.d(LOG_TAG, "initFromIntent - [" + mTextMsg + "], sim id: " + mSlotId);
     }
 
     private void cancelTimeOut() {
+        CatLog.d(LOG_TAG, "cancelTimeOut: " + mSlotId);
         mTimeoutHandler.removeMessages(MSG_ID_TIMEOUT);
     }
 
@@ -215,14 +271,20 @@
         int dialogDuration = StkApp.calculateDurationInMilis(mTextMsg.duration);
         // If duration is specified, this has priority. If not, set timeout
         // according to condition given by the card.
-        if (dialogDuration == 0) {
-            if (waitForUserToClear) {
-                dialogDuration = StkApp.DISP_TEXT_WAIT_FOR_USER_TIMEOUT;
-            } else {
-                dialogDuration = StkApp.DISP_TEXT_CLEAR_AFTER_DELAY_TIMEOUT;
+        if (mTextMsg.userClear == true && mTextMsg.responseNeeded == false) {
+            return;
+        } else {
+            // userClear = false. will dissapear after a while.
+            if (dialogDuration == 0) {
+                if (waitForUserToClear) {
+                    dialogDuration = StkApp.DISP_TEXT_WAIT_FOR_USER_TIMEOUT;
+                } else {
+                    dialogDuration = StkApp.DISP_TEXT_CLEAR_AFTER_DELAY_TIMEOUT;
+                }
             }
-        }
-        mTimeoutHandler.sendMessageDelayed(mTimeoutHandler
+            CatLog.d(LOG_TAG, "startTimeOut: " + mSlotId);
+            mTimeoutHandler.sendMessageDelayed(mTimeoutHandler
                 .obtainMessage(MSG_ID_TIMEOUT), dialogDuration);
+        }
     }
 }
diff --git a/src/com/android/stk/StkInputActivity.java b/src/com/android/stk/StkInputActivity.java
old mode 100644
new mode 100755
index eb66a32..bfaa36d
--- a/src/com/android/stk/StkInputActivity.java
+++ b/src/com/android/stk/StkInputActivity.java
@@ -36,7 +36,7 @@
 import android.widget.TextView;
 import android.widget.EditText;
 import android.widget.TextView.BufferType;
-
+import com.android.internal.telephony.cat.CatLog;
 import com.android.internal.telephony.cat.FontSize;
 import com.android.internal.telephony.cat.Input;
 
@@ -53,9 +53,14 @@
     private TextView mPromptView = null;
     private View mYesNoLayout = null;
     private View mNormalLayout = null;
-    private Input mStkInput = null;
 
     // Constants
+    private static final String className = new Object(){}.getClass().getEnclosingClass().getName();
+    private static final String LOG_TAG = className.substring(className.lastIndexOf('.') + 1);
+
+    private Input mStkInput = null;
+    private boolean mAcceptUsersInput = true;
+    // Constants
     private static final int STATE_TEXT = 1;
     private static final int STATE_YES_NO = 2;
 
@@ -69,15 +74,21 @@
 
     // message id for time out
     private static final int MSG_ID_TIMEOUT = 1;
+    private StkAppService appService = StkAppService.getInstance();
+
+    private boolean mIsResponseSent = false;
+    private int mSlotId = -1;
+    Activity mInstance = null;
 
     Handler mTimeoutHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             switch(msg.what) {
             case MSG_ID_TIMEOUT:
-                //mAcceptUsersInput = false;
+                CatLog.d(LOG_TAG, "Msg timeout.");
+                mAcceptUsersInput = false;
+                appService.getStkContext(mSlotId).setPendingActivityInstance(mInstance);
                 sendResponse(StkAppService.RES_ID_TIMEOUT);
-                finish();
                 break;
             }
         }
@@ -86,39 +97,50 @@
     // Click listener to handle buttons press..
     public void onClick(View v) {
         String input = null;
+        if (!mAcceptUsersInput) {
+            CatLog.d(LOG_TAG, "mAcceptUsersInput:false");
+            return;
+        }
 
         switch (v.getId()) {
         case R.id.button_ok:
             // Check that text entered is valid .
             if (!verfiyTypedText()) {
+                CatLog.d(LOG_TAG, "handleClick, invalid text");
                 return;
             }
+            mAcceptUsersInput = false;
             input = mTextIn.getText().toString();
             break;
         // Yes/No layout buttons.
         case R.id.button_yes:
+            mAcceptUsersInput = false;
             input = YES_STR_RESPONSE;
             break;
         case R.id.button_no:
+            mAcceptUsersInput = false;
             input = NO_STR_RESPONSE;
             break;
         }
-
+        CatLog.d(LOG_TAG, "handleClick, ready to response");
+        appService.getStkContext(mSlotId).setPendingActivityInstance(this);
         sendResponse(StkAppService.RES_ID_INPUT, input, false);
-        finish();
     }
 
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
+        CatLog.d(LOG_TAG, "onCreate - mIsResponseSent[" + mIsResponseSent + "]");
+
         // Set the layout for this activity.
+        requestWindowFeature(Window.FEATURE_LEFT_ICON);
         setContentView(R.layout.stk_input);
 
         // Initialize members
         mTextIn = (EditText) this.findViewById(R.id.in_text);
         mPromptView = (TextView) this.findViewById(R.id.prompt);
-
+        mInstance = this;
         // Set buttons listeners.
         Button okButton = (Button) findViewById(R.id.button_ok);
         Button yesButton = (Button) findViewById(R.id.button_yes);
@@ -130,22 +152,9 @@
 
         mYesNoLayout = findViewById(R.id.yes_no_layout);
         mNormalLayout = findViewById(R.id.normal_layout);
-
-        // Get the calling intent type: text/key, and setup the
-        // display parameters.
-        Intent intent = getIntent();
-        if (intent != null) {
-            mStkInput = intent.getParcelableExtra("INPUT");
-            if (mStkInput == null) {
-                finish();
-            } else {
-                mState = mStkInput.yesNo ? STATE_YES_NO : STATE_TEXT;
-                configInputDisplay();
-            }
-        } else {
-            finish();
-        }
+        initFromIntent(getIntent());
         mContext = getBaseContext();
+        mAcceptUsersInput = true;
     }
 
     @Override
@@ -158,35 +167,84 @@
     @Override
     public void onResume() {
         super.onResume();
-
+        CatLog.d(LOG_TAG, "onResume - mIsResponseSent[" + mIsResponseSent +
+                "], slot id: " + mSlotId);
         startTimeOut();
+        appService.getStkContext(mSlotId).setPendingActivityInstance(null);
     }
 
     @Override
     public void onPause() {
         super.onPause();
+        CatLog.d(LOG_TAG, "onPause - mIsResponseSent[" + mIsResponseSent + "]");
+    }
 
+    @Override
+    public void onStop() {
+        super.onStop();
+        CatLog.d(LOG_TAG, "onStop - mIsResponseSent[" + mIsResponseSent + "]");
+        if (mIsResponseSent) {
+            cancelTimeOut();
+            finish();
+        } else {
+            appService.getStkContext(mSlotId).setPendingActivityInstance(this);
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        CatLog.d(LOG_TAG, "onDestroy - before Send End Session mIsResponseSent[" +
+                mIsResponseSent + " , " + mSlotId + "]");
+        //If the input activity is finished by stkappservice
+        //when receiving OP_LAUNCH_APP from the other SIM, we can not send TR here
+        //, since the input cmd is waiting user to process.
+        if (!mIsResponseSent && !appService.isInputPending(mSlotId)) {
+            CatLog.d(LOG_TAG, "handleDestroy - Send End Session");
+            sendResponse(StkAppService.RES_ID_END_SESSION);
+        }
         cancelTimeOut();
     }
 
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (!mAcceptUsersInput) {
+            CatLog.d(LOG_TAG, "mAcceptUsersInput:false");
+            return true;
+        }
+
         switch (keyCode) {
         case KeyEvent.KEYCODE_BACK:
+            CatLog.d(LOG_TAG, "onKeyDown - KEYCODE_BACK");
+            mAcceptUsersInput = false;
+            appService.getStkContext(mSlotId).setPendingActivityInstance(this);
             sendResponse(StkAppService.RES_ID_BACKWARD, null, false);
-            finish();
-            break;
+            return true;
         }
         return super.onKeyDown(keyCode, event);
     }
 
-    private void sendResponse(int resId) {
+    void sendResponse(int resId) {
         sendResponse(resId, null, false);
     }
 
-    private void sendResponse(int resId, String input, boolean help) {
+    void sendResponse(int resId, String input, boolean help) {
+        if (mSlotId == -1) {
+            CatLog.d(LOG_TAG, "slot id is invalid");
+            return;
+        }
+
+        if (StkAppService.getInstance() == null) {
+            CatLog.d(LOG_TAG, "StkAppService is null, Ignore response: id is " + resId);
+            return;
+        }
+
+        CatLog.d(LOG_TAG, "sendResponse resID[" + resId + "] input[" + input +
+                "] help[" + help + "]");
+        mIsResponseSent = true;
         Bundle args = new Bundle();
         args.putInt(StkAppService.OPCODE, StkAppService.OP_RESPONSE);
+        args.putInt(StkAppService.SLOT_ID, mSlotId);
         args.putInt(StkAppService.RES_ID, resId);
         if (input != null) {
             args.putString(StkAppService.INPUT, input);
@@ -217,12 +275,20 @@
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
+        if (!mAcceptUsersInput) {
+            CatLog.d(LOG_TAG, "mAcceptUsersInput:false");
+            return true;
+        }
         switch (item.getItemId()) {
         case StkApp.MENU_ID_END_SESSION:
+            mAcceptUsersInput = false;
+            cancelTimeOut();
             sendResponse(StkAppService.RES_ID_END_SESSION);
             finish();
             return true;
         case StkApp.MENU_ID_HELP:
+            mAcceptUsersInput = false;
+            cancelTimeOut();
             sendResponse(StkAppService.RES_ID_INPUT, "", true);
             finish();
             return true;
@@ -230,6 +296,18 @@
         return super.onOptionsItemSelected(item);
     }
 
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        CatLog.d(LOG_TAG, "onSaveInstanceState: " + mSlotId);
+        outState.putBoolean("ACCEPT_USERS_INPUT", mAcceptUsersInput);
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Bundle savedInstanceState) {
+        CatLog.d(LOG_TAG, "onRestoreInstanceState: " + mSlotId);
+        mAcceptUsersInput = savedInstanceState.getBoolean("ACCEPT_USERS_INPUT");
+    }
+
     public void beforeTextChanged(CharSequence s, int start, int count,
             int after) {
     }
@@ -329,4 +407,24 @@
 
         return fontSizes[size.ordinal()];
     }
+
+    private void initFromIntent(Intent intent) {
+        // Get the calling intent type: text/key, and setup the
+        // display parameters.
+        CatLog.d(LOG_TAG, "initFromIntent - slot id: " + mSlotId);
+        if (intent != null) {
+            mStkInput = intent.getParcelableExtra("INPUT");
+            mSlotId = intent.getIntExtra(StkAppService.SLOT_ID, -1);
+            CatLog.d(LOG_TAG, "onCreate - slot id: " + mSlotId);
+            if (mStkInput == null) {
+                finish();
+            } else {
+                mState = mStkInput.yesNo ? STATE_YES_NO :
+                        STATE_TEXT;
+                configInputDisplay();
+            }
+        } else {
+            finish();
+        }
+    }
 }
diff --git a/src/com/android/stk/StkLauncherActivity.java b/src/com/android/stk/StkLauncherActivity.java
old mode 100644
new mode 100755
index 194870e..9066c3e
--- a/src/com/android/stk/StkLauncherActivity.java
+++ b/src/com/android/stk/StkLauncherActivity.java
@@ -16,24 +16,222 @@
 
 package com.android.stk;
 
-import android.app.Activity;
+import android.app.ListActivity;
+import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
+import android.view.View;
+import android.view.KeyEvent;
+import android.view.Window;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+import com.android.internal.telephony.cat.Item;
+import com.android.internal.telephony.cat.Menu;
+import com.android.internal.telephony.cat.CatLog;
+import com.android.internal.telephony.PhoneConstants;
+
+import android.telephony.TelephonyManager;
+
+import java.util.ArrayList;
 
 /**
  * Launcher class. Serve as the app's MAIN activity, send an intent to the
  * StkAppService and finish.
  *
  */
-public class StkLauncherActivity extends Activity {
+public class StkLauncherActivity extends ListActivity {
+    private TextView mTitleTextView = null;
+    private ImageView mTitleIconView = null;
+    private static final String className = new Object(){}.getClass().getEnclosingClass().getName();
+    private static final String LOG_TAG = className.substring(className.lastIndexOf('.') + 1);
+    private ArrayList<Item> mStkMenuList = null;
+    private int mSingleSimId = -1;
+    private Context mContext = null;
+    private TelephonyManager mTm = null;
+    private Bitmap mBitMap = null;
+    private boolean mAcceptUsersInput = true;
+
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        CatLog.d(LOG_TAG, "onCreate+");
+        mContext = getBaseContext();
+        mTm = (TelephonyManager) mContext.getSystemService(
+                Context.TELEPHONY_SERVICE);
+        //Check if needs to show the menu list.
+        if (isShowSTKListMenu()) {
+            requestWindowFeature(Window.FEATURE_NO_TITLE);
+            setContentView(R.layout.stk_menu_list);
+            mTitleTextView = (TextView) findViewById(R.id.title_text);
+            mTitleIconView = (ImageView) findViewById(R.id.title_icon);
+            mTitleTextView.setText(R.string.app_name);
+            mBitMap = BitmapFactory.decodeResource(getResources(),
+                    R.drawable.ic_launcher_sim_toolkit);
+        } else {
+            //launch stk menu activity for the SIM.
+            if (mSingleSimId < 0) {
+                finish();
+            }
+        }
+    }
 
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+    }
+
+    @Override
+    protected void onListItemClick(ListView l, View v, int position, long id) {
+        super.onListItemClick(l, v, position, id);
+        if (!mAcceptUsersInput) {
+            CatLog.d(LOG_TAG, "mAcceptUsersInput:false");
+            return;
+        }
+        int simCount = TelephonyManager.from(mContext).getSimCount();
+        Item item = getSelectedItem(position);
+        if (item == null) {
+            CatLog.d(LOG_TAG, "Item is null");
+            return;
+        }
+        CatLog.d(LOG_TAG, "launch stk menu id: " + item.id);
+        if (item.id >= PhoneConstants.SIM_ID_1 && item.id < simCount) {
+            mAcceptUsersInput = false;
+            launchSTKMainMenu(item.id);
+        }
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        CatLog.d(LOG_TAG, "mAcceptUsersInput: " + mAcceptUsersInput);
+        if (!mAcceptUsersInput) {
+            return true;
+        }
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_BACK:
+                CatLog.d(LOG_TAG, "KEYCODE_BACK.");
+                mAcceptUsersInput = false;
+                finish();
+                return true;
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        CatLog.d(LOG_TAG, "onResume");
+        mAcceptUsersInput = true;
+        int itemSize = addStkMenuListItems();
+        if (itemSize == 0) {
+            CatLog.d(LOG_TAG, "item size = 0 so finish.");
+            finish();
+        } else if (itemSize == 1) {
+            launchSTKMainMenu(mSingleSimId);
+            finish();
+        } else {
+            CatLog.d(LOG_TAG, "resume to show multiple stk list.");
+        }
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        CatLog.d(LOG_TAG, "onPause");
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        CatLog.d(LOG_TAG, "onDestroy");
+    }
+
+    private Item getSelectedItem(int position) {
+        Item item = null;
+        if (mStkMenuList != null) {
+            try {
+                item = mStkMenuList.get(position);
+            } catch (IndexOutOfBoundsException e) {
+                if (StkApp.DBG) {
+                    CatLog.d(LOG_TAG, "IOOBE Invalid menu");
+                }
+            } catch (NullPointerException e) {
+                if (StkApp.DBG) {
+                    CatLog.d(LOG_TAG, "NPE Invalid menu");
+                }
+            }
+        }
+        return item;
+    }
+
+    private int addStkMenuListItems() {
+        String appName = mContext.getResources().getString(R.string.app_name);
+        String stkItemName = null;
+        int simCount = TelephonyManager.from(mContext).getSimCount();
+        mStkMenuList = new ArrayList<Item>();
+
+        CatLog.d(LOG_TAG, "simCount: " + simCount);
+        for (int i = 0; i < simCount; i++) {
+            //Check if the card is inserted.
+            if (mTm.hasIccCard(i)) {
+                CatLog.d(LOG_TAG, "SIM " + i + " add to menu.");
+                mSingleSimId = i;
+                stkItemName = new StringBuilder(appName).append(" ")
+                        .append(Integer.toString(i + 1)).toString();
+                Item item = new Item(i + 1, stkItemName, mBitMap);
+                item.id = i;
+                mStkMenuList.add(item);
+            } else {
+                CatLog.d(LOG_TAG, "SIM " + i + " is not inserted.");
+            }
+        }
+        if (mStkMenuList != null && mStkMenuList.size() > 0) {
+            if (mStkMenuList.size() > 1) {
+                StkMenuAdapter adapter = new StkMenuAdapter(this,
+                        mStkMenuList, false);
+                // Bind menu list to the new adapter.
+                this.setListAdapter(adapter);
+            }
+            return mStkMenuList.size();
+        } else {
+            CatLog.d(LOG_TAG, "No stk menu item add.");
+            return 0;
+        }
+    }
+    private boolean isShowSTKListMenu() {
+        int simCount = TelephonyManager.from(mContext).getSimCount();
+        int simInsertedCount = 0;
+        int insertedSlotId = -1;
+
+        CatLog.d(LOG_TAG, "simCount: " + simCount);
+        for (int i = 0; i < simCount; i++) {
+            //Check if the card is inserted.
+            if (mTm.hasIccCard(i)) {
+                CatLog.d(LOG_TAG, "SIM " + i + " is inserted.");
+                mSingleSimId = i;
+                simInsertedCount++;
+            } else {
+                CatLog.d(LOG_TAG, "SIM " + i + " is not inserted.");
+            }
+        }
+        if (simInsertedCount > 1) {
+            return true;
+        } else {
+            //No card or only one card.
+            CatLog.d(LOG_TAG, "do not show stk list menu.");
+            return false;
+        }
+    }
+    private void launchSTKMainMenu(int slodId) {
         Bundle args = new Bundle();
+        CatLog.d(LOG_TAG, "launchSTKMainMenu.");
         args.putInt(StkAppService.OPCODE, StkAppService.OP_LAUNCH_APP);
-        startService(new Intent(this, StkAppService.class).putExtras(args));
-
-        finish();
+        args.putInt(StkAppService.SLOT_ID
+                , PhoneConstants.SIM_ID_1 + slodId);
+        startService(new Intent(this, StkAppService.class)
+                .putExtras(args));
     }
 }
diff --git a/src/com/android/stk/StkMenuActivity.java b/src/com/android/stk/StkMenuActivity.java
old mode 100644
new mode 100755
index 93053f3..9d307f6
--- a/src/com/android/stk/StkMenuActivity.java
+++ b/src/com/android/stk/StkMenuActivity.java
@@ -17,6 +17,7 @@
 package com.android.stk;
 
 import android.app.ListActivity;
+import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
@@ -37,6 +38,7 @@
 import com.android.internal.telephony.cat.Item;
 import com.android.internal.telephony.cat.Menu;
 import com.android.internal.telephony.cat.CatLog;
+import android.telephony.TelephonyManager;
 
 /**
  * ListActivity used for displaying STK menus. These can be SET UP MENU and
@@ -49,17 +51,28 @@
     private Menu mStkMenu = null;
     private int mState = STATE_MAIN;
     private boolean mAcceptUsersInput = true;
+    private int mSlotId = -1;
+    private boolean mIsResponseSent = false;
+    Activity mInstance = null;
 
     private TextView mTitleTextView = null;
     private ImageView mTitleIconView = null;
     private ProgressBar mProgressView = null;
+    private static final String className = new Object(){}.getClass().getEnclosingClass().getName();
+    private static final String LOG_TAG = className.substring(className.lastIndexOf('.') + 1);
 
-    StkAppService appService = StkAppService.getInstance();
+    private StkAppService appService = StkAppService.getInstance();
 
     // Internal state values
+    static final int STATE_INIT = 0;
     static final int STATE_MAIN = 1;
     static final int STATE_SECONDARY = 2;
 
+    // Finish result
+    static final int FINISH_CAUSE_NORMAL = 1;
+    static final int FINISH_CAUSE_NULL_SERVICE = 2;
+    static final int FINISH_CAUSE_NULL_MENU = 3;
+
     // message id for time out
     private static final int MSG_ID_TIMEOUT = 1;
     private static final int CONTEXT_MENU_HELP = 0;
@@ -69,8 +82,13 @@
         public void handleMessage(Message msg) {
             switch(msg.what) {
             case MSG_ID_TIMEOUT:
+                CatLog.d(LOG_TAG, "MSG_ID_TIMEOUT mState: " + mState);
                 mAcceptUsersInput = false;
+                if (mState == STATE_SECONDARY) {
+                    appService.getStkContext(mSlotId).setPendingActivityInstance(mInstance);
+                }
                 sendResponse(StkAppService.RES_ID_TIMEOUT);
+                //finish();//We wait the following commands to trigger onStop of this activity.
                 break;
             }
         }
@@ -80,28 +98,19 @@
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
-        CatLog.d(this, "onCreate");
+        CatLog.d(LOG_TAG, "onCreate");
+        // Remove the default title, customized one is used.
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
         // Set the layout for this activity.
         setContentView(R.layout.stk_menu_list);
-
+        mInstance = this;
         mTitleTextView = (TextView) findViewById(R.id.title_text);
         mTitleIconView = (ImageView) findViewById(R.id.title_icon);
         mProgressView = (ProgressBar) findViewById(R.id.progress_bar);
         mContext = getBaseContext();
-
-        initFromIntent(getIntent());
         mAcceptUsersInput = true;
-
         getListView().setOnCreateContextMenuListener(this);
-    }
-
-    @Override
-    protected void onNewIntent(Intent intent) {
-        super.onNewIntent(intent);
-
-        CatLog.d(this, "onNewIntent");
-        initFromIntent(intent);
-        mAcceptUsersInput = true;
+        initFromIntent(getIntent());
     }
 
     @Override
@@ -109,13 +118,20 @@
         super.onListItemClick(l, v, position, id);
 
         if (!mAcceptUsersInput) {
+            CatLog.d(LOG_TAG, "mAcceptUsersInput:false");
             return;
         }
 
         Item item = getSelectedItem(position);
         if (item == null) {
+            CatLog.d(LOG_TAG, "Item is null");
             return;
         }
+        CatLog.d(LOG_TAG, "onListItemClick Id: " + item.id + ", mState: " + mState);
+        // ONLY set SECONDARY menu. It will be finished when the following command is comming.
+        if (mState == STATE_SECONDARY) {
+            appService.getStkContext(mSlotId).setPendingActivityInstance(this);
+        }
         sendResponse(StkAppService.RES_ID_MENU_SELECTION, item.id, false);
         mAcceptUsersInput = false;
         mProgressView.setVisibility(View.VISIBLE);
@@ -124,21 +140,28 @@
 
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-
+        CatLog.d(LOG_TAG, "mAcceptUsersInput: " + mAcceptUsersInput);
         if (!mAcceptUsersInput) {
             return true;
         }
 
         switch (keyCode) {
         case KeyEvent.KEYCODE_BACK:
+            CatLog.d(LOG_TAG, "KEYCODE_BACK - mState[" + mState + "]");
             switch (mState) {
             case STATE_SECONDARY:
+                CatLog.d(LOG_TAG, "STATE_SECONDARY");
                 cancelTimeOut();
                 mAcceptUsersInput = false;
+                appService.getStkContext(mSlotId).setPendingActivityInstance(this);
                 sendResponse(StkAppService.RES_ID_BACKWARD);
                 return true;
             case STATE_MAIN:
-                break;
+                CatLog.d(LOG_TAG, "STATE_MAIN");
+                appService.getStkContext(mSlotId).setMainActivityInstance(null);
+                cancelTimeOut();
+                finish();
+                return true;
             }
             break;
         }
@@ -146,25 +169,45 @@
     }
 
     @Override
+    public void onRestart() {
+        super.onRestart();
+        CatLog.d(LOG_TAG, "onRestart, slot id: " + mSlotId);
+    }
+
+    @Override
     public void onResume() {
         super.onResume();
 
-        appService.indicateMenuVisibility(true);
-        mStkMenu = appService.getMenu();
+        CatLog.d(LOG_TAG, "onResume, slot id: " + mSlotId + "," + mState);
+        appService.indicateMenuVisibility(true, mSlotId);
+        if (mState == STATE_MAIN) {
+            mStkMenu = appService.getMainMenu(mSlotId);
+        } else {
+            mStkMenu = appService.getMenu(mSlotId);
+        }
         if (mStkMenu == null) {
+            CatLog.d(LOG_TAG, "menu is null");
+            cancelTimeOut();
             finish();
             return;
         }
+        //Set main menu instance here for clean up stack by other SIMs
+        //when receiving OP_LAUNCH_APP.
+        if (mState == STATE_MAIN) {
+            CatLog.d(LOG_TAG, "set main menu instance.");
+            appService.getStkContext(mSlotId).setMainActivityInstance(this);
+        }
         displayMenu();
         startTimeOut();
         // whenever this activity is resumed after a sub activity was invoked
         // (Browser, In call screen) switch back to main state and enable
         // user's input;
         if (!mAcceptUsersInput) {
-            mState = STATE_MAIN;
+            //Remove set mState to STATE_MAIN. This is for single instance flow.
             mAcceptUsersInput = true;
         }
         invalidateOptionsMenu();
+
         // make sure the progress bar is not shown.
         mProgressView.setIndeterminate(false);
         mProgressView.setVisibility(View.GONE);
@@ -173,17 +216,63 @@
     @Override
     public void onPause() {
         super.onPause();
-
-        appService.indicateMenuVisibility(false);
+        CatLog.d(LOG_TAG, "onPause, slot id: " + mSlotId + "," + mState);
+        //If activity is finished in onResume and it reaults from null appService.
+        if (appService != null) {
+            appService.indicateMenuVisibility(false, mSlotId);
+        } else {
+            CatLog.d(LOG_TAG, "onPause: null appService.");
+        }
         cancelTimeOut();
     }
 
     @Override
+    public void onStop() {
+        super.onStop();
+        CatLog.d(LOG_TAG, "onStop, slot id: " + mSlotId + "," + mIsResponseSent + "," + mState);
+        //The menu should stay in background, if
+        //1. the dialog is pop up in the screen, but the user does not response to the dialog.
+        //2. the menu activity enters Stop state (e.g pressing HOME key) but mIsResponseSent is false.
+        if (mIsResponseSent) {
+            // ONLY finish SECONDARY menu. MAIN menu should always stay in the root of stack.
+            if (mState == STATE_SECONDARY) {
+                if (!appService.isStkDialogActivated(mContext)) {
+                    CatLog.d(LOG_TAG, "STATE_SECONDARY finish.");
+                    cancelTimeOut();//To avoid the timer time out and send TR again.
+                    finish();
+                } else {
+                     if (appService != null) {
+                         appService.getStkContext(mSlotId).setPendingActivityInstance(this);
+                     }
+                }
+            }
+        } else {
+            if (appService != null) {
+                appService.getStkContext(mSlotId).setPendingActivityInstance(this);
+            } else {
+                CatLog.d(LOG_TAG, "onStop: null appService.");
+            }
+        }
+    }
+
+    @Override
     public void onDestroy() {
         getListView().setOnCreateContextMenuListener(null);
         super.onDestroy();
-
-        CatLog.d(this, "onDestroy");
+        CatLog.d(LOG_TAG, "onDestroy" + "," + mState);
+        //isMenuPending: if input act is finish by stkappservice when OP_LAUNCH_APP again,
+        //we can not send TR here, since the input cmd is waiting user to process.
+        if (!mIsResponseSent && !appService.isMenuPending(mSlotId)) {
+            CatLog.d(LOG_TAG, "handleDestroy - Send End Session");
+            sendResponse(StkAppService.RES_ID_END_SESSION);
+        }
+        if (mState == STATE_MAIN) {
+            if (appService != null) {
+                appService.getStkContext(mSlotId).setMainActivityInstance(null);
+            } else {
+                CatLog.d(LOG_TAG, "onDestroy: null appService.");
+            }
+        }
     }
 
     @Override
@@ -224,6 +313,8 @@
             mAcceptUsersInput = false;
             // send session end response.
             sendResponse(StkAppService.RES_ID_END_SESSION);
+            cancelTimeOut();
+            finish();
             return true;
         case StkApp.MENU_ID_HELP:
             cancelTimeOut();
@@ -282,17 +373,22 @@
 
     @Override
     protected void onSaveInstanceState(Bundle outState) {
+        CatLog.d(LOG_TAG, "onSaveInstanceState: " + mSlotId);
         outState.putInt("STATE", mState);
         outState.putParcelable("MENU", mStkMenu);
+        outState.putBoolean("ACCEPT_USERS_INPUT", mAcceptUsersInput);
     }
 
     @Override
     protected void onRestoreInstanceState(Bundle savedInstanceState) {
+        CatLog.d(LOG_TAG, "onRestoreInstanceState: " + mSlotId);
         mState = savedInstanceState.getInt("STATE");
         mStkMenu = savedInstanceState.getParcelable("MENU");
+        mAcceptUsersInput = savedInstanceState.getBoolean("ACCEPT_USERS_INPUT");
     }
 
     private void cancelTimeOut() {
+        CatLog.d(LOG_TAG, "cancelTimeOut: " + mSlotId);
         mTimeoutHandler.removeMessages(MSG_ID_TIMEOUT);
     }
 
@@ -300,6 +396,7 @@
         if (mState == STATE_SECONDARY) {
             // Reset timeout.
             cancelTimeOut();
+            CatLog.d(LOG_TAG, "startTimeOut: " + mSlotId);
             mTimeoutHandler.sendMessageDelayed(mTimeoutHandler
                     .obtainMessage(MSG_ID_TIMEOUT), StkApp.UI_TIMEOUT);
         }
@@ -338,7 +435,10 @@
 
         if (intent != null) {
             mState = intent.getIntExtra("STATE", STATE_MAIN);
+            mSlotId = intent.getIntExtra(StkAppService.SLOT_ID, -1);
+            CatLog.d(LOG_TAG, "slot id: " + mSlotId + ", state: " + mState);
         } else {
+            CatLog.d(LOG_TAG, "finish!");
             finish();
         }
     }
@@ -350,11 +450,11 @@
                 item = mStkMenu.items.get(position);
             } catch (IndexOutOfBoundsException e) {
                 if (StkApp.DBG) {
-                    CatLog.d(this, "Invalid menu");
+                    CatLog.d(LOG_TAG, "IOOBE Invalid menu");
                 }
             } catch (NullPointerException e) {
                 if (StkApp.DBG) {
-                    CatLog.d(this, "Invalid menu");
+                    CatLog.d(LOG_TAG, "NPE Invalid menu");
                 }
             }
         }
@@ -366,8 +466,12 @@
     }
 
     private void sendResponse(int resId, int itemId, boolean help) {
+        CatLog.d(LOG_TAG, "sendResponse resID[" + resId + "] itemId[" + itemId +
+            "] help[" + help + "]");
+        mIsResponseSent = true;
         Bundle args = new Bundle();
         args.putInt(StkAppService.OPCODE, StkAppService.OP_RESPONSE);
+        args.putInt(StkAppService.SLOT_ID, mSlotId);
         args.putInt(StkAppService.RES_ID, resId);
         args.putInt(StkAppService.MENU_SELECTION, itemId);
         args.putBoolean(StkAppService.HELP, help);
diff --git a/src/com/android/stk/ToneDialog.java b/src/com/android/stk/ToneDialog.java
index b68340b..57a977d 100644
--- a/src/com/android/stk/ToneDialog.java
+++ b/src/com/android/stk/ToneDialog.java
@@ -27,7 +27,7 @@
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.TextView;
-
+import com.android.internal.telephony.cat.CatLog;
 import com.android.internal.telephony.cat.TextMessage;
 import com.android.internal.telephony.cat.ToneSettings;
 
@@ -39,8 +39,11 @@
     TextMessage toneMsg = null;
     ToneSettings settings = null;
     TonePlayer player = null;
+    int mSlotId = -1;
     boolean mIsResponseSent = false;
 
+    private static final String LOG_TAG = new Object(){}.getClass().getEnclosingClass().getName();
+
     /**
      * Handler used to stop tones from playing when the duration ends.
      */
@@ -65,6 +68,7 @@
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
+        CatLog.d(LOG_TAG, "onCreate");
         mVibrator = (Vibrator)getSystemService(VIBRATOR_SERVICE);
 
         initFromIntent(getIntent());
@@ -79,7 +83,12 @@
         ImageView iv = (ImageView) findViewById(R.id.icon);
 
         // set text and icon
-        tv.setText(toneMsg.text);
+        if ((null == toneMsg) || (null == toneMsg.text) || (toneMsg.text.equals(""))) {
+            CatLog.d(LOG_TAG, "onCreate - null tone text");
+        } else {
+            tv.setText(toneMsg.text);
+        }
+
         if (toneMsg.icon == null) {
             iv.setImageResource(com.android.internal.R.drawable.ic_volume);
         } else {
@@ -87,6 +96,12 @@
         }
 
         // Start playing tone and vibration
+        if (null == settings) {
+            CatLog.d(LOG_TAG, "onCreate - null settings - finish");
+            finish();
+            return;
+        }
+
         player = new TonePlayer();
         player.play(settings.tone);
         int timeout = StkApp.calculateDurationInMilis(settings.duration);
@@ -94,7 +109,7 @@
             timeout = StkApp.TONE_DFEAULT_TIMEOUT;
         }
         mToneStopper.sendEmptyMessageDelayed(MSG_ID_STOP_TONE, timeout);
-        if (settings.vibrate) {
+        if (settings.vibrate && mVibrator != null) {
             mVibrator.vibrate(timeout);
         }
     }
@@ -102,12 +117,20 @@
     @Override
     protected void onDestroy() {
         super.onDestroy();
-        if (mIsResponseSent) {
-            mToneStopper.removeMessages(MSG_ID_STOP_TONE);
+        CatLog.d(LOG_TAG, "onDestroy");
+
+        mToneStopper.removeMessages(MSG_ID_STOP_TONE);
+        if (!mIsResponseSent) {
+            sendResponse(StkAppService.RES_ID_END_SESSION);
         }
-        player.stop();
-        player.release();
-        mVibrator.cancel();
+
+        if (null != player) {
+            player.stop();
+            player.release();
+        }
+        if (null != mVibrator) {
+            mVibrator.cancel();
+        }
     }
 
     @Override
@@ -138,11 +161,13 @@
         }
         toneMsg = intent.getParcelableExtra("TEXT");
         settings = intent.getParcelableExtra("TONE");
+        mSlotId = intent.getIntExtra(StkAppService.SLOT_ID, -1);
     }
 
     private void sendResponse(int resId) {
         Bundle args = new Bundle();
         args.putInt(StkAppService.OPCODE, StkAppService.OP_RESPONSE);
+        args.putInt(StkAppService.SLOT_ID, mSlotId);
         args.putInt(StkAppService.RES_ID, resId);
         startService(new Intent(this, StkAppService.class).putExtras(args));
         mIsResponseSent = true;