Merge "Convert the app signature check to use SHA-256 instead of SHA1." into main
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 819d39b..61ffb02 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -538,7 +538,7 @@
     <string name="incall_error_power_off" product="watch" msgid="7191184639454113633">"通話を発信するには、モバイル ネットワークを ON にし、機内モードまたはバッテリー セーバー モードを OFF にしてください。"</string>
     <string name="incall_error_power_off" product="default" msgid="8131672264311208673">"電話をかけるには機内モードをオフにしてください。"</string>
     <string name="incall_error_power_off_wfc" msgid="9125661184694727052">"電話をかけるには、機内モードをオフにするか無線ネットワークに接続してください。"</string>
-    <string name="incall_error_power_off_thermal" product="default" msgid="8695809601655300168"><b>"スマートフォンが熱くなりすぎています"</b>\n\n"この通話を完了できません。スマートフォンの熱が冷めてから、もう一度お試しください。\n\n緊急通報は通常どおり発信できます。"</string>
+    <string name="incall_error_power_off_thermal" product="default" msgid="8695809601655300168"><b>"スマートフォンが熱くなっています"</b>\n\n"この通話を完了できません。スマートフォンの熱が冷めてから、もう一度お試しください。\n\n緊急通報は通常どおり発信できます。"</string>
     <string name="incall_error_ecm_emergency_only" msgid="5622379058883722080">"緊急通報以外の通話を発信するには、緊急通報待機モードを終了してください。"</string>
     <string name="incall_error_emergency_only" msgid="8786127461027964653">"ご加入の通信サービスがありません"</string>
     <string name="incall_error_out_of_service" msgid="1927265196942672791">"モバイルネットワークが利用できません。"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index ed3e472..6cd806b 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -485,7 +485,7 @@
     <string name="simContacts_title" msgid="2714029230160136647">"Contacten selecteren om te importeren"</string>
     <string name="simContacts_airplaneMode" msgid="4654884030631503808">"Zet de vliegtuigmodus uit om contacten van de simkaart te importeren."</string>
     <string name="enable_pin" msgid="967674051730845376">"SIM pincode aan-/uitzetten"</string>
-    <string name="change_pin" msgid="3657869530942905790">"Pincode simkaart wijzigen"</string>
+    <string name="change_pin" msgid="3657869530942905790">"Pincode van simkaart wijzigen"</string>
     <string name="enter_pin_text" msgid="3182311451978663356">"Pincode simkaart:"</string>
     <string name="oldPinLabel" msgid="8618515202411987721">"Oude pincode"</string>
     <string name="newPinLabel" msgid="3585899083055354732">"Nieuwe pincode"</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 476ab89..397c5c8 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1245,7 +1245,9 @@
     <!-- In-call screen: call failure message displayed in an error dialog when the user is connected to a wireless network, but wifi calling is turned off. [CHAR_LIMIT=NONE] -->
     <string name="incall_error_promote_wfc">Enable Wi-Fi calling to make a call.</string>
     <!-- In-call screen: call failure message displayed in an error dialog when the satellite modem is on. [CHAR_LIMIT=NONE] -->
-    <string name="incall_error_satellite_enabled">Disable satellite mode to make a call.</string>
+    <string name="incall_error_satellite_enabled">To make a call, first end the satellite connection.</string>
+    <!-- In-call screen: call failure message displayed in an error dialog when device is connected to carrier roaming satellite network [CHAR_LIMIT=NONE] -->
+    <string name="incall_error_carrier_roaming_satellite_mode">You can send and receive messages without a mobile or Wi-Fi network.</string>
 
     <!-- Hint for the button of emergency information -->
     <string name="emergency_information_hint">Emergency information</string>
diff --git a/src/com/android/phone/ImsProvisioningController.java b/src/com/android/phone/ImsProvisioningController.java
index b2e34ae..d2c720b 100644
--- a/src/com/android/phone/ImsProvisioningController.java
+++ b/src/com/android/phone/ImsProvisioningController.java
@@ -70,6 +70,7 @@
 import com.android.ims.RcsFeatureManager;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.PhoneConfigurationManager;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.util.HandlerExecutor;
 import com.android.telephony.Rlog;
 
@@ -92,6 +93,7 @@
     @VisibleForTesting
     protected static final int EVENT_MULTI_SIM_CONFIGURATION_CHANGE = 3;
     private static final int EVENT_PROVISIONING_VALUE_CHANGED = 4;
+    private static final int EVENT_NOTIFY_INIT_PROVISIONED_VALUE = 5;
 
     // Provisioning Keys that are handled via AOSP cache and not sent to the ImsService
     private static final int[] LOCAL_IMS_CONFIG_KEYS = {
@@ -121,6 +123,11 @@
             CAPABILITY_TYPE_CALL_COMPOSER
     };
 
+    private static final int[] LOCAL_RCS_CAPABILITY = {
+            CAPABILITY_TYPE_OPTIONS_UCE,
+            CAPABILITY_TYPE_PRESENCE_UCE
+    };
+
     /**
      * map the MmTelCapabilities.MmTelCapability and
      * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_VOICE_INT
@@ -199,6 +206,7 @@
     private final SparseArray<ProvisioningCallbackManager> mProvisioningCallbackManagersSlotMap =
             new SparseArray<>();
     private final ImsProvisioningLoader mImsProvisioningLoader;
+    private final FeatureFlags mFeatureFlags;
 
     private int mNumSlot;
 
@@ -253,6 +261,18 @@
                             + " value : " + (int) msg.obj);
                     updateCapabilityTechFromKey(msg.arg1, msg.arg2, (int) msg.obj);
                     break;
+                case EVENT_NOTIFY_INIT_PROVISIONED_VALUE:
+                    int slotId = msg.arg1;
+                    int subId = msg.arg2;
+                    IFeatureProvisioningCallback callback =
+                            (IFeatureProvisioningCallback) msg.obj;
+                    log("slotId " + slotId + " subId " + subId
+                            + " callback " + (callback != null));
+
+                    // Notify MmTel Provisioning Status
+                    notifyMmTelProvisioningStatus(slotId, subId, callback);
+                    notifyRcsProvisioningStatus(slotId, subId, callback);
+                    break;
                 default:
                     log("unknown message " + msg);
                     break;
@@ -508,6 +528,13 @@
 
                 // notify provisioning key value to ImsService
                 setInitialProvisioningKeys(mSubId);
+
+                if (mFeatureFlags.notifyInitialImsProvisioningStatus()) {
+                    // Notify MmTel provisioning value based on capability and radio tech.
+                    if (mProvisioningCallbackManagersSlotMap.get(mSlotId).hasCallblacks()) {
+                        notifyMmTelProvisioningStatus(mSlotId, mSubId, null);
+                    }
+                }
             } else {
                 // wait until subId is valid
                 mRequiredNotify = true;
@@ -740,6 +767,13 @@
 
                 // notify provisioning key value to ImsService
                 setInitialProvisioningKeys(mSubId);
+
+                if (mFeatureFlags.notifyInitialImsProvisioningStatus()) {
+                    if (mProvisioningCallbackManagersSlotMap.get(mSlotId).hasCallblacks()) {
+                        // Notify RCS provisioning value based on capability and radio tech.
+                        notifyRcsProvisioningStatus(mSlotId, mSubId, null);
+                    }
+                }
             } else {
                 // wait until subId is valid
                 mRequiredNotify = true;
@@ -828,7 +862,7 @@
     @VisibleForTesting
     public ImsProvisioningController(PhoneGlobals app, int numSlot, Looper looper,
             MmTelFeatureConnector mmTelFeatureConnector, RcsFeatureConnector rcsFeatureConnector,
-            ImsProvisioningLoader imsProvisioningLoader) {
+            ImsProvisioningLoader imsProvisioningLoader, FeatureFlags featureFlags) {
         log("ImsProvisioningController");
         mApp = app;
         mNumSlot = numSlot;
@@ -841,6 +875,7 @@
         mTelephonyRegistryManager.addOnSubscriptionsChangedListener(
                 mSubChangedListener, mHandler::post);
         mImsProvisioningLoader = imsProvisioningLoader;
+        mFeatureFlags = featureFlags;
 
         PhoneConfigurationManager.registerForMultiSimConfigChange(mHandler,
                 EVENT_MULTI_SIM_CONFIGURATION_CHANGE, null);
@@ -924,7 +959,8 @@
      * create an instance
      */
     @VisibleForTesting
-    public static ImsProvisioningController make(PhoneGlobals app, int numSlot) {
+    public static ImsProvisioningController make(PhoneGlobals app, int numSlot,
+            FeatureFlags featureFlags) {
         synchronized (ImsProvisioningController.class) {
             if (sInstance == null) {
                 Rlog.i(TAG, "ImsProvisioningController created");
@@ -932,7 +968,7 @@
                 handlerThread.start();
                 sInstance = new ImsProvisioningController(app, numSlot, handlerThread.getLooper(),
                         ImsManager::getConnector, RcsFeatureManager::getConnector,
-                        new ImsProvisioningLoader(app));
+                        new ImsProvisioningLoader(app), featureFlags);
             }
         }
         return sInstance;
@@ -966,6 +1002,11 @@
         try {
             mProvisioningCallbackManagersSlotMap.get(slotId).registerCallback(callback);
             log("Feature Provisioning Callback registered.");
+
+            if (mFeatureFlags.notifyInitialImsProvisioningStatus()) {
+                mHandler.sendMessage(mHandler.obtainMessage(EVENT_NOTIFY_INIT_PROVISIONED_VALUE,
+                        getSlotId(subId), subId, (Object) callback));
+            }
         } catch (NullPointerException e) {
             logw("can not access callback manager to add callback");
         }
@@ -1639,6 +1680,90 @@
         return true;
     }
 
