Skip CARRIER_CONFIG_CHANGED broadcast if SIM not loaded.

Context: App listens to CARRIER_CONFIG_CHANGED broadcast to detect SIM swap.
If a valid subId is in the broadcast intent extras and the subId has changed
for the same slotId, this is a SIM swap and should start entitlement check.

Issue: In case of SIM PIN, CARRIER_CONFIG_CHANGED is sent before SIM PIN
unlocked. And if the entitlement check happens before unlock (timing is
related), it will read null mccmnc from SIM, causing EAP_ID=null and
entitlement check failure. Even though another CARRIER_CONFIG_CHANGED is
sent after PIN locked, since the subId doesn't change, no entitlement check
is redone.

Fix: Check the SIM state on CARRIER_CONFIG_CHANGED, and skip the
broadcast if it's not SIM_STATE_LOADED.

Bug: 200836877
Test: manual, SIM swap with SIM PIN
Test: unit test
Merged-In: I555382fdd5eafb25bbfe428e66de403b0314b155
Change-Id: I555382fdd5eafb25bbfe428e66de403b0314b155
diff --git a/src/com/android/imsserviceentitlement/ImsEntitlementReceiver.java b/src/com/android/imsserviceentitlement/ImsEntitlementReceiver.java
index dc78b0a..d1d3a97 100644
--- a/src/com/android/imsserviceentitlement/ImsEntitlementReceiver.java
+++ b/src/com/android/imsserviceentitlement/ImsEntitlementReceiver.java
@@ -16,6 +16,8 @@
 
 package com.android.imsserviceentitlement;
 
+import static android.telephony.TelephonyManager.SIM_STATE_LOADED;
+
 import static com.android.imsserviceentitlement.entitlement.EntitlementConfiguration.ClientBehavior.NEEDS_TO_RESET;
 import static com.android.imsserviceentitlement.entitlement.EntitlementConfiguration.ClientBehavior.VALID_DURING_VALIDITY;
 import static com.android.imsserviceentitlement.entitlement.EntitlementConfiguration.ClientBehavior.VALID_WITHOUT_DURATION;
@@ -68,6 +70,8 @@
                         SubscriptionManager.INVALID_SIM_SLOT_INDEX);
         Dependencies dependencies = createDependency(context, currentSubId);
         if (!dependencies.userManager.isSystemUser()
+                || !SubscriptionManager.isValidSubscriptionId(currentSubId)
+                || dependencies.telephonyUtils.getSimApplicationState() != SIM_STATE_LOADED
                 || !TelephonyUtils.isImsProvisioningRequired(context, currentSubId)) {
             return;
         }
@@ -89,9 +93,6 @@
     private void handleCarrierConfigChanged(
             Context context, int currentSubId, int slotId, JobManager jobManager,
             PendingResult result) {
-        if (!SubscriptionManager.isValidSubscriptionId(currentSubId)) {
-            return;
-        }
         boolean shouldQuery = false;
 
         // Handle device boot up.
diff --git a/src/com/android/imsserviceentitlement/utils/TelephonyUtils.java b/src/com/android/imsserviceentitlement/utils/TelephonyUtils.java
index 2601fd8..e968c2f 100644
--- a/src/com/android/imsserviceentitlement/utils/TelephonyUtils.java
+++ b/src/com/android/imsserviceentitlement/utils/TelephonyUtils.java
@@ -98,6 +98,11 @@
         return mTelephonyManager.getSimSpecificCarrierId();
     }
 
+    /** Returns SIM card application state. */
+    public int getSimApplicationState() {
+        return mTelephonyManager.getSimApplicationState();
+    }
+
     /**
      * Returns {@code true} if the {@code subId} still point to a actived SIM; {@code false}
      * otherwise.
diff --git a/tests/unittests/src/com/android/imsserviceentitlement/ImsEntitlementReceiverTest.java b/tests/unittests/src/com/android/imsserviceentitlement/ImsEntitlementReceiverTest.java
index dbea9a1..444db10 100644
--- a/tests/unittests/src/com/android/imsserviceentitlement/ImsEntitlementReceiverTest.java
+++ b/tests/unittests/src/com/android/imsserviceentitlement/ImsEntitlementReceiverTest.java
@@ -16,6 +16,9 @@
 
 package com.android.imsserviceentitlement;
 
+import static android.telephony.TelephonyManager.SIM_STATE_LOADED;
+import static android.telephony.TelephonyManager.SIM_STATE_PIN_REQUIRED;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.never;
@@ -117,6 +120,7 @@
         new EntitlementConfiguration(mContext, SUB_ID).reset();
 
         when(mMockUserManager.isSystemUser()).thenReturn(true);
+        when(mMockTelephonyUtils.getSimApplicationState()).thenReturn(SIM_STATE_LOADED);
 
         setLastSubId(LAST_SUB_ID, 0);
         setupCarrierConfig();
@@ -133,6 +137,29 @@
     }
 
     @Test
+    public void onReceive_simChanged_simPinLockedThenLoaded() {
+        // SIM PIN locked
+        when(mMockTelephonyUtils.getSimApplicationState()).thenReturn(SIM_STATE_PIN_REQUIRED);
+
+        mReceiver.onReceive(mContext, getCarrierConfigChangedIntent(SUB_ID, /* slotId= */ 0));
+
+        // no-op
+        assertThat(
+                new EntitlementConfiguration(mContext, LAST_SUB_ID).getVoWifiStatus()).isEqualTo(1);
+        verify(mMockJobManager, never()).queryEntitlementStatusOnceNetworkReady();
+
+        // SIM LOADED
+        when(mMockTelephonyUtils.getSimApplicationState()).thenReturn(SIM_STATE_LOADED);
+
+        mReceiver.onReceive(mContext, getCarrierConfigChangedIntent(SUB_ID, /* slotId= */ 0));
+
+        // configuration reset and entitlement query scheduled.
+        assertThat(
+                new EntitlementConfiguration(mContext, LAST_SUB_ID).getVoWifiStatus()).isEqualTo(2);
+        verify(mMockJobManager, times(1)).queryEntitlementStatusOnceNetworkReady();
+    }
+
+    @Test
     public void onReceive_theSameSim_dataNotReset() {
         mReceiver.onReceive(
                 mContext, getCarrierConfigChangedIntent(LAST_SUB_ID, /* slotId= */ 0));