Merge "Telephony: Display RUN_AT command"
diff --git a/Android.mk b/Android.mk
index 79a84e3..135fcf9 100644
--- a/Android.mk
+++ b/Android.mk
@@ -6,9 +6,11 @@
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_JAVA_LIBRARIES := telephony-common
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
 LOCAL_PACKAGE_NAME := Stk
+LOCAL_PRIVATE_PLATFORM_APIS := true
 LOCAL_CERTIFICATE := platform
 
 include $(BUILD_PACKAGE)
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index e3419a9..289aeef 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -22,12 +22,13 @@
 
     <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" />
     <uses-permission android:name="android.permission.SET_ACTIVITY_WATCHER" />
+    <uses-permission android:name="android.permission.USER_ACTIVITY" />
+    <uses-permission android:name="android.permission.VIBRATE" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
 
     <application android:icon="@drawable/ic_launcher_sim_toolkit"
         android:label="@string/app_name"
@@ -90,14 +91,14 @@
         </activity>
         <activity android:name="StkDialogActivity"
             android:configChanges="orientation|locale|screenSize|keyboardHidden"
-            android:theme="@android:style/Theme.Material.Light"
+            android:theme="@style/Transparent"
             android:exported="false"
             android:taskAffinity="android.task.stk.StkLauncherActivity">
         </activity>
 
         <activity android:name="ToneDialog"
             android:exported="false"
-            android:theme="@android:style/Theme.Material.Light"
+            android:theme="@style/Transparent"
             android:taskAffinity="android.task.stk.StkLauncherActivity">
         </activity>
 
@@ -107,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 e2a657c..cb08ba3 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,4 @@
 amitmahajan@google.com
 rgreenwalt@google.com
 sanketpadawe@google.com
+jminjie@google.com
diff --git a/res/drawable-hdpi/ic_launcher_sim_toolkit.png b/res/drawable-hdpi/ic_launcher_sim_toolkit.png
index 51d6688..d6ebaaf 100644
--- a/res/drawable-hdpi/ic_launcher_sim_toolkit.png
+++ b/res/drawable-hdpi/ic_launcher_sim_toolkit.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_sim_toolkit.png b/res/drawable-mdpi/ic_launcher_sim_toolkit.png
old mode 100755
new mode 100644
index 913ab12..9ff189f
--- a/res/drawable-mdpi/ic_launcher_sim_toolkit.png
+++ b/res/drawable-mdpi/ic_launcher_sim_toolkit.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_sim_toolkit.png b/res/drawable-xhdpi/ic_launcher_sim_toolkit.png
new file mode 100644
index 0000000..fcc57be
--- /dev/null
+++ b/res/drawable-xhdpi/ic_launcher_sim_toolkit.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_sim_toolkit.png b/res/drawable-xxhdpi/ic_launcher_sim_toolkit.png
new file mode 100644
index 0000000..9aed66b
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_launcher_sim_toolkit.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_sim_toolkit.png b/res/drawable-xxxhdpi/ic_launcher_sim_toolkit.png
new file mode 100644
index 0000000..b56c624
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_launcher_sim_toolkit.png
Binary files differ
diff --git a/res/layout/stk_input.xml b/res/layout/stk_input.xml
old mode 100755
new mode 100644
index 40c8b77..7f8f96d
--- 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,42 +80,57 @@
                             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" />
-                    <Button
-                        android:id="@+id/button_ok"
-                        android:layout_gravity="center_horizontal"
-                        android:layout_width="100sp"
+                    <LinearLayout
+                        android:layout_width="match_parent"
                         android:layout_height="wrap_content"
-                        android:textStyle="bold"
-                        android:text="@string/button_ok" />
+                        android:gravity="end"
+                        android:layout_marginStart="4dip"
+                        android:layout_marginBottom="16dip"
+                        android:orientation="horizontal">
+                        <Button
+                            android:id="@+id/button_cancel"
+                            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="48dip"
+                            android:layout_width="wrap_content"
+                            style="@android:style/Widget.Material.Button.Colored"
+                            android:text="@string/button_ok" />
+                    </LinearLayout>
                 </LinearLayout>
                 <LinearLayout
                     android:id="@+id/yes_no_layout"
                     android:visibility="gone"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:gravity="center_horizontal">
-                    <Button
-                        android:id="@+id/button_yes"
-                        android:layout_width="100sp"
-                        android:layout_height="wrap_content"
-                        android:textStyle="bold"
-                        android:text="@string/button_yes" />
+                    android:gravity="end"
+                    android:orientation="horizontal">
                     <Button
                         android:id="@+id/button_no"
-                        android:layout_marginLeft="10dip"
-                        android:layout_width="100sp"
                         android:layout_height="wrap_content"
-                        android:textStyle="bold"
+                        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>
         </LinearLayout>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index bf9d00f..8af507f 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -34,6 +34,7 @@
     <string name="enable_app" msgid="3701224550936728203">"Omogućeno"</string>
     <string name="disable_app" msgid="6725081975611415214">"Onemogućeno"</string>
     <string name="stk_dialog_title" msgid="6954825385456886726">"SIM paket alatki"</string>
