DO NOT MERGE

Merge pie-platform-release (PPRL.181105.017, history only) into master

Bug: 118454372
Change-Id: I6d71632b4cc67a24f28dd12d83d908588cec1bd8
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 29928eb..289aeef 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -22,8 +22,6 @@
 
     <original-package android:name="com.android.stk" />
 
-    <protected-broadcast android:name="com.android.stk.DIALOG_ALARM_TIMEOUT" />
-
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
     <uses-permission android:name="android.permission.GET_TASKS"/>
     <uses-permission android:name="android.permission.RECEIVE_STK_COMMANDS" />
@@ -110,7 +108,6 @@
                 <action android:name= "com.android.internal.stk.session_end" />
                 <action android:name= "com.android.internal.stk.icc_status_change" />
                 <action android:name= "com.android.internal.stk.alpha_notify" />
-                <action android:name= "android.intent.action.LOCALE_CHANGED" />
             </intent-filter>
         </receiver>
 
diff --git a/OWNERS b/OWNERS
index cb08ba3..46b828f 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,4 +1,6 @@
 amitmahajan@google.com
 rgreenwalt@google.com
-sanketpadawe@google.com
 jminjie@google.com
+hallliu@google.com
+paulye@google.com
+breadley@google.com
diff --git a/res/layout/stk_input.xml b/res/layout/stk_input.xml
index c2a34aa..7f8f96d 100644
--- a/res/layout/stk_input.xml
+++ b/res/layout/stk_input.xml
@@ -52,7 +52,6 @@
                 android:layout_height="wrap_content"
                 android:textAppearance="?android:attr/textAppearanceMedium"
                 android:textColor="?android:attr/textColorPrimary"
-                android:gravity="center_horizontal"
                 android:paddingBottom="30dip" />
             <LinearLayout
                 android:layout_width="match_parent"
@@ -62,18 +61,16 @@
                     android:visibility="visible"
                     android:orientation="vertical"
                     android:layout_width="match_parent"
-                    android:layout_marginLeft="10dip"
-                    android:layout_marginRight="10dip"
                     android:layout_height="wrap_content">
                     <LinearLayout
                         android:id="@+id/input_restriction_info"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:layout_marginLeft="4dip"
-                        android:orientation="horizontal">
+                        android:orientation="vertical">
                         <TextView
                             android:id="@+id/input_type"
-                            android:gravity="left"
+                            android:gravity="start"
                             android:textAppearance="?android:attr/textAppearanceMedium"
                             android:textColor="?android:attr/textColorSecondary"
                             android:layout_width="wrap_content"
@@ -83,29 +80,35 @@
                             android:textAppearance="?android:attr/textAppearanceMedium"
                             android:textColor="?android:attr/textColorSecondary"
                             android:layout_width="wrap_content"
-                            android:layout_height="wrap_content"
-                            android:layout_marginLeft="4dip" />
+                            android:layout_height="wrap_content" />
                     </LinearLayout>
                     <EditText
                         android:id="@+id/in_text"
                         android:layout_gravity="center_horizontal"
-                        android:layout_marginBottom="20dip"
+                        android:layout_marginBottom="16dip"
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content" />
                     <LinearLayout
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
                         android:gravity="end"
+                        android:layout_marginStart="4dip"
+                        android:layout_marginBottom="16dip"
                         android:orientation="horizontal">
                         <Button
                             android:id="@+id/button_cancel"
-                            android:layout_height="wrap_content"
+                            android:layout_height="48dip"
                             android:layout_width="wrap_content"
+                            android:layout_weight="1"
+                            android:gravity="center_vertical"
+                            android:paddingStart="0dip"
+                            style="@android:style/Widget.Material.Button.Borderless.Colored"
                             android:text="@string/button_cancel" />
                         <Button
                             android:id="@+id/button_ok"
-                            android:layout_height="wrap_content"
+                            android:layout_height="48dip"
                             android:layout_width="wrap_content"
+                            style="@android:style/Widget.Material.Button.Colored"
                             android:text="@string/button_ok" />
                     </LinearLayout>
                 </LinearLayout>
@@ -120,11 +123,13 @@
                         android:id="@+id/button_no"
                         android:layout_height="wrap_content"
                         android:layout_width="wrap_content"
+                        style="@android:style/Widget.Material.Button.Borderless.Colored"
                         android:text="@string/button_no" />
                     <Button
                         android:id="@+id/button_yes"
                         android:layout_height="wrap_content"
                         android:layout_width="wrap_content"
+                        style="@android:style/Widget.Material.Button.Colored"
                         android:text="@string/button_yes" />
                 </LinearLayout>
             </LinearLayout>
diff --git a/res/layout/stk_title.xml b/res/layout/stk_title.xml
index a5ef109..562e4dc 100755
--- a/res/layout/stk_title.xml
+++ b/res/layout/stk_title.xml
@@ -44,7 +44,6 @@
                 android:gravity="center_vertical"
                 android:layout_width="match_parent"
                 android:layout_height="32dip"
-                android:ellipsize="end"
                 android:maxLines="1"
                 style="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title" />
         </HorizontalScrollView>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 8af507f..10dc7d8 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -29,7 +29,7 @@
     <string name="alphabet" msgid="1583185545938805861">"Abeceda"</string>
     <string name="digits" msgid="1746796679021682388">"Cifre (0-9, *, #, +)"</string>
     <string name="default_call_setup_msg" msgid="7960194995759849940">"Pozivanje je u toku..."</string>
-    <string name="default_setup_call_msg" msgid="6126904475461162162">"Poziv se podešava"</string>
+    <string name="default_setup_call_msg" msgid="6126904475461162162">"Poziv se pokreće"</string>
     <string name="stk_app_state" msgid="18582277302584082">"Stanje aplikacije"</string>
     <string name="enable_app" msgid="3701224550936728203">"Omogućeno"</string>
     <string name="disable_app" msgid="6725081975611415214">"Onemogućeno"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 9d34917..5ed9a87 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -28,7 +28,7 @@
     <string name="button_no" msgid="1824959157582605627">"Nee"</string>
     <string name="alphabet" msgid="1583185545938805861">"Alfabetten"</string>
     <string name="digits" msgid="1746796679021682388">"Symbolen (0-9, *, #, +)"</string>
-    <string name="default_call_setup_msg" msgid="7960194995759849940">"Actieve oproep..."</string>
+    <string name="default_call_setup_msg" msgid="7960194995759849940">"Actief gesprek..."</string>
     <string name="default_setup_call_msg" msgid="6126904475461162162">"Aanroep wordt ingesteld"</string>
     <string name="stk_app_state" msgid="18582277302584082">"Toepassingsstatus"</string>
     <string name="enable_app" msgid="3701224550936728203">"Ingeschakeld"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
