Broadcast new SIM state related intents.
Test: Basic telephony sanity
Bug: 64131518
Change-Id: I3b82a6d1545a0a22b61d41d161c3fa992d45962e
diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
index b9f0cbf..7a3293b 100644
--- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
+++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
@@ -16,6 +16,7 @@
package com.android.internal.telephony;
+import android.Manifest;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.UserSwitchObserver;
@@ -109,6 +110,8 @@
private static Context mContext = null;
private static String mIccId[] = new String[PROJECT_SIM_NUM];
private static int[] mInsertSimState = new int[PROJECT_SIM_NUM];
+ private static int[] sSimCardState = new int[PROJECT_SIM_NUM];
+ private static int[] sSimApplicationState = new int[PROJECT_SIM_NUM];
private SubscriptionManager mSubscriptionManager = null;
private EuiccManager mEuiccManager;
private IPackageManager mPackageManager;
@@ -264,6 +267,8 @@
case EVENT_SIM_UNKNOWN:
updateCarrierServices(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN);
broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN, null);
+ broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_UNKNOWN);
+ broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_UNKNOWN);
break;
case EVENT_SIM_IO_ERROR:
@@ -275,10 +280,14 @@
broadcastSimStateChanged(msg.arg1,
IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED,
IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED);
+ broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_CARD_RESTRICTED);
+ broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY);
break;
case EVENT_SIM_READY:
broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_READY, null);
+ broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_PRESENT);
+ broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY);
break;
case EVENT_SIM_IMSI:
@@ -288,6 +297,8 @@
case EVENT_SIM_NOT_READY:
broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_NOT_READY,
null);
+ broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_PRESENT);
+ broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY);
// intentional fall through
// ICC_NOT_READY is a terminal state for an eSIM on the boot profile. At this
// phase, the subscription list is accessible.
@@ -347,6 +358,24 @@
updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED);
broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED, reason);
+ broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_PRESENT);
+ broadcastSimApplicationStateChanged(slotId, getSimStateFromLockedReason(reason));
+ }
+
+ private static int getSimStateFromLockedReason(String lockedReason) {
+ switch (lockedReason) {
+ case IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN:
+ return TelephonyManager.SIM_STATE_PIN_REQUIRED;
+ case IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK:
+ return TelephonyManager.SIM_STATE_PUK_REQUIRED;
+ case IccCardConstants.INTENT_VALUE_LOCKED_NETWORK:
+ return TelephonyManager.SIM_STATE_NETWORK_LOCKED;
+ case IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED:
+ return TelephonyManager.SIM_STATE_PERM_DISABLED;
+ default:
+ Rlog.e(LOG_TAG, "Unexpected SIM locked reason " + lockedReason);
+ return TelephonyManager.SIM_STATE_UNKNOWN;
+ }
}
private void handleSimLoaded(int slotId) {
@@ -455,6 +484,8 @@
mContext.getContentResolver(), mCurrentlyActiveUserId);
broadcastSimStateChanged(loadedSlotId, IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
+ broadcastSimCardStateChanged(loadedSlotId, TelephonyManager.SIM_STATE_PRESENT);
+ broadcastSimApplicationStateChanged(loadedSlotId, TelephonyManager.SIM_STATE_LOADED);
updateCarrierServices(loadedSlotId, IccCardConstants.INTENT_VALUE_ICC_LOADED);
}
@@ -475,6 +506,8 @@
}
updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_ABSENT);
broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_ABSENT, null);
+ broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_ABSENT);
+ broadcastSimApplicationStateChanged(slotId, TelephonyManager.SIM_STATE_NOT_READY);
}
private void handleSimError(int slotId) {
@@ -488,6 +521,8 @@
updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR);
broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR,
IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR);
+ broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_CARD_IO_ERROR);
+ broadcastSimApplicationStateChanged(slotId, TelephonyManager.SIM_STATE_NOT_READY);
}
/**
@@ -799,6 +834,68 @@
IntentBroadcaster.getInstance().broadcastStickyIntent(i, slotId);
}
+ private void broadcastSimCardStateChanged(int phoneId, int state) {
+ if (state != sSimCardState[phoneId]) {
+ sSimCardState[phoneId] = state;
+ Intent i = new Intent(Intent.ACTION_SIM_CARD_STATE_CHANGED);
+ i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ i.putExtra(TelephonyManager.EXTRA_SIM_STATE, state);
+ SubscriptionManager.putPhoneIdAndSubIdExtra(i, phoneId);
+ logd("Broadcasting intent ACTION_SIM_CARD_STATE_CHANGED " + simStateString(state)
+ + " for phone: " + phoneId);
+ mContext.sendBroadcast(i, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+ }
+ }
+
+ private void broadcastSimApplicationStateChanged(int phoneId, int state) {
+ // Broadcast if the state has changed, except if old state was UNKNOWN and new is NOT_READY,
+ // because that's the initial state and a broadcast should be sent only on a transition
+ // after SIM is PRESENT
+ if (!(state == sSimApplicationState[phoneId]
+ || (state == TelephonyManager.SIM_STATE_NOT_READY
+ && sSimApplicationState[phoneId] == TelephonyManager.SIM_STATE_UNKNOWN))) {
+ sSimApplicationState[phoneId] = state;
+ Intent i = new Intent(Intent.ACTION_SIM_APPLICATION_STATE_CHANGED);
+ i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ i.putExtra(TelephonyManager.EXTRA_SIM_STATE, state);
+ SubscriptionManager.putPhoneIdAndSubIdExtra(i, phoneId);
+ logd("Broadcasting intent ACTION_SIM_APPLICATION_STATE_CHANGED " + simStateString(state)
+ + " for phone: " + phoneId);
+ mContext.sendBroadcast(i, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+ }
+ }
+
+ private static String simStateString(int state) {
+ switch (state) {
+ case TelephonyManager.SIM_STATE_UNKNOWN:
+ return "UNKNOWN";
+ case TelephonyManager.SIM_STATE_ABSENT:
+ return "ABSENT";
+ case TelephonyManager.SIM_STATE_PIN_REQUIRED:
+ return "PIN_REQUIRED";
+ case TelephonyManager.SIM_STATE_PUK_REQUIRED:
+ return "PUK_REQUIRED";
+ case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
+ return "NETWORK_LOCKED";
+ case TelephonyManager.SIM_STATE_READY:
+ return "READY";
+ case TelephonyManager.SIM_STATE_NOT_READY:
+ return "NOT_READY";
+ case TelephonyManager.SIM_STATE_PERM_DISABLED:
+ return "PERM_DISABLED";
+ case TelephonyManager.SIM_STATE_CARD_IO_ERROR:
+ return "CARD_IO_ERROR";
+ case TelephonyManager.SIM_STATE_CARD_RESTRICTED:
+ return "CARD_RESTRICTED";
+ case TelephonyManager.SIM_STATE_LOADED:
+ return "LOADED";
+ case TelephonyManager.SIM_STATE_PRESENT:
+ return "PRESENT";
+ default:
+ return "INVALID";
+ }
+ }
+
// Remove trailing F's from full hexadecimal IccId, as they should be considered padding
private String stripIccIdSuffix(String hexIccId) {
if (hexIccId == null) {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
index c0a2d9c..9310a99 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
@@ -122,6 +122,8 @@
replaceInstance(SubscriptionInfoUpdater.class, "mInsertSimState", null, new int[1]);
replaceInstance(SubscriptionInfoUpdater.class, "mContext", null, null);
replaceInstance(SubscriptionInfoUpdater.class, "PROJECT_SIM_NUM", null, 1);
+ replaceInstance(SubscriptionInfoUpdater.class, "sSimCardState", null, new int[1]);
+ replaceInstance(SubscriptionInfoUpdater.class, "sSimApplicationState", null, new int[1]);
replaceInstance(EuiccController.class, "sInstance", null, mEuiccController);
replaceInstance(IntentBroadcaster.class, "sIntentBroadcaster", null, mIntentBroadcaster);
@@ -388,6 +390,10 @@
replaceInstance(SubscriptionInfoUpdater.class, "mInsertSimState", null,
new int[]{SubscriptionInfoUpdater.SIM_NOT_CHANGE,
SubscriptionInfoUpdater.SIM_NOT_CHANGE});
+ replaceInstance(SubscriptionInfoUpdater.class, "sSimCardState", null,
+ new int[]{0, 0});
+ replaceInstance(SubscriptionInfoUpdater.class, "sSimApplicationState", null,
+ new int[]{0, 0});
doReturn(new int[]{FAKE_SUB_ID_1, FAKE_SUB_ID_2}).when(mSubscriptionManager)
.getActiveSubscriptionIdList();