+    <string name="default_tone_dialog_msg" msgid="4595366992944391641">"Zvuk se reprodukuje"</string>
     <string name="default_open_channel_msg" msgid="2216070254100295924">"Želite li da otvorite kanal?"</string>
     <string name="default_send_data_msg" msgid="6011219698689931272">"Slanje podataka"</string>
     <string name="default_receive_data_msg" msgid="618096941772010682">"Primanje podataka"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index c9a8bf6..069b72b 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -34,6 +34,7 @@
     <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">"Playing Tone"</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>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 5a8520d..5fb2c5c 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -34,6 +34,7 @@
     <string name="enable_app" msgid="3701224550936728203">"Omogućeno"</string>
     <string name="disable_app" msgid="6725081975611415214">"Onemogućeno"</string>
     <string name="stk_dialog_title" msgid="6954825385456886726">"SIM ToolKit"</string>
+    <string name="default_tone_dialog_msg" msgid="4595366992944391641">"Reproduciranje tona"</string>
     <string name="default_open_channel_msg" msgid="2216070254100295924">"Otvoriti kanal?"</string>
     <string name="default_send_data_msg" msgid="6011219698689931272">"Slanje podataka"</string>
     <string name="default_receive_data_msg" msgid="618096941772010682">"Primanje podataka"</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
new file mode 100755
index 0000000..a786fdc
--- /dev/null
+++ b/res/values/styles.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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>
+    <style name="Transparent" parent="@android:style/Theme.Material.Light">
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:windowContentOverlay">@null</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowIsFloating">true</item>
+        <item name="android:backgroundDimEnabled">true</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
+    </style>
+</resources>
diff --git a/src/com/android/stk/StkAppService.java b/src/com/android/stk/StkAppService.java
index 0dd2a7e..397272f 100644
--- a/src/com/android/stk/StkAppService.java
+++ b/src/com/android/stk/StkAppService.java
@@ -19,6 +19,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.AlertDialog;
+import android.app.KeyguardManager;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
@@ -27,6 +28,7 @@
 import android.app.Activity;
 import android.app.ActivityManagerNative;
 import android.app.IProcessObserver;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -37,6 +39,7 @@
 import android.content.res.Resources.NotFoundException;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.media.RingtoneManager;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -47,22 +50,28 @@
 import android.os.PersistableBundle;
 import android.os.PowerManager;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.Vibrator;
 import android.provider.Settings;
+import android.support.v4.content.LocalBroadcastManager;
 import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.view.Gravity;
+import android.view.IWindowManager;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.WindowManager;
+import android.view.WindowManagerPolicy;
 import android.widget.ImageView;
 import android.widget.TextView;
 import android.widget.Toast;
 import android.content.IntentFilter;
 
 import com.android.internal.telephony.cat.AppInterface;
+import com.android.internal.telephony.cat.Input;
 import com.android.internal.telephony.cat.LaunchBrowserMode;
 import com.android.internal.telephony.cat.Menu;
 import com.android.internal.telephony.cat.Item;
@@ -88,6 +97,8 @@
                    SetupEventListConstants.IDLE_SCREEN_AVAILABLE_EVENT;
 import static com.android.internal.telephony.cat.CatCmdMessage.
                    SetupEventListConstants.LANGUAGE_SELECTION_EVENT;
+import static com.android.internal.telephony.cat.CatCmdMessage.
+                   SetupEventListConstants.USER_ACTIVITY_EVENT;
 
 /**
  * SIM toolkit application level service. Interacts with Telephopny messages,
@@ -107,7 +118,8 @@
         protected boolean mIsInputPending = false;
         protected boolean mIsMenuPending = false;
         protected boolean mIsDialogPending = false;
-        protected boolean responseNeeded = true;
+        protected boolean mNotificationOnKeyguard = false;
+        protected boolean mNoResponseFromUser = false;
         protected boolean launchBrowser = false;
         protected BrowserSettings mBrowserSettings = null;
         protected LinkedList<DelayedCmd> mCmdsQ = null;
@@ -118,7 +130,7 @@
         protected int mOpCode = -1;
         private Activity mActivityInstance = null;
         private Activity mDialogInstance = null;
-        private Activity mMainActivityInstance = null;
+        private Activity mImmediateDialogInstance = null;
         private int mSlotId = 0;
         private SetupEventListSettings mSetupEventListSettings = null;
         private boolean mClearSelectItem = false;
@@ -144,14 +156,14 @@
                     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 void setImmediateDialogInstance(Activity act) {
+            CatLog.d(this, "setImmediateDialogInstance act : " + mSlotId + ", " + act);
+            callSetActivityInstMsg(OP_SET_IMMED_DAL_INST, mSlotId, act);
         }
-        final synchronized Activity getMainActivityInstance() {
-            CatLog.d(this, "getMainActivityInstance act : " + mSlotId + ", " +
-                    mMainActivityInstance);
-            return mMainActivityInstance;
+        final synchronized Activity getImmediateDialogInstance() {
+            CatLog.d(this, "getImmediateDialogInstance act : " + mSlotId + ", " +
+                    mImmediateDialogInstance);
+            return mImmediateDialogInstance;
         }
     }
 
@@ -164,8 +176,10 @@
     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;
 
     // Used for setting FLAG_ACTIVITY_NO_USER_ACTION when
     // creating an intent.
@@ -206,10 +220,10 @@
     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;
-    static final int OP_LOCALE_CHANGED = 11;
-    static final int OP_ALPHA_NOTIFY = 12;
-    static final int OP_IDLE_SCREEN = 13;
+    static final int OP_LOCALE_CHANGED = 10;
+    static final int OP_ALPHA_NOTIFY = 11;
+    static final int OP_IDLE_SCREEN = 12;
+    static final int OP_SET_IMMED_DAL_INST = 13;
 
     //Invalid SetupEvent
     static final int INVALID_SETUP_EVENT = 0xFF;
@@ -223,6 +237,9 @@
     // Message id to remove stop tone message from queue.
     private static final int STOP_TONE_WHAT = 100;
 
+    // Message id to send user activity event to card.
+    private static final int OP_USER_ACTIVITY = 20;
+
     // Response ids
     static final int RES_ID_MENU_SELECTION = 11;
     static final int RES_ID_INPUT = 12;
@@ -254,6 +271,8 @@
 
     private static final String LOG_TAG = new Object(){}.getClass().getEnclosingClass().getName();
 
+    static final String SESSION_ENDED = "session_ended";
+
     // Inner class used for queuing telephony messages (proactive commands,
     // session end) while the service is busy processing a previous message.
     private class DelayedCmd {
@@ -272,6 +291,10 @@
     // system property to set the STK specific default url for launch browser proactive cmds
     private static final String STK_BROWSER_DEFAULT_URL_SYSPROP = "persist.radio.stk.default_url";
 
+    private static final int NOTIFICATION_ON_KEYGUARD = 1;
+    private static final long[] VIBRATION_PATTERN = new long[] { 0, 350, 250, 350 };
+    private BroadcastReceiver mUserPresentReceiver = null;
+
     @Override
     public void onCreate() {
         CatLog.d(LOG_TAG, "onCreate()+");
@@ -376,7 +399,9 @@
     @Override
     public void onDestroy() {
         CatLog.d(LOG_TAG, "onDestroy()");
+        unregisterUserActivityReceiver();
         unregisterProcessObserver();
+        unregisterLocaleChangeReceiver();
         sInstance = null;
         waitForLooper();
         mServiceLooper.quit();
@@ -438,6 +463,14 @@
         return false;
     }
 
+    boolean isMainMenuAvailable(int slotId) {
+        if (slotId >= 0 && slotId < mSimCount) {
+            // The main menu can handle the next user operation if the previous session finished.
+            return (mStkContext[slotId].lastSelectedItem == null) ? true : false;
+        }
+        return false;
+    }
+
     /*
      * Package api used by StkMenuActivity to get its Menu parameter.
      */