deleted file mode 100644
index e827784..0000000
--- a/res/values-or/strings.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2007 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="8396461461738434341">"SIM ଟୁଲକିଟ୍‌"</string>
-    <string name="menu_end_session" msgid="7368541737750982217">"ସେସନ୍‍ ସମାପ୍ତ କରନ୍ତୁ"</string>
-    <string name="help" msgid="9209980881219397319">"ସହାୟତା"</string>
-    <string name="menu_back" msgid="301227740977453364">"ପଛକୁ"</string>
-    <string name="service_name" msgid="6860303747999592491">"ସେବାର ନାମ"</string>
-    <string name="stk_no_service" msgid="5427773116839809131">"କୌଣସି ସେବା ଉପଲବ୍ଧ ନାହିଁ"</string>
-    <string name="button_ok" msgid="5760722312558549555">"ଠିକ୍‌ ଅଛି"</string>
-    <string name="button_cancel" msgid="1997847915560800261">"କ୍ୟାନ୍ସଲ୍‍ କରନ୍ତୁ"</string>
-    <string name="button_yes" msgid="624420260648337203">"ହଁ"</string>
-    <string name="button_no" msgid="1824959157582605627">"ନା"</string>
-    <string name="alphabet" msgid="1583185545938805861">"ଅକ୍ଷର"</string>
-    <string name="digits" msgid="1746796679021682388">"ସଂଖ୍ୟା (0-9, *, #, +)"</string>
-    <string name="default_call_setup_msg" msgid="7960194995759849940">"କଲ୍‌ ଚାଲୁଛି…"</string>
-    <string name="default_setup_call_msg" msgid="6126904475461162162">"କଲ୍‌ ସେଟଅପ୍‌ ହେଉଛି"</string>
-    <string name="stk_app_state" msgid="18582277302584082">"ଆପ୍ଲିକେଶନ୍‌ର ସ୍ଥିତି"</string>
-    <string name="enable_app" msgid="3701224550936728203">"ଚାଲୁ ହୋଇଛି"</string>
-    <string name="disable_app" msgid="6725081975611415214">"ବନ୍ଦ ହୋଇଛି"</string>
-    <string name="stk_dialog_title" msgid="6954825385456886726">"SIM ଟୁଲକିଟ୍‌"</string>
-    <string name="default_tone_dialog_msg" msgid="4595366992944391641">"ଟୋନ୍‌ ବଜାଯାଉଛି"</string>
-    <string name="default_open_channel_msg" msgid="2216070254100295924">"ଚ୍ୟାନେଲ୍‌ ଖୋଲିବେ?"</string>
-    <string name="default_send_data_msg" msgid="6011219698689931272">"ଡାଟା ପଠାଯାଉଛି"</string>
-    <string name="default_receive_data_msg" msgid="618096941772010682">"ଡାଟା ପ୍ରାପ୍ତ କରୁଛି"</string>
-    <string name="default_close_channel_msg" msgid="765364262263839824">"ଚ୍ୟାନେଲ୍‌ ବନ୍ଦ ଅଛି"</string>
-    <string name="stk_dialog_accept" msgid="8498901537508923727">"ହଁ"</string>
-    <string name="stk_dialog_reject" msgid="921848059485746796">"ନା"</string>
-    <string name="no_sim_card_inserted" msgid="5316620398365235988">"SIM ଟୁଲକିଟ୍‌ ଲଞ୍ଚ କରିବାଲାଗି ଦୟାକରି SIM କାର୍ଡ ଭର୍ତ୍ତି କରନ୍ତୁ"</string>
-    <string name="stk_channel_name" msgid="8828587788561382056">"ମୋବାଇଲ୍‍ ସେବା ମେସେଜ୍‌"</string>
-</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 1cd5f21..fbd1cc6 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="8396461461738434341">"Toolkit do SIM"</string>
+    <string name="app_name" msgid="8396461461738434341">"Toolkit do chip"</string>
     <string name="menu_end_session" msgid="7368541737750982217">"Finalizar a sessão"</string>
     <string name="help" msgid="9209980881219397319">"Ajuda"</string>
     <string name="menu_back" msgid="301227740977453364">"Voltar"</string>
@@ -33,7 +33,7 @@
     <string name="stk_app_state" msgid="18582277302584082">"Estado do app"</string>
     <string name="enable_app" msgid="3701224550936728203">"Ativado"</string>
     <string name="disable_app" msgid="6725081975611415214">"Desativado"</string>
-    <string name="stk_dialog_title" msgid="6954825385456886726">"Toolkit do SIM"</string>
+    <string name="stk_dialog_title" msgid="6954825385456886726">"Toolkit do chip"</string>
     <string name="default_tone_dialog_msg" msgid="4595366992944391641">"Reproduzindo tom"</string>
     <string name="default_open_channel_msg" msgid="2216070254100295924">"Abrir canal?"</string>
     <string name="default_send_data_msg" msgid="6011219698689931272">"Enviando dados"</string>
@@ -41,6 +41,6 @@
     <string name="default_close_channel_msg" msgid="765364262263839824">"Canal fechado"</string>
     <string name="stk_dialog_accept" msgid="8498901537508923727">"SIM"</string>
     <string name="stk_dialog_reject" msgid="921848059485746796">"NÃO"</string>
-    <string name="no_sim_card_inserted" msgid="5316620398365235988">"Insira o cartão SIM para iniciar a Barra de ferramentas SIM."</string>
+    <string name="no_sim_card_inserted" msgid="5316620398365235988">"Insira o chip para iniciar a Barra de ferramentas SIM."</string>
     <string name="stk_channel_name" msgid="8828587788561382056">"Mensagens de serviço móvel"</string>
 </resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 0438132..644e789 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -29,7 +29,7 @@
     <string name="alphabet" msgid="1583185545938805861">"Абецеда"</string>
     <string name="digits" msgid="1746796679021682388">"Цифре (0-9, *, #, +)"</string>
     <string name="default_call_setup_msg" msgid="7960194995759849940">"Позивање је у току..."</string>
-    <string name="default_setup_call_msg" msgid="6126904475461162162">"Позив се подешава"</string>
+    <string name="default_setup_call_msg" msgid="6126904475461162162">"Позив се покреће"</string>
     <string name="stk_app_state" msgid="18582277302584082">"Стање апликације"</string>
     <string name="enable_app" msgid="3701224550936728203">"Омогућено"</string>
     <string name="disable_app" msgid="6725081975611415214">"Онемогућено"</string>
diff --git a/src/com/android/stk/StkAppService.java b/src/com/android/stk/StkAppService.java
index 0a49cc5..2c51efe 100644
--- a/src/com/android/stk/StkAppService.java
+++ b/src/com/android/stk/StkAppService.java
@@ -29,6 +29,7 @@
 import android.app.ActivityManagerNative;
 import android.app.IProcessObserver;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -56,6 +57,7 @@
 import android.provider.Settings;
 import android.support.v4.content.LocalBroadcastManager;
 import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -90,8 +92,8 @@
 
 import java.util.Iterator;
 import java.util.LinkedList;
-import java.lang.System;
 import java.util.List;
+import java.util.regex.Pattern;
 
 import static com.android.internal.telephony.cat.CatCmdMessage.
                    SetupEventListConstants.IDLE_SCREEN_AVAILABLE_EVENT;
@@ -125,7 +127,7 @@
         protected LinkedList<DelayedCmd> mCmdsQ = null;
         protected boolean mCmdInProgress = false;
         protected int mStkServiceState = STATE_UNKNOWN;
-        protected int mSetupMenuState = STATE_UNKNOWN;
+        protected int mSetupMenuState = STATE_NOT_EXIST;
         protected int mMenuState = StkMenuActivity.STATE_INIT;
         protected int mOpCode = -1;
         private Activity mActivityInstance = null;
@@ -138,6 +140,8 @@
         private CatCmdMessage mCurrentSetupEventCmd = null;
         private CatCmdMessage mIdleModeTextCmd = null;
         private boolean mIdleModeTextVisible = false;
+        // Determins whether the current session was initiated by user operation.
+        protected boolean mIsSessionFromUser = false;
         final synchronized void setPendingActivityInstance(Activity act) {
             CatLog.d(this, "setPendingActivityInstance act : " + mSlotId + ", " + act);
             callSetActivityInstMsg(OP_SET_ACT_INST, mSlotId, act);
@@ -176,6 +180,7 @@
     private StkContext[] mStkContext = null;
     private int mSimCount = 0;
     private IProcessObserver.Stub mProcessObserver = null;
+    private BroadcastReceiver mLocaleChangeReceiver = null;
     private TonePlayer mTonePlayer = null;
     private Vibrator mVibrator = null;
     private BroadcastReceiver mUserActivityReceiver = null;
@@ -400,6 +405,7 @@
         CatLog.d(LOG_TAG, "onDestroy()");
         unregisterUserActivityReceiver();
         unregisterProcessObserver();
+        unregisterLocaleChangeReceiver();
         sInstance = null;
         waitForLooper();
         mServiceLooper.quit();
@@ -632,20 +638,44 @@
             case OP_SET_ACT_INST:
                 Activity act = (Activity) msg.obj;
                 if (mStkContext[slotId].mActivityInstance != act) {
-                    CatLog.d(LOG_TAG, "Set activity instance - " + act);
+                    CatLog.d(LOG_TAG, "Set pending activity instance - " + act);
                     Activity previous = mStkContext[slotId].mActivityInstance;
                     mStkContext[slotId].mActivityInstance = act;
-                    // Finish the previous one if it has not been finished yet somehow.
-                    if (previous != null && !previous.isDestroyed() && !previous.isFinishing()) {
+                    // Finish the previous one if it was replaced with new one
+                    // but it has not been finished yet somehow.
+                    if (act != null && previous != null && !previous.isDestroyed()
+                            && !previous.isFinishing()) {
                         CatLog.d(LOG_TAG, "Finish the previous pending activity - " + previous);
                         previous.finish();
                     }
+                    // Pending activity is registered in the following 2 scnarios;
+                    // A. TERMINAL RESPONSE was sent to the card.
+                    // B. Activity was moved to the background before TR is sent to the card.
+                    // No need to observe idle screen for the pending activity in the scenario A.
+                    if (act != null && mStkContext[slotId].mCmdInProgress) {
+                        startToObserveIdleScreen(slotId);
+                    } else {
+                        if (mStkContext[slotId].mCurrentCmd != null) {
+                            unregisterProcessObserver(
+                                    mStkContext[slotId].mCurrentCmd.getCmdType(), slotId);
+                        }
+                    }
                 }
                 break;
             case OP_SET_DAL_INST:
                 Activity dal = (Activity) msg.obj;
-                CatLog.d(LOG_TAG, "Set dialog instance. " + dal);
-                mStkContext[slotId].mDialogInstance = dal;
+                if (mStkContext[slotId].mDialogInstance != dal) {
+                    CatLog.d(LOG_TAG, "Set pending dialog instance - " + dal);
+                    mStkContext[slotId].mDialogInstance = dal;
+                    if (dal != null) {
+                        startToObserveIdleScreen(slotId);
+                    } else {
+                        if (mStkContext[slotId].mCurrentCmd != null) {
+                            unregisterProcessObserver(
+                                    mStkContext[slotId].mCurrentCmd.getCmdType(), slotId);
+                        }
+                    }
+                }
                 break;
             case OP_SET_IMMED_DAL_INST:
                 Activity immedDal = (Activity) msg.obj;
@@ -693,6 +723,7 @@
                 cancelIdleText(slotId);
                 mStkContext[slotId].mCurrentMenu = null;
                 mStkContext[slotId].mMainCmd = null;
+                mStkService[slotId] = null;
                 if (isAllOtherCardsAbsent(slotId)) {
                     CatLog.d(LOG_TAG, "All CARDs are ABSENT");
                     StkAppInstaller.unInstall(mContext);
@@ -708,15 +739,6 @@
                     // Clear Idle Text
                     cancelIdleText(slotId);
                 }
-
-                if (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) {
-                    // Uninstall STkmenu
-                    if (isAllOtherCardsAbsent(slotId)) {
-                        StkAppInstaller.unInstall(mContext);
-                    }
-                    mStkContext[slotId].mCurrentMenu = null;
-                    mStkContext[slotId].mMainCmd = null;
-                }
             }
         }
     }
