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;