@@ -612,16 +645,14 @@
                 }
                 break;
             case OP_SET_DAL_INST:
-                Activity dal = new Activity();
+                Activity dal = (Activity) msg.obj;
                 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;
+            case OP_SET_IMMED_DAL_INST:
+                Activity immedDal = (Activity) msg.obj;
+                CatLog.d(LOG_TAG, "Set dialog instance for immediate response. " + immedDal);
+                mStkContext[slotId].mImmediateDialogInstance = immedDal;
                 break;
             case OP_LOCALE_CHANGED:
                 CatLog.d(this, "Locale Changed");
@@ -646,6 +677,11 @@
                 CatLog.d(this, "Stop tone");
                 handleStopTone(msg, slotId);
                 break;
+            case OP_USER_ACTIVITY:
+                for (int slot = PhoneConstants.SIM_ID_1; slot < mSimCount; slot++) {
+                    checkForSetupEvent(USER_ACTIVITY_EVENT, null, slot);
+                }
+                break;
             }
         }
 
@@ -839,6 +875,7 @@
         mStkContext[slotId].mIsInputPending = false;
         mStkContext[slotId].mIsMenuPending = false;
         mStkContext[slotId].mIsDialogPending = false;
+        mStkContext[slotId].mNoResponseFromUser = false;
 
         if (mStkContext[slotId].mMainCmd == null) {
             CatLog.d(LOG_TAG, "[handleSessionEnd][mMainCmd is null!]");
@@ -850,13 +887,16 @@
             mStkContext[slotId].mCurrentMenu = mStkContext[slotId].mMainCmd.getMenu();
         }
         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);
+            mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
         }
+
+        // Send a local broadcast as a notice that this service handled the session end event.
+        Intent intent = new Intent(SESSION_ENDED);
+        intent.putExtra(SLOT_ID, slotId);
+        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
+
         if (mStkContext[slotId].mCmdsQ.size() != 0) {
             callDelayedMsg(slotId);
         } else {
@@ -1256,6 +1296,24 @@
             return;
         }
 
+        switch (args.getInt(RES_ID)) {
+            case RES_ID_MENU_SELECTION:
+            case RES_ID_INPUT:
+            case RES_ID_CONFIRM:
+            case RES_ID_CHOICE:
+            case RES_ID_BACKWARD:
+            case RES_ID_END_SESSION:
+                mStkContext[slotId].mNoResponseFromUser = false;
+                break;
+            case RES_ID_TIMEOUT:
+                cancelNotificationOnKeyguard(slotId);
+                mStkContext[slotId].mNoResponseFromUser = true;
+                break;
+            default:
+                // The other IDs cannot be used to judge if there is no response from user.
+                break;
+        }
+
         if (null != mStkContext[slotId].mCurrentCmd &&
                 null != mStkContext[slotId].mCurrentCmd.getCmdType()) {
             CatLog.d(LOG_TAG, "handleCmdResponse- cmdName[" +
@@ -1354,6 +1412,21 @@
         }
     }
 