@@ -767,8 +789,36 @@
         return false;
     }
 
-    private void handleIdleScreen(int slotId) {
+    private void startToObserveIdleScreen(int slotId) {
+        if (!mStkContext[slotId].mIsSessionFromUser) {
+            if (!isScreenIdle()) {
+                synchronized (this) {
+                    if (mProcessObserver == null && !mServiceHandler.hasMessages(OP_IDLE_SCREEN)) {
+                        registerProcessObserver();
+                    }
+                }
+            } else {
+                handleIdleScreen(slotId);
+            }
+        }
+    }
 
+    private void handleIdleScreen(int slotId) {
+        // It might be hard for user to recognize that the dialog or screens belong to SIM Toolkit
+        // application if the current session was not initiated by user but by the SIM card,
+        // so it is recommended to send TERMINAL RESPONSE if user goes to the idle screen.
+        if (!mStkContext[slotId].mIsSessionFromUser) {
+            Activity dialog = mStkContext[slotId].getPendingDialogInstance();
+            if (dialog != null) {
+                dialog.finish();
+                mStkContext[slotId].mDialogInstance = null;
+            }
+            Activity activity = mStkContext[slotId].getPendingActivityInstance();
+            if (activity != null) {
+                activity.finish();
+                mStkContext[slotId].mActivityInstance = null;
+            }
+        }
         // If the idle screen event is present in the list need to send the
         // response to SIM.
         CatLog.d(this, "Need to send IDLE SCREEN Available event to SIM");
@@ -795,6 +845,20 @@
         }
     }
 