+    private void notifyMmTelProvisioningStatus(int slotId, int subId,
+            @Nullable IFeatureProvisioningCallback callback) {
+        int value = ImsProvisioningLoader.STATUS_NOT_SET;
+        int[] techArray;
+        for (int capability : LOCAL_MMTEL_CAPABILITY) {
+            techArray = getTechsFromCarrierConfig(subId, capability, /*isMmTle*/true);
+            if (techArray == null) {
+                continue;
+            }
+
+            for (int radioTech : techArray) {
+                value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
+                        capability, radioTech);
+                if (value == ImsProvisioningLoader.STATUS_NOT_SET) {
+                    // Not yet provisioned
+                    continue;
+                }
+
+                value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
+                        ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
+
+                // Notify all registered callbacks
+                if (callback == null) {
+                    mProvisioningCallbackManagersSlotMap.get(slotId)
+                            .notifyProvisioningCapabilityChanged(
+                                    new FeatureProvisioningData(
+                                            capability,
+                                            radioTech,
+                                            getBoolValue(value),
+                                            /*isMmTle*/true));
+                } else {
+                    try {
+                        callback.onFeatureProvisioningChanged(capability, radioTech,
+                                getBoolValue(value));
+                    } catch (RemoteException e) {
+                        logw("notifyMmTelProvisioningStatus callback is not available");
+                    }
+                }
+            }
+        }
+    }
+
+    private void notifyRcsProvisioningStatus(int slotId, int subId,
+            @Nullable IFeatureProvisioningCallback callback) {
+        int value = ImsProvisioningLoader.STATUS_NOT_SET;
+        int[] techArray;
+        for (int capability : LOCAL_RCS_CAPABILITY) {
+            techArray = getTechsFromCarrierConfig(subId, capability, /*isMmTle*/false);
+            if (techArray == null) {
+                continue;
+            }
+
+            for (int radioTech : techArray) {
+                value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_RCS,
+                        capability, radioTech);
+                if (value == ImsProvisioningLoader.STATUS_NOT_SET) {
+                    // Not yet provisioned
+                    continue;
+                }
+
+                value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
+                        ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
+
+                // Notify all registered callbacks
+                if (callback == null) {
+                    mProvisioningCallbackManagersSlotMap.get(slotId)
+                            .notifyProvisioningCapabilityChanged(
+                                    new FeatureProvisioningData(
+                                            capability,
+                                            radioTech,
+                                            getBoolValue(value),
+                                            /*isMmTle*/false));
+                } else {
+                    try {
+                        callback.onRcsFeatureProvisioningChanged(capability, radioTech,
+                                getBoolValue(value));
+                    } catch (RemoteException e) {
+                        logw("notifyRcsProvisioningStatus callback is not available");
+                    }
+                }
+            }
+        }
+    }
+
     private void log(String s) {
         Rlog.d(TAG, s);
     }
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index c3d7305..0c97cc2 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -91,6 +91,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Global state for the telephony subsystem when running in the primary
@@ -189,13 +190,15 @@
                     ROAMING_NOTIFICATION_REASON_DATA_ROAMING_SETTING_CHANGED,
                     ROAMING_NOTIFICATION_REASON_CARRIER_CONFIG_CHANGED,
                     ROAMING_NOTIFICATION_REASON_SERVICE_STATE_CHANGED,
-                    ROAMING_NOTIFICATION_REASON_DEFAULT_DATA_SUBS_CHANGED})
+                    ROAMING_NOTIFICATION_REASON_DEFAULT_DATA_SUBS_CHANGED,
+                    ROAMING_NOTIFICATION_REASON_DISCONNECTED_SINGLE_NETWORK})
     public @interface RoamingNotificationReason {}
     private static final int ROAMING_NOTIFICATION_REASON_DATA_SETTING_CHANGED = 0;
     private static final int ROAMING_NOTIFICATION_REASON_DATA_ROAMING_SETTING_CHANGED = 1;
     private static final int ROAMING_NOTIFICATION_REASON_CARRIER_CONFIG_CHANGED = 2;
     private static final int ROAMING_NOTIFICATION_REASON_SERVICE_STATE_CHANGED = 3;
     private static final int ROAMING_NOTIFICATION_REASON_DEFAULT_DATA_SUBS_CHANGED = 4;
+    private static final int ROAMING_NOTIFICATION_REASON_DISCONNECTED_SINGLE_NETWORK = 5;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -214,6 +217,14 @@
     private int mCurrentRoamingNotification = ROAMING_NOTIFICATION_NO_NOTIFICATION;
 
     /**
+     * If true, update roaming notifications after the Internet is completely disconnected. If
+     * carrier allows only a single data network, wait until the Internet connection is completely
+     * disconnected and then update the roaming notification once more to check if
+     * ONLY_ALLOWED_SINGLE_NETWORK disallow reason is disappeared.
+     */
+    private AtomicBoolean mWaitForInternetDisconnection = new AtomicBoolean(false);
+
+    /**
      * Reasons that have already shown notification to prevent duplicate shows for the same reason.
      */
     private ArraySet<String> mShownNotificationReasons = new ArraySet<>();
@@ -252,7 +263,8 @@
     private FeatureFlags mFeatureFlags = new FeatureFlagsImpl();
 
     private class PhoneAppCallback extends TelephonyCallback implements
-            TelephonyCallback.ServiceStateListener {
+            TelephonyCallback.ServiceStateListener,
+            TelephonyCallback.DataConnectionStateListener {
         private final int mSubId;
 
         PhoneAppCallback(int subId) {
@@ -266,6 +278,23 @@
             handleServiceStateChanged(serviceState, mSubId);
         }
 
+        @Override
+        public void onDataConnectionStateChanged(int state, int networkType) {
+            if (mSubId == mDefaultDataSubId && state == TelephonyManager.DATA_DISCONNECTED) {
+                // onDataConnectionStateChanged is an event about the state of exact DataNetwork,
+                // but since the DataNetwork of internet may not have been completely removed from
+                // the DataNetworkController list, The post handler event expects the internet data
+                // network to be completely removed from the DataNetworkController list.
+                mHandler.post(() -> {
+                    if (mWaitForInternetDisconnection.compareAndSet(true, false)) {
+                        Log.d(LOG_TAG, "onDisconnectedInternetDataNetwork.");
+                        updateDataRoamingStatus(
+                                ROAMING_NOTIFICATION_REASON_DISCONNECTED_SINGLE_NETWORK);
+                    }
+                });
+            }
+        }
+
         public int getSubId() {
             return mSubId;
         }
@@ -611,7 +640,8 @@
                 mTelephonyRcsService.initialize();
                 imsRcsController.setRcsService(mTelephonyRcsService);
                 mImsProvisioningController =
-                        ImsProvisioningController.make(this, PhoneFactory.getPhones().length);
+                        ImsProvisioningController.make(this, PhoneFactory.getPhones().length,
+                                mFeatureFlags);
             }
 
             // Create the CallNotifier singleton, which handles
@@ -1006,10 +1036,9 @@
      * When roaming, if mobile data cannot be established due to data roaming not enabled, we need
      * to notify the user so they can enable it through settings. Vise versa if the condition
      * changes, we need to dismiss the notification.
-     * @param reason to inform which event is called for notification update.
+     * @param notificationReason to inform which event is called for notification update.
      */
-    private void updateDataRoamingStatus(@RoamingNotificationReason int reason) {
-        if (VDBG) Log.v(LOG_TAG, "updateDataRoamingStatus");
+    private void updateDataRoamingStatus(@RoamingNotificationReason int notificationReason) {
         Phone phone = getPhone(mDefaultDataSubId);
         if (phone == null) {
             Log.w(LOG_TAG, "Can't get phone with sub id = " + mDefaultDataSubId);
@@ -1022,20 +1051,59 @@
             return;
         }
 
+        List<DataDisallowedReason> disallowReasons = phone.getDataNetworkController()
+                .getInternetDataDisallowedReasons();
+
+        if (mFeatureFlags.roamingNotificationForSingleDataNetwork()) {
+            if (disallowReasons.contains(DataDisallowedReason.ONLY_ALLOWED_SINGLE_NETWORK)
+                    && disallowReasons.contains(DataDisallowedReason.ROAMING_DISABLED)
+                    && (notificationReason == ROAMING_NOTIFICATION_REASON_DATA_SETTING_CHANGED
+                            || notificationReason
+                                    == ROAMING_NOTIFICATION_REASON_DATA_ROAMING_SETTING_CHANGED)) {
+                // If the ONLY_ALLOWED_SINGLE_NETWORK disallow reason has not yet been removed due
+                // to a change in mobile_data (including roaming_data) settings, update roaming
+                // notification again after the Internet is completely disconnected to check
+                // ONLY_ALLOWED_SINGLE_NETWORK disallow reason is removed.
+                mWaitForInternetDisconnection.set(true);
+                Log.d(LOG_TAG, "updateDataRoamingStatus,"
+                        + " wait for internet disconnection for single data network");
+            } else if (!disallowReasons.contains(DataDisallowedReason.ONLY_ALLOWED_SINGLE_NETWORK)
+                    && mWaitForInternetDisconnection.compareAndSet(true, false)) {
+                // If the ONLY_ALLOWED_SINGLE_NETWORK disallow reason has been removed,
+                // no longer wait for Internet disconnection.
+                Log.d(LOG_TAG, "updateDataRoamingStatus,"
+                        + " cancel to wait for internet disconnection for single data network");
+            }
+        }
+
+        updateDataRoamingStatus(notificationReason, disallowReasons, serviceState);
+    }
+
+    /**
+     * When roaming, if mobile data cannot be established due to data roaming not enabled, we need
+     * to notify the user so they can enable it through settings. Vise versa if the condition
+     * changes, we need to dismiss the notification.
+     * @param notificationReason to inform which event is called for notification update.
+     * @param disallowReasons List of reasons why internet data is not allowed. An empty list if
+     *                       internet is allowed.
+     * @param serviceState Service state from phone
+     */
+    private void updateDataRoamingStatus(@RoamingNotificationReason int notificationReason,
+            List<DataDisallowedReason> disallowReasons, ServiceState serviceState) {
+
+        if (VDBG) Log.v(LOG_TAG, "updateDataRoamingStatus");
         String roamingNumeric = serviceState.getOperatorNumeric();
         String roamingNumericReason = "RoamingNumeric=" + roamingNumeric;
-        String callingReason = "CallingReason=" + reason;
+        String callingReason = "CallingReason=" + notificationReason;
         boolean dataIsNowRoaming = serviceState.getDataRoaming();
         boolean dataAllowed;
         boolean notAllowedDueToRoamingOff;
-        List<DataDisallowedReason> reasons = phone.getDataNetworkController()
-                .getInternetDataDisallowedReasons();
-        dataAllowed = reasons.isEmpty();
-        notAllowedDueToRoamingOff = (reasons.size() == 1
-                && reasons.contains(DataDisallowedReason.ROAMING_DISABLED));
+        dataAllowed = disallowReasons.isEmpty();
+        notAllowedDueToRoamingOff = (disallowReasons.size() == 1
+                && disallowReasons.contains(DataDisallowedReason.ROAMING_DISABLED));
         StringBuilder sb = new StringBuilder("updateDataRoamingStatus");
         sb.append(" dataAllowed=").append(dataAllowed);
-        sb.append(", reasons=").append(reasons);
+        sb.append(", disallowReasons=").append(disallowReasons);
         sb.append(", dataIsNowRoaming=").append(dataIsNowRoaming);
         sb.append(", ").append(roamingNumericReason);
         sb.append(", ").append(callingReason);
@@ -1046,8 +1114,8 @@
 
         // Determine if a given roaming numeric has never been shown.
         boolean shownInThisNumeric = false;
-        if (reason == ROAMING_NOTIFICATION_REASON_CARRIER_CONFIG_CHANGED
-                || reason == ROAMING_NOTIFICATION_REASON_SERVICE_STATE_CHANGED) {
+        if (notificationReason == ROAMING_NOTIFICATION_REASON_CARRIER_CONFIG_CHANGED
+                || notificationReason == ROAMING_NOTIFICATION_REASON_SERVICE_STATE_CHANGED) {
             shownInThisNumeric = mShownNotificationReasons.contains(roamingNumericReason);
         }
         // Determine if a notification has never been shown by given calling reason.
@@ -1058,7 +1126,7 @@
                 mShownNotificationReasons.add(roamingNumericReason);
             }
             if (!shownForThisReason
-                    && reason == ROAMING_NOTIFICATION_REASON_CARRIER_CONFIG_CHANGED) {
+                    && notificationReason == ROAMING_NOTIFICATION_REASON_CARRIER_CONFIG_CHANGED) {
                 mShownNotificationReasons.add(callingReason);
             }
             // No need to show it again if we never cancelled it explicitly.
@@ -1085,7 +1153,7 @@
                 mShownNotificationReasons.add(roamingNumericReason);
             }
             if (!shownForThisReason
-                    && reason == ROAMING_NOTIFICATION_REASON_CARRIER_CONFIG_CHANGED) {
+                    && notificationReason == ROAMING_NOTIFICATION_REASON_CARRIER_CONFIG_CHANGED) {
                 mShownNotificationReasons.add(callingReason);
             }
             boolean shouldShowRoamingNotification = shouldShowRoamingNotification(roamingNumeric);
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 26e9185..2779bdb 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -13033,7 +13033,7 @@
                     }
                     if (isAllowed) {
                         mSatelliteController.requestSatelliteEnabled(
-                                subId, enableSatellite, enableDemoMode, callback);
+                                subId, enableSatellite, enableDemoMode, isEmergency, callback);
                     } else {
                         result.accept(SATELLITE_RESULT_ACCESS_BARRED);
                     }
