Merge "Improve the logic to determine the idle mode"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
old mode 100755
new mode 100644
index aef271d..e3419a9
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -27,6 +27,7 @@
<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" />
<application android:icon="@drawable/ic_launcher_sim_toolkit"
android:label="@string/app_name"
diff --git a/src/com/android/stk/StkAppService.java b/src/com/android/stk/StkAppService.java
index 4e8ae9a..2e51e21 100644
--- a/src/com/android/stk/StkAppService.java
+++ b/src/com/android/stk/StkAppService.java
@@ -25,9 +25,13 @@
import android.app.PendingIntent;
import android.app.Service;
import android.app.Activity;
+import android.app.ActivityManagerNative;
+import android.app.IProcessObserver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
@@ -42,6 +46,7 @@
import android.os.Parcel;
import android.os.PersistableBundle;
import android.os.PowerManager;
+import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.Vibrator;
import android.provider.Settings;
@@ -120,6 +125,7 @@
private boolean mDisplayTextDlgIsVisibile = false;
private CatCmdMessage mCurrentSetupEventCmd = null;
private CatCmdMessage mIdleModeTextCmd = null;
+ private boolean mIdleModeTextVisible = false;
final synchronized void setPendingActivityInstance(Activity act) {
CatLog.d(this, "setPendingActivityInstance act : " + mSlotId + ", " + act);
callSetActivityInstMsg(OP_SET_ACT_INST, mSlotId, act);
@@ -157,8 +163,7 @@
private AppInterface[] mStkService = null;
private StkContext[] mStkContext = null;
private int mSimCount = 0;
- private PowerManager mPowerManager = null;
- private StkCmdReceiver mStkCmdReceiver = null;
+ private IProcessObserver.Stub mProcessObserver = null;
private TonePlayer mTonePlayer = null;
private Vibrator mVibrator = null;
@@ -277,9 +282,7 @@
CatLog.d(LOG_TAG, "simCount: " + mSimCount);
mStkService = new AppInterface[mSimCount];
mStkContext = new StkContext[mSimCount];
- mPowerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
- mStkCmdReceiver = new StkCmdReceiver();
- registerReceiver(mStkCmdReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
+
for (i = 0; i < mSimCount; i++) {
CatLog.d(LOG_TAG, "slotId: " + i);
mStkService[i] = CatService.getInstance(i);
@@ -373,11 +376,7 @@
@Override
public void onDestroy() {
CatLog.d(LOG_TAG, "onDestroy()");
- if (mStkCmdReceiver != null) {
- unregisterReceiver(mStkCmdReceiver);
- mStkCmdReceiver = null;
- }
- mPowerManager = null;
+ unregisterProcessObserver();
sInstance = null;
waitForLooper();
mServiceLooper.quit();
@@ -657,7 +656,7 @@
if (cardStatus == false) {
CatLog.d(LOG_TAG, "CARD is ABSENT");
// Uninstall STKAPP, Clear Idle text, Stop StkAppService
- mNotificationManager.cancel(getNotificationId(slotId));
+ cancelIdleText(slotId);
mStkContext[slotId].mCurrentMenu = null;
mStkContext[slotId].mMainCmd = null;
if (isAllOtherCardsAbsent(slotId)) {
@@ -673,7 +672,7 @@
if ((state.refreshResult == IccRefreshResponse.REFRESH_RESULT_INIT) ||
(state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET)) {
// Clear Idle Text
- mNotificationManager.cancel(getNotificationId(slotId));
+ cancelIdleText(slotId);
}
if (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) {
@@ -707,12 +706,31 @@
}
}
- /*
- * If the device is not in an interactive state, we can assume
- * that the screen is idle.
- */
- private boolean isScreenIdle() {
- return (!mPowerManager.isInteractive());
+ /* package */ boolean isScreenIdle() {
+ ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
+ List<RunningTaskInfo> tasks = am.getRunningTasks(1);
+ if (tasks == null || tasks.isEmpty()) {
+ return false;
+ }
+
+ String top = tasks.get(0).topActivity.getPackageName();
+ if (top == null) {
+ return false;
+ }
+
+ // We can assume that the screen is idle if the home application is in the foreground.
+ final Intent intent = new Intent(Intent.ACTION_MAIN, null);
+ intent.addCategory(Intent.CATEGORY_HOME);
+
+ ResolveInfo info = getPackageManager().resolveActivity(intent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ if (info != null) {
+ if (top.equals(info.activityInfo.packageName)) {
+ return true;
+ }
+ }
+
+ return false;
}
private void handleIdleScreen(int slotId) {
@@ -722,8 +740,9 @@
CatLog.d(this, "Need to send IDLE SCREEN Available event to SIM");
checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId);
- if (mStkContext[slotId].mIdleModeTextCmd != null) {
- launchIdleText(slotId);
+ if (mStkContext[slotId].mIdleModeTextCmd != null
+ && !mStkContext[slotId].mIdleModeTextVisible) {
+ launchIdleText(slotId);
}
}
@@ -977,14 +996,17 @@
waitForUsersResponse = false;
mStkContext[slotId].mIdleModeTextCmd = mStkContext[slotId].mCurrentCmd;
TextMessage idleModeText = mStkContext[slotId].mCurrentCmd.geTextMessage();
- if (idleModeText == null) {
- launchIdleText(slotId);
- mStkContext[slotId].mIdleModeTextCmd = null;
+ if (idleModeText == null || TextUtils.isEmpty(idleModeText.text)) {
+ cancelIdleText(slotId);
}
mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
- if ((mStkContext[slotId].mIdleModeTextCmd != null) && isScreenIdle()) {
- CatLog.d(this, "set up idle mode");
- launchIdleText(slotId);
+ if (mStkContext[slotId].mIdleModeTextCmd != null) {
+ if (mStkContext[slotId].mIdleModeTextVisible || isScreenIdle()) {
+ CatLog.d(this, "set up idle mode");
+ launchIdleText(slotId);
+ } else {
+ registerProcessObserver();
+ }
}
break;
case SEND_DTMF:
@@ -1069,10 +1091,7 @@
launchEventMessage(slotId);
break;
case SET_UP_EVENT_LIST:
- mStkContext[slotId].mSetupEventListSettings =
- mStkContext[slotId].mCurrentCmd.getSetEventList();
- mStkContext[slotId].mCurrentSetupEventCmd = mStkContext[slotId].mCurrentCmd;
- mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
+ replaceEventList(slotId);
if (isScreenIdle()) {
CatLog.d(this," Check if IDLE_SCREEN_AVAILABLE_EVENT is present in List");
checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId);
@@ -1437,6 +1456,123 @@
return activated;
}
+ private void replaceEventList(int slotId) {
+ if (mStkContext[slotId].mSetupEventListSettings != null) {
+ for (int current : mStkContext[slotId].mSetupEventListSettings.eventList) {
+ if (current != INVALID_SETUP_EVENT) {
+ // Cancel the event notification if it is not listed in the new event list.
+ if ((mStkContext[slotId].mCurrentCmd.getSetEventList() == null)
+ || !findEvent(current, mStkContext[slotId].mCurrentCmd
+ .getSetEventList().eventList)) {
+ unregisterEvent(current, slotId);
+ }
+ }
+ }
+ }
+ mStkContext[slotId].mSetupEventListSettings
+ = mStkContext[slotId].mCurrentCmd.getSetEventList();
+ mStkContext[slotId].mCurrentSetupEventCmd = mStkContext[slotId].mCurrentCmd;
+ mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
+ registerEvents(slotId);
+ }
+
+ private boolean findEvent(int event, int[] eventList) {
+ for (int content : eventList) {
+ if (content == event) return true;
+ }
+ return false;
+ }
+
+ private void unregisterEvent(int event, int slotId) {
+ switch (event) {
+ case IDLE_SCREEN_AVAILABLE_EVENT:
+ unregisterProcessObserver(AppInterface.CommandType.SET_UP_EVENT_LIST, slotId);
+ break;
+ case LANGUAGE_SELECTION_EVENT:
+ default:
+ break;
+ }
+ }
+
+ private void registerEvents(int slotId) {
+ if (mStkContext[slotId].mSetupEventListSettings == null) {
+ return;
+ }
+ for (int event : mStkContext[slotId].mSetupEventListSettings.eventList) {
+ switch (event) {
+ case IDLE_SCREEN_AVAILABLE_EVENT:
+ registerProcessObserver();
+ break;
+ case LANGUAGE_SELECTION_EVENT:
+ default:
+ break;
+ }
+ }
+ }
+
+ private synchronized void registerProcessObserver() {
+ if (mProcessObserver == null) {
+ try {
+ IProcessObserver.Stub observer = new IProcessObserver.Stub() {
+ @Override
+ public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
+ if (isScreenIdle()) {
+ Message message = mServiceHandler.obtainMessage();
+ message.arg1 = OP_IDLE_SCREEN;
+ mServiceHandler.sendMessage(message);
+ unregisterProcessObserver();
+ }
+ }
+
+ @Override
+ public void onProcessDied(int pid, int uid) {
+ }
+ };
+ ActivityManagerNative.getDefault().registerProcessObserver(observer);
+ mProcessObserver = observer;
+ } catch (RemoteException e) {
+ CatLog.d(this, "Failed to register the process observer");
+ }
+ }
+ }
+
+ private void unregisterProcessObserver(AppInterface.CommandType command, int slotId) {
+ // Check if there is any pending command which still needs the process observer
+ // except for the current command and slot.
+ for (int slot = PhoneConstants.SIM_ID_1; slot < mSimCount; slot++) {
+ if (command != AppInterface.CommandType.SET_UP_IDLE_MODE_TEXT || slot != slotId) {
+ if (mStkContext[slot].mIdleModeTextCmd != null
+ && !mStkContext[slot].mIdleModeTextVisible) {
+ // Keep the process observer registered
+ // as there is an idle mode text which has not been visible yet.
+ return;
+ }
+ }
+ if (command != AppInterface.CommandType.SET_UP_EVENT_LIST || slot != slotId) {
+ if (mStkContext[slot].mSetupEventListSettings != null) {
+ if (findEvent(IDLE_SCREEN_AVAILABLE_EVENT,
+ mStkContext[slot].mSetupEventListSettings.eventList)) {
+ // Keep the process observer registered
+ // as there is a SIM card which still want IDLE SCREEN AVAILABLE event.
+ return;
+ }
+ }
+ }
+ }
+ unregisterProcessObserver();
+ }
+
+ private synchronized void unregisterProcessObserver() {
+ if (mProcessObserver != null) {
+ try {
+ ActivityManagerNative.getDefault().unregisterProcessObserver(mProcessObserver);
+ mProcessObserver = null;
+ } catch (RemoteException e) {
+ CatLog.d(this, "Failed to unregister the process observer");
+ }
+ }
+ }
+
private void sendSetUpEventResponse(int event, byte[] addedInfo, int slotId) {
CatLog.d(this, "sendSetUpEventResponse: event : " + event + "slotId = " + slotId);
@@ -1498,7 +1634,7 @@
}
}
- private void removeSetUpEvent(int event, int slotId) {
+ private void removeSetUpEvent(int event, int slotId) {
CatLog.d(this, "Remove Event :" + event);
if (mStkContext[slotId].mSetupEventListSettings != null) {
@@ -1508,6 +1644,16 @@
for (int i = 0; i < mStkContext[slotId].mSetupEventListSettings.eventList.length; i++) {
if (event == mStkContext[slotId].mSetupEventListSettings.eventList[i]) {
mStkContext[slotId].mSetupEventListSettings.eventList[i] = INVALID_SETUP_EVENT;
+
+ switch (event) {
+ case IDLE_SCREEN_AVAILABLE_EVENT:
+ // The process observer can be unregistered
+ // as the idle screen has already been available.
+ unregisterProcessObserver();
+ break;
+ default:
+ break;
+ }
break;
}
}
@@ -1627,15 +1773,17 @@
} catch (InterruptedException e) {}
}
+ private void cancelIdleText(int slotId) {
+ unregisterProcessObserver(AppInterface.CommandType.SET_UP_IDLE_MODE_TEXT, slotId);
+ mNotificationManager.cancel(getNotificationId(slotId));
+ mStkContext[slotId].mIdleModeTextCmd = null;
+ mStkContext[slotId].mIdleModeTextVisible = false;
+ }
+
private void launchIdleText(int slotId) {
TextMessage msg = mStkContext[slotId].mIdleModeTextCmd.geTextMessage();
- if (msg == null || msg.text ==null) {
- CatLog.d(LOG_TAG, msg == null ? "mCurrent.getTextMessage is NULL"
- : "mCurrent.getTextMessage.text is NULL");
- mNotificationManager.cancel(getNotificationId(slotId));
- return;
- } else {
+ if (msg != null && !TextUtils.isEmpty(msg.text)) {
CatLog.d(LOG_TAG, "launchIdleText - text[" + msg.text
+ "] iconSelfExplanatory[" + msg.iconSelfExplanatory
+ "] icon[" + msg.icon + "], sim id: " + slotId);
@@ -1672,6 +1820,7 @@
notificationBuilder.setColor(mContext.getResources().getColor(
com.android.internal.R.color.system_notification_accent_color));
mNotificationManager.notify(getNotificationId(slotId), notificationBuilder.build());
+ mStkContext[slotId].mIdleModeTextVisible = true;
}
}
diff --git a/src/com/android/stk/StkCmdReceiver.java b/src/com/android/stk/StkCmdReceiver.java
index fd6f382..d011eee 100644
--- a/src/com/android/stk/StkCmdReceiver.java
+++ b/src/com/android/stk/StkCmdReceiver.java
@@ -49,8 +49,6 @@
handleLocaleChange(context);
} else if (action.equals(AppInterface.CAT_ALPHA_NOTIFY_ACTION)) {
handleAction(context, intent, StkAppService.OP_ALPHA_NOTIFY);
- } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
- handleIdleScreen(context);
}
}
@@ -95,11 +93,4 @@
context.startService(new Intent(context, StkAppService.class)
.putExtras(args));
}
-
- private void handleIdleScreen(Context context) {
- Bundle args = new Bundle();
- args.putInt(StkAppService.OPCODE, StkAppService.OP_IDLE_SCREEN);
- context.startService(new Intent(context, StkAppService.class)
- .putExtras(args));
- }
}