+    /**
+     * Sends TERMINAL RESPONSE or ENVELOPE
+     *
+     * @param args detailed parameters of the response
+     * @param slotId slot identifier
+     */
+    public void sendResponse(Bundle args, int slotId) {
+        Message msg = mServiceHandler.obtainMessage();
+        msg.arg1 = OP_RESPONSE;
+        msg.arg2 = slotId;
+        msg.obj = args;
+        mServiceHandler.sendMessage(msg);
+    }
+
     private void sendResponse(int resId, int slotId, boolean confirm) {
         Message msg = mServiceHandler.obtainMessage();
         msg.arg1 = OP_RESPONSE;
@@ -810,6 +874,8 @@
         switch (cmd.getCmdType()) {
         case SEND_DTMF:
         case SEND_SMS:
+        case REFRESH:
+        case RUN_AT:
         case SEND_SS:
         case SEND_USSD:
         case SET_UP_IDLE_MODE_TEXT:
@@ -878,6 +944,7 @@
             CatLog.d(LOG_TAG, "[handleSessionEnd][mMainCmd is null!]");
         }
         mStkContext[slotId].lastSelectedItem = null;
+        mStkContext[slotId].mIsSessionFromUser = false;
         // In case of SET UP MENU command which removed the app, don't
         // update the current menu member.
         if (mStkContext[slotId].mCurrentMenu != null && mStkContext[slotId].mMainCmd != null) {
@@ -925,23 +992,26 @@
     /**
      * Get the boolean config from carrier config manager.
      *
-     * @param context the context to get carrier service
      * @param key config key defined in CarrierConfigManager
+     * @param slotId slot ID.
      * @return boolean value of corresponding key.
      */
-    private static boolean getBooleanCarrierConfig(Context context, String key) {
-        CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
-                Context.CARRIER_CONFIG_SERVICE);
+    private boolean getBooleanCarrierConfig(String key, int slotId) {
+        CarrierConfigManager ccm = (CarrierConfigManager) getSystemService(CARRIER_CONFIG_SERVICE);
+        SubscriptionManager sm = (SubscriptionManager) getSystemService(
+                Context.TELEPHONY_SUBSCRIPTION_SERVICE);
         PersistableBundle b = null;
-        if (configManager != null) {
-            b = configManager.getConfig();
+        if (ccm != null && sm != null) {
+            SubscriptionInfo info = sm.getActiveSubscriptionInfoForSimSlotIndex(slotId);
+            if (info != null) {
+                b = ccm.getConfigForSubId(info.getSubscriptionId());
+            }
         }
         if (b != null) {
             return b.getBoolean(key);
-        } else {
-            // Return static default defined in CarrierConfigManager.
-            return CarrierConfigManager.getDefaultConfig().getBoolean(key);
         }
+        // Return static default defined in CarrierConfigManager.
+        return CarrierConfigManager.getDefaultConfig().getBoolean(key);
     }
 
     private void handleCmd(CatCmdMessage cmdMsg, int slotId) {
@@ -1007,9 +1077,7 @@
                 mStkContext[slotId].mMainCmd = 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[i].mSetupMenuState == STATE_UNKNOWN
-                            || mStkContext[i].mSetupMenuState == STATE_EXIST)) {
+                    if (i != slotId && mStkContext[i].mSetupMenuState != STATE_NOT_EXIST) {
                         CatLog.d(LOG_TAG, "Not Uninstall App:" + i + ","
                                 + mStkContext[i].mSetupMenuState);
                         break;
@@ -1049,6 +1117,8 @@
             break;
         case SEND_DTMF:
         case SEND_SMS:
+        case REFRESH:
+        case RUN_AT:
         case SEND_SS:
         case SEND_USSD:
         case GET_CHANNEL_STATUS:
@@ -1065,8 +1135,8 @@
             }
 
             /* Check if Carrier would not want to launch browser */
-            if (getBooleanCarrierConfig(mContext,
-                    CarrierConfigManager.KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL)) {
+            if (getBooleanCarrierConfig(CarrierConfigManager.KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL,
+                    slotId)) {
                 CatLog.d(this, "Browser is not launched as per carrier.");
                 sendResponse(RES_ID_DONE, slotId, true);
                 break;
@@ -1146,6 +1216,7 @@
         }
     }
 
+    @SuppressWarnings("FallThrough")
     private void handleCmdResponse(Bundle args, int slotId) {
         CatLog.d(LOG_TAG, "handleCmdResponse, sim id: " + slotId);
         if (mStkContext[slotId].mCurrentCmd == null) {
@@ -1175,6 +1246,8 @@
             int menuSelection = args.getInt(MENU_SELECTION);
             switch(mStkContext[slotId].mCurrentMenuCmd.getCmdType()) {
             case SET_UP_MENU:
+                mStkContext[slotId].mIsSessionFromUser = true;
+                // Fall through
             case SELECT_ITEM:
                 mStkContext[slotId].lastSelectedItem = getItemName(menuSelection, slotId);
                 if (helpRequired) {
@@ -1335,29 +1408,27 @@
     }
     /**
      * This method is used for cleaning up pending instances in stack.
+     * No terminal response will be sent for pending instances.
      */
     private void cleanUpInstanceStackBySlot(int slotId) {
         Activity activity = mStkContext[slotId].getPendingActivityInstance();
         Activity dialog = mStkContext[slotId].getPendingDialogInstance();
         CatLog.d(LOG_TAG, "cleanUpInstanceStackBySlot slotId: " + slotId);
-        if (mStkContext[slotId].mCurrentCmd == null) {
-            CatLog.d(LOG_TAG, "current cmd is null.");
-            return;
-        }
         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 {
+            if (mStkContext[slotId].mCurrentCmd != 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;
+                }
             }
             CatLog.d(LOG_TAG, "finish pending activity.");
             activity.finish();
@@ -1619,19 +1690,23 @@
         return getNotificationId(slotId) + (notificationType * mSimCount);
     }
 
-    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;
+    /**
+     * Checks whether the dialog exists as the top activity of this task.
+     *
+     * @return true if the top activity of this task is the dialog.
+     */
+    public boolean isStkDialogActivated() {
+        ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+        ComponentName componentName = am.getAppTasks().get(0).getTaskInfo().topActivity;
+        if (componentName != null) {
+            String[] split = componentName.getClassName().split(Pattern.quote("."));
+            String topActivity = split[split.length - 1];
+            CatLog.d(LOG_TAG, "Top activity: " + topActivity);
+            if (TextUtils.equals(topActivity, StkDialogActivity.class.getSimpleName())) {
+                return true;
+            }
         }
-        CatLog.d(LOG_TAG, "activated : " + activated);
-        return activated;
+        return false;
     }
 
     private void replaceEventList(int slotId) {
@@ -1662,6 +1737,18 @@
     }
 
     private void unregisterEvent(int event, int slotId) {
+        for (int slot = PhoneConstants.SIM_ID_1; slot < mSimCount; slot++) {
+            if (slot != slotId) {
+                if (mStkContext[slot].mSetupEventListSettings != null) {
+                    if (findEvent(event, mStkContext[slot].mSetupEventListSettings.eventList)) {
+                        // The specified event shall never be canceled
+                        // if there is any other SIM card which requests the event.
+                        return;
+                    }
+                }
+            }
+        }
+
         switch (event) {
             case USER_ACTIVITY_EVENT:
                 unregisterUserActivityReceiver();
@@ -1670,6 +1757,8 @@
                 unregisterProcessObserver(AppInterface.CommandType.SET_UP_EVENT_LIST, slotId);
                 break;
             case LANGUAGE_SELECTION_EVENT:
+                unregisterLocaleChangeReceiver();
+                break;
             default:
                 break;
         }
@@ -1688,6 +1777,8 @@
                     registerProcessObserver();
                     break;
                 case LANGUAGE_SELECTION_EVENT:
+                    registerLocaleChangeReceiver();
+                    break;
                 default:
                     break;
             }
@@ -1745,6 +1836,7 @@
                     }
                 };
                 ActivityManagerNative.getDefault().registerProcessObserver(observer);
+                CatLog.d(this, "Started to observe the foreground activity");
                 mProcessObserver = observer;
             } catch (RemoteException e) {
                 CatLog.d(this, "Failed to register the process observer");
@@ -1782,6 +1874,7 @@
         if (mProcessObserver != null) {
             try {
                 ActivityManagerNative.getDefault().unregisterProcessObserver(mProcessObserver);
+                CatLog.d(this, "Stopped to observe the foreground activity");
                 mProcessObserver = null;
             } catch (RemoteException e) {
                 CatLog.d(this, "Failed to unregister the process observer");
@@ -1789,6 +1882,28 @@
         }
     }
 
+    private synchronized void registerLocaleChangeReceiver() {
+        if (mLocaleChangeReceiver == null) {
+            mLocaleChangeReceiver = new BroadcastReceiver() {
+                @Override public void onReceive(Context context, Intent intent) {
+                    if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
+                        Message message = mServiceHandler.obtainMessage();
+                        message.arg1 = OP_LOCALE_CHANGED;
+                        mServiceHandler.sendMessage(message);
+                    }
+                }
+            };
+            registerReceiver(mLocaleChangeReceiver, new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
+        }
+    }
+
+    private synchronized void unregisterLocaleChangeReceiver() {
+        if (mLocaleChangeReceiver != null) {
+            unregisterReceiver(mLocaleChangeReceiver);
+            mLocaleChangeReceiver = null;
+        }
+    }
+
     private void sendSetUpEventResponse(int event, byte[] addedInfo, int slotId) {
         CatLog.d(this, "sendSetUpEventResponse: event : " + event + "slotId = " + slotId);
 
diff --git a/src/com/android/stk/StkCmdReceiver.java b/src/com/android/stk/StkCmdReceiver.java
index d011eee..aeb4e22 100644
--- a/src/com/android/stk/StkCmdReceiver.java
+++ b/src/com/android/stk/StkCmdReceiver.java
@@ -45,8 +45,6 @@
             handleAction(context, intent, StkAppService.OP_END_SESSION);
         } else if (action.equals(AppInterface.CAT_ICC_STATUS_CHANGE)) {
             handleAction(context, intent, StkAppService.OP_CARD_STATUS_CHANGED);
-        } else if (action.equals(Intent.ACTION_LOCALE_CHANGED)) {
-            handleLocaleChange(context);
         } else if (action.equals(AppInterface.CAT_ALPHA_NOTIFY_ACTION)) {
             handleAction(context, intent, StkAppService.OP_ALPHA_NOTIFY);
         }
@@ -86,11 +84,4 @@
         toService.putExtras(args);
         context.startService(toService);
     }
-
-    private void handleLocaleChange(Context context) {
-        Bundle args = new Bundle();
-        args.putInt(StkAppService.OPCODE, StkAppService.OP_LOCALE_CHANGED);
-        context.startService(new Intent(context, StkAppService.class)
-                .putExtras(args));
-    }
 }
diff --git a/src/com/android/stk/StkDialogActivity.java b/src/com/android/stk/StkDialogActivity.java
index be43747..1462480 100644
--- a/src/com/android/stk/StkDialogActivity.java
+++ b/src/com/android/stk/StkDialogActivity.java
@@ -16,19 +16,12 @@
 
 package com.android.stk;
 
-import com.android.internal.telephony.cat.CatLog;
-import com.android.internal.telephony.cat.TextMessage;
-
 import android.app.Activity;
 import android.app.AlarmManager;
 import android.app.AlertDialog;
-import android.app.PendingIntent;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
-
+import android.content.Intent;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.SystemClock;
@@ -39,6 +32,9 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import com.android.internal.telephony.cat.CatLog;
+import com.android.internal.telephony.cat.TextMessage;
+
 /**
  * AlertDialog used for DISPLAY TEXT commands.
  *
@@ -52,16 +48,20 @@
     private StkAppService appService = StkAppService.getInstance();
     // Determines whether Terminal Response (TR) has been sent
     private boolean mIsResponseSent = false;
-    private Context mContext;
+    // Determines whether this is in the pending state.
+    private boolean mIsPending = false;
     // Utilize AlarmManager for real-time countdown
-    private PendingIntent mTimeoutIntent;
-    private AlarmManager mAlarmManager;
-    private final static String ALARM_TIMEOUT = "com.android.stk.DIALOG_ALARM_TIMEOUT";
+    private static final String DIALOG_ALARM_TAG = LOG_TAG;
+    private static final long NO_DIALOG_ALARM = -1;
+    private long mAlarmTime = NO_DIALOG_ALARM;
 
     // Keys for saving the state of the dialog in the bundle
     private static final String TEXT_KEY = "text";
-    private static final String TIMEOUT_INTENT_KEY = "timeout";
+    private static final String ALARM_TIME_KEY = "alarm_time";
+    private static final String RESPONSE_SENT_KEY = "response_sent";
     private static final String SLOT_ID_KEY = "slotid";
+    private static final String PENDING = "pending";
+
 
     private AlertDialog mAlertDialog;
 
@@ -89,9 +89,7 @@
                     @Override
                     public void onClick(DialogInterface dialog, int id) {
                         CatLog.d(LOG_TAG, "OK Clicked!, mSlotId: " + mSlotId);
-                        cancelTimeOut();
                         sendResponse(StkAppService.RES_ID_CONFIRM, true);
-                        finish();
                     }
                 });
 
@@ -100,9 +98,7 @@
                     @Override
                     public void onClick(DialogInterface dialog,int id) {
                         CatLog.d(LOG_TAG, "Cancel Clicked!, mSlotId: " + mSlotId);
-                        cancelTimeOut();
                         sendResponse(StkAppService.RES_ID_CONFIRM, false);
-                        finish();
                     }
                 });
 
@@ -110,9 +106,7 @@
                     @Override
                     public void onCancel(DialogInterface dialog) {
                         CatLog.d(LOG_TAG, "Moving backward!, mSlotId: " + mSlotId);
-                        cancelTimeOut();
                         sendResponse(StkAppService.RES_ID_BACKWARD);
-                        finish();
                     }
                 });
 
@@ -157,12 +151,6 @@
         mAlertDialog = alertDialogBuilder.create();
         mAlertDialog.setCanceledOnTouchOutside(false);
         mAlertDialog.show();
-
-        mContext = getBaseContext();
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(ALARM_TIMEOUT);
-        mContext.registerReceiver(mBroadcastReceiver, intentFilter);
-        mAlarmManager =(AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
     }
 
     @Override
@@ -170,6 +158,8 @@
         super.onResume();
         CatLog.d(LOG_TAG, "onResume - mIsResponseSent[" + mIsResponseSent +
                 "], sim id: " + mSlotId);
+        // The pending dialog is unregistered if this instance was registered as it before.
+        setPendingState(false);
 
         /*
          * If the userClear flag is set and dialogduration is set to 0, the display Text
@@ -192,12 +182,8 @@
          * inform the SIM in correct time when there is no response from the User
          * to a dialog.
          */
-        if (mTimeoutIntent != null) {
-            CatLog.d(LOG_TAG, "Pending Alarm! Let it finish counting down...");
-        }
-        else {
-            CatLog.d(LOG_TAG, "No Pending Alarm! OK to start timer...");
-            startTimeOut(mTextMsg.userClear);
+        if (mAlarmTime == NO_DIALOG_ALARM) {
+            startTimeOut();
         }
     }
 
@@ -230,23 +216,13 @@
         CatLog.d(LOG_TAG, "onStop - before Send CONFIRM false mIsResponseSent[" +
                 mIsResponseSent + "], sim id: " + mSlotId);
 
-        // Avoid calling finish() or setPendingDialogInstance()
-        // if the activity is being restarted now.
-        if (isChangingConfigurations()) {
+        // Nothing should be done here if this activity is being finished or restarted now.
+        if (isFinishing() || isChangingConfigurations()) {
             return;
         }
 
-        if (!mTextMsg.responseNeeded) {
-            return;
-        }
-        if (!mIsResponseSent) {
-            appService.getStkContext(mSlotId).setPendingDialogInstance(this);
-        } else {
-            CatLog.d(LOG_TAG, "finish.");
-            appService.getStkContext(mSlotId).setPendingDialogInstance(null);
-            cancelTimeOut();
-            finish();
-        }
+        // This is registered as the pending dialog as this was sent to the background.
+        setPendingState(true);
     }
 
     @Override
@@ -270,34 +246,43 @@
             if (!mIsResponseSent && appService != null && !appService.isDialogPending(mSlotId)) {
                 sendResponse(StkAppService.RES_ID_CONFIRM, false);
             }
-            cancelTimeOut();
         }
-        // Cleanup broadcast receivers to avoid leaks
-        if (mBroadcastReceiver != null) {
-            unregisterReceiver(mBroadcastReceiver);
-        }
+        cancelTimeOut();
     }
 
     @Override
     public void onSaveInstanceState(Bundle outState) {
-        CatLog.d(LOG_TAG, "onSaveInstanceState");
-
         super.onSaveInstanceState(outState);
 
+        CatLog.d(LOG_TAG, "onSaveInstanceState");
+
         outState.putParcelable(TEXT_KEY, mTextMsg);
-        outState.putParcelable(TIMEOUT_INTENT_KEY, mTimeoutIntent);
+        outState.putBoolean(RESPONSE_SENT_KEY, mIsResponseSent);
+        outState.putLong(ALARM_TIME_KEY, mAlarmTime);
         outState.putInt(SLOT_ID_KEY, mSlotId);
+        outState.putBoolean(PENDING, mIsPending);
     }
 
     @Override
     public void onRestoreInstanceState(Bundle savedInstanceState) {
         super.onRestoreInstanceState(savedInstanceState);
 
+        CatLog.d(LOG_TAG, "onRestoreInstanceState");
+
         mTextMsg = savedInstanceState.getParcelable(TEXT_KEY);
-        mTimeoutIntent = savedInstanceState.getParcelable(TIMEOUT_INTENT_KEY);
+        mIsResponseSent = savedInstanceState.getBoolean(RESPONSE_SENT_KEY);
+        mAlarmTime = savedInstanceState.getLong(ALARM_TIME_KEY, NO_DIALOG_ALARM);
         mSlotId = savedInstanceState.getInt(SLOT_ID_KEY);
-        appService.getStkContext(mSlotId).setPendingDialogInstance(this);
-        CatLog.d(LOG_TAG, "onRestoreInstanceState - [" + mTextMsg + "]");
+
+        // The pending dialog must be replaced if the previous instance was in the pending state.
+        if (savedInstanceState.getBoolean(PENDING)) {
+            setPendingState(true);
+        }
+
+        if (mAlarmTime != NO_DIALOG_ALARM) {
+            startTimeOut();
+        }
+
     }
 
     @Override
