Merge "Prevent advance <-> idle pingpong" into main
diff --git a/flags/data.aconfig b/flags/data.aconfig
index a993d51..0fd094d 100644
--- a/flags/data.aconfig
+++ b/flags/data.aconfig
@@ -121,3 +121,14 @@
   }
 }
 
+# OWNER=jackyu TARGET=25Q1
+flag {
+  name: "sim_disabled_graceful_tear_down"
+  namespace: "telephony"
+  description: "Gracefully tear down the networks when SIM is disabled."
+  bug: "362372940"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 6044746..6fe1232 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -5497,7 +5497,7 @@
     public void refreshSafetySources(String refreshBroadcastId) {
         if (mFeatureFlags.enableIdentifierDisclosureTransparencyUnsolEvents()
                 || mFeatureFlags.enableModemCipherTransparencyUnsolEvents()) {
-            mSafetySource.refresh(mContext, refreshBroadcastId);
+            post(() -> mSafetySource.refresh(mContext, refreshBroadcastId));
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/LocaleTracker.java b/src/java/com/android/internal/telephony/LocaleTracker.java
index 0afe119..42ec8d3 100644
--- a/src/java/com/android/internal/telephony/LocaleTracker.java
+++ b/src/java/com/android/internal/telephony/LocaleTracker.java
@@ -566,7 +566,7 @@
             }
 
             if (mFeatureFlags.oemEnabledSatelliteFlag()) {
-                TelephonyCountryDetector.getInstance(mPhone.getContext())
+                TelephonyCountryDetector.getInstance(mPhone.getContext(), mFeatureFlags)
                         .onNetworkCountryCodeChanged(mPhone, countryIso);
             }
             Intent intent = new Intent(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED);
diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java
index 0436ae5..e98b996 100644
--- a/src/java/com/android/internal/telephony/MultiSimSettingController.java
+++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java
@@ -642,7 +642,7 @@
         if (DBG) log("updateDefaultValues: change: " + change);
         if (change == PRIMARY_SUB_NO_CHANGE) return;
 
-        // If there's only one primary subscription active, we trigger PREFERRED_PICK_DIALOG
+        // If there's only one primary subscription active, we trigger mobile data
         // dialog if and only if there were multiple primary SIM cards and one is removed.
         // Otherwise, if user just inserted their first SIM, or there's one primary and one
         // opportunistic subscription active (activeSubInfos.size() > 1), we automatically
@@ -658,7 +658,19 @@
             if (hasCalling()) mSubscriptionManagerService.setDefaultVoiceSubId(subId);
             if (hasMessaging()) mSubscriptionManagerService.setDefaultSmsSubId(subId);
             if (!mSubscriptionManagerService.isEsimBootStrapProvisioningActivated()) {
-                sendDefaultSubConfirmedNotification(subId);
+                // Determines the appropriate notification type
+                // Preconditions:
+                // - There is only one active primary subscription.
+                // - The eSIM bootstrap is NOT activated.
+                // Behavior:
+                // - If the primary subscription is not deactivated OR the device is in single SIM
+                //   mode, send a notification to dismiss the SIM dialog.
+                // - Otherwise, send a notification to trigger the preferred SIM/data pick dialog.
+                @TelephonyManager.DefaultSubscriptionSelectType
+                int type = (change != PRIMARY_SUB_REMOVED || mActiveModemCount == 1)
+                        ? EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DISMISS
+                        : EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL;
+                sendDefaultSubConfirmedNotification(type, subId);
             }
             return;
         }
@@ -770,14 +782,14 @@
         }
     }
 
-    private void sendDefaultSubConfirmedNotification(int defaultSubId) {
+    private void sendDefaultSubConfirmedNotification(
+            @TelephonyManager.DefaultSubscriptionSelectType int type, int defaultSubId) {
         Intent intent = new Intent();
         intent.setAction(ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED);
         intent.setClassName("com.android.settings",
                 "com.android.settings.sim.SimSelectNotification");
 
-        intent.putExtra(EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE,
-                EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DISMISS);
+        intent.putExtra(EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE, type);
         intent.putExtra(EXTRA_SUBSCRIPTION_ID, defaultSubId);
 
         mContext.sendBroadcast(intent);
diff --git a/src/java/com/android/internal/telephony/TelephonyCountryDetector.java b/src/java/com/android/internal/telephony/TelephonyCountryDetector.java
index fed4931..b604431 100644
--- a/src/java/com/android/internal/telephony/TelephonyCountryDetector.java
+++ b/src/java/com/android/internal/telephony/TelephonyCountryDetector.java
@@ -43,6 +43,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.flags.FeatureFlags;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -109,6 +110,10 @@
     private Map<String, Long> mOverriddenCachedNetworkCountryCodes = new HashMap<>();
     @GuardedBy("mLock")
     private boolean mIsCountryCodesOverridden = false;
+    private final RegistrantList mCountryCodeChangedRegistrants = new RegistrantList();
+
+    private FeatureFlags mFeatureFlags = null;
+
     @NonNull private final LocationListener mLocationListener = new LocationListener() {
         @Override
         public void onLocationChanged(Location location) {
@@ -186,22 +191,26 @@
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     protected TelephonyCountryDetector(@NonNull Looper looper, @NonNull Context context,
             @NonNull LocationManager locationManager,
-            @NonNull ConnectivityManager connectivityManager) {
+            @NonNull ConnectivityManager connectivityManager,
+            FeatureFlags featureFlags) {
         super(looper);
         mLocationManager = locationManager;
         mGeocoder = new Geocoder(context);
         mConnectivityManager = connectivityManager;
+        mFeatureFlags = featureFlags;
         initialize();
     }
 
     /** @return the singleton instance of the {@link TelephonyCountryDetector} */
-    public static synchronized TelephonyCountryDetector getInstance(@NonNull Context context) {
+    public static synchronized TelephonyCountryDetector getInstance(@NonNull Context context,
+            FeatureFlags featureFlags) {
         if (sInstance == null) {
             HandlerThread handlerThread = new HandlerThread("TelephonyCountryDetector");
             handlerThread.start();
             sInstance = new TelephonyCountryDetector(handlerThread.getLooper(), context,
                     context.getSystemService(LocationManager.class),
-                    context.getSystemService(ConnectivityManager.class));
+                    context.getSystemService(ConnectivityManager.class),
+                    featureFlags);
         }
         return sInstance;
     }
@@ -473,6 +482,12 @@
             }
         }
         evaluateRequestingLocationUpdates();
+        if (mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("mCountryCodeChangedRegistrants.notifyRegistrants()");
+            mCountryCodeChangedRegistrants.notifyRegistrants();
+        } else {
+            logd("mCountryCodeChangedRegistrants.notifyRegistrants() is not called");
+        }
     }
 
     private void handleEventWifiConnectivityStateChanged() {
@@ -587,6 +602,26 @@
                 || SystemProperties.getBoolean(BOOT_ALLOW_MOCK_MODEM_PROPERTY, false));
     }
 