+    @Override
+    public void startActivity(Intent intent) {
+        int slotId = intent.getIntExtra(SLOT_ID, SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+        // Close the dialog displayed for DISPLAY TEXT command with an immediate response object
+        // before new dialog is displayed.
+        if (SubscriptionManager.isValidSlotIndex(slotId)) {
+            Activity dialog = mStkContext[slotId].getImmediateDialogInstance();
+            if (dialog != null) {
+                CatLog.d(LOG_TAG, "finish dialog for immediate response.");
+                dialog.finish();
+            }
+        }
+        super.startActivity(intent);
+    }
+
     private void launchMenuActivity(Menu menu, int slotId) {
         Intent newIntent = new Intent(Intent.ACTION_VIEW);
         String targetActivity = STK_MENU_ACTIVITY_NAME;
@@ -1370,15 +1443,6 @@
         if (menu == null) {
             // We assume this was initiated by the user pressing the tool kit icon
             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 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 &&
@@ -1397,7 +1461,7 @@
         newIntent.putExtra(SLOT_ID, slotId);
         newIntent.setData(uriData);
         newIntent.setFlags(intentFlags);
-        mContext.startActivity(newIntent);
+        startActivity(newIntent);
     }
 
     private void launchInputActivity(int slotId) {
@@ -1406,15 +1470,20 @@
         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);
+        Input input = mStkContext[slotId].mCurrentCmd.geInput();
 
         CatLog.d(LOG_TAG, "launchInputActivity, slotId: " + slotId);
         newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                             | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
         newIntent.setClassName(PACKAGE_NAME, targetActivity);
-        newIntent.putExtra("INPUT", mStkContext[slotId].mCurrentCmd.geInput());
+        newIntent.putExtra("INPUT", input);
         newIntent.putExtra(SLOT_ID, slotId);
         newIntent.setData(uriData);
-        mContext.startActivity(newIntent);
+
+        if (input != null) {
+            notifyUserIfNecessary(slotId, input.text);
+        }
+        startActivity(newIntent);
     }
 
     private void launchTextDialog(int slotId) {
@@ -1425,22 +1494,133 @@
         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);
-            // For display texts with immediate response, send the terminal response
-            // immediately. responseNeeded will be false, if display text command has
-            // the immediate response tlv.
-            if (!mStkContext[slotId].mCurrentCmd.geTextMessage().responseNeeded) {
-                sendResponse(RES_ID_CONFIRM, slotId, true);
+        TextMessage textMessage = mStkContext[slotId].mCurrentCmd.geTextMessage();
+
+        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", textMessage);
+        newIntent.putExtra(SLOT_ID, slotId);
+
+        if (textMessage != null) {
+            notifyUserIfNecessary(slotId, textMessage.text);
+        }
+        startActivity(newIntent);
+        // For display texts with immediate response, send the terminal response
+        // immediately. responseNeeded will be false, if display text command has
+        // the immediate response tlv.
+        if (!mStkContext[slotId].mCurrentCmd.geTextMessage().responseNeeded) {
+            sendResponse(RES_ID_CONFIRM, slotId, true);
+        }
+    }
+
+    private void notifyUserIfNecessary(int slotId, String message) {
+        createAllChannels();
+
+        if (mStkContext[slotId].mNoResponseFromUser) {
+            // No response from user was observed in the current session.
+            // Do nothing in that case in order to avoid turning on the screen again and again
+            // when the card repeatedly sends the same command in its retry procedure.
+            return;
+        }
+
+        PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
+
+        if (((KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE)).isKeyguardLocked()) {
+            // Display the notification on the keyguard screen
+            // if user cannot see the message from the card right now because of it.
+            // The notification can be dismissed if user removed the keyguard screen.
+            launchNotificationOnKeyguard(slotId, message);
+        } else if (!(pm.isInteractive() && isTopOfStack())) {
+            // User might be doing something but it is not related to the SIM Toolkit.
+            // Play the tone and do vibration in order to attract user's attention.
+            // User will see the input screen or the dialog soon in this case.
+            NotificationChannel channel = mNotificationManager
+                    .getNotificationChannel(STK_NOTIFICATION_CHANNEL_ID);
+            Uri uri = channel.getSound();
+            if (uri != null && !Uri.EMPTY.equals(uri)
+                    && (NotificationManager.IMPORTANCE_LOW) < channel.getImportance()) {
+                RingtoneManager.getRingtone(getApplicationContext(), uri).play();
+            }
+            long[] pattern = channel.getVibrationPattern();
+            if (pattern != null && channel.shouldVibrate()) {
+                ((Vibrator) this.getSystemService(Context.VIBRATOR_SERVICE))
+                        .vibrate(pattern, -1);
             }
         }
+
+        // Turn on the screen.
+        PowerManager.WakeLock wakelock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK
+                | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, LOG_TAG);
+        wakelock.acquire();
+        wakelock.release();
+    }
+
+    private void launchNotificationOnKeyguard(int slotId, String message) {
+        Notification.Builder builder = new Notification.Builder(this, STK_NOTIFICATION_CHANNEL_ID);
+
+        builder.setStyle(new Notification.BigTextStyle(builder).bigText(message));
+        builder.setContentText(message);
+
+        Menu menu = getMainMenu(slotId);
+        if (menu == null || TextUtils.isEmpty(menu.title)) {
+            builder.setContentTitle(getResources().getString(R.string.app_name));
+        } else {
+            builder.setContentTitle(menu.title);
+        }
+
+        builder.setSmallIcon(com.android.internal.R.drawable.stat_notify_sim_toolkit);
+        builder.setOngoing(true);
+        builder.setOnlyAlertOnce(true);
+        builder.setColor(getResources().getColor(
+                com.android.internal.R.color.system_notification_accent_color));
+
+        registerUserPresentReceiver();
+        mNotificationManager.notify(getNotificationId(NOTIFICATION_ON_KEYGUARD, slotId),
+                builder.build());
+        mStkContext[slotId].mNotificationOnKeyguard = true;
+    }
+
+    private void cancelNotificationOnKeyguard(int slotId) {
+        mNotificationManager.cancel(getNotificationId(NOTIFICATION_ON_KEYGUARD, slotId));
+        mStkContext[slotId].mNotificationOnKeyguard = false;
+        unregisterUserPresentReceiver(slotId);
+    }
+
+    private synchronized void registerUserPresentReceiver() {
+        if (mUserPresentReceiver == null) {
+            mUserPresentReceiver = new BroadcastReceiver() {
+                @Override public void onReceive(Context context, Intent intent) {
+                    if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
+                        for (int slot = 0; slot < mSimCount; slot++) {
+                            cancelNotificationOnKeyguard(slot);
+                        }
+                    }
+                }
+            };
+            registerReceiver(mUserPresentReceiver, new IntentFilter(Intent.ACTION_USER_PRESENT));
+        }
+    }
+
+    private synchronized void unregisterUserPresentReceiver(int slotId) {
+        if (mUserPresentReceiver != null) {
+            for (int slot = PhoneConstants.SIM_ID_1; slot < mSimCount; slot++) {
+                if (slot != slotId) {
+                    if (mStkContext[slot].mNotificationOnKeyguard) {
+                        // The broadcast receiver is still necessary for other SIM card.
+                        return;
+                    }
+                }
+            }
+            unregisterReceiver(mUserPresentReceiver);
+            mUserPresentReceiver = null;
+        }
+    }
+
+    private int getNotificationId(int notificationType, int slotId) {
+        return getNotificationId(slotId) + (notificationType * mSimCount);
     }
 
     public boolean isStkDialogActivated(Context context) {
@@ -1486,11 +1666,28 @@
     }
 
     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();