@@ -13044,7 +13044,7 @@
         } else {
             // No need to check if satellite is allowed at current location when disabling satellite
             mSatelliteController.requestSatelliteEnabled(
-                    subId, enableSatellite, enableDemoMode, callback);
+                    subId, enableSatellite, enableDemoMode, isEmergency, callback);
         }
     }
 
diff --git a/src/com/android/phone/satellite/entitlement/SatelliteEntitlementApi.java b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementApi.java
index 45482ec..6c55709 100644
--- a/src/com/android/phone/satellite/entitlement/SatelliteEntitlementApi.java
+++ b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementApi.java
@@ -61,7 +61,8 @@
         SatelliteEntitlementResponse satelliteEntitlementResponse =
                 new SatelliteEntitlementResponse(response);
         return new SatelliteEntitlementResult(satelliteEntitlementResponse.getEntitlementStatus(),
-                satelliteEntitlementResponse.getPlmnAllowed());
+                satelliteEntitlementResponse.getPlmnAllowed(),
+                satelliteEntitlementResponse.getPlmnBarredList());
     }
 
     @NonNull
diff --git a/src/com/android/phone/satellite/entitlement/SatelliteEntitlementController.java b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementController.java
index accae32..d193a7d 100644
--- a/src/com/android/phone/satellite/entitlement/SatelliteEntitlementController.java
+++ b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementController.java
@@ -429,7 +429,8 @@
         updateSatelliteEntitlementStatus(subId,
                 mSatelliteEntitlementResultPerSub.get(subId).getEntitlementStatus()
                         == SATELLITE_ENTITLEMENT_STATUS_ENABLED,
-                mSatelliteEntitlementResultPerSub.get(subId).getAllowedPLMNList());
+                mSatelliteEntitlementResultPerSub.get(subId).getAllowedPLMNList(),
+                mSatelliteEntitlementResultPerSub.get(subId).getBarredPLMNList());
         stopExponentialBackoff(subId);
         mRetryCountPerSub.remove(subId);
     }
@@ -528,9 +529,9 @@
      */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     public void updateSatelliteEntitlementStatus(int subId, boolean enabled,
-            List<String> plmnAllowedList) {
+            List<String> plmnAllowedList, List<String> plmnBarredList) {
         SatelliteController.getInstance().onSatelliteEntitlementStatusUpdated(subId, enabled,
-                plmnAllowedList, null);
+                plmnAllowedList, plmnBarredList, null);
     }
 
     private static void logd(String log) {
diff --git a/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResponse.java b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResponse.java
index b877bee..97cb355 100644
--- a/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResponse.java
+++ b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResponse.java
@@ -97,7 +97,6 @@
      * Get the PLMNBarredList from the response
      * @return The PLMNs Barred List
      */
-    @VisibleForTesting
     public List<String> getPlmnBarredList() {
         return mPlmnBarredList.stream().map(String::new).collect(Collectors.toList());
     }
@@ -137,7 +136,10 @@
                 mPlmnBarredList = new ArrayList<>();
                 JSONArray jsonArray = jsonToken.getJSONArray(PLMN_BARRED_KEY);
                 for (int i = 0; i < jsonArray.length(); i++) {
-                    mPlmnBarredList.add(jsonArray.getJSONObject(i).getString(PLMN_KEY));
+                    String plmn = jsonArray.getJSONObject(i).getString(PLMN_KEY);
+                    if (!TextUtils.isEmpty(plmn)) {
+                        mPlmnBarredList.add(plmn);
+                    }
                 }
             }
         } catch (JSONException e) {
diff --git a/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResult.java b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResult.java
index 3289232..014e28e 100644
--- a/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResult.java
+++ b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResult.java
@@ -53,17 +53,25 @@
      * item of the satellite configuration received from the entitlement server.
      */
     private List<SatelliteNetworkInfo> mAllowedSatelliteNetworkInfoList;
+    /**
+     * List consisting of the PLMN in the PLMNBarred item of the satellite configuration received
+     * from the entitlement server
+     */
+    private List<String> mBarredPlmnList;
 
     /**
      * Store the result of the satellite entitlement response.
      *
      * @param entitlementStatus The entitlement status.
      * @param allowedSatelliteNetworkInfoList The allowedSatelliteNetworkInfoList
+     * @param barredPlmnList The barred plmn list
      */
     public SatelliteEntitlementResult(@SatelliteEntitlementStatus int entitlementStatus,
-            List<SatelliteNetworkInfo> allowedSatelliteNetworkInfoList) {
+            List<SatelliteNetworkInfo> allowedSatelliteNetworkInfoList,
+            List<String> barredPlmnList) {
         mEntitlementStatus = entitlementStatus;
         mAllowedSatelliteNetworkInfoList = allowedSatelliteNetworkInfoList;
+        mBarredPlmnList = barredPlmnList;
     }
 
     /**
@@ -86,6 +94,15 @@
     }
 
     /**
+     * Get the plmn barred list
+     *
+     * @return The plmn barred list.
+     */
+    public List<String> getBarredPLMNList() {
+        return mBarredPlmnList.stream().map(String::new).collect(Collectors.toList());
+    }
+
+    /**
      * Get the default SatelliteEntitlementResult. EntitlementStatus set to
      * `SATELLITE_ENTITLEMENT_STATUS_DISABLED` and SatelliteNetworkInfo list set to empty.
      *
@@ -93,6 +110,6 @@
      */
     public static SatelliteEntitlementResult getDefaultResult() {
         return new SatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_DISABLED,
-                new ArrayList<>());
+                new ArrayList<>(), new ArrayList<>());
     }
 }
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index d1961fd..48786dc 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -32,6 +32,7 @@
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.flags.FeatureFlagsImpl;
+import com.android.internal.telephony.satellite.SatelliteController;
 import com.android.phone.ImsUtil;
 import com.android.phone.PhoneGlobals;
 import com.android.phone.R;
@@ -457,7 +458,7 @@
                 resourceId = R.string.callFailed_wfc_service_not_available_in_this_location;
                 break;
             case android.telephony.DisconnectCause.SATELLITE_ENABLED:
-                resourceId = R.string.incall_error_satellite_enabled;
+                resourceId = getSatelliteErrorString();
                 break;
             default:
                 break;
@@ -641,7 +642,7 @@
                         resourceId = R.string.clh_incall_error_out_of_service_txt;
                         break;
                     case android.telephony.DisconnectCause.SATELLITE_ENABLED:
-                        resourceId = R.string.clh_callFailed_satelliteEnabled_txt;
+                        resourceId = getSatelliteErrorString();
                         break;
                     default:
                         resourceId = R.string.clh_card_title_call_ended_txt;
@@ -885,7 +886,7 @@
                 resourceId = R.string.callFailed_wfc_service_not_available_in_this_location;
                 break;
             case android.telephony.DisconnectCause.SATELLITE_ENABLED:
-                resourceId = R.string.incall_error_satellite_enabled;
+                resourceId = getSatelliteErrorString();
                 break;
             default:
                 break;
@@ -929,6 +930,8 @@
                 return DisconnectCause.REASON_IMS_ACCESS_BLOCKED;
             case android.telephony.DisconnectCause.OUTGOING_EMERGENCY_CALL_PLACED:
                 return DisconnectCause.REASON_EMERGENCY_CALL_PLACED;
+            case android.telephony.DisconnectCause.SATELLITE_ENABLED:
+                return reason;
         }
 
         // If no specific code-mapping found, then fall back to using the reason.
@@ -1041,4 +1044,11 @@
         boolean is2gEnabled = (currentlyAllowedNetworkTypes & bitmask2g) != 0;
         return !is2gEnabled;
     }
+
+    private static Integer getSatelliteErrorString() {
+        if (SatelliteController.getInstance().isSatelliteEnabled()) {
+            return R.string.incall_error_satellite_enabled;
+        }
+        return R.string.incall_error_carrier_roaming_satellite_mode;
+    }
 }
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 228fb4e..f71ea9a 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -149,6 +149,10 @@
     private static final Pattern CDMA_ACTIVATION_CODE_REGEX_PATTERN =
             Pattern.compile("\\*228[0-9]{0,2}");
 
+    private static final String DISCONNECT_REASON_SATELLITE_ENABLED = "SATELLITE_ENABLED";
+    private static final String DISCONNECT_REASON_CARRIER_ROAMING_SATELLITE_MODE =
+            "CARRIER_ROAMING_SATELLITE_MODE";
+
     private final TelephonyConnectionServiceProxy mTelephonyConnectionServiceProxy =
             new TelephonyConnectionServiceProxy() {
         @Override
@@ -1245,15 +1249,23 @@
             }
 
             if (!isEmergencyNumber) {
-                if ((mSatelliteController.isSatelliteEnabled()
-                        || isCallDisallowedDueToSatellite(phone))
-                        && (imsPhone == null || !imsPhone.canMakeWifiCall())) {
-                    Log.d(this, "onCreateOutgoingConnection, cannot make call in satellite mode.");
+                if (mSatelliteController.isSatelliteEnabled()) {
+                    Log.d(this, "onCreateOutgoingConnection, cannot make call in "
+                            + "satellite mode.");
                     return Connection.createFailedConnection(
                             mDisconnectCauseFactory.toTelecomDisconnectCause(
                                     android.telephony.DisconnectCause.SATELLITE_ENABLED,
-                                    "Call failed because satellite modem is enabled."));
+                                    DISCONNECT_REASON_SATELLITE_ENABLED));
+                } else if (isCallDisallowedDueToSatellite(phone)
+                        && (imsPhone == null || !imsPhone.canMakeWifiCall())) {
+                    Log.d(this, "onCreateOutgoingConnection, cannot make call "
+                            + "when device is connected to carrier roaming satellite network");
+                    return Connection.createFailedConnection(
+                            mDisconnectCauseFactory.toTelecomDisconnectCause(
+                                    android.telephony.DisconnectCause.SATELLITE_ENABLED,
+                                    DISCONNECT_REASON_CARRIER_ROAMING_SATELLITE_MODE));
                 }