@@ -318,7 +303,18 @@
         }
     }
 
+    private void setPendingState(boolean on) {
+        if (mTextMsg.responseNeeded) {
+            if (mIsPending != on) {
+                appService.getStkContext(mSlotId).setPendingDialogInstance(on ? this : null);
+                mIsPending = on;
+            }
+        }
+    }
+
     private void sendResponse(int resId, boolean confirmed) {
+        cancelTimeOut();
+
         if (mSlotId == -1) {
             CatLog.d(LOG_TAG, "sim id is invalid");
             return;
@@ -340,6 +336,10 @@
             startService(new Intent(this, StkAppService.class).putExtras(args));
             mIsResponseSent = true;
         }
+        if (!isFinishing()) {
+            finish();
+        }
+
     }
 
     private void sendResponse(int resId) {
@@ -360,61 +360,47 @@
     }
 
     private void cancelTimeOut() {
-        CatLog.d(LOG_TAG, "cancelTimeOut: " + mSlotId);
-        if (mTimeoutIntent != null) {
-            mAlarmManager.cancel(mTimeoutIntent);
-            mTimeoutIntent = null;
+        if (mAlarmTime != NO_DIALOG_ALARM) {
+            CatLog.d(LOG_TAG, "cancelTimeOut - slot id: " + mSlotId);
+            AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+            am.cancel(mAlarmListener);
+            mAlarmTime = NO_DIALOG_ALARM;
         }
     }
 
-    private void startTimeOut(boolean waitForUserToClear) {
-
-        // Reset timeout.
-        cancelTimeOut();
-        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 (mTextMsg.userClear == true && mTextMsg.responseNeeded == false) {
+    private void startTimeOut() {
+        // No need to set alarm if device sent TERMINAL RESPONSE already
+        // and it is required to wait for user to clear the message.
+        if (mIsResponseSent || (mTextMsg.userClear && !mTextMsg.responseNeeded)) {
             return;
-        } else {
-            // userClear = false. will disappear after a while.
-            if (dialogDuration == 0) {
-                if (waitForUserToClear) {
-                    dialogDuration = StkApp.DISP_TEXT_WAIT_FOR_USER_TIMEOUT;
+        }
+
+        if (mAlarmTime == NO_DIALOG_ALARM) {
+            int duration = StkApp.calculateDurationInMilis(mTextMsg.duration);
+            // If no duration is specified, the timeout set by the terminal manufacturer is applied.
+            if (duration == 0) {
+                if (mTextMsg.userClear) {
+                    duration = StkApp.DISP_TEXT_WAIT_FOR_USER_TIMEOUT;
                 } else {
-                    dialogDuration = StkApp.DISP_TEXT_CLEAR_AFTER_DELAY_TIMEOUT;
+                    duration = StkApp.DISP_TEXT_CLEAR_AFTER_DELAY_TIMEOUT;
                 }
             }
-            CatLog.d(LOG_TAG, "startTimeOut: " + mSlotId);
-            Intent mAlarmIntent = new Intent(ALARM_TIMEOUT);
-            mAlarmIntent.putExtra(StkAppService.SLOT_ID, mSlotId);
-            mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, mAlarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
-
-            // Try to use a more stringent timer not affected by system sleep.
-            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
-                mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                        SystemClock.elapsedRealtime() + dialogDuration, mTimeoutIntent);
-            }
-            else {
-                mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                        SystemClock.elapsedRealtime() + dialogDuration, mTimeoutIntent);
-            }
+            mAlarmTime = SystemClock.elapsedRealtime() + duration;
         }
+
+        CatLog.d(LOG_TAG, "startTimeOut: " + mAlarmTime + "ms, slot id: " + mSlotId);
+        AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+        am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, mAlarmTime, DIALOG_ALARM_TAG,
+                mAlarmListener, null);
     }
 
-    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        @Override public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            int slotID = intent.getIntExtra(StkAppService.SLOT_ID, 0);
-
-            if (action == null || slotID != mSlotId) return;
-            CatLog.d(LOG_TAG, "onReceive, action=" + action + ", sim id: " + slotID);
-            if (action.equals(ALARM_TIMEOUT)) {
-                CatLog.d(LOG_TAG, "ALARM_TIMEOUT rcvd");
-                mTimeoutIntent = null;
-                sendResponse(StkAppService.RES_ID_TIMEOUT);
-                finish();
-            }
-        }
-    };
+    private final AlarmManager.OnAlarmListener mAlarmListener =
+            new AlarmManager.OnAlarmListener() {
+                @Override
+                public void onAlarm() {
+                    CatLog.d(LOG_TAG, "The alarm time is reached");
+                    mAlarmTime = NO_DIALOG_ALARM;
+                    sendResponse(StkAppService.RES_ID_TIMEOUT);
+                }
+            };
 }