+    /**
+     * Register a callback for country code changed events
+     *
+     * @param h    Handler to notify
+     * @param what msg.what when the message is delivered
+     * @param obj  AsyncResult.userObj when the message is delivered
+     */
+    public void registerForCountryCodeChanged(Handler h, int what, Object obj) {
+        mCountryCodeChangedRegistrants.add(h, what, obj);
+    }
+
+    /**
+     * Unregister a callback for country code changed events
+     *
+     * @param h Handler to notifyf
+     */
+    public void unregisterForCountryCodeChanged(Handler h) {
+        mCountryCodeChangedRegistrants.remove(h);
+    }
+
     private static void logd(@NonNull String log) {
         Rlog.d(TAG, log);
     }
diff --git a/src/java/com/android/internal/telephony/data/DataEvaluation.java b/src/java/com/android/internal/telephony/data/DataEvaluation.java
index f5eae91..40c0081 100644
--- a/src/java/com/android/internal/telephony/data/DataEvaluation.java
+++ b/src/java/com/android/internal/telephony/data/DataEvaluation.java
@@ -225,6 +225,8 @@
         SIM_LOADED(true),
         /** SIM is removed. */
         SIM_REMOVAL(true),
+        /** SIM is disabled. */
+        SIM_DISABLED(true),
         /** Data profiles changed. */
         DATA_PROFILES_CHANGED(true),
         /** When service state changes.(For now only considering data RAT and data registration). */
diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java
index 89153ab..5d31283 100644
--- a/src/java/com/android/internal/telephony/data/DataNetworkController.java
+++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java
@@ -3543,15 +3543,6 @@
     }
 
     /**
-     * Called when SIM is absent.
-     */
-    private void onSimAbsent() {
-        log("onSimAbsent");
-        sendMessage(obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS,
-                DataEvaluationReason.SIM_REMOVAL));
-    }
-
-    /**
      * Called when SIM state changes.
      *
      * @param simState SIM state. (Note this is mixed with card state and application state.)
@@ -3559,13 +3550,22 @@
     private void onSimStateChanged(@SimState int simState) {
         log("onSimStateChanged: state=" + TelephonyManager.simStateToString(simState));
         if (mSimState != simState) {
-            mSimState = simState;
             if (simState == TelephonyManager.SIM_STATE_ABSENT) {
-                onSimAbsent();
+                log("onSimStateChanged: SIM absent.");
+                sendMessage(obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS,
+                        DataEvaluationReason.SIM_REMOVAL));
+            } else if (simState == TelephonyManager.SIM_STATE_NOT_READY
+                    && mSimState == TelephonyManager.SIM_STATE_LOADED) {
+                if (mFeatureFlags.simDisabledGracefulTearDown()) {
+                    log("onSimStateChanged: SIM disabled.");
+                    sendMessage(obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS,
+                            DataEvaluationReason.SIM_DISABLED));
+                }
             } else if (simState == TelephonyManager.SIM_STATE_LOADED) {
                 sendMessage(obtainMessage(EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS,
                         DataEvaluationReason.SIM_LOADED));
             }
+            mSimState = simState;
             mDataNetworkControllerCallbacks.forEach(callback -> callback.invokeFromExecutor(
                     () -> callback.onSimStateChanged(mSimState)));
         }
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index ab54e9f..7e9f3ff 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -238,9 +238,9 @@
     private static final int EVENT_SATELLITE_CONFIG_DATA_UPDATED = 40;
     private static final int EVENT_SATELLITE_SUPPORTED_STATE_CHANGED = 41;
     private static final int EVENT_NOTIFY_NTN_HYSTERESIS_TIMED_OUT = 42;
-    private static final int EVENT_EVALUATE_ESOS_PROFILES_PRIORITIZATION = 43;
-    private static final int CMD_PROVISION_SATELLITE_TOKEN_UPDATED = 44;
-    private static final int EVENT_PROVISION_SATELLITE_TOKEN_UPDATED = 45;
+    private static final int CMD_EVALUATE_ESOS_PROFILES_PRIORITIZATION = 43;
+    private static final int CMD_UPDATE_PROVISION_SATELLITE_TOKEN = 44;
+    private static final int EVENT_UPDATE_PROVISION_SATELLITE_TOKEN_DONE = 45;
     private static final int EVENT_NOTIFY_NTN_ELIGIBILITY_HYSTERESIS_TIMED_OUT = 46;
     private static final int EVENT_WIFI_CONNECTIVITY_STATE_CHANGED = 47;
     private static final int EVENT_SATELLITE_ACCESS_RESTRICTION_CHECKING_RESULT = 48;
@@ -512,10 +512,24 @@
 
     // Variable for backup and restore device's screen rotation settings.
     private String mDeviceRotationLockToBackupAndRestore = null;
+    // This is used for testing only. Context#getSystemService is a final API and cannot be
+    // mocked. Using this to inject a mock SubscriptionManager to work around this limitation.
+    private SubscriptionManager mInjectSubscriptionManager = null;
 
     private final Object mIsWifiConnectedLock = new Object();
     @GuardedBy("mIsWifiConnectedLock")
     private boolean mIsWifiConnected = false;
+    private BroadcastReceiver
+            mDefaultSmsSubscriptionChangedBroadcastReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    if (intent.getAction().equals(
+                            SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED)) {
+                        plogd("Default SMS subscription changed");
+                        sendRequestAsync(CMD_EVALUATE_ESOS_PROFILES_PRIORITIZATION, null, null);
+                    }
+                }
+            };
 
     /**
      * @return The singleton instance of SatelliteController.
@@ -567,7 +581,7 @@
         // to the satellite service and HAL interface.
         mSatelliteModemInterface = SatelliteModemInterface.make(
                 mContext, this, mFeatureFlags);
-        mCountryDetector = TelephonyCountryDetector.getInstance(context);
+        mCountryDetector = TelephonyCountryDetector.getInstance(context, mFeatureFlags);
         mCountryDetector.registerForWifiConnectivityStateChanged(this,
                 EVENT_WIFI_CONNECTIVITY_STATE_CHANGED, null);
         mTelecomManager = mContext.getSystemService(TelecomManager.class);
@@ -648,7 +662,7 @@
                 getDemoPointingNotAlignedDurationMillisFromResources();
         mSatelliteEmergencyModeDurationMillis =
                 getSatelliteEmergencyModeDurationFromOverlayConfig(context);
-        sendMessageDelayed(obtainMessage(EVENT_EVALUATE_ESOS_PROFILES_PRIORITIZATION),
+        sendMessageDelayed(obtainMessage(CMD_EVALUATE_ESOS_PROFILES_PRIORITIZATION),
                 /* delayMillis= */ TimeUnit.MINUTES.toMillis(1));
 
         SubscriptionManager subscriptionManager = mContext.getSystemService(
@@ -658,6 +672,7 @@
             subscriptionManager.addOnSubscriptionsChangedListener(
                     new HandlerExecutor(new Handler(looper)), mSubscriptionsChangedListener);
         }
