Showing up network selection notification if out of service for a while.
1. In case network selection notification shows up repeatedly under
unstable network condition. Should check the service state is out of
service for a while then shows up No Service Notification.
2. Support multi-sim for network selection notification.
3. Dismiss network selection notification if sub id is inactive.
Bug: 72380747
Bug: 110119009
Test: In manual
1. Check the Notification should not show up under Automatically
select network mode.
2. In case under Manual select mode, the Notification should not
show up when selected a valid PLMN (Camped on).
3. In case under Manual select mode, the Notification show up
after 10 secends when selected a forbidden PLMN.
Change-Id: I94d8ea2f903e219ead8236eb17f364a306577a52
Merged-In: Ic37fa8edb1868dffff9c9d4d63c4ee4f9b38d8b0
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index 5aa87d0..de3fffc 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -30,7 +30,10 @@
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.net.Uri;
+import android.os.Handler;
+import android.os.Message;
import android.os.PersistableBundle;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -50,6 +53,7 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.SparseArray;
import android.widget.Toast;
import com.android.internal.telephony.Phone;
@@ -89,6 +93,14 @@
static final int DATA_DISCONNECTED_ROAMING_NOTIFICATION = 5;
static final int SELECTED_OPERATOR_FAIL_NOTIFICATION = 6;
+ // Event for network selection notification.
+ private static final int EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION = 1;
+
+ private static final long NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIME_IN_MS = 10000L;
+ private static final int NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIMES = 10;
+
+ private static final int STATE_UNKNOWN_SERVICE = -1;
+
/** The singleton NotificationMgr instance. */
private static NotificationMgr sInstance;
@@ -103,12 +115,36 @@
private TelecomManager mTelecomManager;
private TelephonyManager mTelephonyManager;
- // used to track the notification of selected network unavailable
- private boolean mSelectedUnavailableNotify = false;
+ // used to track the notification of selected network unavailable, per subscription id.
+ private SparseArray<Boolean> mSelectedUnavailableNotify = new SparseArray<>();
// used to track whether the message waiting indicator is visible, per subscription id.
private ArrayMap<Integer, Boolean> mMwiVisible = new ArrayMap<Integer, Boolean>();
+ // those flags are used to track whether to show network selection notification or not.
+ private SparseArray<Integer> mPreviousServiceState = new SparseArray<>();
+ private SparseArray<Long> mOOSTimestamp = new SparseArray<>();
+ private SparseArray<Integer> mPendingEventCounter = new SparseArray<>();
+ // maps each subId to selected network operator name.
+ private SparseArray<String> mSelectedNetworkOperatorName = new SparseArray<>();
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION:
+ int subId = (int) msg.obj;
+ TelephonyManager telephonyManager =
+ mTelephonyManager.createForSubscriptionId(subId);
+ if (telephonyManager.getServiceState() != null) {
+ shouldShowNotification(telephonyManager.getServiceState().getState(),
+ subId);
+ }
+ break;
+ }
+ }
+ };
+
/**
* Private constructor (this is a singleton).
* @see #init(PhoneGlobals)
@@ -592,19 +628,21 @@
intent.putExtra(GsmUmtsOptions.EXTRA_SUB_ID, subId);
builder.setContentIntent(PendingIntent.getActivity(mContext, 0, intent, 0));
mNotificationManager.notifyAsUser(
- null /* tag */,
+ Integer.toString(subId) /* tag */,
SELECTED_OPERATOR_FAIL_NOTIFICATION,
builder.build(),
UserHandle.ALL);
+ mSelectedUnavailableNotify.put(subId, true);
}
/**
* Turn off the network selection "no service" notification
*/
- private void cancelNetworkSelection() {
+ private void cancelNetworkSelection(int subId) {
if (DBG) log("cancelNetworkSelection()...");
mNotificationManager.cancelAsUser(
- null /* tag */, SELECTED_OPERATOR_FAIL_NOTIFICATION, UserHandle.ALL);
+ Integer.toString(subId) /* tag */, SELECTED_OPERATOR_FAIL_NOTIFICATION,
+ UserHandle.ALL);
}
/**
@@ -645,18 +683,34 @@
+ (isManualSelection ? selectedNetworkOperatorName : ""));
}
- if (serviceState == ServiceState.STATE_OUT_OF_SERVICE && isManualSelection) {
- showNetworkSelection(selectedNetworkOperatorName, subId);
- mSelectedUnavailableNotify = true;
+ if (isManualSelection) {
+ mSelectedNetworkOperatorName.put(subId, selectedNetworkOperatorName);
+ shouldShowNotification(serviceState, subId);
} else {
- if (mSelectedUnavailableNotify) {
- cancelNetworkSelection();
- mSelectedUnavailableNotify = false;
- }
+ dismissNetworkSelectionNotification(subId);
+ clearUpNetworkSelectionNotificationParam(subId);
}
} else {
if (DBG) log("updateNetworkSelection()..." + "state = " +
serviceState + " not updating network due to invalid subId " + subId);
+ dismissNetworkSelectionNotificationForInactiveSubId();
+ }
+ }
+ }
+
+ private void dismissNetworkSelectionNotification(int subId) {
+ if (mSelectedUnavailableNotify.get(subId, false)) {
+ cancelNetworkSelection(subId);
+ mSelectedUnavailableNotify.remove(subId);
+ }
+ }
+
+ private void dismissNetworkSelectionNotificationForInactiveSubId() {
+ for (int i = 0; i < mSelectedUnavailableNotify.size(); i++) {
+ int subId = mSelectedUnavailableNotify.keyAt(i);
+ if (!mSubscriptionManager.isActiveSubId(subId)) {
+ dismissNetworkSelectionNotification(subId);
+ clearUpNetworkSelectionNotificationParam(subId);
}
}
}
@@ -677,4 +731,65 @@
private void logi(String msg) {
Log.i(LOG_TAG, msg);
}
+
+ /**
+ * In case network selection notification shows up repeatedly under
+ * unstable network condition. The logic is to check whether or not
+ * the service state keeps in no service condition for at least
+ * {@link #NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIME_IN_MS}.
+ * And checking {@link #NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIMES} times.
+ * To avoid the notification showing up for the momentary state.
+ */
+ private void shouldShowNotification(int serviceState, int subId) {
+ if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
+ if (mPreviousServiceState.get(subId, STATE_UNKNOWN_SERVICE)
+ != ServiceState.STATE_OUT_OF_SERVICE) {
+ mOOSTimestamp.put(subId, getTimeStamp());
+ }
+ if ((getTimeStamp() - mOOSTimestamp.get(subId, 0L)
+ >= NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIME_IN_MS)
+ || mPendingEventCounter.get(subId, 0)
+ > NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIMES) {
+ showNetworkSelection(mSelectedNetworkOperatorName.get(subId), subId);
+ clearUpNetworkSelectionNotificationParam(subId);
+ } else {
+ startPendingNetworkSelectionNotification(subId);
+ }
+ } else {
+ dismissNetworkSelectionNotification(subId);
+ }
+ mPreviousServiceState.put(subId, serviceState);
+ if (DBG) {
+ log("shouldShowNotification()..." + " subId = " + subId
+ + " serviceState = " + serviceState
+ + " mOOSTimestamp = " + mOOSTimestamp
+ + " mPendingEventCounter = " + mPendingEventCounter);
+ }
+ }
+
+ private void startPendingNetworkSelectionNotification(int subId) {
+ if (!mHandler.hasMessages(EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION, subId)) {
+ if (DBG) {
+ log("startPendingNetworkSelectionNotification: subId = " + subId);
+ }
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION, subId),
+ NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIME_IN_MS);
+ mPendingEventCounter.put(subId, mPendingEventCounter.get(subId, 0) + 1);
+ }
+ }
+
+ private void clearUpNetworkSelectionNotificationParam(int subId) {
+ if (mHandler.hasMessages(EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION, subId)) {
+ mHandler.removeMessages(EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION, subId);
+ }
+ mPreviousServiceState.remove(subId);
+ mOOSTimestamp.remove(subId);
+ mPendingEventCounter.remove(subId);
+ mSelectedNetworkOperatorName.remove(subId);
+ }
+
+ private static long getTimeStamp() {
+ return SystemClock.elapsedRealtime();
+ }
}