diff --git a/src/com/android/stk/StkInputActivity.java b/src/com/android/stk/StkInputActivity.java
index 6c633b7..6f3598a 100644
--- a/src/com/android/stk/StkInputActivity.java
+++ b/src/com/android/stk/StkInputActivity.java
@@ -1,11 +1,11 @@
 /*
  * Copyright (C) 2007 The Android Open Source Project
  *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,33 +18,31 @@
 
 import android.app.ActionBar;
 import android.app.Activity;
+import android.app.AlarmManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
-import android.graphics.drawable.BitmapDrawable;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
+import android.os.SystemClock;
 import android.text.Editable;
 import android.text.InputFilter;
-import android.text.InputType;
 import android.text.TextUtils;
 import android.text.TextWatcher;
 import android.text.method.PasswordTransformationMethod;
-import android.view.inputmethod.EditorInfo;
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
-import android.view.Window;
+import android.view.WindowManager;
+import android.view.inputmethod.EditorInfo;
 import android.widget.Button;
+import android.widget.EditText;
 import android.widget.ImageView;
 import android.widget.PopupMenu;
 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;
 
 /**
@@ -55,7 +53,6 @@
 
     // Members
     private int mState;
-    private Context mContext;
     private EditText mTextIn = null;
     private TextView mPromptView = null;
     private View mMoreOptions = null;
@@ -68,7 +65,6 @@
     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;
@@ -82,63 +78,43 @@
     static final float SMALL_FONT_FACTOR = (1 / 2);
 
     // Keys for saving the state of the activity in the bundle
-    private static final String ACCEPT_USERS_INPUT_KEY = "accept_users_input";
     private static final String RESPONSE_SENT_KEY = "response_sent";
     private static final String INPUT_STRING_KEY = "input_string";
+    private static final String ALARM_TIME_KEY = "alarm_time";
+    private static final String PENDING = "pending";
 
-    // message id for time out
-    private static final int MSG_ID_TIMEOUT = 1;
+    private static final String INPUT_ALARM_TAG = LOG_TAG;
+    private static final long NO_INPUT_ALARM = -1;
+    private long mAlarmTime = NO_INPUT_ALARM;
+
     private StkAppService appService = StkAppService.getInstance();
 
     private boolean mIsResponseSent = false;
+    // Determines whether this is in the pending state.
+    private boolean mIsPending = 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:
-                CatLog.d(LOG_TAG, "Msg timeout.");
-                mAcceptUsersInput = false;
-                appService.getStkContext(mSlotId).setPendingActivityInstance(mInstance);
-                sendResponse(StkAppService.RES_ID_TIMEOUT);
-                break;
-            }
-        }
-    };
 
     // Click listener to handle buttons press..
     public void onClick(View v) {
         String input = null;
-        if (!mAcceptUsersInput) {
-            CatLog.d(LOG_TAG, "mAcceptUsersInput:false");
+        if (mIsResponseSent) {
+            CatLog.d(LOG_TAG, "Already responded");
             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;
         case R.id.button_cancel:
-            mAcceptUsersInput = false;
-            cancelTimeOut();
-            appService.getStkContext(mSlotId).setPendingActivityInstance(this);
             sendResponse(StkAppService.RES_ID_END_SESSION);
+            finish();
             return;
         // 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;
         case R.id.more:
@@ -165,8 +141,6 @@
             break;
         }
         CatLog.d(LOG_TAG, "handleClick, ready to response");
-        cancelTimeOut();
-        appService.getStkContext(mSlotId).setPendingActivityInstance(this);
         sendResponse(StkAppService.RES_ID_INPUT, input, false);
     }
 
@@ -204,7 +178,6 @@
         // 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 cancelButton = (Button) findViewById(R.id.button_cancel);
@@ -219,8 +192,6 @@
         mYesNoLayout = findViewById(R.id.yes_no_layout);
         mNormalLayout = findViewById(R.id.normal_layout);
         initFromIntent(getIntent());
-        mContext = getBaseContext();
-        mAcceptUsersInput = true;
     }
 
     @Override
@@ -235,7 +206,15 @@
         super.onResume();
         CatLog.d(LOG_TAG, "onResume - mIsResponseSent[" + mIsResponseSent +
                 "], slot id: " + mSlotId);
-        startTimeOut();
+        // If the terminal has already sent response to the card when this activity is resumed,
+        // keep this as a pending activity as this should be finished when the session ends.
+        if (!mIsResponseSent) {
+            setPendingState(false);
+        }
+
+        if (mAlarmTime == NO_INPUT_ALARM) {
+            startTimeOut();
+        }
     }
 
     @Override
@@ -252,18 +231,21 @@
         super.onStop();
         CatLog.d(LOG_TAG, "onStop - mIsResponseSent[" + mIsResponseSent + "]");
 
-        // Nothing should be done here if this activity is being restarted now.
-        if (isChangingConfigurations()) {
+        // Nothing should be done here if this activity is being finished or restarted now.
+        if (isFinishing() || isChangingConfigurations()) {
             return;
         }
 
-        // It is unnecessary to keep this activity if the response was already sent and
-        // this got invisible because of the other full-screen activity in this application.
-        if (mIsResponseSent && appService.isTopOfStack()) {
-            cancelTimeOut();
-            finish();
+        if (mIsResponseSent) {
+            // It is unnecessary to keep this activity if the response was already sent and
+            // the dialog activity is NOT on the top of this activity.
+            if (!appService.isStkDialogActivated()) {
+                finish();
+            }
         } else {
-            appService.getStkContext(mSlotId).setPendingActivityInstance(this);
+            // This should be registered as the pending activity here
+            // only when no response has been sent back to the card.
+            setPendingState(true);
         }
     }
 
@@ -285,8 +267,8 @@
                 CatLog.d(LOG_TAG, "handleDestroy - Send End Session");
                 sendResponse(StkAppService.RES_ID_END_SESSION);
             }
-            cancelTimeOut();
         }
+        cancelTimeOut();
     }
 
     @Override
@@ -299,17 +281,14 @@
 
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (!mAcceptUsersInput) {
-            CatLog.d(LOG_TAG, "mAcceptUsersInput:false");
+        if (mIsResponseSent) {
+            CatLog.d(LOG_TAG, "Already responded");
             return true;
         }
 
         switch (keyCode) {
         case KeyEvent.KEYCODE_BACK:
             CatLog.d(LOG_TAG, "onKeyDown - KEYCODE_BACK");
-            mAcceptUsersInput = false;
-            cancelTimeOut();
-            appService.getStkContext(mSlotId).setPendingActivityInstance(this);
             sendResponse(StkAppService.RES_ID_BACKWARD, null, false);
             return true;
         }
@@ -321,6 +300,8 @@
     }
 
     void sendResponse(int resId, String input, boolean help) {
+        cancelTimeOut();
+
         if (mSlotId == -1) {
             CatLog.d(LOG_TAG, "slot id is invalid");
             return;
@@ -339,15 +320,17 @@
                 + 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);
         }
         args.putBoolean(StkAppService.HELP, help);
-        mContext.startService(new Intent(mContext, StkAppService.class)
-                .putExtras(args));
+        appService.sendResponse(args, mSlotId);
+
+        // This instance should be set as a pending activity and finished by the service
+        if (resId != StkAppService.RES_ID_END_SESSION) {
+            setPendingState(true);
+        }
     }
 
     @Override
@@ -383,22 +366,17 @@
     }
 
     private boolean optionsItemSelectedInternal(MenuItem item) {
-        if (!mAcceptUsersInput) {
-            CatLog.d(LOG_TAG, "mAcceptUsersInput:false");
+        if (mIsResponseSent) {
+            CatLog.d(LOG_TAG, "Already responded");
             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;
         }
         return false;
@@ -407,25 +385,46 @@
     @Override
     protected void onSaveInstanceState(Bundle outState) {
         CatLog.d(LOG_TAG, "onSaveInstanceState: " + mSlotId);
-        outState.putBoolean(ACCEPT_USERS_INPUT_KEY, mAcceptUsersInput);
         outState.putBoolean(RESPONSE_SENT_KEY, mIsResponseSent);
         outState.putString(INPUT_STRING_KEY, mTextIn.getText().toString());
+        outState.putLong(ALARM_TIME_KEY, mAlarmTime);
+        outState.putBoolean(PENDING, mIsPending);
     }
 
     @Override
     protected void onRestoreInstanceState(Bundle savedInstanceState) {
         CatLog.d(LOG_TAG, "onRestoreInstanceState: " + mSlotId);
 
-        mAcceptUsersInput = savedInstanceState.getBoolean(ACCEPT_USERS_INPUT_KEY);
-        if ((mAcceptUsersInput == false) && (mMoreOptions != null)) {
+        mIsResponseSent = savedInstanceState.getBoolean(RESPONSE_SENT_KEY);
+        if (mIsResponseSent && (mMoreOptions != null)) {
             mMoreOptions.setVisibility(View.INVISIBLE);
         }
 
-        mIsResponseSent = savedInstanceState.getBoolean(RESPONSE_SENT_KEY);
-
         String savedString = savedInstanceState.getString(INPUT_STRING_KEY);
         if (!TextUtils.isEmpty(savedString)) {
             mTextIn.setText(savedString);
+            updateButton();
+        }
+
+        mAlarmTime = savedInstanceState.getLong(ALARM_TIME_KEY, NO_INPUT_ALARM);
+        if (mAlarmTime != NO_INPUT_ALARM) {
+            startTimeOut();
+        }
+
+        if (!mIsResponseSent && !savedInstanceState.getBoolean(PENDING)) {
+            // If this is in the foreground and no response has been sent to the card,
+            // this must not be registered as pending activity by the previous instance.
+            // No need to renew nor clear pending activity in this case.
+        } else {
+            // Renew the instance of the pending activity.
+            setPendingState(true);
+        }
+    }
+
+    private void setPendingState(boolean on) {
+        if (mIsPending != on) {
+            appService.getStkContext(mSlotId).setPendingActivityInstance(on ? this : null);
+            mIsPending = on;
         }
     }
 
@@ -435,34 +434,47 @@
 
     public void onTextChanged(CharSequence s, int start, int before, int count) {
         // Reset timeout.
+        cancelTimeOut();
         startTimeOut();
+        updateButton();
     }
 
     public void afterTextChanged(Editable s) {
     }
 
-    private boolean verfiyTypedText() {
-        // If not enough input was typed in stay on the edit screen.
-        if (mTextIn.getText().length() < mStkInput.minLen) {
-            return false;
-        }
-
-        return true;
+    private void updateButton() {
+        // Disable the button if the length of the input text does not meet the expectation.
+        Button okButton = (Button) findViewById(R.id.button_ok);
+        okButton.setEnabled((mTextIn.getText().length() < mStkInput.minLen) ? false : true);
     }
 
     private void cancelTimeOut() {
-        mTimeoutHandler.removeMessages(MSG_ID_TIMEOUT);
+        if (mAlarmTime != NO_INPUT_ALARM) {
+            CatLog.d(LOG_TAG, "cancelTimeOut - slot id: " + mSlotId);
+            AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+            am.cancel(mAlarmListener);
+            mAlarmTime = NO_INPUT_ALARM;
+        }
     }
 
     private void startTimeOut() {
-        int duration = StkApp.calculateDurationInMilis(mStkInput.duration);
-
-        if (duration <= 0) {
-            duration = StkApp.UI_TIMEOUT;
+        // No need to set alarm if device sent TERMINAL RESPONSE already.
+        if (mIsResponseSent) {
+            return;
         }
-        cancelTimeOut();
-        mTimeoutHandler.sendMessageDelayed(mTimeoutHandler
-                .obtainMessage(MSG_ID_TIMEOUT), duration);
+
+        if (mAlarmTime == NO_INPUT_ALARM) {
+            int duration = StkApp.calculateDurationInMilis(mStkInput.duration);
+            if (duration <= 0) {
+                duration = StkApp.UI_TIMEOUT;
+            }
+            mAlarmTime = SystemClock.elapsedRealtime() + duration;
+        }
+
+        CatLog.d(LOG_TAG, "startTimeOut: " + mAlarmTime + "ms, slot id: " + mSlotId);
+        AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+        am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, mAlarmTime, INPUT_ALARM_TAG,
+                mAlarmListener, null);
     }
 
     private void configInputDisplay() {
@@ -513,6 +525,10 @@
                         .getInstance());
             }
             mTextIn.setImeOptions(EditorInfo.IME_FLAG_NO_FULLSCREEN);
+            // Request the initial focus on the edit box and show the software keyboard.
+            mTextIn.requestFocus();
+            getWindow().setSoftInputMode(
+                    WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
             // Set default text if present.
             if (mStkInput.defaultText != null) {
                 mTextIn.setText(mStkInput.defaultText);
@@ -520,6 +536,7 @@
                 // make sure the text is cleared
                 mTextIn.setText("", BufferType.EDITABLE);
             }
+            updateButton();
 
             break;
         case STATE_YES_NO:
@@ -530,13 +547,6 @@
         }
     }
 
-    private float getFontSizeFactor(FontSize size) {
-        final float[] fontSizes =
-            {NORMAL_FONT_FACTOR, LARGE_FONT_FACTOR, SMALL_FONT_FACTOR};
-
-        return fontSizes[size.ordinal()];
-    }
-
     private void initFromIntent(Intent intent) {
         // Get the calling intent type: text/key, and setup the
         // display parameters.
@@ -556,4 +566,14 @@
             finish();
         }
     }
+
+    private final AlarmManager.OnAlarmListener mAlarmListener =
+            new AlarmManager.OnAlarmListener() {
+                @Override
+                public void onAlarm() {
+                    CatLog.d(LOG_TAG, "The alarm time is reached");
+                    mAlarmTime = NO_INPUT_ALARM;
+                    sendResponse(StkAppService.RES_ID_TIMEOUT);
+                }
+            };
 }
diff --git a/src/com/android/stk/StkMenuActivity.java b/src/com/android/stk/StkMenuActivity.java
index bc12eee..bc62e5e 100644
--- a/src/com/android/stk/StkMenuActivity.java
+++ b/src/com/android/stk/StkMenuActivity.java
@@ -16,16 +16,15 @@
 
 package com.android.stk;
 
-import android.app.ListActivity;
 import android.app.ActionBar;
-import android.app.Activity;
+import android.app.AlarmManager;
+import android.app.ListActivity;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
+import android.os.SystemClock;
 import android.support.v4.content.LocalBroadcastManager;
 import android.telephony.SubscriptionManager;
 import android.view.ContextMenu;
@@ -33,17 +32,15 @@
 import android.view.KeyEvent;
 import android.view.MenuItem;
 import android.view.View;
-import android.view.Window;
 import android.widget.AdapterView;
 import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
+import com.android.internal.telephony.cat.CatLog;
 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
@@ -52,13 +49,13 @@
  *
  */
 public class StkMenuActivity extends ListActivity implements View.OnCreateContextMenuListener {
-    private Context mContext;
     private Menu mStkMenu = null;
     private int mState = STATE_MAIN;
     private boolean mAcceptUsersInput = true;
     private int mSlotId = -1;
     private boolean mIsResponseSent = false;
-    Activity mInstance = null;
+    // Determines whether this is in the pending state.
+    private boolean mIsPending = false;
 
     private TextView mTitleTextView = null;
     private ImageView mTitleIconView = null;
@@ -73,37 +70,20 @@
     private static final String MENU_KEY = "menu";
     private static final String ACCEPT_USERS_INPUT_KEY = "accept_users_input";
     private static final String RESPONSE_SENT_KEY = "response_sent";
+    private static final String ALARM_TIME_KEY = "alarm_time";
+    private static final String PENDING = "pending";
+
+    private static final String SELECT_ALARM_TAG = LOG_TAG;
+    private static final long NO_SELECT_ALARM = -1;
+    private long mAlarmTime = NO_SELECT_ALARM;
 
     // 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;
 
-    Handler mTimeoutHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch(msg.what) {
-            case MSG_ID_TIMEOUT:
-                CatLog.d(LOG_TAG, "MSG_ID_TIMEOUT mState: " + mState);
-                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;
-            }
-        }
-    };
-
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -116,11 +96,9 @@
 
         // 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();
         getListView().setOnCreateContextMenuListener(this);
 
         // appService can be null if this activity is automatically recreated by the system