+        registerDefaultSmsSubscriptionChangedBroadcastReceiver();
     }
 
     class SatelliteSubscriptionsChangedListener
@@ -1573,50 +1588,49 @@
                 break;
             }
 
-            case EVENT_EVALUATE_ESOS_PROFILES_PRIORITIZATION: {
+            case CMD_EVALUATE_ESOS_PROFILES_PRIORITIZATION: {
                 evaluateESOSProfilesPrioritization();
                 break;
             }
 
-            case CMD_PROVISION_SATELLITE_TOKEN_UPDATED: {
+            case CMD_UPDATE_PROVISION_SATELLITE_TOKEN: {
                 request = (SatelliteControllerHandlerRequest) msg.obj;
                 RequestProvisionSatelliteArgument argument =
                         (RequestProvisionSatelliteArgument) request.argument;
-                onCompleted = obtainMessage(EVENT_PROVISION_SATELLITE_TOKEN_UPDATED, request);
+                onCompleted = obtainMessage(EVENT_UPDATE_PROVISION_SATELLITE_TOKEN_DONE, request);
                 // only pass to index 0.
                 // TODO: Select the subscription with highest priority and set it to mSatelliteSubId
                 int subId = -1;
                 synchronized (mSatelliteTokenProvisionedLock) {
                     subId = mSubscriberIdPerSub.getOrDefault(
                             argument.mSatelliteSubscriberInfoList.get(0).getSubscriberId(), -1);
-                    for (SatelliteSubscriberInfo subscriberInfo :
-                            argument.mSatelliteSubscriberInfoList) {
-                        mProvisionedSubscriberId.put(subscriberInfo.getSubscriberId(), true);
-                    }
                 }
                 setSatellitePhone(subId);
                 String iccId = mSubscriptionManagerService.getSubscriptionInfo(subId).getIccId();
                 argument.setIccId(iccId);
+                boolean sendResponse = false;
                 synchronized (mSatelliteTokenProvisionedLock) {
                     if (!iccId.equals(mLastConfiguredIccId)) {
                         logd("updateSatelliteSubscription subId=" + subId + ", iccId=" + iccId
                                 + " to modem");
                         mSatelliteModemInterface.updateSatelliteSubscription(iccId, onCompleted);
+                    } else {
+                        sendResponse = true;
                     }
                 }
-                Consumer<Integer> result = new Consumer<Integer>() {
-                    @Override
-                    public void accept(Integer integer) {
-                        logd("invoke CMD_PROVISION_SATELLITE_TOKEN_UPDATED done.");
-                    }
-                };
-                ProvisionSatelliteServiceArgument internalArgument =
-                        new ProvisionSatelliteServiceArgument(iccId, null, result, subId);
-                sendRequestAsync(CMD_PROVISION_SATELLITE_SERVICE, internalArgument, null);
+                handleEventSatelliteSubscriptionProvisionStateChanged(
+                        argument.mSatelliteSubscriberInfoList, true);
+                if (sendResponse) {
+                    // The response is sent immediately because the ICCID has already been
+                    // delivered to the modem.
+                    Bundle bundle = new Bundle();
+                    bundle.putBoolean(SatelliteManager.KEY_PROVISION_SATELLITE_TOKENS, true);
+                    argument.mResult.send(SATELLITE_RESULT_SUCCESS, bundle);
+                }
                 break;
             }
 
-            case EVENT_PROVISION_SATELLITE_TOKEN_UPDATED: {
+            case EVENT_UPDATE_PROVISION_SATELLITE_TOKEN_DONE: {
                 ar = (AsyncResult) msg.obj;
                 request = (SatelliteControllerHandlerRequest) ar.userObj;
                 RequestProvisionSatelliteArgument argument =
@@ -3790,6 +3804,48 @@
         });
     }
 
+    private void handleEventSatelliteSubscriptionProvisionStateChanged(
+            List<SatelliteSubscriberInfo> newList, boolean provisioned) {
+        logd("handleEventSatelliteSubscriptionProvisionStateChanged: newList=" + newList
+                + " , provisioned=" + provisioned);
+        boolean provisionChanged = false;
+        synchronized (mSatelliteTokenProvisionedLock) {
+            for (SatelliteSubscriberInfo subscriberInfo : newList) {
+                if (mProvisionedSubscriberId.getOrDefault(subscriberInfo.getSubscriberId(), false)
+                        == provisioned) {
+                    continue;
+                }
+                provisionChanged = true;
+                mProvisionedSubscriberId.put(subscriberInfo.getSubscriberId(), provisioned);
+            }
+        }
+        if (!provisionChanged) {
+            logd("handleEventSatelliteSubscriptionProvisionStateChanged: provision state nothing "
+                    + "changed.");
+            return;
+        }
+        List<SatelliteSubscriberProvisionStatus> informList =
+                getPrioritizedSatelliteSubscriberProvisionStatusList();
+        plogd("handleEventSatelliteSubscriptionProvisionStateChanged: " + informList);
+        notifySatelliteSubscriptionProvisionStateChanged(informList);
+    }
+
+    private void notifySatelliteSubscriptionProvisionStateChanged(
+            @NonNull List<SatelliteSubscriberProvisionStatus> list) {
+        List<ISatelliteProvisionStateCallback> deadCallersList = new ArrayList<>();
+        mSatelliteProvisionStateChangedListeners.values().forEach(listener -> {
+            try {
+                listener.onSatelliteSubscriptionProvisionStateChanged(list);
+            } catch (RemoteException e) {
+                plogd("notifySatelliteSubscriptionProvisionStateChanged: " + e);
+                deadCallersList.add(listener);
+            }
+        });
+        deadCallersList.forEach(listener -> {
+            mSatelliteProvisionStateChangedListeners.remove(listener.asBinder());
+        });
+    }
+
     private void handleEventSatelliteModemStateChanged(
             @SatelliteManager.SatelliteModemState int state) {
         plogd("handleEventSatelliteModemStateChanged: state=" + state);
@@ -4312,13 +4368,13 @@
         processNewCarrierConfigData(subId);
         resetCarrierRoamingSatelliteModeParams(subId);
         handleStateChangedForCarrierRoamingNtnEligibility();
-        sendMessageDelayed(obtainMessage(EVENT_EVALUATE_ESOS_PROFILES_PRIORITIZATION),
+        sendMessageDelayed(obtainMessage(CMD_EVALUATE_ESOS_PROFILES_PRIORITIZATION),
                 TimeUnit.MINUTES.toMillis(1));
     }
 
     // imsi, msisdn, default sms subId change
     private void handleSubscriptionsChanged() {
-        sendMessageDelayed(obtainMessage(EVENT_EVALUATE_ESOS_PROFILES_PRIORITIZATION),
+        sendMessageDelayed(obtainMessage(CMD_EVALUATE_ESOS_PROFILES_PRIORITIZATION),
                 TimeUnit.MINUTES.toMillis(1));
     }
 
@@ -5577,11 +5633,12 @@
      */
     private void evaluateESOSProfilesPrioritization() {
         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+            plogd("evaluateESOSProfilesPrioritization: Flag CarrierRoamingNbIotNtn is disabled");
             return;
         }
         List<SubscriptionInfo> allSubInfos = mSubscriptionManagerService.getAllSubInfoList(
                 mContext.getOpPackageName(), mContext.getAttributionTag());
-        //key : priority, low value is high, value : List<SubscriptionInfo>
+        // Key : priority - lower value has higher priority; Value : List<SubscriptionInfo>
         Map<Integer, List<SubscriptionInfo>> newSubsInfoListPerPriority = new HashMap<>();
         for (SubscriptionInfo info : allSubInfos) {
             int subId = info.getSubscriptionId();
@@ -5599,15 +5656,18 @@
             if (keyPriority != -1) {
                 newSubsInfoListPerPriority.computeIfAbsent(keyPriority,
                         k -> new ArrayList<>()).add(info);
+            } else {
+                plogw("evaluateESOSProfilesPrioritization: Got -1 keyPriority for subId="
+                        + info.getSubscriptionId());
             }
         }
 
         if (newSubsInfoListPerPriority.size() == 0) {
-            logd("evaluateESOSProfilesPrioritization: no available");
+            logd("evaluateESOSProfilesPrioritization: no satellite subscription available");
             return;
         }
 
-        // if priority is changed, send broadcast for provisioned ESOS subs ids
+        // If priority has changed, send broadcast for provisioned ESOS subs IDs
         synchronized (mSatelliteTokenProvisionedLock) {
             if (isPriorityChanged(mSubsInfoListPerPriority, newSubsInfoListPerPriority)) {
                 mSubsInfoListPerPriority = newSubsInfoListPerPriority;
@@ -5639,6 +5699,10 @@
                 subId);
         SubscriptionManager subscriptionManager = mContext.getSystemService(
                 SubscriptionManager.class);
+        if (mInjectSubscriptionManager != null) {
+            logd("getPhoneNumberBasedCarrier: InjectSubscriptionManager");
+            subscriptionManager = mInjectSubscriptionManager;
+        }
         String phoneNumber = subscriptionManager.getPhoneNumber(subId);
         if (phoneNumber == null) {
             logd("getPhoneNumberBasedCarrier: phoneNumber null");
@@ -5707,15 +5771,23 @@
             result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null);
             return;
         }
+        List<SatelliteSubscriberProvisionStatus> list =
+                getPrioritizedSatelliteSubscriberProvisionStatusList();
+        logd("requestSatelliteSubscriberProvisionStatus: " + list);
+        final Bundle bundle = new Bundle();
+        bundle.putParcelableList(SatelliteManager.KEY_REQUEST_PROVISION_SUBSCRIBER_ID_TOKEN, list);
+        result.send(SATELLITE_RESULT_SUCCESS, bundle);
+    }
 
+    private List<SatelliteSubscriberProvisionStatus>
+            getPrioritizedSatelliteSubscriberProvisionStatusList() {
         List<SatelliteSubscriberProvisionStatus> list = new ArrayList<>();
         synchronized (mSatelliteTokenProvisionedLock) {
-            mSubscriberIdPerSub = new HashMap<>();
             for (int priority : mSubsInfoListPerPriority.keySet()) {
                 List<SubscriptionInfo> infoList = mSubsInfoListPerPriority.get(priority);
                 if (infoList == null) {
-                    logd("requestSatelliteSubscriberProvisionStatus: no exist this priority "
-                            + priority);
+                    logd("getPrioritySatelliteSubscriberProvisionStatusList: no exist this "
+                            + "priority " + priority);
                     continue;
                 }
                 for (SubscriptionInfo info : infoList) {
@@ -5724,10 +5796,10 @@
                     int carrierId = info.getCarrierId();
                     String apn = getConfigForSubId(info.getSubscriptionId())
                             .getString(KEY_SATELLITE_NIDD_APN_NAME_STRING, "");
-                    logd("requestSatelliteSubscriberProvisionStatus: subscriberId:"
+                    logd("getPrioritySatelliteSubscriberProvisionStatusList: subscriberId:"
                             + subscriberId + " , carrierId=" + carrierId + " , apn=" + apn);
                     if (subscriberId.isEmpty()) {
-                        logd("requestSatelliteSubscriberProvisionStatus: getSubscriberId "
+                        logd("getPrioritySatelliteSubscriberProvisionStatusList: getSubscriberId "
                                 + "failed skip this subscriberId.");
                         continue;
                     }
@@ -5737,10 +5809,11 @@
                                     .setSubId(info.getSubscriptionId())
                                     .setSubscriberIdType(subscriberIdPair.second)
                                     .build();
-                    boolean provisioned = mProvisionedSubscriberId.getOrDefault(
-                            subscriberId, false);
-                    logd("requestSatelliteSubscriberProvisionStatus: satelliteSubscriberInfo="
-                            + satelliteSubscriberInfo + ", provisioned=" + provisioned);
+                    boolean provisioned = mProvisionedSubscriberId.getOrDefault(subscriberId,
+                            false);
+                    logd("getPrioritySatelliteSubscriberProvisionStatusList: "
+                            + "satelliteSubscriberInfo=" + satelliteSubscriberInfo
+                            + ", provisioned=" + provisioned);
                     list.add(new SatelliteSubscriberProvisionStatus.Builder()
                             .setSatelliteSubscriberInfo(satelliteSubscriberInfo)
                             .setProvisionStatus(provisioned).build());
@@ -5748,11 +5821,7 @@
                 }
             }
         }
-
-        logd("requestSatelliteSubscriberProvisionStatus: " + list);
-        final Bundle bundle = new Bundle();
-        bundle.putParcelableList(SatelliteManager.KEY_REQUEST_PROVISION_SUBSCRIBER_ID_TOKEN, list);
-        result.send(SATELLITE_RESULT_SUCCESS, bundle);
+        return list;
     }
 
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@@ -5795,7 +5864,7 @@
         logd("provisionSatellite:" + list);
         RequestProvisionSatelliteArgument request = new RequestProvisionSatelliteArgument(list,
                 result);
-        sendRequestAsync(CMD_PROVISION_SATELLITE_TOKEN_UPDATED, request, null);
+        sendRequestAsync(CMD_UPDATE_PROVISION_SATELLITE_TOKEN, request, null);
     }
 
 
@@ -5969,4 +6038,15 @@
             }
         }
     }