+
                 final Connection resultConnection = getTelephonyConnection(request, numberToDial,
                         false, handle, phone);
                 if (isAdhocConference) {
@@ -2800,6 +2812,25 @@
                 .findFirst().orElse(null);
     }
 
+    /**
+     * Determines the phone with which emergency callback mode was set.
+     * @return The {@link Phone} with which emergency callback mode was set,
+     *         or {@code null} if none was found.
+     */
+    @VisibleForTesting
+    public Phone getPhoneInEmergencyCallbackMode() {
+        if (!mDomainSelectionResolver.isDomainSelectionSupported()) {
+            // This is applicable for the AP domain selection service.
+            return null;
+        }
+        if (mEmergencyStateTracker == null) {
+            mEmergencyStateTracker = EmergencyStateTracker.getInstance();
+        }
+        return Stream.of(mPhoneFactoryProxy.getPhones())
+                .filter(p -> mEmergencyStateTracker.isInEcm(p))
+                .findFirst().orElse(null);
+    }
+
     private boolean isVoiceInService(Phone phone, boolean imsVoiceCapable) {
         // Dialing normal call is available.
         if (phone.isWifiCallingEnabled()) {
@@ -3303,6 +3334,15 @@
             return normalRoutingPhone;
         }
 
+        if (mDomainSelectionResolver.isDomainSelectionSupported()) {
+            Phone phoneInEcm = getPhoneInEmergencyCallbackMode();
+            if (phoneInEcm != null) {
+                Log.i(this, "getPhoneForAccount: in ECBM, using phoneId=%d/subId=%d",
+                        phoneInEcm.getPhoneId(), phoneInEcm.getSubId());
+                return phoneInEcm;
+            }
+        }
+
         // Default emergency call phone selection logic:
         // This is an emergency call and the phone we originally planned to make this call
         // with is not in service or was invalid, try to find one that is in service, using the
diff --git a/testapps/TestSatelliteApp/AndroidManifest.xml b/testapps/TestSatelliteApp/AndroidManifest.xml
index fb30bf3..eaddf95 100644
--- a/testapps/TestSatelliteApp/AndroidManifest.xml
+++ b/testapps/TestSatelliteApp/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2023 The Android Open Source Project
+  ~ Copyright (C) 2024 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -46,6 +46,7 @@
         <activity android:name=".Provisioning" />
         <activity android:name=".MultipleSendReceive" />
         <activity android:name=".SendReceive" />
+        <activity android:name=".NbIotSatellite" />
         <activity android:name=".TestSatelliteWrapper" />
     </application>
 </manifest>
diff --git a/testapps/TestSatelliteApp/res/layout/activity_NbIotSatellite.xml b/testapps/TestSatelliteApp/res/layout/activity_NbIotSatellite.xml
new file mode 100644
index 0000000..c33522e
--- /dev/null
+++ b/testapps/TestSatelliteApp/res/layout/activity_NbIotSatellite.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:gravity="center"
+    android:paddingStart="4dp"
+    android:paddingEnd="4dp">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="0dp"
+        android:layout_weight="0"
+        android:textColor="@android:color/holo_blue_dark"
+        android:textSize="20sp"
+        android:text="@string/NbIotSatellite"/>
+    <Button
+        android:id="@+id/testRegisterForSupportedStateChanged"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="4dp"
+        android:paddingEnd="4dp"
+        android:text="@string/testRegisterForSupportedStateChanged"/>
+    <Button
+        android:id="@+id/testUnregisterForSupportedStateChanged"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="4dp"
+        android:paddingEnd="4dp"
+        android:text="@string/testUnregisterForSupportedStateChanged"/>
+    <Button
+        android:id="@+id/testRequestIsSupported"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="4dp"
+        android:paddingEnd="4dp"
+        android:text="@string/testRequestIsSupported"/>
+     <Button
+        android:id="@+id/reportSatelliteSupportedFromModem"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="4dp"
+        android:paddingEnd="4dp"
+        android:text="@string/reportSatelliteSupportedFromModem"/>
+    <Button
+        android:id="@+id/reportSatelliteNotSupportedFromModem"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="4dp"
+        android:paddingEnd="4dp"
+        android:text="@string/reportSatelliteNotSupportedFromModem"/>
+    <Button
+        android:id="@+id/showCurrentSatelliteSupportedStated"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="4dp"
+        android:paddingEnd="4dp"
+        android:text="@string/showCurrentSatelliteSupportedStated"/>
+    <Button
+        android:id="@+id/Back"
+        android:onClick="Back"
+        android:textColor="@android:color/holo_blue_dark"
+        android:layout_marginTop="100dp"
+        android:layout_gravity="center"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingStart="4dp"
+        android:paddingEnd="4dp"
+        android:text="@string/Back"/>
+    <TextView
+        android:id="@+id/text_id"
+        android:layout_width="300dp"
+        android:layout_height="200dp"
+        android:textColor="@android:color/holo_blue_light"
+        android:textSize="15sp" />
+</LinearLayout>
diff --git a/testapps/TestSatelliteApp/res/layout/activity_SatelliteControl.xml b/testapps/TestSatelliteApp/res/layout/activity_SatelliteControl.xml
index 6a79412..6aec1da 100644
--- a/testapps/TestSatelliteApp/res/layout/activity_SatelliteControl.xml
+++ b/testapps/TestSatelliteApp/res/layout/activity_SatelliteControl.xml
@@ -119,6 +119,12 @@
             android:layout_height="wrap_content"
             android:paddingRight="4dp"
             android:text="@string/isRequestIsSatelliteEnabledForCarrier"/>
+        <Button
+            android:id="@+id/getIsEmergency"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingRight="4dp"
+            android:text="@string/getIsEmergency"/>
          <Button
             android:id="@+id/Back"
             android:onClick="Back"
diff --git a/testapps/TestSatelliteApp/res/layout/activity_SatelliteTestApp.xml b/testapps/TestSatelliteApp/res/layout/activity_SatelliteTestApp.xml
index 0753b82..5ba7946 100644
--- a/testapps/TestSatelliteApp/res/layout/activity_SatelliteTestApp.xml
+++ b/testapps/TestSatelliteApp/res/layout/activity_SatelliteTestApp.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2023 The Android Open Source Project
+  ~ Copyright (C) 2024 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -65,9 +65,17 @@
              android:paddingRight="4dp"
              android:text="@string/SendReceive"/>
         <Button
+            android:id="@+id/NbIotSatellite"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingStart="4dp"
+            android:paddingEnd="4dp"
+            android:text="@string/NbIotSatellite"/>
+        <Button
             android:id="@+id/TestSatelliteWrapper"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:paddingStart="4dp"
             android:paddingEnd="4dp"
             android:text="@string/TestSatelliteWrapper"/>
     </LinearLayout>
diff --git a/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml b/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml
index 20f5ca8..df2aaf7 100644
--- a/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml
+++ b/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2023 The Android Open Source Project
+  ~ Copyright (C) 2024 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
     <string name="Provisioning">Provisioning APIs</string>
     <string name="MultipleSendReceive">Test multiple poll and send</string>
     <string name="SendReceive">Send and Receive datagrams</string>
+    <string name="NbIotSatellite">NB IoT Satellite modem interface test</string>
 
     <string name="enableSatellite">enableSatellite</string>
     <string name="disableSatellite">disableSatellite</string>
@@ -30,6 +31,7 @@
     <string name="requestSatelliteCapabilities">requestSatelliteCapabilities</string>
     <string name="requestIsSatelliteCommunicationAllowedForCurrentLocation">requestIsSatelliteCommunicationAllowedForCurrentLocation</string>
     <string name="requestTimeForNextSatelliteVisibility">requestTimeForNextSatelliteVisibility</string>
+    <string name="getIsEmergency">getIsEmergency</string>
 
     <string name="pollPendingSatelliteDatagrams">pollPendingSatelliteDatagrams</string>
     <string name="sendSatelliteDatagram">sendSatelliteDatagram</string>
@@ -82,6 +84,13 @@
     <string name="isSatelliteEnabledForCarrier">isSatelliteEnabledForCarrier</string>
     <string name="isRequestIsSatelliteEnabledForCarrier">isRequestIsSatelliteEnabledForCarrier</string>
 
+    <string name="testRegisterForSupportedStateChanged">testRegisterForSupportedStateChanged</string>
+    <string name="testUnregisterForSupportedStateChanged">testUnregisterForSupportedStateChanged</string>
+    <string name="testRequestIsSupported">testRequestIsSupported</string>
+    <string name="reportSatelliteSupportedFromModem">reportSatelliteSupportedFromModem</string>
+    <string name="reportSatelliteNotSupportedFromModem">reportSatelliteNotSupportedFromModem</string>
+    <string name="showCurrentSatelliteSupportedStated">showCurrentSatelliteSupportedStated</string>
+
     <string name="Back">Back</string>
     <string name="ClearLog">Clear Log</string>
 </resources>
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/NbIotSatellite.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/NbIotSatellite.java
new file mode 100644
index 0000000..17646f0
--- /dev/null
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/NbIotSatellite.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone.testapps.satellitetestapp;
+
+import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.os.OutcomeReceiver;
+import android.telephony.satellite.SatelliteManager;
+import android.telephony.satellite.SatelliteSupportedStateCallback;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.TextView;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Activity related to NB IoT satellite APIs.
+ */
+public class NbIotSatellite extends Activity {
+
+    private static final String TAG = "NbIotSatellite";
+    private static final String MY_SHARED_PREF = "MySharedPref";
+    private static final String SHARED_PREF_KEY = "supported_stated";
+    TextView mTextView;
+    private boolean mSatelliteSupported = false;
+    public static TestSatelliteService sSatelliteService;
+    private SatelliteManager mSatelliteManager;
+    private TestSatelliteSupportedStateCallback mSatelliteSupportedStateCallback;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        sSatelliteService = SatelliteTestApp.getTestSatelliteService();
+        mSatelliteManager = getSystemService(SatelliteManager.class);
+
+        setContentView(R.layout.activity_NbIotSatellite);
+        findViewById(R.id.testRegisterForSupportedStateChanged)
+                .setOnClickListener(this::testRegisterForSupportedStateChanged);
+        findViewById(R.id.testUnregisterForSupportedStateChanged)
+                .setOnClickListener(this::testUnregisterForSupportedStateChanged);
+        findViewById(R.id.testRequestIsSupported)
+                .setOnClickListener(this::testRequestIsSupported);
+        findViewById(R.id.reportSatelliteSupportedFromModem)
+                .setOnClickListener(this::reportSatelliteSupportedFromModem);
+        findViewById(R.id.reportSatelliteNotSupportedFromModem)
+                .setOnClickListener(this::reportSatelliteNotSupportedFromModem);
+        findViewById(R.id.showCurrentSatelliteSupportedStated)
+                .setOnClickListener(this::showCurrentSatelliteSupportedStated);
+        findViewById(R.id.Back).setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                startActivity(new Intent(NbIotSatellite.this, SatelliteTestApp.class));
+            }
+        });
+
+        mTextView = findViewById(R.id.text_id);
+    }
+
+    protected class TestSatelliteSupportedStateCallback implements SatelliteSupportedStateCallback {
+        @Override
+        public void onSatelliteSupportedStateChanged(boolean supported) {
+            mSatelliteSupported = supported;
+            updateLogMessage("onSatelliteSupportedStateChanged: "
+                    + (mSatelliteSupported ? "Satellite is supported"
+                    : "Satellite is not supported"));
+            Log.d(TAG, "onSatelliteSupportedStateChanged(): supported="
+                    + mSatelliteSupported);
+        }
+    }
+
+    @SuppressLint("MissingPermission")
+    private void testRegisterForSupportedStateChanged(View view) {
+        if (mSatelliteSupportedStateCallback == null) {
+            mSatelliteSupportedStateCallback = new TestSatelliteSupportedStateCallback();
+        }
+        int result = mSatelliteManager.registerForSupportedStateChanged(Runnable::run,
+                mSatelliteSupportedStateCallback);
+
+        if (result == SATELLITE_RESULT_SUCCESS) {
+            updateLogMessage("testRegisterForSupportedStateChanged(): "
+                    + "registered mSatelliteSupportedStateCallback");
+        } else {
+            updateLogMessage("Failed to registerForSupportedStateChanged(), reason=" + result);
+        }
+    }
+
+    @SuppressLint("MissingPermission")
+    private void testUnregisterForSupportedStateChanged(View view) {
+        if (mSatelliteSupportedStateCallback != null) {
+            mSatelliteManager.unregisterForSupportedStateChanged(mSatelliteSupportedStateCallback);
+            mSatelliteSupportedStateCallback = null;
+            updateLogMessage("testUnregisterForSupportedStateChanged(): unregister callback.");
+        } else {
+            updateLogMessage("testUnregisterForSupportedStateChanged(): ignored, "
+                    + "mSatelliteSupportedStateCallback is already null");
+        }
+    }
+
+    private void testRequestIsSupported(View view) {
+        final AtomicReference<Boolean> enabled = new AtomicReference<>();
+        final AtomicReference<Integer> errorCode = new AtomicReference<>();
+        OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> mReceiver =
+                new OutcomeReceiver<>() {
+                        @Override
+                        public void onResult(Boolean result) {
+                            enabled.set(result);
+                            updateLogMessage("Status for requestIsSupported result: "
+                                    + enabled.get());
+                        }
+
+                        @Override
+                        public void onError(SatelliteManager.SatelliteException exception) {
+                            errorCode.set(exception.getErrorCode());
+                            updateLogMessage("Status for requestIsSupported error : "
+                                    + SatelliteErrorUtils.mapError(errorCode.get()));
+                        }
+                    };
+        mSatelliteManager.requestIsSupported(Runnable::run, mReceiver);
+    }
+
+    private void showCurrentSatelliteSupportedStated(View view) {
+        boolean mModemSupportedState = sSatelliteService.getSatelliteSupportedState();
+        updateLogMessage("reported supported state is " + mSatelliteSupported
+                        + ", modem supported state is " + mModemSupportedState);
+    }
+
+    private void reportSatelliteSupportedFromModem(View view) {
+        sSatelliteService.updateSatelliteSupportedState(true);
+    }
+
+    private void reportSatelliteNotSupportedFromModem(View view) {
+        sSatelliteService.updateSatelliteSupportedState(false);
+    }
+
+    // Fetch the stored data in onResume()
+    // Because this is what will be called when the app opens again
+    @Override
+    protected void onResume() {
+        super.onResume();
+        // Fetching the stored data from the SharedPreference
+        SharedPreferences sh = getSharedPreferences("MySharedPref", MODE_PRIVATE);
+        boolean isProvisioned = sh.getBoolean("provision_state", mSatelliteSupported);
+
+        // Setting the fetched data
+        mSatelliteSupported = isProvisioned;
+    }
+
+    // Store the data in the SharedPreference in the onPause() method
+    // When the user closes the application onPause() will be called and data will be stored
+    @Override
+    protected void onPause() {
+        super.onPause();
+        // Creating a shared pref object with a file name "MySharedPref" in private mode
+        SharedPreferences sharedPreferences = getSharedPreferences(MY_SHARED_PREF, MODE_PRIVATE);
+        SharedPreferences.Editor myEdit = sharedPreferences.edit();
+
+        // write all the data entered by the user in SharedPreference and apply
+        myEdit.putBoolean(SHARED_PREF_KEY, mSatelliteSupported);
+        myEdit.apply();
+    }
+
+    private void updateLogMessage(String message) {
+        runOnUiThread(() -> mTextView.setText(message));
+    }
+
+    protected void onDestroy() {
+        super.onDestroy();
+        SharedPreferences sharedPreferences = getSharedPreferences(MY_SHARED_PREF, MODE_PRIVATE);
+
+        final SharedPreferences.Editor sharedPrefsEditor = sharedPreferences.edit();
+        sharedPrefsEditor.remove(SHARED_PREF_KEY);
+        sharedPrefsEditor.apply();
+    }
+}
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteControl.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteControl.java
index dd7b825..a03f04e 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteControl.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteControl.java
@@ -81,6 +81,8 @@
                 .setOnClickListener(this::isSatelliteEnabledForCarrierApp);
         findViewById(R.id.isRequestIsSatelliteEnabledForCarrier)
                 .setOnClickListener(this::isRequestIsSatelliteEnabledForCarrierApp);