@@ -156,11 +134,6 @@
         }
 
         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);
-        }
-        cancelTimeOut();
         sendResponse(StkAppService.RES_ID_MENU_SELECTION, item.id, false);
         invalidateOptionsMenu();
     }
@@ -178,13 +151,10 @@
             switch (mState) {
             case STATE_SECONDARY:
                 CatLog.d(LOG_TAG, "STATE_SECONDARY");
-                cancelTimeOut();
-                appService.getStkContext(mSlotId).setPendingActivityInstance(this);
                 sendResponse(StkAppService.RES_ID_BACKWARD);
                 return true;
             case STATE_MAIN:
                 CatLog.d(LOG_TAG, "STATE_MAIN");
-                cancelTimeOut();
                 finish();
                 return true;
             }
@@ -194,12 +164,6 @@
     }
 
     @Override
-    public void onRestart() {
-        super.onRestart();
-        CatLog.d(LOG_TAG, "onRestart, slot id: " + mSlotId);
-    }
-
-    @Override
     public void onResume() {
         super.onResume();
 
@@ -217,7 +181,16 @@
             return;
         }
         displayMenu();
-        startTimeOut();
+
+        // If the terminal has already sent response to the card when this activity is resumed,
+        // keep this as a pending activity as this should be finished when the session ends.
+        if (!mIsResponseSent) {
+            setPendingState(false);
+        }
+        if (mAlarmTime == NO_SELECT_ALARM) {
+            startTimeOut();
+        }
+
         invalidateOptionsMenu();
     }
 
