aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/java/com/android/internal/telephony/CarrierServiceBindHelper.java9
-rw-r--r--src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java144
-rw-r--r--src/java/com/android/internal/telephony/uicc/UiccController.java336
-rw-r--r--src/java/com/android/internal/telephony/uicc/UiccProfile.java9
-rw-r--r--src/java/com/android/internal/telephony/uicc/UiccSlot.java31
5 files changed, 511 insertions, 18 deletions
diff --git a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java
index dfa53b3958..960d794303 100644
--- a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java
+++ b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java
@@ -16,6 +16,7 @@
package com.android.internal.telephony;
+import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -200,7 +201,13 @@ public class CarrierServiceBindHelper {
}
}
- void updateForPhoneId(int phoneId, String simState) {
+ /**
+ * Update SIM state.
+ *
+ * @param phoneId The phone id.
+ * @param simState The legacy SIM state.
+ */
+ public void updateForPhoneId(int phoneId, @NonNull String simState) {
logdWithLocalLog("update binding for phoneId: " + phoneId + " simState: " + simState);
if (!SubscriptionManager.isValidPhoneId(phoneId)) {
return;
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
index 5be96c1234..9e314280e0 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
@@ -59,6 +59,7 @@ import android.telephony.SubscriptionManager.SubscriptionType;
import android.telephony.SubscriptionManager.UsageSetting;
import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.TelephonyManager;
+import android.telephony.TelephonyManager.SimState;
import android.telephony.TelephonyRegistryManager;
import android.telephony.UiccAccessRule;
import android.telephony.euicc.EuiccManager;
@@ -427,6 +428,10 @@ public class SubscriptionManagerService extends ISub.Stub {
@Override
public void onDatabaseLoaded() {
log("Subscription database has been loaded.");
+ for (int phoneId = 0; phoneId < mTelephonyManager.getActiveModemCount()
+ ; phoneId++) {
+ markSubscriptionsInactive(phoneId);
+ }
}
/**
@@ -826,7 +831,7 @@ public class SubscriptionManagerService extends ISub.Stub {
/**
* Mark all subscriptions on this SIM slot index inactive.
*
- * @param simSlotIndex The SIM slot index.
+ * @param simSlotIndex The logical SIM slot index (i.e. phone id).
*/
public void markSubscriptionsInactive(int simSlotIndex) {
mSubscriptionDatabaseManager.getAllSubscriptions().stream()
@@ -986,6 +991,15 @@ public class SubscriptionManagerService extends ISub.Stub {
}
/**
+ * Update the subscriptions on the logical SIM slot index (i.e. phone id).
+ *
+ * @param slotIndex The logical SIM slot index.
+ */
+ private void updateSubscriptions(int slotIndex) {
+
+ }
+
+ /**
* Get all subscription info records from SIMs that are inserted now or previously inserted.
*
* <p>
@@ -3175,6 +3189,134 @@ public class SubscriptionManagerService extends ISub.Stub {
}
/**
+ * Called when SIM state changed to absent.
+ *
+ * @param slotIndex The logical SIM slot index.
+ */
+ private void onSimAbsent(int slotIndex) {
+ if (mSlotIndexToSubId.containsKey(slotIndex)) {
+ // Re-enable the SIM when it's removed, so it will be in enabled state when it gets
+ // re-inserted again. (pre-U behavior)
+ mSubscriptionDatabaseManager.setUiccApplicationsEnabled(
+ mSlotIndexToSubId.get(slotIndex), true);
+ // When sim is absent, set the port index to invalid port index. (pre-U behavior)
+ mSubscriptionDatabaseManager.setPortIndex(mSlotIndexToSubId.get(slotIndex),
+ TelephonyManager.INVALID_PORT_INDEX);
+ }
+ updateSubscriptions(slotIndex);
+ }
+
+ /**
+ * Called when SIM state changed to locked.
+ *
+ * @param slotIndex The logical SIM slot index.
+ */
+ private void onSimLocked(int slotIndex) {
+
+ }
+
+ /**
+ * Called when SIM state changed to ready.
+ *
+ * @param slotIndex The logical SIM slot index.
+ */
+ private void onSimReady(int slotIndex) {
+
+ }
+
+ /**
+ * Called when SIM state changed to not ready.
+ *
+ * @param slotIndex The logical SIM slot index.
+ */
+ private void onSimNotReady(int slotIndex) {
+
+ }
+
+ /**
+ * Called when SIM encounters error.
+ *
+ * @param slotIndex The logical SIM slot index.
+ */
+ private void onSimError(int slotIndex) {
+
+ }
+
+ /**
+ * Called when SIM state changed to loaded.
+ *
+ * @param slotIndex The logical SIM slot index.
+ */
+ private void onSimLoaded(int slotIndex) {
+ }
+
+ /**
+ * Called when eSIM becomes inactive.
+ *
+ * @param slotIndex The logical SIM slot index.
+ */
+ public void updateSimStateForInactivePort(int slotIndex) {
+ mHandler.post(() -> {
+ if (mSlotIndexToSubId.containsKey(slotIndex)) {
+ // Re-enable the UICC application , so it will be in enabled state when it becomes
+ // active again. (pre-U behavior)
+ mSubscriptionDatabaseManager.setUiccApplicationsEnabled(
+ mSlotIndexToSubId.get(slotIndex), true);
+ updateSubscriptions(slotIndex);
+ }
+ });
+ }
+
+ /**
+ * Update SIM state. This method is supposed to be called by {@link UiccController} only.
+ *
+ * @param slotIndex The logical SIM slot index.
+ * @param simState SIM state.
+ * @param executor The executor to execute the callback.
+ * @param updateCompleteCallback The callback to call when subscription manager service
+ * completes subscription update. SIM state changed event will be broadcasted by
+ * {@link UiccController} upon receiving callback.
+ */
+ public void updateSimState(int slotIndex, @SimState int simState,
+ @Nullable @CallbackExecutor Executor executor,
+ @Nullable Runnable updateCompleteCallback) {
+ mHandler.post(() -> {
+ switch (simState) {
+ case TelephonyManager.SIM_STATE_ABSENT:
+ onSimAbsent(slotIndex);
+ break;
+ case TelephonyManager.SIM_STATE_PIN_REQUIRED:
+ case TelephonyManager.SIM_STATE_PUK_REQUIRED:
+ case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
+ case TelephonyManager.SIM_STATE_PERM_DISABLED:
+ onSimLocked(slotIndex);
+ break;
+ case TelephonyManager.SIM_STATE_READY:
+ onSimReady(slotIndex);
+ break;
+ case TelephonyManager.SIM_STATE_NOT_READY:
+ onSimNotReady(slotIndex);
+ break;
+ case TelephonyManager.SIM_STATE_CARD_IO_ERROR:
+ onSimError(slotIndex);
+ break;
+ case TelephonyManager.SIM_STATE_CARD_RESTRICTED:
+ // No specific things needed to be done. Just return and broadcast the SIM
+ // states.
+ break;
+ case TelephonyManager.SIM_STATE_LOADED:
+ onSimLoaded(slotIndex);
+ break;
+ default:
+ break;
+ }
+ if (executor != null && updateCompleteCallback != null) {
+ executor.execute(updateCompleteCallback);
+ }
+ });
+ }
+
+ /**
* Log debug messages.
*
* @param s debug messages
diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java
index 70cfce00b6..94d5d3bef8 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccController.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccController.java
@@ -21,6 +21,8 @@ import static android.telephony.TelephonyManager.UNSUPPORTED_CARD_ID;
import static java.util.Arrays.copyOf;
+import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.BroadcastOptions;
import android.compat.annotation.UnsupportedAppUsage;
@@ -38,8 +40,10 @@ import android.preference.PreferenceManager;
import android.sysprop.TelephonyProperties;
import android.telephony.AnomalyReporter;
import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.telephony.TelephonyManager.SimState;
import android.telephony.UiccCardInfo;
import android.telephony.UiccPortInfo;
import android.telephony.UiccSlotMapping;
@@ -49,14 +53,20 @@ import android.util.LocalLog;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.CarrierServiceBindHelper;
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.IccCard;
import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.IntentBroadcaster;
import com.android.internal.telephony.PhoneConfigurationManager;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.RadioConfig;
import com.android.internal.telephony.SubscriptionInfoUpdater;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.metrics.TelephonyMetrics;
+import com.android.internal.telephony.subscription.SubscriptionManagerService;
import com.android.internal.telephony.uicc.euicc.EuiccCard;
import com.android.internal.telephony.util.TelephonyUtils;
import com.android.telephony.Rlog;
@@ -140,6 +150,9 @@ public class UiccController extends Handler {
private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 10;
// NOTE: any new EVENT_* values must be added to eventToString.
+ @NonNull
+ private final TelephonyManager mTelephonyManager;
+
// this needs to be here, because on bootup we dont know which index maps to which UiccSlot
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private CommandsInterface[] mCis;
@@ -151,11 +164,25 @@ public class UiccController extends Handler {
// This maps the externally exposed card ID (int) to the internal card ID string (ICCID/EID).
// The array index is the card ID (int).
// This mapping exists to expose card-based functionality without exposing the EID, which is
- // considered sensetive information.
+ // considered sensitive information.
// mCardStrings is populated using values from the IccSlotStatus and IccCardStatus. For
// HAL < 1.2, these do not contain the EID or the ICCID, so mCardStrings will be empty
private ArrayList<String> mCardStrings;
+ /**
+ * SIM card state.
+ */
+ @NonNull
+ @SimState
+ private final int[] mSimCardState;
+
+ /**
+ * SIM application state.
+ */
+ @NonNull
+ @SimState
+ private final int[] mSimApplicationState;
+
// This is the card ID of the default eUICC. It starts as UNINITIALIZED_CARD_ID.
// When we load the EID (either with slot status or from the EuiccCard), we set it to the eUICC
// with the lowest slot index.
@@ -205,6 +232,9 @@ public class UiccController extends Handler {
protected RegistrantList mIccChangedRegistrants = new RegistrantList();
+ @NonNull
+ private final CarrierServiceBindHelper mCarrierServiceBindHelper;
+
private UiccStateChangedLauncher mLauncher;
private RadioConfig mRadioConfig;
@@ -243,8 +273,13 @@ public class UiccController extends Handler {
numPhysicalSlots = mCis.length;
}
+ mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+
mUiccSlots = new UiccSlot[numPhysicalSlots];
mPhoneIdToSlotId = new int[mCis.length];
+ int supportedModemCount = mTelephonyManager.getSupportedModemCount();
+ mSimCardState = new int[supportedModemCount];
+ mSimApplicationState = new int[supportedModemCount];
Arrays.fill(mPhoneIdToSlotId, INVALID_SLOT_ID);
if (VDBG) logPhoneIdToSlotIdMapping();
mRadioConfig = RadioConfig.getInstance();
@@ -260,6 +295,8 @@ public class UiccController extends Handler {
mCardStrings = loadCardStrings();
mDefaultEuiccCardId = UNINITIALIZED_CARD_ID;
+ mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext);
+
mEuiccSlots = mContext.getResources()
.getIntArray(com.android.internal.R.array.non_removable_euicc_slots);
mHasBuiltInEuicc = hasBuiltInEuicc();
@@ -300,13 +337,11 @@ public class UiccController extends Handler {
@UnsupportedAppUsage
public static UiccController getInstance() {
- synchronized (mLock) {
- if (mInstance == null) {
- throw new RuntimeException(
- "UiccController.getInstance can't be called before make()");
- }
- return mInstance;
+ if (mInstance == null) {
+ throw new RuntimeException(
+ "UiccController.getInstance can't be called before make()");
}
+ return mInstance;
}
@UnsupportedAppUsage
@@ -739,6 +774,293 @@ public class UiccController extends Handler {
}
}
+ /**
+ * Update SIM state for the inactive eSIM port.
+ *
+ * @param phoneId Previously active phone id.
+ * @param iccId ICCID of the SIM.
+ */
+ public void updateSimStateForInactivePort(int phoneId, String iccId) {
+ post(() -> {
+ if (SubscriptionManager.isValidPhoneId(phoneId)) {
+ // Mark SIM state as ABSENT on previously phoneId.
+ mTelephonyManager.setSimStateForPhone(phoneId,
+ IccCardConstants.State.ABSENT.toString());
+ }
+
+ SubscriptionManagerService.getInstance().updateSimStateForInactivePort(phoneId);
+ });
+ }
+
+ /**
+ * Broadcast the legacy SIM state changed event.
+ *
+ * @param phoneId The phone id.
+ * @param state The legacy SIM state.
+ * @param reason The reason of SIM state change.
+ */
+ private void broadcastSimStateChanged(int phoneId, @NonNull String state,
+ @Nullable String reason) {
+ // Note: This intent is way deprecated and is only being kept around because there's no
+ // graceful way to deprecate a sticky broadcast that has a lot of listeners.
+ // DO NOT add any new extras to this broadcast -- it is not protected by any permissions.
+ Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
+ intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, state);
+ intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
+ SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
+ Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_STATE_CHANGED " + state + " reason "
+ + reason + " for phone: " + phoneId);
+ IntentBroadcaster.getInstance().broadcastStickyIntent(mContext, intent, phoneId);
+ }
+
+ /**
+ * Broadcast SIM card state changed event.
+ *
+ * @param phoneId The phone id.
+ * @param state The SIM card state.
+ */
+ private void broadcastSimCardStateChanged(int phoneId, @SimState int state) {
+ if (state != mSimCardState[phoneId]) {
+ mSimCardState[phoneId] = state;
+ Intent intent = new Intent(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.putExtra(TelephonyManager.EXTRA_SIM_STATE, state);
+ SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
+ // TODO(b/130664115) we manually populate this intent with the slotId. In the future we
+ // should do a review of whether to make this public
+ UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId);
+ int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId);
+ intent.putExtra(PhoneConstants.SLOT_KEY, slotId);
+ if (slot != null) {
+ intent.putExtra(PhoneConstants.PORT_KEY, slot.getPortIndexFromPhoneId(phoneId));
+ }
+ Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_CARD_STATE_CHANGED "
+ + TelephonyManager.simStateToString(state) + " for phone: " + phoneId
+ + " slot: " + slotId + " port: " + slot.getPortIndexFromPhoneId(phoneId));
+ mContext.sendBroadcast(intent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+ TelephonyMetrics.getInstance().updateSimState(phoneId, state);
+ }
+ }
+
+ /**
+ * Broadcast SIM application state changed event.
+ *
+ * @param phoneId The phone id.
+ * @param state The SIM application state.
+ */
+ private void broadcastSimApplicationStateChanged(int phoneId, @SimState 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. The only exception is eSIM boot profile, where NOT_READY is the
+ // terminal state.
+ boolean isUnknownToNotReady =
+ (mSimApplicationState[phoneId] == TelephonyManager.SIM_STATE_UNKNOWN
+ && state == TelephonyManager.SIM_STATE_NOT_READY);
+ IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard();
+ boolean emptyProfile = iccCard != null && iccCard.isEmptyProfile();
+ if (state != mSimApplicationState[phoneId] && (!isUnknownToNotReady || emptyProfile)) {
+ mSimApplicationState[phoneId] = state;
+ Intent intent = new Intent(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.putExtra(TelephonyManager.EXTRA_SIM_STATE, state);
+ SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
+ // TODO(b/130664115) we populate this intent with the actual slotId. In the future we
+ // should do a review of whether to make this public
+ UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId);
+ int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId);
+ intent.putExtra(PhoneConstants.SLOT_KEY, slotId);
+ if (slot != null) {
+ intent.putExtra(PhoneConstants.PORT_KEY, slot.getPortIndexFromPhoneId(phoneId));
+ }
+ Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_APPLICATION_STATE_CHANGED "
+ + TelephonyManager.simStateToString(state)
+ + " for phone: " + phoneId + " slot: " + slotId + "port: "
+ + slot.getPortIndexFromPhoneId(phoneId));
+ mContext.sendBroadcast(intent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+ TelephonyMetrics.getInstance().updateSimState(phoneId, state);
+ }
+ }
+
+ /**
+ * Get SIM state from SIM lock reason.
+ *
+ * @param lockedReason The SIM lock reason.
+ *
+ * @return The SIM state.
+ */
+ @SimState
+ 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;
+ }
+ }
+
+ /**
+ * Broadcast SIM state events.
+ *
+ * @param phoneId The phone id.
+ * @param simState The SIM state.
+ * @param reason SIM state changed reason.
+ */
+ private void broadcastSimStateEvents(int phoneId, IccCardConstants.State simState,
+ @Nullable String reason) {
+ String legacyStringSimState = getIccStateIntentString(simState);
+ int cardState = TelephonyManager.SIM_STATE_UNKNOWN;
+ int applicationState = TelephonyManager.SIM_STATE_UNKNOWN;
+
+ switch (simState) {
+ case ABSENT:
+ cardState = TelephonyManager.SIM_STATE_ABSENT;
+ break;
+ case PIN_REQUIRED:
+ case PUK_REQUIRED:
+ case NETWORK_LOCKED:
+ case PERM_DISABLED:
+ cardState = TelephonyManager.SIM_STATE_PRESENT;
+ applicationState = getSimStateFromLockedReason(reason);
+ break;
+ case READY:
+ case NOT_READY:
+ // Both READY and NOT_READY have the same card state and application state.
+ cardState = TelephonyManager.SIM_STATE_PRESENT;
+ applicationState = TelephonyManager.SIM_STATE_NOT_READY;
+ break;
+ case CARD_IO_ERROR:
+ cardState = TelephonyManager.SIM_STATE_CARD_IO_ERROR;
+ applicationState = TelephonyManager.SIM_STATE_NOT_READY;
+ break;
+ case CARD_RESTRICTED:
+ cardState = TelephonyManager.SIM_STATE_CARD_RESTRICTED;
+ applicationState = TelephonyManager.SIM_STATE_NOT_READY;
+ break;
+ case LOADED:
+ cardState = TelephonyManager.SIM_STATE_PRESENT;
+ applicationState = TelephonyManager.SIM_STATE_LOADED;
+ break;
+ case UNKNOWN:
+ default:
+ break;
+ }
+
+ broadcastSimStateChanged(phoneId, legacyStringSimState, reason);
+ broadcastSimCardStateChanged(phoneId, cardState);
+ broadcastSimApplicationStateChanged(phoneId, applicationState);
+ }
+
+ /**
+ * Update carrier service.
+ *
+ * @param phoneId The phone id.
+ * @param simState The SIM state.
+ */
+ private void updateCarrierServices(int phoneId, @NonNull String simState) {
+ CarrierConfigManager configManager = mContext.getSystemService(CarrierConfigManager.class);
+ if (configManager != null) {
+ configManager.updateConfigForPhoneId(phoneId, simState);
+ }
+ mCarrierServiceBindHelper.updateForPhoneId(phoneId, simState);
+ }
+
+ /**
+ * Check if the SIM application is enabled on the card or not.
+ *
+ * @param phoneId The phone id.
+ * @return {@code true} if the application is enabled.
+ */
+ private boolean areUiccAppsEnabledOnCard(int phoneId) {
+ // When uicc apps are disabled(supported in IRadio 1.5), we will still get IccId from
+ // cardStatus (since IRadio 1.2). Amd upon cardStatus change we'll receive another
+ // handleSimNotReady so this will be evaluated again.
+ UiccSlot slot = getUiccSlotForPhone(phoneId);
+ if (slot == null) return false;
+ UiccPort port = getUiccPort(phoneId);
+ String iccId = (port == null) ? null : port.getIccId();
+ if (iccId == null) {
+ return false;
+ }
+ SubscriptionInfo info = SubscriptionManagerService.getInstance()
+ .getAllSubInfoList(mContext.getOpPackageName(), mContext.getAttributionTag())
+ .stream().filter(subInfo -> subInfo.getIccId().equals(
+ IccUtils.stripTrailingFs(iccId)))
+ .findFirst().orElse(null);
+ return info != null && info.areUiccApplicationsEnabled();
+ }
+
+ /**
+ * Update the SIM state.
+ *
+ * @param phoneId Phone id.
+ * @param state SIM state (legacy).
+ * @param reason The reason for SIM state update.
+ */
+ public void updateSimState(int phoneId, @NonNull IccCardConstants.State state,
+ @Nullable String reason) {
+ post(() -> {
+ log("updateSimState: phoneId=" + phoneId + ", state=" + state + ", reason="
+ + reason);
+ if (!SubscriptionManager.isValidPhoneId(phoneId)) {
+ Rlog.e(LOG_TAG, "updateInternalIccState: Invalid phone id " + phoneId);
+ return;
+ }
+
+ mTelephonyManager.setSimStateForPhone(phoneId, state.toString());
+
+ String legacySimState = getIccStateIntentString(state);
+ int simState = state.ordinal();
+ SubscriptionManagerService.getInstance().updateSimState(phoneId, simState,
+ this::post,
+ () -> {
+ // The following are executed after subscription update completed in
+ // subscription manager service.
+
+ broadcastSimStateEvents(phoneId, state, reason);
+
+ UiccProfile uiccProfile = getUiccProfileForPhone(phoneId);
+
+ if (simState == TelephonyManager.SIM_STATE_READY) {
+ // SIM_STATE_READY is not a final state.
+ return;
+ }
+
+ if (simState == TelephonyManager.SIM_STATE_NOT_READY
+ && (uiccProfile != null && !uiccProfile.isEmptyProfile())
+ && areUiccAppsEnabledOnCard(phoneId)) {
+ // STATE_NOT_READY is not a final state for when both
+ // 1) It's not an empty profile, and
+ // 2) Its uicc applications are set to enabled.
+ //
+ // At this phase, we consider STATE_NOT_READY not a final state, so
+ // return for now.
+ log("updateSimState: SIM_STATE_NOT_READY is not a final "
+ + "state.");
+ return;
+ }
+
+ // At this point, the SIM state must be a final state (meaning we won't
+ // get more SIM state updates). So resolve the carrier id and update the
+ // carrier services.
+ log("updateSimState: resolve carrier id and update carrier "
+ + "services.");
+ PhoneFactory.getPhone(phoneId).resolveSubscriptionCarrierId(
+ legacySimState);
+ updateCarrierServices(phoneId, legacySimState);
+ }
+ );
+ });
+ }
+
private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) {
if (ar.exception != null) {
Rlog.e(LOG_TAG,"Error getting ICC status. "
diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
index b1d8dc2335..746a3606d6 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
@@ -801,8 +801,13 @@ public class UiccProfile extends IccCard {
}
log("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState);
- UiccController.updateInternalIccState(mContext, mExternalState,
- getIccStateReason(mExternalState), mPhoneId);
+ if (PhoneFactory.isSubscriptionManagerServiceEnabled()) {
+ UiccController.getInstance().updateSimState(mPhoneId, mExternalState,
+ getIccStateReason(mExternalState));
+ } else {
+ UiccController.updateInternalIccState(mContext, mExternalState,
+ getIccStateReason(mExternalState), mPhoneId);
+ }
}
}
diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java
index 9b5b315b56..2490efa344 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java
@@ -187,9 +187,15 @@ public class UiccSlot extends Handler {
if (!iss.mSimPortInfos[i].mPortActive) {
// TODO: (b/79432584) evaluate whether should broadcast card state change
// even if it's inactive.
- UiccController.updateInternalIccStateForInactivePort(mContext,
- mPortIdxToPhoneId.getOrDefault(i, INVALID_PHONE_ID),
- iss.mSimPortInfos[i].mIccId);
+ if (PhoneFactory.isSubscriptionManagerServiceEnabled()) {
+ UiccController.getInstance().updateSimStateForInactivePort(
+ mPortIdxToPhoneId.getOrDefault(i, INVALID_PHONE_ID),
+ iss.mSimPortInfos[i].mIccId);
+ } else {
+ UiccController.updateInternalIccStateForInactivePort(mContext,
+ mPortIdxToPhoneId.getOrDefault(i, INVALID_PHONE_ID),
+ iss.mSimPortInfos[i].mIccId);
+ }
mLastRadioState.put(i, TelephonyManager.RADIO_POWER_UNAVAILABLE);
if (mUiccCard != null) {
// Dispose the port
@@ -321,8 +327,14 @@ public class UiccSlot extends Handler {
if (DBG) log("update: notify card removed");
sendMessage(obtainMessage(EVENT_CARD_REMOVED, null));
}
- UiccController.updateInternalIccState(mContext, IccCardConstants.State.ABSENT,
- null, phoneId);
+
+ if (PhoneFactory.isSubscriptionManagerServiceEnabled()) {
+ UiccController.getInstance().updateSimState(phoneId, IccCardConstants.State.ABSENT,
+ null);
+ } else {
+ UiccController.updateInternalIccState(mContext, IccCardConstants.State.ABSENT,
+ null, phoneId);
+ }
// no card present in the slot now; dispose card and make mUiccCard null
nullifyUiccCard(false /* sim state is not unknown */);
mLastRadioState.put(portIndex, TelephonyManager.RADIO_POWER_UNAVAILABLE);
@@ -575,8 +587,13 @@ public class UiccSlot extends Handler {
nullifyUiccCard(true /* sim state is unknown */);
if (phoneId != INVALID_PHONE_ID) {
- UiccController.updateInternalIccState(
- mContext, IccCardConstants.State.UNKNOWN, null, phoneId);
+ if (PhoneFactory.isSubscriptionManagerServiceEnabled()) {
+ UiccController.getInstance().updateSimState(phoneId,
+ IccCardConstants.State.UNKNOWN, null);
+ } else {
+ UiccController.updateInternalIccState(
+ mContext, IccCardConstants.State.UNKNOWN, null, phoneId);
+ }
mLastRadioState.put(getPortIndexFromPhoneId(phoneId),
TelephonyManager.RADIO_POWER_UNAVAILABLE);
}