+                break;
             case IDLE_SCREEN_AVAILABLE_EVENT:
                 unregisterProcessObserver(AppInterface.CommandType.SET_UP_EVENT_LIST, slotId);
                 break;
             case LANGUAGE_SELECTION_EVENT:
+                unregisterLocaleChangeReceiver();
+                break;
             default:
                 break;
         }
@@ -1502,16 +1699,53 @@
         }
         for (int event : mStkContext[slotId].mSetupEventListSettings.eventList) {
             switch (event) {
+                case USER_ACTIVITY_EVENT:
+                    registerUserActivityReceiver();
+                    break;
                 case IDLE_SCREEN_AVAILABLE_EVENT:
                     registerProcessObserver();
                     break;
                 case LANGUAGE_SELECTION_EVENT:
+                    registerLocaleChangeReceiver();
+                    break;
                 default:
                     break;
             }
         }
     }
 
+    private synchronized void registerUserActivityReceiver() {
+        if (mUserActivityReceiver == null) {
+            mUserActivityReceiver = new BroadcastReceiver() {
+                @Override public void onReceive(Context context, Intent intent) {
+                    if (WindowManagerPolicy.ACTION_USER_ACTIVITY_NOTIFICATION.equals(
+                            intent.getAction())) {
+                        Message message = mServiceHandler.obtainMessage();
+                        message.arg1 = OP_USER_ACTIVITY;
+                        mServiceHandler.sendMessage(message);
+                        unregisterUserActivityReceiver();
+                    }
+                }
+            };
+            registerReceiver(mUserActivityReceiver, new IntentFilter(
+                    WindowManagerPolicy.ACTION_USER_ACTIVITY_NOTIFICATION));
+            try {
+                IWindowManager wm = IWindowManager.Stub.asInterface(
+                        ServiceManager.getService(Context.WINDOW_SERVICE));
+                wm.requestUserActivityNotification();
+            } catch (RemoteException e) {
+                CatLog.e(this, "failed to init WindowManager:" + e);
+            }
+        }
+    }
+
+    private synchronized void unregisterUserActivityReceiver() {
+        if (mUserActivityReceiver != null) {
+            unregisterReceiver(mUserActivityReceiver);
+            mUserActivityReceiver = null;
+        }
+    }
+
     private synchronized void registerProcessObserver() {
         if (mProcessObserver == null) {
             try {
@@ -1575,6 +1809,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);
 
@@ -1611,6 +1867,7 @@
                 CatLog.d(this, " Event " + event + "exists in the EventList");
 
                 switch (event) {
+                    case USER_ACTIVITY_EVENT:
                     case IDLE_SCREEN_AVAILABLE_EVENT:
                         sendSetUpEventResponse(event, addedInfo, slotId);
                         removeSetUpEvent(event, slotId);
@@ -1648,6 +1905,11 @@
                     mStkContext[slotId].mSetupEventListSettings.eventList[i] = INVALID_SETUP_EVENT;
 
                     switch (event) {
+                        case USER_ACTIVITY_EVENT:
+                            // The broadcast receiver can be unregistered
+                            // as the event has already been sent to the card.
+                            unregisterUserActivityReceiver();
+                            break;
                         case IDLE_SCREEN_AVAILABLE_EVENT:
                             // The process observer can be unregistered
                             // as the idle screen has already been available.
@@ -1710,17 +1972,15 @@
         //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);
-        }
+        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) {
@@ -1805,6 +2065,7 @@
                     .setSmallIcon(com.android.internal.R.drawable.stat_notify_sim_toolkit);
             notificationBuilder.setContentIntent(pendingIntent);
             notificationBuilder.setOngoing(true);
+            notificationBuilder.setOnlyAlertOnce(true);
             // Set text and icon for the status bar and notification body.
             if (mStkContext[slotId].mIdleModeTextCmd.hasIconLoadFailed() ||
                     !msg.iconSelfExplanatory) {
@@ -1831,10 +2092,15 @@
      * ignore this call.
      */
     private void createAllChannels() {
-        mNotificationManager.createNotificationChannel(new NotificationChannel(
+        NotificationChannel notificationChannel = new NotificationChannel(
                 STK_NOTIFICATION_CHANNEL_ID,
                 getResources().getString(R.string.stk_channel_name),
-                NotificationManager.IMPORTANCE_MIN));
+                NotificationManager.IMPORTANCE_DEFAULT);
+
+        notificationChannel.enableVibration(true);
+        notificationChannel.setVibrationPattern(VIBRATION_PATTERN);
+
+        mNotificationManager.createNotificationChannel(notificationChannel);
     }
 
     private void launchToneDialog(int 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 283ae09..3503134 100644
--- a/src/com/android/stk/StkDialogActivity.java
+++ b/src/com/android/stk/StkDialogActivity.java
@@ -16,29 +16,25 @@
 
 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.view.KeyEvent;
-
+import android.content.Intent;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.SystemClock;
+import android.telephony.SubscriptionManager;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
 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;
+
 /**
  * AlertDialog used for DISPLAY TEXT commands.
  *
@@ -52,15 +48,15 @@
     private StkAppService appService = StkAppService.getInstance();
     // Determines whether Terminal Response (TR) has been sent
     private boolean mIsResponseSent = false;
-    private Context mContext;
     // 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 AlertDialog mAlertDialog;
@@ -105,6 +101,17 @@
                         finish();
                     }
                 });
+
+        alertDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() {
+                    @Override
+                    public void onCancel(DialogInterface dialog) {
+                        CatLog.d(LOG_TAG, "Moving backward!, mSlotId: " + mSlotId);
+                        cancelTimeOut();
+                        sendResponse(StkAppService.RES_ID_BACKWARD);
+                        finish();
+                    }
+                });
+
         alertDialogBuilder.create();
 
         initFromIntent(getIntent());
@@ -115,6 +122,10 @@
 
         if (!mTextMsg.responseNeeded) {
             alertDialogBuilder.setNegativeButton(null, null);
+            // Register the instance of this activity because the dialog displayed for DISPLAY TEXT
+            // command with an immediate response object should disappear when the terminal receives
+            // a subsequent proactive command containing display data.
+            appService.getStkContext(mSlotId).setImmediateDialogInstance(this);
         }
 
         alertDialogBuilder.setTitle(mTextMsg.title);
@@ -142,27 +153,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);
-
-        setFinishOnTouchOutside(false);
-    }
-
-    @Override
-    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;
-        }
-        return false;
     }
 
     @Override
@@ -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();
         }
     }
 
@@ -270,22 +256,19 @@
             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);
     }
 
@@ -293,11 +276,18 @@
     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 + "]");
+
+        if (mAlarmTime != NO_DIALOG_ALARM) {
+            startTimeOut();
+        }
+
     }
 
     @Override
@@ -306,6 +296,18 @@
         setIntent(intent);
     }
 
+    @Override
+    public void finish() {
+        super.finish();
+        // Unregister the instance for DISPLAY TEXT command with an immediate response object
+        // as it is unnecessary to ask the service to finish this anymore.
+        if ((appService != null) && (mTextMsg != null) && !mTextMsg.responseNeeded) {
+            if (SubscriptionManager.isValidSlotIndex(mSlotId)) {
+                appService.getStkContext(mSlotId).setImmediateDialogInstance(null);
+            }
+        }
+    }
+
     private void sendResponse(int resId, boolean confirmed) {
         if (mSlotId == -1) {
             CatLog.d(LOG_TAG, "sim id is invalid");
@@ -348,61 +350,48 @@
     }
 
     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);
+                    finish();
+                }
+            };
 }
diff --git a/src/com/android/stk/StkInputActivity.java b/src/com/android/stk/StkInputActivity.java
index a4e6daf..6c633b7 100644
--- a/src/com/android/stk/StkInputActivity.java
+++ b/src/com/android/stk/StkInputActivity.java
@@ -81,6 +81,11 @@
     static final float LARGE_FONT_FACTOR = 2;
     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";
+
     // message id for time out
     private static final int MSG_ID_TIMEOUT = 1;
     private StkAppService appService = StkAppService.getInstance();
@@ -121,6 +126,12 @@
             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);
+            return;
         // Yes/No layout buttons.
         case R.id.button_yes:
             mAcceptUsersInput = false;
@@ -160,8 +171,8 @@
     }
 
     @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
 
         CatLog.d(LOG_TAG, "onCreate - mIsResponseSent[" + mIsResponseSent + "]");
 
@@ -196,10 +207,12 @@
         mInstance = this;
         // Set buttons listeners.
         Button okButton = (Button) findViewById(R.id.button_ok);
+        Button cancelButton = (Button) findViewById(R.id.button_cancel);
         Button yesButton = (Button) findViewById(R.id.button_yes);
         Button noButton = (Button) findViewById(R.id.button_no);
 
         okButton.setOnClickListener(this);
+        cancelButton.setOnClickListener(this);
         yesButton.setOnClickListener(this);
         noButton.setOnClickListener(this);
 
@@ -238,6 +251,12 @@
     public void onStop() {
         super.onStop();
         CatLog.d(LOG_TAG, "onStop - mIsResponseSent[" + mIsResponseSent + "]");
+
+        // Nothing should be done here if this activity is being restarted now.
+        if (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()) {
@@ -256,14 +275,18 @@
         if (appService == null) {
             return;
         }
-        //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);
+        // Avoid sending the terminal response while the activty is being restarted
+        // due to some kind of configuration change.
+        if (!isChangingConfigurations()) {
+            // 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();
         }
-        cancelTimeOut();
     }
 
     @Override
@@ -384,16 +407,26 @@
     @Override
     protected void onSaveInstanceState(Bundle outState) {
         CatLog.d(LOG_TAG, "onSaveInstanceState: " + mSlotId);
-        outState.putBoolean("ACCEPT_USERS_INPUT", mAcceptUsersInput);
+        outState.putBoolean(ACCEPT_USERS_INPUT_KEY, mAcceptUsersInput);
+        outState.putBoolean(RESPONSE_SENT_KEY, mIsResponseSent);
+        outState.putString(INPUT_STRING_KEY, mTextIn.getText().toString());
     }
 
     @Override
     protected void onRestoreInstanceState(Bundle savedInstanceState) {
         CatLog.d(LOG_TAG, "onRestoreInstanceState: " + mSlotId);
-        mAcceptUsersInput = savedInstanceState.getBoolean("ACCEPT_USERS_INPUT");
+
+        mAcceptUsersInput = savedInstanceState.getBoolean(ACCEPT_USERS_INPUT_KEY);
         if ((mAcceptUsersInput == false) && (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);
+        }
     }
 
     public void beforeTextChanged(CharSequence s, int start, int count,
diff --git a/src/com/android/stk/StkMenuActivity.java b/src/com/android/stk/StkMenuActivity.java
old mode 100755
new mode 100644
index 04e5ed0..bc12eee
--- a/src/com/android/stk/StkMenuActivity.java
+++ b/src/com/android/stk/StkMenuActivity.java
@@ -19,11 +19,14 @@
 import android.app.ListActivity;
 import android.app.ActionBar;
 import android.app.Activity;
+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.support.v4.content.LocalBroadcastManager;
 import android.telephony.SubscriptionManager;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
@@ -65,6 +68,12 @@
 
     private StkAppService appService = StkAppService.getInstance();
 
+    // Keys for saving the state of the dialog in the bundle
+    private static final String STATE_KEY = "state";
+    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";
+
     // Internal state values
     static final int STATE_INIT = 0;
     static final int STATE_MAIN = 1;
@@ -85,7 +94,6 @@
             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);
                 }
@@ -97,8 +105,8 @@
     };
 
     @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
 
         CatLog.d(LOG_TAG, "onCreate");
 
@@ -113,7 +121,6 @@
         mTitleIconView = (ImageView) findViewById(R.id.title_icon);
         mProgressView = (ProgressBar) findViewById(R.id.progress_bar);
         mContext = getBaseContext();
-        mAcceptUsersInput = true;
         getListView().setOnCreateContextMenuListener(this);
 
         // appService can be null if this activity is automatically recreated by the system
@@ -124,6 +131,8 @@
             return;
         }
 
+        LocalBroadcastManager.getInstance(this).registerReceiver(mLocalBroadcastReceiver,
+                new IntentFilter(StkAppService.SESSION_ENDED));
         initFromIntent(getIntent());
         if (!SubscriptionManager.isValidSlotIndex(mSlotId)) {
             finish();
@@ -153,10 +162,6 @@
         }
         cancelTimeOut();
         sendResponse(StkAppService.RES_ID_MENU_SELECTION, item.id, false);
-        mAcceptUsersInput = false;
-        mProgressView.setVisibility(View.VISIBLE);
-        mProgressView.setIndeterminate(true);
-
         invalidateOptionsMenu();
     }
 
@@ -174,13 +179,11 @@
             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:
                 CatLog.d(LOG_TAG, "STATE_MAIN");
-                appService.getStkContext(mSlotId).setMainActivityInstance(null);
                 cancelTimeOut();
                 finish();
                 return true;
@@ -213,26 +216,9 @@
             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) {
-            //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);
     }
 
     @Override
@@ -262,6 +248,12 @@
     public void onStop() {
         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()) {
+            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.
@@ -300,16 +292,14 @@
         //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 (mState == STATE_SECONDARY && !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.");
+            // Avoid sending the terminal response while the activty is being restarted
+            // due to some kind of configuration change.
+            if (!isChangingConfigurations()) {
+                CatLog.d(LOG_TAG, "handleDestroy - Send End Session");
+                sendResponse(StkAppService.RES_ID_END_SESSION);
             }
         }
+        LocalBroadcastManager.getInstance(this).unregisterReceiver(mLocalBroadcastReceiver);
     }
 
     @Override
@@ -341,7 +331,6 @@
         switch (item.getItemId()) {
         case StkApp.MENU_ID_END_SESSION:
             cancelTimeOut();
-            mAcceptUsersInput = false;
             // send session end response.
             sendResponse(StkAppService.RES_ID_END_SESSION);
             cancelTimeOut();
@@ -378,7 +367,6 @@
         switch (item.getItemId()) {
             case CONTEXT_MENU_HELP:
                 cancelTimeOut();
-                mAcceptUsersInput = false;
                 int position = info.position;
                 CatLog.d(this, "Position:" + position);
                 Item stkItem = getSelectedItem(position);
@@ -396,17 +384,27 @@
     @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);
+        outState.putInt(STATE_KEY, mState);
+        outState.putParcelable(MENU_KEY, mStkMenu);
+        outState.putBoolean(ACCEPT_USERS_INPUT_KEY, mAcceptUsersInput);
+        outState.putBoolean(RESPONSE_SENT_KEY, mIsResponseSent);
     }
 
     @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");
+        mState = savedInstanceState.getInt(STATE_KEY);
+        mStkMenu = savedInstanceState.getParcelable(MENU_KEY);
+        mAcceptUsersInput = savedInstanceState.getBoolean(ACCEPT_USERS_INPUT_KEY);
+        if (!mAcceptUsersInput) {
+            // Check the latest information as the saved instance state can be outdated.
+            if ((mState == STATE_MAIN) && appService.isMainMenuAvailable(mSlotId)) {
+                mAcceptUsersInput = true;
+            } else {
+                showProgressBar(true);
+            }
+        }
+        mIsResponseSent = savedInstanceState.getBoolean(RESPONSE_SENT_KEY);
     }
 
     private void cancelTimeOut() {
@@ -453,6 +451,16 @@
         }
     }
 
+    private void showProgressBar(boolean show) {
+        if (show) {
+            mProgressView.setIndeterminate(true);
+            mProgressView.setVisibility(View.VISIBLE);
+        } else {
+            mProgressView.setIndeterminate(false);
+            mProgressView.setVisibility(View.GONE);
+        }
+    }
+
     private void initFromIntent(Intent intent) {
 
         if (intent != null) {
@@ -490,6 +498,13 @@
     private void sendResponse(int resId, int itemId, boolean help) {
         CatLog.d(LOG_TAG, "sendResponse resID[" + resId + "] itemId[" + itemId +
             "] help[" + help + "]");
+
+        // Disallow user operation temporarily until receiving the result of the response.
+        mAcceptUsersInput = false;
+        if (resId == StkAppService.RES_ID_MENU_SELECTION) {
+            showProgressBar(true);
+        }
+
         mIsResponseSent = true;
         Bundle args = new Bundle();
         args.putInt(StkAppService.OPCODE, StkAppService.OP_RESPONSE);
@@ -500,4 +515,17 @@
         mContext.startService(new Intent(mContext, StkAppService.class)
                 .putExtras(args));
     }
+
+    private final BroadcastReceiver mLocalBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (StkAppService.SESSION_ENDED.equals(intent.getAction())) {
+                int slotId = intent.getIntExtra(StkAppService.SLOT_ID, 0);
+                if ((mState == STATE_MAIN) && (mSlotId == slotId)) {
+                    mAcceptUsersInput = true;
+                    showProgressBar(false);
+                }
+            }
+        }
+    };
 }
diff --git a/src/com/android/stk/ToneDialog.java b/src/com/android/stk/ToneDialog.java
index f9b8754..1c5fca6 100755
--- a/src/com/android/stk/ToneDialog.java
+++ b/src/com/android/stk/ToneDialog.java
@@ -20,14 +20,13 @@
 import android.app.AlertDialog;
 import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
-import android.view.KeyEvent;
 import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -42,6 +41,7 @@
 public class ToneDialog extends Activity {
     TextMessage toneMsg = null;
     int mSlotId = -1;
+    private AlertDialog mAlertDialog;
 
     private static final String LOG_TAG = new Object(){}.getClass().getEnclosingClass().getName();
 
@@ -80,36 +80,30 @@
         if (toneMsg.iconSelfExplanatory && toneMsg.icon != null) {
             tv.setVisibility(View.GONE);
         }
+
+        alertDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() {
+                    @Override
+                    public void onCancel(DialogInterface dialog) {
+                        sendStopTone();
+                        finish();
+                    }
+                });
+
+        mAlertDialog = alertDialogBuilder.create();
+        mAlertDialog.show();
     }
 
     @Override
     protected void onDestroy() {
         CatLog.d(LOG_TAG, "onDestroy");
-        // Unregister receiver
-        unregisterReceiver(mFinishActivityReceiver);
         super.onDestroy();
-    }
 
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        switch (keyCode) {
-        case KeyEvent.KEYCODE_BACK:
-            sendStopTone();
-            finish();
-            break;
-        }
-        return false;
-    }
+        unregisterReceiver(mFinishActivityReceiver);
 
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        switch (event.getAction()) {
-        case MotionEvent.ACTION_DOWN:
-            sendStopTone();
-            finish();
-            return true;
+        if (mAlertDialog != null && mAlertDialog.isShowing()) {
+            mAlertDialog.dismiss();
+            mAlertDialog = null;
         }
-        return super.onTouchEvent(event);
     }
 
     private BroadcastReceiver mFinishActivityReceiver = new BroadcastReceiver() {