+
+    private void registerDefaultSmsSubscriptionChangedBroadcastReceiver() {
+        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+            plogd("registerDefaultSmsSubscriptionChangedBroadcastReceiver: Flag "
+                    + "CarrierRoamingNbIotNtn is disabled");
+            return;
+        }
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED);
+        mContext.registerReceiver(mDefaultSmsSubscriptionChangedBroadcastReceiver, intentFilter);
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyCountryDetectorTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyCountryDetectorTest.java
index 1daab00..9b3777b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyCountryDetectorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyCountryDetectorTest.java
@@ -51,6 +51,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.telephony.flags.FeatureFlags;
 
 import org.junit.After;
 import org.junit.Before;
@@ -76,6 +77,8 @@
     LocaleTracker mMockLocaleTracker2;
     @Mock Location mMockLocation;
     @Mock Network mMockNetwork;
+    @Mock
+    private FeatureFlags mMockFeatureFlags;
 
     @Captor
     private ArgumentCaptor<LocationListener> mLocationListenerCaptor;
@@ -118,8 +121,9 @@
 
         when(mLocationManager.getProviders(true)).thenReturn(Arrays.asList("TEST_PROVIDER"));
 
+        when(mMockFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
         mCountryDetectorUT = new TestTelephonyCountryDetector(
-                mLooper, mContext, mLocationManager, mConnectivityManager);
+                mLooper, mContext, mLocationManager, mConnectivityManager, mMockFeatureFlags);
         if (isGeoCoderImplemented()) {
             verify(mLocationManager).requestLocationUpdates(anyString(), anyLong(), anyFloat(),
                     mLocationListenerCaptor.capture());
@@ -141,8 +145,10 @@
         clearInvocations(mLocationManager);
         clearInvocations(mConnectivityManager);
         when(mMockLocaleTracker.getCurrentCountry()).thenReturn("US");
-        TelephonyCountryDetector inst1 = TelephonyCountryDetector.getInstance(mContext);
-        TelephonyCountryDetector inst2 = TelephonyCountryDetector.getInstance(mContext);
+        TelephonyCountryDetector inst1 = TelephonyCountryDetector
+                .getInstance(mContext, mMockFeatureFlags);
+        TelephonyCountryDetector inst2 = TelephonyCountryDetector
+                .getInstance(mContext, mMockFeatureFlags);
         assertEquals(inst1, inst2);
         if (isGeoCoderImplemented()) {
             verify(mLocationManager, never()).requestLocationUpdates(anyString(), anyLong(),
@@ -386,8 +392,9 @@
          * @param locationManager  The LocationManager instance.
          */
         TestTelephonyCountryDetector(Looper looper, Context context,
-                LocationManager locationManager, ConnectivityManager connectivityManager) {
-            super(looper, context, locationManager, connectivityManager);
+                LocationManager locationManager, ConnectivityManager connectivityManager,
+                FeatureFlags featureFlags) {
+            super(looper, context, locationManager, connectivityManager, featureFlags);
         }
 
         @Override
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
index 5dce5c2..0b66459 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
@@ -888,8 +888,11 @@
         doReturn(PhoneConstants.State.IDLE).when(mCT).getState();
         doReturn(new SubscriptionInfoInternal.Builder().setId(1).build())
                 .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt());
+
         doReturn(true).when(mFeatureFlags).carrierEnabledSatelliteFlag();
         doReturn(true).when(mFeatureFlags).satelliteInternet();
+        doReturn(true).when(mFeatureFlags).simDisabledGracefulTearDown();
+
         when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
         doReturn(true).when(mMockPackageManager).hasSystemFeature(anyString());
 
@@ -4196,7 +4199,7 @@
     }
 
     @Test
-    public void testImsGracefulTearDown() throws Exception {
+    public void testImsGracefulTearDownSimRemoval() throws Exception {
         setImsRegistered(true);
         setRcsRegistered(true);
 
@@ -4242,6 +4245,52 @@
     }
 
     @Test
+    public void testImsGracefulTearDownSimDisabled() throws Exception {
+        setImsRegistered(true);
+        setRcsRegistered(true);
+
+        NetworkCapabilities netCaps = new NetworkCapabilities();
+        netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
+        netCaps.maybeMarkCapabilitiesRestricted();
+        netCaps.setRequestorPackageName(FAKE_MMTEL_PACKAGE);
+
+        NetworkRequest nativeNetworkRequest = new NetworkRequest(netCaps,
+                ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST);
+        TelephonyNetworkRequest networkRequest = new TelephonyNetworkRequest(
+                nativeNetworkRequest, mPhone, mFeatureFlags);
+
+        mDataNetworkControllerUT.addNetworkRequest(networkRequest);
+
+        processAllMessages();
+        Mockito.clearInvocations(mPhone);
+
+        // SIM disabled
+        mDataNetworkControllerUT.obtainMessage(9/*EVENT_SIM_STATE_CHANGED*/,
+                TelephonyManager.SIM_STATE_NOT_READY, 0).sendToTarget();
+        processAllMessages();
+
+        // Make sure data network enters disconnecting state
+        ArgumentCaptor<PreciseDataConnectionState> pdcsCaptor =
+                ArgumentCaptor.forClass(PreciseDataConnectionState.class);
+        verify(mPhone).notifyDataConnection(pdcsCaptor.capture());
+        PreciseDataConnectionState pdcs = pdcsCaptor.getValue();
+        assertThat(pdcs.getState()).isEqualTo(TelephonyManager.DATA_DISCONNECTING);
+
+        // IMS de-registered. Now data network is safe to be torn down.
+        Mockito.clearInvocations(mPhone);
+        setImsRegistered(false);
+        setRcsRegistered(false);
+        processAllMessages();
+
+        // All data should be disconnected.
+        verifyAllDataDisconnected();
+        verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
+        verify(mPhone).notifyDataConnection(pdcsCaptor.capture());
+        pdcs = pdcsCaptor.getValue();
+        assertThat(pdcs.getState()).isEqualTo(TelephonyManager.DATA_DISCONNECTED);
+    }
+
+    @Test
     public void testNoGracefulTearDownForEmergencyDataNetwork() throws Exception {
         setImsRegistered(true);
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
index 483db50..872cc28 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
@@ -21,6 +21,8 @@
 import static android.telephony.CarrierConfigManager.KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT;
 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL;
 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT;
+import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ESOS_SUPPORTED_BOOL;
+import static android.telephony.CarrierConfigManager.KEY_SATELLITE_NIDD_APN_NAME_STRING;
 import static android.telephony.NetworkRegistrationInfo.SERVICE_TYPE_DATA;
 import static android.telephony.SubscriptionManager.SATELLITE_ENTITLEMENT_STATUS;
 import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_GOOD;
@@ -30,6 +32,8 @@
 import static android.telephony.satellite.SatelliteManager.KEY_DEMO_MODE_ENABLED;
 import static android.telephony.satellite.SatelliteManager.KEY_EMERGENCY_MODE_ENABLED;
 import static android.telephony.satellite.SatelliteManager.KEY_NTN_SIGNAL_STRENGTH;
+import static android.telephony.satellite.SatelliteManager.KEY_PROVISION_SATELLITE_TOKENS;
+import static android.telephony.satellite.SatelliteManager.KEY_REQUEST_PROVISION_SUBSCRIBER_ID_TOKEN;
 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_CAPABILITIES;
 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED;
 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_ENABLED;
@@ -96,6 +100,7 @@
 import android.app.NotificationManager;
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.content.res.Resources;
 import android.os.AsyncResult;
 import android.os.Bundle;
 import android.os.CancellationSignal;
@@ -113,6 +118,8 @@
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.telephony.satellite.INtnSignalStrengthCallback;
 import android.telephony.satellite.ISatelliteCapabilitiesCallback;
 import android.telephony.satellite.ISatelliteDatagramCallback;
@@ -126,6 +133,7 @@
 import android.telephony.satellite.SatelliteManager;
 import android.telephony.satellite.SatelliteManager.SatelliteException;
 import android.telephony.satellite.SatelliteModemEnableRequestAttributes;
+import android.telephony.satellite.SatelliteSubscriberInfo;
 import android.telephony.satellite.SatelliteSubscriberProvisionStatus;
 import android.telephony.satellite.SatelliteSubscriptionInfo;
 import android.testing.AndroidTestingRunner;
@@ -146,6 +154,7 @@
 import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
 import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats;
 import com.android.internal.telephony.satellite.metrics.SessionMetricsStats;
+import com.android.internal.telephony.subscription.SubscriptionInfoInternal;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
 
 import org.junit.After;
@@ -157,6 +166,7 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -216,6 +226,9 @@
     @Mock private CellSignalStrength mCellSignalStrength;
     @Mock private SatelliteConfig mMockConfig;
     @Mock private DemoSimulator mMockDemoSimulator;
+    @Mock private Resources mResources;
+    @Mock private SubscriptionManager mSubscriptionManager;
+    @Mock private SubscriptionInfo mSubscriptionInfo;
 
     private Semaphore mIIntegerConsumerSemaphore = new Semaphore(0);
     private IIntegerConsumer mIIntegerConsumer = new IIntegerConsumer.Stub() {
@@ -244,6 +257,17 @@
     private SatelliteCapabilities mEmptySatelliteCapabilities = new SatelliteCapabilities(
             new HashSet<>(), mIsPointingRequired, MAX_BYTES_PER_OUT_GOING_DATAGRAM,
             new HashMap<>());
+    final int mCarrierId = 0;
+    final String mImsi = "1234567890123";
+    final String mNiddApn = "testApn";
+    final String mMsisdn = "0987654321";
+    final String mSubscriberId = mImsi.substring(0, 6) + mMsisdn;
+    final String mIccId = "1000000000000001";
+    final String mIccId2 = "2000000000000002";
+    final String mImsi2 = "2345678901234";
+    final String mMsisdn2 = "9876543210";
+    final String mSubscriberId2 = mIccId2;
+
     private Semaphore mSatelliteCapabilitiesSemaphore = new Semaphore(0);
     private SatelliteCapabilities mQueriedSatelliteCapabilities = null;
     private int mQueriedSatelliteCapabilitiesResultCode = SATELLITE_RESULT_SUCCESS;
@@ -600,6 +624,9 @@
 
         doReturn(mMockConfigParser).when(mMockTelephonyConfigUpdateInstallReceiver)
                 .getConfigParser(ConfigProviderAdaptor.DOMAIN_SATELLITE);
+        doReturn(mSubscriptionInfo).when(mMockSubscriptionManagerService).getSubscriptionInfo(
+                anyInt());
+        doReturn("").when(mSubscriptionInfo).getIccId();
     }
 
     @After
@@ -4087,6 +4114,264 @@
         assertFalse(mSatelliteControllerUT.getWwanIsInService(mServiceState));
     }
 
+    private boolean mProvisionState = false;
+    private int mProvisionSateResultCode = -1;
+    private Semaphore mProvisionSateSemaphore = new Semaphore(0);
+    private ResultReceiver mProvisionSatelliteReceiver = new ResultReceiver(null) {
+        @Override
+        protected void onReceiveResult(int resultCode, Bundle resultData) {
+            mProvisionSateResultCode = resultCode;
+            logd("mProvisionSatelliteReceiver: resultCode=" + resultCode);
+            if (resultCode == SATELLITE_RESULT_SUCCESS) {
+                if (resultData.containsKey(KEY_PROVISION_SATELLITE_TOKENS)) {
+                    mProvisionState = resultData.getBoolean(KEY_PROVISION_SATELLITE_TOKENS);
+                    logd("mProvisionSatelliteReceiver: mProvisionState=" + mProvisionState);
+                } else {
+                    loge("KEY_PROVISION_SATELLITE_TOKENS does not exist.");
+                    mProvisionState = false;
+                }
+            } else {
+                mProvisionState = false;
+            }
+            try {
+                mProvisionSateSemaphore.release();
+            } catch (Exception ex) {
+                loge("mProvisionSatelliteReceiver: Got exception in releasing semaphore, ex=" + ex);
+            }
+        }
+    };
+
+    private List<SatelliteSubscriberProvisionStatus>
+            mRequestSatelliteSubscriberProvisionStatusResultList = new ArrayList<>();
+    private int mRequestSatelliteSubscriberProvisionStatusResultCode = SATELLITE_RESULT_SUCCESS;
+    private Semaphore mRequestSatelliteSubscriberProvisionStatusSemaphore = new Semaphore(0);
+    private ResultReceiver mRequestSatelliteSubscriberProvisionStatusReceiver = new ResultReceiver(
+            null) {
+        @Override
+        protected void onReceiveResult(int resultCode, Bundle resultData) {
+            mRequestSatelliteSubscriberProvisionStatusResultCode = resultCode;
+            logd("mRequestSatelliteSubscriberProvisionStatusReceiver: resultCode=" + resultCode);
+            if (resultCode == SATELLITE_RESULT_SUCCESS) {
+                if (resultData.containsKey(KEY_REQUEST_PROVISION_SUBSCRIBER_ID_TOKEN)) {
+                    mRequestSatelliteSubscriberProvisionStatusResultList =
+                            resultData.getParcelableArrayList(
+                                    KEY_REQUEST_PROVISION_SUBSCRIBER_ID_TOKEN,
+                                    SatelliteSubscriberProvisionStatus.class);
+                } else {
+                    loge("KEY_REQUEST_PROVISION_SUBSCRIBER_ID_TOKEN does not exist.");
+                    mRequestSatelliteSubscriberProvisionStatusResultList = new ArrayList<>();
+                }
+            } else {
+                mRequestSatelliteSubscriberProvisionStatusResultList = new ArrayList<>();
+            }
+            try {
+                mRequestSatelliteSubscriberProvisionStatusSemaphore.release();
+            } catch (Exception ex) {
+                loge("mRequestSatelliteSubscriberProvisionStatusReceiver: Got exception in "
+                        + "releasing "
+                        + "semaphore, ex=" + ex);
+            }
+        }
+    };
+
+    @Test
+    public void testRequestSatelliteSubscriberProvisionStatus() throws Exception {
+        when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true);
+        when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+        verifyRequestSatelliteSubscriberProvisionStatus();
+    }
+
+    private void verifyRequestSatelliteSubscriberProvisionStatus() throws Exception {
+        setSatelliteSubscriberTesting();
+        List<SatelliteSubscriberInfo> list = getExpectedSatelliteSubscriberInfoList();
+        mCarrierConfigBundle.putString(KEY_SATELLITE_NIDD_APN_NAME_STRING, mNiddApn);
+        mCarrierConfigBundle.putBoolean(KEY_SATELLITE_ESOS_SUPPORTED_BOOL, true);
+        for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
+                : mCarrierConfigChangedListenerList) {
+            pair.first.execute(() -> pair.second.onCarrierConfigChanged(
+                    /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0)
+            );
+        }
+        moveTimeForward(TimeUnit.MINUTES.toMillis(1));
+        processAllMessages();
+
+        // Verify that calling requestSatelliteSubscriberProvisionStatus returns the expected
+        // list of SatelliteSubscriberProvisionStatus.
+        mSatelliteControllerUT.requestSatelliteSubscriberProvisionStatus(
+                mRequestSatelliteSubscriberProvisionStatusReceiver);
+        moveTimeForward(TimeUnit.MINUTES.toMillis(1));
+        processAllMessages();
+        assertEquals(SATELLITE_RESULT_SUCCESS,
+                mRequestSatelliteSubscriberProvisionStatusResultCode);
+        assertEquals(list.get(0), mRequestSatelliteSubscriberProvisionStatusResultList.get(
+                0).getSatelliteSubscriberInfo());
+    }
+
+    @Test
+    public void testProvisionSatellite() throws Exception {
+        when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true);
+        when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+        verifyRequestSatelliteSubscriberProvisionStatus();
+        List<SatelliteSubscriberInfo> inputList = getExpectedSatelliteSubscriberInfoList();
+        verifyProvisionSatellite(inputList);
+    }
+
+    private void verifyProvisionSatellite(List<SatelliteSubscriberInfo> inputList) {
+        doAnswer(invocation -> {
+            Message message = (Message) invocation.getArguments()[1];
+            AsyncResult.forMessage(message, null, new SatelliteException(SATELLITE_RESULT_SUCCESS));
+            message.sendToTarget();
+            return null;
+        }).when(mMockSatelliteModemInterface).updateSatelliteSubscription(anyString(), any());
+
+        mSatelliteControllerUT.provisionSatellite(inputList, mProvisionSatelliteReceiver);
+        processAllMessages();
+        assertEquals(SATELLITE_RESULT_SUCCESS, mProvisionSateResultCode);
+        assertTrue(mProvisionState);
+    }
+
+
+    @Test
+    public void testRegisterForSatelliteSubscriptionProvisionStateChanged() throws Exception {
+        when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true);
+        when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+
+        Semaphore semaphore = new Semaphore(0);
+        SatelliteSubscriberProvisionStatus[] resultArray =
+                new SatelliteSubscriberProvisionStatus[2];
+        ISatelliteProvisionStateCallback callback = new ISatelliteProvisionStateCallback.Stub() {
+            @Override
+            public void onSatelliteProvisionStateChanged(boolean provisioned) {
+                logd("onSatelliteProvisionStateChanged: provisioned=" + provisioned);
+            }
+
+            @Override
+            public void onSatelliteSubscriptionProvisionStateChanged(
+                    List<SatelliteSubscriberProvisionStatus> satelliteSubscriberProvisionStatus) {
+                logd("onSatelliteSubscriptionProvisionStateChanged: "
+                        + satelliteSubscriberProvisionStatus);
+                for (int i = 0; i < satelliteSubscriberProvisionStatus.size(); i++) {
+                    resultArray[i] = satelliteSubscriberProvisionStatus.get(i);
+                }
+                try {
+                    semaphore.release();
+                } catch (Exception ex) {
+                    loge("onSatelliteSubscriptionProvisionStateChanged: Got exception in releasing "
+                            + "semaphore, ex=" + ex);
+                }
+            }
+        };
+        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        int errorCode = mSatelliteControllerUT.registerForSatelliteProvisionStateChanged(SUB_ID,
+                callback);
+        processAllMessages();
+        assertEquals(SATELLITE_RESULT_SUCCESS, errorCode);
+
+        verifyRequestSatelliteSubscriberProvisionStatus();
+
+        // Verify that onSatelliteSubscriptionProvisionStateChanged is called when requesting
+        // provisioning for the first time.
+        List<SatelliteSubscriberInfo> list = getExpectedSatelliteSubscriberInfoList();
+        List<SatelliteSubscriberInfo> inputList = new ArrayList<>();
+        inputList.add(list.get(0));
+        verifyProvisionSatellite(inputList);
+
+        verify(mMockSatelliteModemInterface, times(1)).updateSatelliteSubscription(anyString(),
+                any());
+        assertTrue(waitForForEvents(
+                semaphore, 1, "testRegisterForSatelliteSubscriptionProvisionStateChanged"));
+        assertTrue(resultArray[0].getProvisionStatus());
+        assertEquals(mSubscriberId, resultArray[0].getSatelliteSubscriberInfo().getSubscriberId());
+
+        // Request provisioning with SatelliteSubscriberInfo that has not been provisioned
+        // before, and verify that onSatelliteSubscriptionProvisionStateChanged is called.
+        inputList = new ArrayList<>();
+        inputList.add(list.get(1));
+        verifyProvisionSatellite(inputList);
+
+        verify(mMockSatelliteModemInterface, times(2)).updateSatelliteSubscription(anyString(),
+                any());
+        assertTrue(waitForForEvents(
+                semaphore, 1, "testRegisterForSatelliteSubscriptionProvisionStateChanged"));
+        assertTrue(resultArray[1].getProvisionStatus());
+        assertEquals(mSubscriberId2, resultArray[1].getSatelliteSubscriberInfo().getSubscriberId());
+
+        // Request provisioning with the same SatelliteSubscriberInfo that was previously
+        // requested, and verify that onSatelliteSubscriptionProvisionStateChanged is not called.
+        verifyProvisionSatellite(inputList);
+
+        verify(mMockSatelliteModemInterface, times(2)).updateSatelliteSubscription(anyString(),
+                any());
+        assertFalse(waitForForEvents(
+                semaphore, 1, "testRegisterForSatelliteSubscriptionProvisionStateChanged"));
+    }
+
+    private void setSatelliteSubscriberTesting() throws Exception {
+        doReturn("123").when(mContext).getAttributionTag();
+        final int carrierId = 0;
+        SubscriptionInfo subscriptionInfo = new SubscriptionInfo.Builder()
+                .setId(SUB_ID).setIccId(mIccId).setSimSlotIndex(0).setOnlyNonTerrestrialNetwork(
+                        false).setSatelliteESOSSupported(true).setCarrierId(carrierId).build();
+        SubscriptionInfo subscriptionInfo2 = new SubscriptionInfo.Builder()
+                .setId(SUB_ID1).setIccId(mIccId2).setSimSlotIndex(1).setOnlyNonTerrestrialNetwork(
+                        true).setSatelliteESOSSupported(false).setCarrierId(carrierId).build();
+        List<SubscriptionInfo> allSubInfos = new ArrayList<>();
+        allSubInfos.add(subscriptionInfo);
+        allSubInfos.add(subscriptionInfo2);
+        doReturn(allSubInfos).when(mMockSubscriptionManagerService).getAllSubInfoList(
+                anyString(), anyString());
+        SubscriptionInfoInternal subInfoInternal =
+                new SubscriptionInfoInternal.Builder().setCarrierId(0).setImsi(mImsi).setIccId(
+                        mIccId).build();
+        SubscriptionInfoInternal subInfoInternal2 =
+                new SubscriptionInfoInternal.Builder().setCarrierId(0).setImsi(mImsi2).setIccId(
+                        mIccId2).build();
+        doReturn(subscriptionInfo).when(mMockSubscriptionManagerService).getSubscriptionInfo(
+                eq(SUB_ID));
+        doReturn(subscriptionInfo2).when(mMockSubscriptionManagerService).getSubscriptionInfo(
+                eq(SUB_ID1));
+        Field field = SatelliteController.class.getDeclaredField("mInjectSubscriptionManager");
+        field.setAccessible(true);
+        field.set(mSatelliteControllerUT, mSubscriptionManager);
+        doReturn(mMsisdn).when(mSubscriptionManager).getPhoneNumber(eq(SUB_ID));
+        doReturn(mMsisdn2).when(mSubscriptionManager).getPhoneNumber(eq(SUB_ID1));
+        Field provisionedSubscriberIdField = SatelliteController.class.getDeclaredField(
+                "mProvisionedSubscriberId");
+        provisionedSubscriberIdField.setAccessible(true);
+        provisionedSubscriberIdField.set(mSatelliteControllerUT, new HashMap<>());
+        Field subscriberIdPerSubField = SatelliteController.class.getDeclaredField(
+                "mSubscriberIdPerSub");
+        subscriberIdPerSubField.setAccessible(true);
+        subscriberIdPerSubField.set(mSatelliteControllerUT, new HashMap<>());
+        Field lastConfiguredIccIdField = SatelliteController.class.getDeclaredField(
+                "mLastConfiguredIccId");
+        lastConfiguredIccIdField.setAccessible(true);
+        lastConfiguredIccIdField.set(mSatelliteControllerUT, null);
+        doReturn(subInfoInternal).when(mMockSubscriptionManagerService).getSubscriptionInfoInternal(
+                eq(SUB_ID));
+        doReturn(subInfoInternal2).when(
+                mMockSubscriptionManagerService).getSubscriptionInfoInternal(eq(SUB_ID1));
+        doReturn(mResources).when(mContext).getResources();
+        doReturn("package").when(mResources).getString(
+                eq(R.string.config_satellite_gateway_service_package));
+        doReturn("className").when(mResources).getString(
+                eq(R.string.config_satellite_carrier_roaming_esos_provisioned_class));
+        doReturn("action").when(mResources).getString(
+                eq(R.string.config_satellite_carrier_roaming_esos_provisioned_intent_action));
+    }
+
+    private List<SatelliteSubscriberInfo> getExpectedSatelliteSubscriberInfoList() {
+        List<SatelliteSubscriberInfo> list = new ArrayList<>();
+        list.add(new SatelliteSubscriberInfo.Builder().setSubscriberId(mSubscriberId).setCarrierId(
+                mCarrierId).setNiddApn(mNiddApn).setSubId(SUB_ID).setSubscriberIdType(
+                SatelliteSubscriberInfo.IMSI_MSISDN).build());
+        list.add(new SatelliteSubscriberInfo.Builder().setSubscriberId(mSubscriberId2).setCarrierId(
+                mCarrierId).setNiddApn(mNiddApn).setSubId(SUB_ID1).setSubscriberIdType(
+                SatelliteSubscriberInfo.ICCID).build());
+        return list;
+    }
+
     private void resetSatelliteControllerUTEnabledState() {
         logd("resetSatelliteControllerUTEnabledState");
         setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_RADIO_NOT_AVAILABLE);