+        findViewById(R.id.getIsEmergency)
+                .setOnClickListener(this::getIsEmergencyApp);
         findViewById(R.id.Back).setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View view) {
@@ -92,8 +94,8 @@
     private void enableSatelliteApp(View view) {
         LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1);
         mSatelliteManager.requestEnabled(
-                new EnableRequestAttributes.Builder(true).setDemoMode(true).build(),
-                Runnable::run, error::offer);
+                new EnableRequestAttributes.Builder(true).setDemoMode(true).setEmergencyMode(true)
+                        .build(), Runnable::run, error::offer);
         TextView textView = findViewById(R.id.text_id);
         try {
             Integer value = error.poll(TIMEOUT, TimeUnit.MILLISECONDS);
@@ -374,4 +376,11 @@
                 + SatelliteTestApp.getTestSatelliteService()
                 .isRequestIsSatelliteEnabledForCarrier());
     }
+
+    private void getIsEmergencyApp(View view) {
+        TextView textView = findViewById(R.id.text_id);
+        textView.setText("[SatelliteService] getIsEmergencyApp= "
+                + SatelliteTestApp.getTestSatelliteService()
+                .getIsEmergency());
+    }
 }
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteTestApp.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteTestApp.java
index c8ee5fa..7c4ae00 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteTestApp.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteTestApp.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -89,6 +89,13 @@
                 startActivity(intent);
             }
         });