@@ -249,35 +222,21 @@
         super.onStop();
         CatLog.d(LOG_TAG, "onStop, slot id: " + mSlotId + "," + mIsResponseSent + "," + mState);
 
-        // Nothing should be done here if this activity is being restarted now.
-        if (isChangingConfigurations()) {
+        // Nothing should be done here if this activity is being finished or restarted now.
+        if (isFinishing() || isChangingConfigurations()) {
             return;
         }
 
-        //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);
-                     }
-                }
+            // It is unnecessary to keep this activity if the response was already sent and
+            // the dialog activity is NOT on the top of this activity.
+            if (mState == STATE_SECONDARY && !appService.isStkDialogActivated()) {
+                finish();
             }
         } else {
-            if (appService != null) {
-                if (mState == STATE_SECONDARY) {
-                    appService.getStkContext(mSlotId).setPendingActivityInstance(this);
-                }
-            } else {
-                CatLog.d(LOG_TAG, "onStop: null appService.");
-            }
+            // This instance should be registered as the pending activity here
+            // only when no response has been sent back to the card.
+            setPendingState(true);
         }
     }
 
@@ -299,6 +258,7 @@
                 sendResponse(StkAppService.RES_ID_END_SESSION);
             }
         }
+        cancelTimeOut();
         LocalBroadcastManager.getInstance(this).unregisterReceiver(mLocalBroadcastReceiver);
     }
 
@@ -330,10 +290,8 @@
         }
         switch (item.getItemId()) {
         case StkApp.MENU_ID_END_SESSION:
-            cancelTimeOut();
             // send session end response.
             sendResponse(StkAppService.RES_ID_END_SESSION);
-            cancelTimeOut();
             finish();
             return true;
         default:
@@ -366,7 +324,6 @@
         }
         switch (item.getItemId()) {
             case CONTEXT_MENU_HELP:
-                cancelTimeOut();
                 int position = info.position;
                 CatLog.d(this, "Position:" + position);
                 Item stkItem = getSelectedItem(position);
@@ -388,6 +345,8 @@
         outState.putParcelable(MENU_KEY, mStkMenu);
         outState.putBoolean(ACCEPT_USERS_INPUT_KEY, mAcceptUsersInput);
         outState.putBoolean(RESPONSE_SENT_KEY, mIsResponseSent);
+        outState.putLong(ALARM_TIME_KEY, mAlarmTime);
+        outState.putBoolean(PENDING, mIsPending);
     }
 
     @Override
@@ -405,21 +364,54 @@
             }
         }
         mIsResponseSent = savedInstanceState.getBoolean(RESPONSE_SENT_KEY);
+
+        mAlarmTime = savedInstanceState.getLong(ALARM_TIME_KEY, NO_SELECT_ALARM);
+        if (mAlarmTime != NO_SELECT_ALARM) {
+            startTimeOut();
+        }
+
+        if (!mIsResponseSent && !savedInstanceState.getBoolean(PENDING)) {
+            // If this is in the foreground and no response has been sent to the card,
+            // this must not be registered as pending activity by the previous instance.
+            // No need to renew nor clear pending activity in this case.
+        } else {
+            // Renew the instance of the pending activity.
+            setPendingState(true);
+        }
+    }
+
+    private void setPendingState(boolean on) {
+        if (mState == STATE_SECONDARY) {
+            if (mIsPending != on) {
+                appService.getStkContext(mSlotId).setPendingActivityInstance(on ? this : null);
+                mIsPending = on;
+            }
+        }
     }
 
     private void cancelTimeOut() {
-        CatLog.d(LOG_TAG, "cancelTimeOut: " + mSlotId);
-        mTimeoutHandler.removeMessages(MSG_ID_TIMEOUT);
+        if (mAlarmTime != NO_SELECT_ALARM) {
+            CatLog.d(LOG_TAG, "cancelTimeOut - slot id: " + mSlotId);
+            AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+            am.cancel(mAlarmListener);
+            mAlarmTime = NO_SELECT_ALARM;
+        }
     }
 
     private void startTimeOut() {
-        if (mState == STATE_SECONDARY) {
-            // Reset timeout.
-            cancelTimeOut();
-            CatLog.d(LOG_TAG, "startTimeOut: " + mSlotId);
-            mTimeoutHandler.sendMessageDelayed(mTimeoutHandler
-                    .obtainMessage(MSG_ID_TIMEOUT), StkApp.UI_TIMEOUT);
+        // No need to set alarm if this is the main menu or device sent TERMINAL RESPONSE already.
+        if (mState != STATE_SECONDARY || mIsResponseSent) {
+            return;
         }
+
+        if (mAlarmTime == NO_SELECT_ALARM) {
+            mAlarmTime = SystemClock.elapsedRealtime() + StkApp.UI_TIMEOUT;
+        }
+
+        CatLog.d(LOG_TAG, "startTimeOut: " + mAlarmTime + "ms, slot id: " + mSlotId);
+        AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+        am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, mAlarmTime, SELECT_ALARM_TAG,
+                mAlarmListener, null);
     }
 
     // Bind list adapter to the items list.
@@ -504,16 +496,19 @@
         if (resId == StkAppService.RES_ID_MENU_SELECTION) {
             showProgressBar(true);
         }
+        cancelTimeOut();
 
         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);
-        mContext.startService(new Intent(mContext, StkAppService.class)
-                .putExtras(args));
+        appService.sendResponse(args, mSlotId);
+
+        // This instance should be set as a pending activity and finished by the service.
+        if (resId != StkAppService.RES_ID_END_SESSION) {
+            setPendingState(true);
+        }
     }
 
     private final BroadcastReceiver mLocalBroadcastReceiver = new BroadcastReceiver() {
@@ -528,4 +523,14 @@
             }
         }
     };
+
+    private final AlarmManager.OnAlarmListener mAlarmListener =
+            new AlarmManager.OnAlarmListener() {
+                @Override
+                public void onAlarm() {
+                    CatLog.d(LOG_TAG, "The alarm time is reached");
+                    mAlarmTime = NO_SELECT_ALARM;
+                    sendResponse(StkAppService.RES_ID_TIMEOUT);
+                }
+            };
 }
diff --git a/src/com/android/stk/StkMenuConfig.java b/src/com/android/stk/StkMenuConfig.java
index 88ce272..d0fa0d8 100644
--- a/src/com/android/stk/StkMenuConfig.java
+++ b/src/com/android/stk/StkMenuConfig.java
@@ -21,6 +21,7 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.os.Build;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -111,15 +112,18 @@
     }
 
     private void findConfig(int slotId) {
-        int[] subId = SubscriptionManager.getSubId(slotId);
-        if (subId == null) {
+        SubscriptionManager sm = (SubscriptionManager) mContext.getSystemService(
+                Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+        SubscriptionInfo info = (sm != null) ? sm.getActiveSubscriptionInfoForSimSlotIndex(slotId)
+                : null;
+        if (info == null) {
             mConfigs[slotId] = NO_CONFIG;
             return;
         }
 
         TelephonyManager telephony =
                 (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
-        String operator = telephony.getSimOperator(subId[0]);
+        String operator = telephony.getSimOperator(info.getSubscriptionId());
         if (TextUtils.isEmpty(operator) || (operator.length() < 5)) {
             mConfigs[slotId] = NO_CONFIG;
             return;