+        findViewById(R.id.NbIotSatellite).setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                Intent intent = new Intent(SatelliteTestApp.this, NbIotSatellite.class);
+                startActivity(intent);
+            }
+        });
         findViewById(R.id.TestSatelliteWrapper).setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View view) {
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java
index ed9fa10..d79240e 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -100,6 +100,7 @@
     private List<String> mAllPlmnList = new ArrayList<>();
     private boolean mIsSatelliteEnabledForCarrier;
     private boolean mIsRequestIsSatelliteEnabledForCarrier;
+    private boolean mIsEmergnecy;
 
     /**
      * Create TestSatelliteService using the Executor specified for methods being called from
@@ -117,6 +118,7 @@
         mIsCellularModemEnabledMode = false;
         mIsSatelliteEnabledForCarrier = false;
         mIsRequestIsSatelliteEnabledForCarrier = false;
+        mIsEmergnecy = false;
     }
 
     /**
@@ -184,8 +186,9 @@
 
     @Override
     public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode,
-            @NonNull IIntegerConsumer errorCallback) {
-        logd("requestSatelliteEnabled: mErrorCode=" + mErrorCode + " enable = " + enableSatellite);
+            boolean isEmergency, @NonNull IIntegerConsumer errorCallback) {
+        logd("requestSatelliteEnabled: mErrorCode=" + mErrorCode + " enable = " + enableSatellite
+                + " isEmergency=" + isEmergency);
         if (mErrorCode != SatelliteResult.SATELLITE_RESULT_SUCCESS) {
             runWithExecutor(() -> errorCallback.accept(mErrorCode));
             return;
@@ -196,6 +199,7 @@
         } else {
             disableSatellite(errorCallback);
         }
+        mIsEmergnecy = isEmergency;
     }
 
     private void enableSatellite(@NonNull IIntegerConsumer errorCallback) {
@@ -467,6 +471,16 @@
     }
 
     /**
+     * Helper method to report satellite supported from modem side for testing purpose.
+     * @param supported whether satellite is supported from modem or not.
+     */
+    public void sendOnSatelliteSupportedStateChanged(boolean supported) {
+        logd("sendOnSatelliteSupportedStateChanged: supported=" + supported);
+        mRemoteListeners.values().forEach(listener -> runWithExecutor(() ->
+                listener.onSatelliteSupportedStateChanged(supported)));
+    }
+
+    /**
      * Helper method to verify that the satellite modem is properly configured to receive
      * requests.
      *
@@ -565,6 +579,26 @@
         return mIsRequestIsSatelliteEnabledForCarrier;
     }
 
+    public boolean getIsEmergency() {
+        return mIsEmergnecy;
+    }
+
+    /**
+     * Helper methoid to provide a way to set supported state from test application to mock modem.
+     * @param supported whether satellite is supported by modem or not.
+     */
+    public void updateSatelliteSupportedState(boolean  supported) {
+        logd("updateSatelliteSupportedState: supported=" + supported);
+        mIsSupported = supported;
+        mRemoteListeners.values().forEach(listener -> runWithExecutor(
+                () -> listener.onSatelliteSupportedStateChanged(mIsSupported)));
+
+    }
+
+    public boolean getSatelliteSupportedState() {
+        return mIsSupported;
+    }
+
     /**
      * Log the message to the radio buffer with {@code DEBUG} priority.
      *
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java
index 4f0679d..27967f4 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java
@@ -248,7 +248,7 @@
                         String message = "Received SatelliteCapabillities : "
                                 + SatelliteCapabilities;
                         logd(message);
-                        runOnUiThread(() -> addLogMessage(message));
+                        addLogMessage(message);
                     };
         }
 
@@ -281,7 +281,7 @@
                 @NonNull NtnSignalStrengthWrapper ntnSignalStrength) {
             String message = "Received NTN SignalStrength : " + ntnSignalStrength.getLevel();
             logd(message);
-            runOnUiThread(() -> addLogMessage(message));
+            addLogMessage(message);
         }
     }
 
@@ -317,7 +317,7 @@
         }
 
         Consumer<Integer> callback = result -> {
-            runOnUiThread(() -> addLogMessage("requestAttachEnabledForCarrier result: " + result));
+            addLogMessage("requestAttachEnabledForCarrier result: " + result);
             logd("requestAttachEnabledForCarrier result: " + result);
         };
 
@@ -342,7 +342,7 @@
         }
 
         Consumer<Integer> callback = result -> {
-            runOnUiThread(() -> addLogMessage("requestAttachEnabledForCarrier result: " + result));
+            addLogMessage("requestAttachEnabledForCarrier result: " + result);
             logd("requestAttachEnabledForCarrier result: " + result);
         };
 
@@ -409,7 +409,7 @@
         int reason = SatelliteManagerWrapper.SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER;
 
         Consumer<Integer> callback = result -> {
-            runOnUiThread(() -> addLogMessage("addAttachRestrictionForCarrier result: " + result));
+            addLogMessage("addAttachRestrictionForCarrier result: " + result);
             logd("addAttachRestrictionForCarrier result: " + result);
         };
 
@@ -436,8 +436,7 @@
         int reason = SatelliteManagerWrapper.SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER;
 
         Consumer<Integer> callback = result -> {
-            runOnUiThread(
-                    () -> addLogMessage("removeAttachRestrictionForCarrier result: " + result));
+            addLogMessage("removeAttachRestrictionForCarrier result: " + result);
             logd("removeAttachRestrictionForCarrier result: " + result);
         };
 
@@ -569,9 +568,11 @@
     }
 
     private void addLogMessage(String message) {
-        mLogMessages.add(message);
-        mAdapter.notifyDataSetChanged();
-        mLogListView.setSelection(mAdapter.getCount() - 1);
+        runOnUiThread(() -> {
+            mLogMessages.add(message);
+            mAdapter.notifyDataSetChanged();
+            mLogListView.setSelection(mAdapter.getCount() - 1);
+        });
     }
 
     private static void logd(String message) {
diff --git a/tests/src/com/android/phone/ImsProvisioningControllerTest.java b/tests/src/com/android/phone/ImsProvisioningControllerTest.java
index e12be53..6599f03 100644
--- a/tests/src/com/android/phone/ImsProvisioningControllerTest.java
+++ b/tests/src/com/android/phone/ImsProvisioningControllerTest.java
@@ -77,6 +77,7 @@
 import com.android.ims.ImsConfig;
 import com.android.ims.ImsManager;
 import com.android.ims.RcsFeatureManager;
+import com.android.internal.telephony.flags.FeatureFlags;
 
 import org.junit.After;
 import org.junit.Before;
@@ -169,6 +170,9 @@
     @Mock
     IBinder mIbinder1;
 
+    @Mock
+    FeatureFlags mFeatureFlags;
+
     private SubscriptionManager.OnSubscriptionsChangedListener mSubChangedListener;
 
     private Handler mHandler;
@@ -192,7 +196,7 @@
         TestImsProvisioningController() {
             super(mPhone, 2, mHandlerThread.getLooper(),
                     mMmTelFeatureConnector, mRcsFeatureConnector,
-                    mImsProvisioningLoader);
+                    mImsProvisioningLoader, mFeatureFlags);
         }
 
         protected int getSubId(int slotId) {
@@ -369,8 +373,6 @@
         }
 
         // verify other interactions
-        verifyNoMoreInteractions(mIFeatureProvisioningCallback0);
-        verifyNoMoreInteractions(mIFeatureProvisioningCallback1);
         verifyNoMoreInteractions(mImsConfig);
     }
 
@@ -408,8 +410,6 @@
         verify(mImsConfig, times(1)).setConfig(eq(key), anyInt());
 
         // verify other interactions
-        verifyNoMoreInteractions(mIFeatureProvisioningCallback0);
-        verifyNoMoreInteractions(mIFeatureProvisioningCallback1);
         verifyNoMoreInteractions(mImsConfig);
     }
 
@@ -926,8 +926,6 @@
         verify(mImsConfig, times(1)).setConfig(
                 eq(KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE), eq(PROVISIONING_VALUE_ENABLED));
 
-        verifyNoMoreInteractions(mIFeatureProvisioningCallback0);
-        verifyNoMoreInteractions(mIFeatureProvisioningCallback1);
         verifyNoMoreInteractions(mImsConfig);
         verifyNoMoreInteractions(mImsProvisioningLoader);
     }
@@ -1849,6 +1847,184 @@
         verifyNoMoreInteractions(mImsConfig);
     }
 
+    @Test
+    @SmallTest
+    public void initialNotifyMmTelProvisioningStatusWhenCallbackRegistered() throws Exception {
+        when(mFeatureFlags.notifyInitialImsProvisioningStatus()).thenReturn(true);
+
+        createImsProvisioningController();
+
+        // Provisioning required for capability on all network type
+        setCarrierConfig(mSubId0, CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_VOICE_INT_ARRAY,
+                RADIO_TECHS);
+        setCarrierConfig(mSubId0, CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_VIDEO_INT_ARRAY,
+                RADIO_TECHS);
+        setCarrierConfig(mSubId0, CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_UT_INT_ARRAY,
+                RADIO_TECHS);
+        setCarrierConfig(mSubId0, CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_SMS_INT_ARRAY,
+                RADIO_TECHS);
+        setCarrierConfig(mSubId0,
+                CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_CALL_COMPOSER_INT_ARRAY, RADIO_TECHS);
+
+        // Stored provisioning Status
+        mMmTelProvisioningStorage = new int[][] {
+                {CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_LTE, 0},
+                {CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_IWLAN, 1},
+                {CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_CROSS_SIM, 1},
+                {CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_NR, 1},
+                {CAPABILITY_TYPE_VIDEO, REGISTRATION_TECH_LTE, 0},
+                {CAPABILITY_TYPE_VIDEO, REGISTRATION_TECH_IWLAN, 0},
+                {CAPABILITY_TYPE_VIDEO, REGISTRATION_TECH_CROSS_SIM, 1},
+                {CAPABILITY_TYPE_VIDEO, REGISTRATION_TECH_NR, 1},
+                {CAPABILITY_TYPE_UT, REGISTRATION_TECH_LTE, 0},
+                {CAPABILITY_TYPE_UT, REGISTRATION_TECH_IWLAN, 0},
+                {CAPABILITY_TYPE_UT, REGISTRATION_TECH_CROSS_SIM, 0},
+                {CAPABILITY_TYPE_UT, REGISTRATION_TECH_NR, 0},
+                {CAPABILITY_TYPE_SMS, REGISTRATION_TECH_LTE, 1},
+                {CAPABILITY_TYPE_SMS, REGISTRATION_TECH_IWLAN, 1},
+                {CAPABILITY_TYPE_SMS, REGISTRATION_TECH_CROSS_SIM, 1},
+                {CAPABILITY_TYPE_SMS, REGISTRATION_TECH_NR, 1},
+                {CAPABILITY_TYPE_CALL_COMPOSER, REGISTRATION_TECH_LTE, 1},
+                {CAPABILITY_TYPE_CALL_COMPOSER, REGISTRATION_TECH_IWLAN, 1},
+                {CAPABILITY_TYPE_CALL_COMPOSER, REGISTRATION_TECH_CROSS_SIM, 0},
+                {CAPABILITY_TYPE_CALL_COMPOSER, REGISTRATION_TECH_NR, 1}
+        };
+
+        try {
+            mTestImsProvisioningController.addFeatureProvisioningChangedCallback(
+                    mSubId0, mIFeatureProvisioningCallback0);
+        } catch (Exception e) {
+            throw new AssertionError("not expected exception", e);
+        }
+        processAllMessages();
+
+        for (int[] capa: mMmTelProvisioningStorage) {
+            verify(mIFeatureProvisioningCallback0, times(1))
+                    .onFeatureProvisioningChanged(eq(capa[0]), eq(capa[1]), eq(capa[2] == 1));
+        }
+    }
+
+    @Test
+    @SmallTest
+    public void initialNotifyRcsProvisioningStatusWhenCallbackRegistered() throws Exception {
+        when(mFeatureFlags.notifyInitialImsProvisioningStatus()).thenReturn(true);
+
+        createImsProvisioningController();
+
+        // Provisioning required capability : PRESENCE, tech : all
+        setCarrierConfig(mSubId0,
+                CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY, RADIO_TECHS);
+
+        // Stored provisioning Status
+        mRcsProvisioningStorage = new int[][]{
+                {CAPABILITY_TYPE_PRESENCE_UCE, REGISTRATION_TECH_LTE, 1},
+                {CAPABILITY_TYPE_PRESENCE_UCE, REGISTRATION_TECH_IWLAN, 1},
+                {CAPABILITY_TYPE_PRESENCE_UCE, REGISTRATION_TECH_CROSS_SIM, 0},
+                {CAPABILITY_TYPE_PRESENCE_UCE, REGISTRATION_TECH_NR, 1}
+        };
+
+        try {
+            mTestImsProvisioningController.addFeatureProvisioningChangedCallback(
+                    mSubId0, mIFeatureProvisioningCallback0);
+        } catch (Exception e) {
+            throw new AssertionError("not expected exception", e);
+        }
+        processAllMessages();
+
+        for (int[] capa: mRcsProvisioningStorage) {
+            verify(mIFeatureProvisioningCallback0, times(1))
+                    .onRcsFeatureProvisioningChanged(eq(capa[0]), eq(capa[1]), eq(capa[2] == 1));
+        }
+    }
+
+    @Test
+    @SmallTest
+    public void initialNotifyMmTelProvisioningStatusWhenImsServiceConnected() throws Exception {
+        when(mFeatureFlags.notifyInitialImsProvisioningStatus()).thenReturn(true);
+
+        createImsProvisioningController();
+
+        // Provisioning required for capability on all network type
+        setCarrierConfig(mSubId0, CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_VOICE_INT_ARRAY,
+                RADIO_TECHS);
+        setCarrierConfig(mSubId0, CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_VIDEO_INT_ARRAY,
+                RADIO_TECHS);
+
+        // Stored provisioning Status
+        mMmTelProvisioningStorage = new int[][] {
+                {CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_LTE, 1},
+                {CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_IWLAN, 1},
+                {CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_CROSS_SIM, 1},
+                {CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_NR, 1},
+                {CAPABILITY_TYPE_VIDEO, REGISTRATION_TECH_LTE, 1},
+                {CAPABILITY_TYPE_VIDEO, REGISTRATION_TECH_IWLAN, 0},
+                {CAPABILITY_TYPE_VIDEO, REGISTRATION_TECH_CROSS_SIM, 0},
+                {CAPABILITY_TYPE_VIDEO, REGISTRATION_TECH_NR, 1},
+        };
+
+        try {
+            mTestImsProvisioningController.addFeatureProvisioningChangedCallback(
+                    mSubId0, mIFeatureProvisioningCallback0);
+        } catch (Exception e) {
+            throw new AssertionError("not expected exception", e);
+        }
+        processAllMessages();
+
+        // clear interactions
+        clearInvocations(mIFeatureProvisioningCallback0);
+
+        // ImsService connected
+        mMmTelConnectorListener0.getValue().connectionReady(mImsManager, mSubId0);
+
+        for (int[] capa: mMmTelProvisioningStorage) {
+            verify(mIFeatureProvisioningCallback0, times(1))
+                    .onFeatureProvisioningChanged(eq(capa[0]), eq(capa[1]), eq(capa[2] == 1));
+        }
+
+        verifyNoMoreInteractions(mIFeatureProvisioningCallback0);
+    }
+
+    @Test
+    @SmallTest
+    public void initialNotifyRcsProvisioningStatusWhenRcsServiceConnected() throws Exception {
+        when(mFeatureFlags.notifyInitialImsProvisioningStatus()).thenReturn(true);
+
+        createImsProvisioningController();
+
+        // Provisioning required capability : PRESENCE, tech : all
+        setCarrierConfig(mSubId0,
+                CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY, RADIO_TECHS);
+
+        // Stored provisioning Status
+        mRcsProvisioningStorage = new int[][]{
+                {CAPABILITY_TYPE_PRESENCE_UCE, REGISTRATION_TECH_LTE, 1},
+                {CAPABILITY_TYPE_PRESENCE_UCE, REGISTRATION_TECH_IWLAN, 0},
+                {CAPABILITY_TYPE_PRESENCE_UCE, REGISTRATION_TECH_CROSS_SIM, 0},
+                {CAPABILITY_TYPE_PRESENCE_UCE, REGISTRATION_TECH_NR, 1}
+        };
+
+        try {
+            mTestImsProvisioningController.addFeatureProvisioningChangedCallback(
+                    mSubId0, mIFeatureProvisioningCallback0);
+        } catch (Exception e) {
+            throw new AssertionError("not expected exception", e);
+        }
+        processAllMessages();
+
+        // clear interactions
+        clearInvocations(mIFeatureProvisioningCallback0);
+
+        // ImsService connected
+        mRcsConnectorListener0.getValue().connectionReady(mRcsFeatureManager, mSubId0);
+
+        for (int[] capa: mRcsProvisioningStorage) {
+            verify(mIFeatureProvisioningCallback0, times(1))
+                    .onRcsFeatureProvisioningChanged(eq(capa[0]), eq(capa[1]), eq(capa[2] == 1));
+        }
+
+        verifyNoMoreInteractions(mIFeatureProvisioningCallback0);
+    }
+
     private void createImsProvisioningController() throws Exception {
         if (Looper.myLooper() == null) {
             Looper.prepare();
diff --git a/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java b/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java
index 18a0284..dd9ea65 100644
--- a/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java
+++ b/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java
@@ -79,6 +79,7 @@
     private static final int[] ACTIVE_SUB_ID = {SUB_ID};
     private static final int DEFAULT_QUERY_REFRESH_DAY = 30;
     private static final List<String> PLMN_ALLOWED_LIST = Arrays.asList("31026", "302820");
+    private static final List<String> PLMN_BARRED_LIST = Arrays.asList("12345", "98765");
     @Mock
     CarrierConfigManager mCarrierConfigManager;
     @Mock
@@ -166,7 +167,7 @@
 
         verify(mSatelliteEntitlementApi, never()).checkEntitlementStatus();
         verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
-                anyBoolean(), anyList(), any());
+                anyBoolean(), anyList(), anyList(), any());
 
         mCarrierConfigBundle.putBoolean(
                 CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, true);
@@ -177,7 +178,7 @@
 
         verify(mSatelliteEntitlementApi, never()).checkEntitlementStatus();
         verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
-                anyBoolean(), anyList(), any());
+                anyBoolean(), anyList(), anyList(), any());
 
         replaceInstance(SatelliteEntitlementController.class, "mExponentialBackoffPerSub",
                 mSatelliteEntitlementController, new HashMap<>());
@@ -188,7 +189,7 @@
 
         verify(mSatelliteEntitlementApi, never()).checkEntitlementStatus();
         verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
-                anyBoolean(), anyList(), any());
+                anyBoolean(), anyList(), anyList(), any());
 
         setInternetConnected(true);
         // Verify don't start the query when last query refresh time is not expired.
@@ -197,18 +198,19 @@
 
         verify(mSatelliteEntitlementApi, never()).checkEntitlementStatus();
         verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
-                anyBoolean(), anyList(), any());
+                anyBoolean(), anyList(), anyList(), any());
 
         // Verify start the query when isQueryAvailable return true
         setLastQueryTime(0L);
         doReturn(mSatelliteEntitlementResult).when(
                 mSatelliteEntitlementApi).checkEntitlementStatus();
-        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST);
+        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST,
+                PLMN_BARRED_LIST);
         mSatelliteEntitlementController.handleCmdStartQueryEntitlement();
 
         verify(mSatelliteEntitlementApi).checkEntitlementStatus();
         verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(anyInt(),
-                anyBoolean(), anyList(), any());
+                anyBoolean(), anyList(), anyList(), any());
     }
 
     @Test
@@ -221,7 +223,7 @@
         verify(mSatelliteEntitlementApi, never()).checkEntitlementStatus();
         // Verify don't call the updateSatelliteEntitlementStatus.
         verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
-                anyBoolean(), anyList(), any());
+                anyBoolean(), anyList(), anyList(), any());
 
         // Verify call the checkSatelliteEntitlementStatus with invalid response.
         setIsQueryAvailableTrue();
@@ -234,26 +236,27 @@
 
         verify(mSatelliteEntitlementApi).checkEntitlementStatus();
         // Verify call the updateSatelliteEntitlementStatus with satellite service is disabled
-        // and empty PLMNAllowed
+        // , empty PLMNAllowed and empty PLMNBarred.
         verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID),
-                eq(false), eq(new ArrayList<>()), any());
+                eq(false), eq(new ArrayList<>()), eq(new ArrayList<>()), any());
 
         // Verify call the checkSatelliteEntitlementStatus with the subscribed result.
         clearInvocationsForMock();
         setIsQueryAvailableTrue();
         doReturn(mSatelliteEntitlementResult).when(
                 mSatelliteEntitlementApi).checkEntitlementStatus();
-        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST);
+        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST,
+                PLMN_BARRED_LIST);
         mSatelliteEntitlementController.handleCmdStartQueryEntitlement();
 
         verify(mSatelliteEntitlementApi).checkEntitlementStatus();
-        // Verify call the updateSatelliteEntitlementStatus with satellite service is enable and
-        // availablePLMNAllowedList
+        // Verify call the updateSatelliteEntitlementStatus with satellite service is enable,
+        // availablePLMNAllowedList and availablePLMNBarredList.
         verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID), eq(true),
-                eq(PLMN_ALLOWED_LIST), any());
+                eq(PLMN_ALLOWED_LIST), eq(PLMN_BARRED_LIST), any());
 
-        // Change subId and verify call the updateSatelliteEntitlementStatus with  satellite
-        // service is enable and availablePLMNAllowedList
+        // Change subId and verify call the updateSatelliteEntitlementStatus with satellite
+        // service is enable, availablePLMNAllowedList and availablePLMNBarredList
         clearInvocationsForMock();
         doReturn(new int[]{SUB_ID_2}).when(mMockSubscriptionManagerService).getActiveSubIdList(
                 true);
@@ -261,7 +264,43 @@
 
         verify(mSatelliteEntitlementApi).checkEntitlementStatus();
         verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID_2), eq(true),
-                eq(PLMN_ALLOWED_LIST), any());
+                eq(PLMN_ALLOWED_LIST), eq(PLMN_BARRED_LIST), any());
+
+        // Verify call the updateSatelliteEntitlementStatus with satellite service is enable,
+        // availablePLMNAllowedList and empty plmn barred list.
+        clearInvocationsForMock();
+        setIsQueryAvailableTrue();
+        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST,
+                new ArrayList<>());
+        mSatelliteEntitlementController.handleCmdStartQueryEntitlement();
+
+        verify(mSatelliteEntitlementApi).checkEntitlementStatus();
+        verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID), eq(true),
+                eq(PLMN_ALLOWED_LIST), eq(new ArrayList<>()), any());
+
+        // Verify call the updateSatelliteEntitlementStatus with satellite service is enable,
+        // empty PLMNAllowedList and PLMNBarredList.
+        clearInvocationsForMock();
+        setIsQueryAvailableTrue();
+        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, new ArrayList<>(),
+                new ArrayList<>());
+        mSatelliteEntitlementController.handleCmdStartQueryEntitlement();
+
+        verify(mSatelliteEntitlementApi).checkEntitlementStatus();
+        verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID), eq(true),
+                eq(new ArrayList<>()), eq(new ArrayList<>()), any());
+
+        // Verify call the updateSatelliteEntitlementStatus with satellite service is enable,
+        // empty PLMNAllowedList and availablePLMNBarredList.
+        clearInvocationsForMock();
+        setIsQueryAvailableTrue();
+        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, new ArrayList<>(),
+                PLMN_BARRED_LIST);
+        mSatelliteEntitlementController.handleCmdStartQueryEntitlement();
+
+        verify(mSatelliteEntitlementApi).checkEntitlementStatus();
+        verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID), eq(true),
+                eq(new ArrayList<>()), eq(PLMN_BARRED_LIST), any());
     }
 
     @Test
@@ -277,7 +316,8 @@
         // Verify the called the checkSatelliteEntitlementStatus when Internet is connected.
         setInternetConnected(true);
         setLastQueryTime(0L);
-        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST);
+        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST,
+                PLMN_BARRED_LIST);
 
         networkCallback.onAvailable(mockNetwork);
         mTestableLooper.processAllMessages();
@@ -285,7 +325,7 @@
         verify(mSatelliteEntitlementApi).checkEntitlementStatus();
         // Verify call the updateSatelliteEntitlementStatus with satellite service is available.
         verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID), eq(true),
-                eq(PLMN_ALLOWED_LIST), any());
+                eq(PLMN_ALLOWED_LIST), eq(PLMN_BARRED_LIST), any());
     }
 
     @Test
@@ -294,13 +334,14 @@
         // occurred and Internet is connected.
         setInternetConnected(true);
         setLastQueryTime(0L);
-        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST);
+        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST,
+                PLMN_BARRED_LIST);
         triggerCarrierConfigChanged();
 
         verify(mSatelliteEntitlementApi).checkEntitlementStatus();
         // Verify call the updateSatelliteEntitlementStatus with satellite service is available.
         verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID), eq(true),
-                eq(PLMN_ALLOWED_LIST), any());
+                eq(PLMN_ALLOWED_LIST), eq(PLMN_BARRED_LIST), any());
     }
 
     private void triggerCarrierConfigChanged() {
@@ -344,9 +385,10 @@
     }
 
     private void setSatelliteEntitlementResult(int entitlementStatus,
-            List<String> plmnAllowedList) {
+            List<String> plmnAllowedList, List<String> plmnBarredList) {
         doReturn(entitlementStatus).when(mSatelliteEntitlementResult).getEntitlementStatus();
         doReturn(plmnAllowedList).when(mSatelliteEntitlementResult).getAllowedPLMNList();
+        doReturn(plmnBarredList).when(mSatelliteEntitlementResult).getBarredPLMNList();
     }
 
     private void setLastQueryTime(Long lastQueryTime) throws Exception {
diff --git a/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResponseTest.java b/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResponseTest.java
index 13d43c8..8e45a73 100644
--- a/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResponseTest.java
+++ b/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResponseTest.java
@@ -136,27 +136,55 @@
         assertTrue(response.getPlmnBarredList().size() == 2);
         assertEquals(TEST_PLMN_BARRED_LIST, response.getPlmnBarredList());
 
+        // Received the body without plmn barred key.
+        response = new SatelliteEntitlementResponse(
+                getChangedAllowedPLMNListResponse(TEST_PLMN_DATA_PLAN_TYPE_LIST.get(0).mPlmn,
+                        TEST_PLMN_DATA_PLAN_TYPE_LIST.get(1).mPlmn));
+        assertEquals(SATELLITE_ENTITLEMENT_STATUS_ENABLED, response.getEntitlementStatus());
+        assertTrue(response.getPlmnAllowed().size() == 2);
+        assertTrue(response.getPlmnBarredList().size() == 0);
+
         String plmn = "123456";
-        // Received 123456 and empty string list
+        // Received the allowed plmn list set as 123456, empty string
         response = new SatelliteEntitlementResponse(
-                getChangedPLMNListResponse(plmn, ""));
+                getChangedAllowedPLMNListResponse(plmn, ""));
         assertEquals(SATELLITE_ENTITLEMENT_STATUS_ENABLED, response.getEntitlementStatus());
         assertTrue(response.getPlmnAllowed().size() == 1);
         assertEquals(plmn, response.getPlmnAllowed().get(0).mPlmn);
 
-        // Received empty string and 123456 list
+        // Received the allowed plmn list set as 123456, empty string
         response = new SatelliteEntitlementResponse(
-                getChangedPLMNListResponse("", plmn));
+                getChangedAllowedPLMNListResponse("", plmn));
         assertEquals(SATELLITE_ENTITLEMENT_STATUS_ENABLED, response.getEntitlementStatus());
         assertTrue(response.getPlmnAllowed().size() == 1);
         assertEquals(plmn, response.getPlmnAllowed().get(0).mPlmn);
 
-        // Received all empty strings list
+        // RReceived the allowed plmn list set as empty strings
         response = new SatelliteEntitlementResponse(
-                getChangedPLMNListResponse("", ""));
+                getChangedAllowedPLMNListResponse("", ""));
         assertEquals(SATELLITE_ENTITLEMENT_STATUS_ENABLED, response.getEntitlementStatus());
         assertTrue(response.getPlmnAllowed().size() == 0);
 
+        // Received the barred plmn list set as 123456, empty string
+        response = new SatelliteEntitlementResponse(
+                getChangedBarredPLMNListResponse(plmn, ""));
+        assertEquals(SATELLITE_ENTITLEMENT_STATUS_ENABLED, response.getEntitlementStatus());
+        assertTrue(response.getPlmnBarredList().size() == 1);
+        assertEquals(plmn, response.getPlmnBarredList().get(0));
+
+        // Received the barred plmn list set as empty string, 123456
+        response = new SatelliteEntitlementResponse(
+                getChangedBarredPLMNListResponse("", plmn));
+        assertEquals(SATELLITE_ENTITLEMENT_STATUS_ENABLED, response.getEntitlementStatus());
+        assertTrue(response.getPlmnBarredList().size() == 1);
+        assertEquals(plmn, response.getPlmnBarredList().get(0));
+
+        // Received the barred plmn list set as empty strings
+        response = new SatelliteEntitlementResponse(
+                getChangedBarredPLMNListResponse("", ""));
+        assertEquals(SATELLITE_ENTITLEMENT_STATUS_ENABLED, response.getEntitlementStatus());
+        assertTrue(response.getPlmnBarredList().size() == 0);
+
         // Received null
         response = new SatelliteEntitlementResponse(null);
         assertEquals(SATELLITE_ENTITLEMENT_STATUS_DISABLED, response.getEntitlementStatus());
@@ -190,7 +218,12 @@
                 + "{\"PLMN\":\"" + secondPlmn + "\",\"DataPlanType\":\"metered\"}]";
     }
 
-    private String getChangedPLMNListResponse(String firstPlmn, String secondPlmn) {
+    private String getBarredPlmns(String firstPlmn, String secondPlmn) {
+        return ",\"PLMNBarred\":[{\"PLMN\":\"" + firstPlmn + "\"}," + "{\"PLMN\":\"" + secondPlmn
+                + "\"}]";
+    }
+
+    private String getChangedAllowedPLMNListResponse(String firstPlmn, String secondPlmn) {
         return "{\"VERS\":{\"version\":\"1\",\"validity\":\"172800\"},"
                 + "\"TOKEN\":{\"token\":\"ASH127AHHA88SF\"},\""
                 + ServiceEntitlement.APP_SATELLITE_ENTITLEMENT + "\":{"
@@ -198,4 +231,15 @@
                 + getAllowedPlmns(firstPlmn, secondPlmn)
                 + "}}";
     }
+
+    private String getChangedBarredPLMNListResponse(String firstPlmn, String secondPlmn) {
+        return "{\"VERS\":{\"version\":\"1\",\"validity\":\"172800\"},"
+                + "\"TOKEN\":{\"token\":\"ASH127AHHA88SF\"},\""
+                + ServiceEntitlement.APP_SATELLITE_ENTITLEMENT + "\":{"
+                + "\"EntitlementStatus\":\"" + SATELLITE_ENTITLEMENT_STATUS_ENABLED + "\""
+                + ",\"PLMNAllowed\":[{\"PLMN\":\"31026\",\"DataPlanType\":\"unmetered\"},"
+                + "{\"PLMN\":\"302820\",\"DataPlanType\":\"metered\"}]"
+                + getBarredPlmns(firstPlmn, secondPlmn)
+                + "}}";
+    }
 }
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index bad3b4e..2b805c3 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -224,6 +224,9 @@
     private static final Uri TEST_ADDRESS = Uri.parse("tel:+16505551212");
     private static final String TELECOM_CALL_ID1 = "TC1";
     private static final String TEST_EMERGENCY_NUMBER = "911";
+    private static final String DISCONNECT_REASON_SATELLITE_ENABLED = "SATELLITE_ENABLED";
+    private static final String DISCONNECT_REASON_CARRIER_ROAMING_SATELLITE_MODE =
+            "CARRIER_ROAMING_SATELLITE_MODE";
     private android.telecom.Connection mConnection;
 
     @Mock TelephonyConnectionService.TelephonyManagerProxy mTelephonyManagerProxy;
@@ -3475,6 +3478,7 @@
         DisconnectCause disconnectCause = mConnection.getDisconnectCause();
         assertEquals(android.telephony.DisconnectCause.SATELLITE_ENABLED,
                 disconnectCause.getTelephonyDisconnectCause());
+        assertEquals(DISCONNECT_REASON_SATELLITE_ENABLED, disconnectCause.getReason());
     }
 
     @Test
@@ -3492,6 +3496,7 @@
         DisconnectCause disconnectCause = mConnection.getDisconnectCause();
         assertEquals(android.telephony.DisconnectCause.SATELLITE_ENABLED,
                 disconnectCause.getTelephonyDisconnectCause());
+        assertEquals(DISCONNECT_REASON_CARRIER_ROAMING_SATELLITE_MODE, disconnectCause.getReason());
 
         // Call is supported while using satellite
         when(mSatelliteController.getCapabilitiesForCarrierRoamingSatelliteMode(any()))
@@ -3518,6 +3523,7 @@
         DisconnectCause disconnectCause = mConnection.getDisconnectCause();
         assertEquals(android.telephony.DisconnectCause.SATELLITE_ENABLED,
                 disconnectCause.getTelephonyDisconnectCause());
+        assertEquals(DISCONNECT_REASON_CARRIER_ROAMING_SATELLITE_MODE, disconnectCause.getReason());
 
         // Call is supported when device is connected to satellite within hysteresis time
         setupForCallTest();
@@ -3735,6 +3741,30 @@
                         NORMAL_ROUTED_EMERGENCY_NUMBER));
     }
 
+    /**
+     * Verify where there are two sims, we choose the sim in emergency callback mode for the
+     * next emergency call.
+     */
+    @Test
+    public void testGetPhoneInEmergencyCallbackModeMultiSim() {
+        Phone mockPhone1 = Mockito.mock(Phone.class);
+        Phone mockPhone2 = Mockito.mock(Phone.class);
+
+        when(mPhoneFactoryProxy.getPhones()).thenReturn(
+                new Phone[] {mockPhone1, mockPhone2});
+
+        doReturn(false).when(mEmergencyStateTracker).isInEcm(eq(mockPhone1));
+        doReturn(true).when(mEmergencyStateTracker).isInEcm(eq(mockPhone2));
+
+        // Only applicable for AP domain seleciton service
+        assertNull(mTestConnectionService.getPhoneInEmergencyCallbackMode());
+
+        doReturn(true).when(mDomainSelectionResolver).isDomainSelectionSupported();
+
+        assertEquals(mockPhone2,
+                mTestConnectionService.getPhoneInEmergencyCallbackMode());
+    }
+
     private void setupMockEmergencyNumbers(Phone mockPhone, List<EmergencyNumber> numbers) {
         EmergencyNumberTracker emergencyNumberTracker = Mockito.mock(EmergencyNumberTracker.class);
         // Yuck.  There should really be a fake emergency number class which makes it easy to inject