Merge "Using carrier config value if there is no value of the call forward no reply time from MMI code" into main
diff --git a/flags/calling.aconfig b/flags/calling.aconfig
index c1dc7e7..2809f79 100644
--- a/flags/calling.aconfig
+++ b/flags/calling.aconfig
@@ -21,6 +21,17 @@
 
 # OWNER=stevestatia TARGET=24Q4
 flag {
+    name: "national_country_code_formatting_for_local_calls"
+    namespace: "telephony"
+    description: "Make requests and bug fixes for formatting local calls based on country codes easier with a more scalable solution."
+    bug: "293993310"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+# OWNER=stevestatia TARGET=24Q4
+flag {
     name: "remove_country_code_from_local_singapore_calls"
     namespace: "telephony"
     description: "Fix bug where the country code is being shown when merging in local Singapore numbers to conference calls."
diff --git a/flags/ims.aconfig b/flags/ims.aconfig
index 4eff505..1056ea3 100644
--- a/flags/ims.aconfig
+++ b/flags/ims.aconfig
@@ -115,3 +115,14 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+# OWNER=joonhunshin TARGET=24Q4
+flag {
+    name: "prevent_hangup_during_call_merge"
+    namespace: "telephony"
+    description: "This flag prevents hangup call during call merge"
+    bug:"317070933"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/flags/misc.aconfig b/flags/misc.aconfig
index 9d5cbd6..538a114 100644
--- a/flags/misc.aconfig
+++ b/flags/misc.aconfig
@@ -217,3 +217,25 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+# OWNER=rambowang TARGET=24Q4
+flag {
+    name: "support_phone_uid_check_for_multiuser"
+    namespace: "telephony"
+    description: "Check phone/system processes from UID with multiuser-aware way"
+    bug:"328511085"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+# OWNER=joonhunshin TARGET=24Q4
+flag {
+    name: "use_carrier_config_for_cfnry_time_via_mmi"
+    namespace: "telephony"
+    description: "This flag allows the no reply timer to be referenced in the carrier config when setting up call forward via MMI code and there is no timer value."
+    bug:"342346827"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/flags/satellite.aconfig b/flags/satellite.aconfig
index 2eea80a..f663de8 100644
--- a/flags/satellite.aconfig
+++ b/flags/satellite.aconfig
@@ -33,4 +33,21 @@
     namespace: "telephony"
     description: "This flag enables satellite persistent logging"
     bug:"339877723"
-}
\ No newline at end of file
+}
+
+# OWNER=hyosunkim TARGET=24Q3
+flag {
+    name: "carrier_roaming_nb_iot_ntn"
+    namespace: "telephony"
+    description: "This flag enables satellite carrier roaming to nb iot ntn."
+    bug:"348253735"
+}
+
+# OWNER=tnd TARGET=24Q4
+flag {
+    name: "oem_enabled_satellite_phase_2"
+    is_exported: true
+    namespace: "telephony"
+    description: "This flag controls satellite communication supported by OEMs in phase 2."
+    bug:"349624547"
+}
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index a9e21a3..aa62acb 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -150,10 +150,10 @@
  */
 
 public abstract class Phone extends Handler implements PhoneInternalInterface {
-    private static final String LOG_TAG = "Phone";
 
     protected final static Object lockForRadioTechnologyChange = new Object();
 
+    private final String mLogTag;
     protected final int USSD_MAX_QUEUE = 10;
 
     // Key used to read and write the saved network selection numeric value
@@ -597,6 +597,7 @@
                     boolean unitTestMode, int phoneId,
                     TelephonyComponentFactory telephonyComponentFactory,
                     FeatureFlags featureFlags) {
+        mLogTag = "Phone-" + phoneId;
         mPhoneId = phoneId;
         mName = name;
         mNotifier = notifier;
@@ -638,10 +639,10 @@
          */
         mDoesRilSendMultipleCallRing = TelephonyProperties.ril_sends_multiple_call_ring()
                 .orElse(true);
-        Rlog.d(LOG_TAG, "mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing);
+        Rlog.d(mLogTag, "mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing);
 
         mCallRingDelay = TelephonyProperties.call_ring_delay().orElse(3000);
-        Rlog.d(LOG_TAG, "mCallRingDelay=" + mCallRingDelay);
+        Rlog.d(mLogTag, "mCallRingDelay=" + mCallRingDelay);
 
         // Initialize SMS stats
         mSmsStats = new SmsStats(this);
@@ -785,7 +786,7 @@
 
         switch(msg.what) {
             case EVENT_CALL_RING:
-                Rlog.d(LOG_TAG, "Event EVENT_CALL_RING Received state=" + getState());
+                Rlog.d(mLogTag, "Event EVENT_CALL_RING Received state=" + getState());
                 ar = (AsyncResult)msg.obj;
                 if (ar.exception == null) {
                     PhoneConstants.State state = getState();
@@ -801,7 +802,7 @@
                 break;
 
             case EVENT_CALL_RING_CONTINUE:
-                Rlog.d(LOG_TAG, "Event EVENT_CALL_RING_CONTINUE Received state=" + getState());
+                Rlog.d(mLogTag, "Event EVENT_CALL_RING_CONTINUE Received state=" + getState());
                 if (getState() == PhoneConstants.State.RINGING) {
                     sendIncomingCallRingNotification(msg.arg1);
                 }
@@ -814,7 +815,7 @@
             case EVENT_INITIATE_SILENT_REDIAL:
                 // This is an ImsPhone -> GsmCdmaPhone redial
                 // See ImsPhone#initiateSilentRedial
-                Rlog.d(LOG_TAG, "Event EVENT_INITIATE_SILENT_REDIAL Received");
+                Rlog.d(mLogTag, "Event EVENT_INITIATE_SILENT_REDIAL Received");
                 ar = (AsyncResult) msg.obj;
                 if ((ar.exception == null) && (ar.result != null)) {
                     SilentRedialParam result = (SilentRedialParam) ar.result;
@@ -828,13 +829,13 @@
                         // one with a callback registered to TelephonyConnection. Notify the
                         // redial happened over that Phone so that it can be replaced with the
                         // new GSM/CDMA Connection.
-                        Rlog.d(LOG_TAG, "Notify redial connection changed cn: " + cn);
+                        Rlog.d(mLogTag, "Notify redial connection changed cn: " + cn);
                         if (mImsPhone != null) {
                             // Don't care it is null or not.
                             mImsPhone.notifyRedialConnectionChanged(cn);
                         }
                     } catch (CallStateException e) {
-                        Rlog.e(LOG_TAG, "silent redial failed: " + e);
+                        Rlog.e(mLogTag, "silent redial failed: " + e);
                         if (mImsPhone != null) {
                             mImsPhone.notifyRedialConnectionChanged(null);
                         }
@@ -847,7 +848,7 @@
                 if (ar.exception == null) {
                     handleSrvccStateChanged((int[]) ar.result);
                 } else {
-                    Rlog.e(LOG_TAG, "Srvcc exception: " + ar.exception);
+                    Rlog.e(mLogTag, "Srvcc exception: " + ar.exception);
                 }
                 break;
 
@@ -866,7 +867,7 @@
                     try {
                         mUsageSettingFromModem = ((int[]) ar.result)[0];
                     } catch (NullPointerException | ClassCastException e) {
-                        Rlog.e(LOG_TAG, "Invalid response for usage setting " + ar.result);
+                        Rlog.e(mLogTag, "Invalid response for usage setting " + ar.result);
                         break;
                     }
 
@@ -881,9 +882,9 @@
                         if (ce.getCommandError() == CommandException.Error.REQUEST_NOT_SUPPORTED) {
                             mIsUsageSettingSupported = false;
                         }
-                        Rlog.w(LOG_TAG, "Unexpected failure to retrieve usage setting " + ce);
+                        Rlog.w(mLogTag, "Unexpected failure to retrieve usage setting " + ce);
                     } catch (ClassCastException unused) {
-                        Rlog.e(LOG_TAG, "Invalid Exception for usage setting " + ar.exception);
+                        Rlog.e(mLogTag, "Invalid Exception for usage setting " + ar.exception);
                         break; // technically extraneous, but good hygiene
                     }
                 }
@@ -896,9 +897,9 @@
                         if (ce.getCommandError() == CommandException.Error.REQUEST_NOT_SUPPORTED) {
                             mIsUsageSettingSupported = false;
                         }
-                        Rlog.w(LOG_TAG, "Unexpected failure to set usage setting " + ce);
+                        Rlog.w(mLogTag, "Unexpected failure to set usage setting " + ce);
                     } catch (ClassCastException unused) {
-                        Rlog.e(LOG_TAG, "Invalid Exception for usage setting " + ar.exception);
+                        Rlog.e(mLogTag, "Invalid Exception for usage setting " + ar.exception);
                         break; // technically extraneous, but good hygiene
                     }
                 }
@@ -932,7 +933,7 @@
     }
 
     private void handleSrvccStateChanged(int[] ret) {
-        Rlog.d(LOG_TAG, "handleSrvccStateChanged");
+        Rlog.d(mLogTag, "handleSrvccStateChanged");
 
         ArrayList<Connection> conn = null;
         Phone imsPhone = mImsPhone;
@@ -949,7 +950,7 @@
                         conn = imsPhone.getHandoverConnection();
                         migrateFrom(imsPhone);
                     } else {
-                        Rlog.d(LOG_TAG, "HANDOVER_STARTED: mImsPhone null");
+                        Rlog.d(mLogTag, "HANDOVER_STARTED: mImsPhone null");
                     }
                     break;
                 case TelephonyManager.SRVCC_STATE_HANDOVER_COMPLETED:
@@ -1187,7 +1188,7 @@
                     to.add((Registrant) from.get(i));
                 }
             } else {
-                Rlog.d(LOG_TAG, "msg is null");
+                Rlog.d(mLogTag, "msg is null");
             }
         }
     }
@@ -1484,7 +1485,7 @@
      */
     @UnsupportedAppUsage
     public void setNetworkSelectionModeAutomatic(Message response) {
-        Rlog.d(LOG_TAG, "setNetworkSelectionModeAutomatic, querying current mode");
+        Rlog.d(mLogTag, "setNetworkSelectionModeAutomatic, querying current mode");
         // we don't want to do this unnecessarily - it actually causes
         // the radio to repeat network selection and is costly
         // first check if we're already in automatic mode
@@ -1519,11 +1520,11 @@
         nsm.operatorAlphaShort = "";
 
         if (doAutomatic) {
-            Rlog.d(LOG_TAG, "setNetworkSelectionModeAutomatic - set network selection auto");
+            Rlog.d(mLogTag, "setNetworkSelectionModeAutomatic - set network selection auto");
             Message msg = obtainMessage(EVENT_SET_NETWORK_AUTOMATIC_COMPLETE, nsm);
             mCi.setNetworkSelectionModeAutomatic(msg);
         } else {
-            Rlog.d(LOG_TAG, "setNetworkSelectionModeAutomatic - already auto, ignoring");
+            Rlog.d(mLogTag, "setNetworkSelectionModeAutomatic - already auto, ignoring");
             // let the calling application know that the we are ignoring automatic mode switch.
             if (nsm.message != null) {
                 nsm.message.arg1 = ALREADY_IN_AUTO_SELECTION;
@@ -1617,10 +1618,10 @@
 
             // commit and log the result.
             if (!editor.commit()) {
-                Rlog.e(LOG_TAG, "failed to commit network selection preference");
+                Rlog.e(mLogTag, "failed to commit network selection preference");
             }
         } else {
-            Rlog.e(LOG_TAG, "Cannot update network selection preference due to invalid subId " +
+            Rlog.e(mLogTag, "Cannot update network selection preference due to invalid subId " +
                     subId);
         }
     }
@@ -1631,7 +1632,7 @@
      * @param nsm PLMN info of the selected network
      */
     protected void updateManualNetworkSelection(NetworkSelectMessage nsm)  {
-        Rlog.e(LOG_TAG, "updateManualNetworkSelection() should be overridden");
+        Rlog.e(mLogTag, "updateManualNetworkSelection() should be overridden");
     }
 
     /**
@@ -1641,7 +1642,7 @@
         // look for our wrapper within the asyncresult, skip the rest if it
         // is null.
         if (!(ar.userObj instanceof NetworkSelectMessage)) {
-            Rlog.e(LOG_TAG, "unexpected result from user object.");
+            Rlog.e(mLogTag, "unexpected result from user object.");
             return;
         }
 
@@ -1705,12 +1706,12 @@
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
         SharedPreferences.Editor editor = sp.edit();
         editor.putInt(CLIR_KEY + getSubId(), commandInterfaceCLIRMode);
-        Rlog.i(LOG_TAG, "saveClirSetting: " + CLIR_KEY + getSubId() + "="
+        Rlog.i(mLogTag, "saveClirSetting: " + CLIR_KEY + getSubId() + "="
                 + commandInterfaceCLIRMode);
 
         // Commit and log the result.
         if (!editor.commit()) {
-            Rlog.e(LOG_TAG, "Failed to commit CLIR preference");
+            Rlog.e(mLogTag, "Failed to commit CLIR preference");
         }
     }
 
@@ -1932,13 +1933,13 @@
         IccFileHandler fh;
 
         if (uiccApplication == null) {
-            Rlog.d(LOG_TAG, "getIccFileHandler: uiccApplication == null, return null");
+            Rlog.d(mLogTag, "getIccFileHandler: uiccApplication == null, return null");
             fh = null;
         } else {
             fh = uiccApplication.getIccFileHandler();
         }
 
-        Rlog.d(LOG_TAG, "getIccFileHandler: fh=" + fh);
+        Rlog.d(mLogTag, "getIccFileHandler: fh=" + fh);
         return fh;
     }
 
@@ -2025,7 +2026,7 @@
      * Retrieves the SignalStrengthController of the phone instance.
      */
     public SignalStrengthController getSignalStrengthController() {
-        Log.wtf(LOG_TAG, "getSignalStrengthController return null.");
+        Log.wtf(mLogTag, "getSignalStrengthController return null.");
         return null;
     }
 
@@ -2059,7 +2060,7 @@
      * Update voice mail count related fields and notify listeners
      */
     public void updateVoiceMail() {
-        Rlog.e(LOG_TAG, "updateVoiceMail() should be overridden");
+        Rlog.e(mLogTag, "updateVoiceMail() should be overridden");
     }
 
     public AppType getCurrentUiccAppType() {
@@ -2185,7 +2186,7 @@
         if (SubscriptionManager.isValidSubscriptionId(subId)) {
             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
             status = sp.getInt(CF_STATUS + subId, IccRecords.CALL_FORWARDING_STATUS_UNKNOWN);
-            Rlog.d(LOG_TAG, "getCallForwardingIndicatorFromSharedPref: for subId " + subId + "= " +
+            Rlog.d(mLogTag, "getCallForwardingIndicatorFromSharedPref: for subId " + subId + "= " +
                     status);
             // Check for old preference if status is UNKNOWN for current subId. This part of the
             // code is needed only when upgrading from M to N.
@@ -2199,9 +2200,9 @@
                         status = sp.getInt(CF_STATUS, IccRecords.CALL_FORWARDING_STATUS_DISABLED);
                         setCallForwardingIndicatorInSharedPref(
                                 status == IccRecords.CALL_FORWARDING_STATUS_ENABLED ? true : false);
-                        Rlog.d(LOG_TAG, "getCallForwardingIndicatorFromSharedPref: " + status);
+                        Rlog.d(mLogTag, "getCallForwardingIndicatorFromSharedPref: " + status);
                     } else {
-                        Rlog.d(LOG_TAG, "getCallForwardingIndicatorFromSharedPref: returning " +
+                        Rlog.d(mLogTag, "getCallForwardingIndicatorFromSharedPref: returning " +
                                 "DISABLED as status for matching subscriberId not found");
                     }
 
@@ -2213,7 +2214,7 @@
                 }
             }
         } else {
-            Rlog.e(LOG_TAG, "getCallForwardingIndicatorFromSharedPref: invalid subId " + subId);
+            Rlog.e(mLogTag, "getCallForwardingIndicatorFromSharedPref: invalid subId " + subId);
         }
         return status;
     }
@@ -2222,7 +2223,7 @@
         int status = enable ? IccRecords.CALL_FORWARDING_STATUS_ENABLED :
                 IccRecords.CALL_FORWARDING_STATUS_DISABLED;
         int subId = getSubId();
-        Rlog.i(LOG_TAG, "setCallForwardingIndicatorInSharedPref: Storing status = " + status +
+        Rlog.i(mLogTag, "setCallForwardingIndicatorInSharedPref: Storing status = " + status +
                 " in pref " + CF_STATUS + subId);
 
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
@@ -2265,7 +2266,7 @@
      */
     public boolean getCallForwardingIndicator() {
         if (getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
-            Rlog.e(LOG_TAG, "getCallForwardingIndicator: not possible in CDMA");
+            Rlog.e(mLogTag, "getCallForwardingIndicator: not possible in CDMA");
             return false;
         }
         IccRecords r = getIccRecords();
@@ -2276,7 +2277,7 @@
         if (callForwardingIndicator == IccRecords.CALL_FORWARDING_STATUS_UNKNOWN) {
             callForwardingIndicator = getCallForwardingIndicatorFromSharedPref();
         }
-        Rlog.v(LOG_TAG, "getCallForwardingIndicator: iccForwardingFlag=" + (r != null
+        Rlog.v(mLogTag, "getCallForwardingIndicator: iccForwardingFlag=" + (r != null
                     ? r.getVoiceCallForwardingFlag() : "null") + ", sharedPrefFlag="
                     + getCallForwardingIndicatorFromSharedPref());
         return (callForwardingIndicator == IccRecords.CALL_FORWARDING_STATUS_ENABLED);
@@ -2473,7 +2474,7 @@
             for (String pair : result.trim().split(",")) {
                 String[] networkTypesValues = (pair.trim().toLowerCase(Locale.ROOT)).split("=");
                 if (networkTypesValues.length != 2) {
-                    Rlog.e(LOG_TAG, "Invalid ALLOWED_NETWORK_TYPES from DB, value = " + pair);
+                    Rlog.e(mLogTag, "Invalid ALLOWED_NETWORK_TYPES from DB, value = " + pair);
                     continue;
                 }
                 int key = convertAllowedNetworkTypeDbNameToMapIndex(networkTypesValues[0]);
@@ -2493,7 +2494,7 @@
                 }
             }
         } catch (NumberFormatException e) {
-            Rlog.e(LOG_TAG, "allowedNetworkTypes NumberFormat exception" + e);
+            Rlog.e(mLogTag, "allowedNetworkTypes NumberFormat exception" + e);
         }
 
         for (int key : oldAllowedNetworkTypes.keySet()) {
@@ -2612,7 +2613,7 @@
     protected void updateAllowedNetworkTypes(Message response) {
         int modemRaf = getRadioAccessFamily();
         if (modemRaf == RadioAccessFamily.RAF_UNKNOWN) {
-            Rlog.d(LOG_TAG, "setPreferredNetworkType: Abort, unknown RAF: "
+            Rlog.d(mLogTag, "setPreferredNetworkType: Abort, unknown RAF: "
                     + modemRaf);
             if (response != null) {
                 CommandException ex;
@@ -2721,7 +2722,7 @@
      * @param onComplete a callback message when the action is completed
      */
     public void setUiTTYMode(int uiTtyMode, Message onComplete) {
-        Rlog.d(LOG_TAG, "unexpected setUiTTYMode method call");
+        Rlog.d(mLogTag, "unexpected setUiTTYMode method call");
     }
 
     /**
@@ -2848,7 +2849,7 @@
     public boolean eraseDataInSharedPreferences() {
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
         SharedPreferences.Editor editor = sp.edit();
-        Rlog.d(LOG_TAG, "Erase all data saved in SharedPreferences");
+        Rlog.d(mLogTag, "Erase all data saved in SharedPreferences");
         editor.clear();
         return editor.commit();
     }
@@ -3094,7 +3095,7 @@
                     isVideoCallOrConference(mImsPhone.getBackgroundCall()) ||
                     isVideoCallOrConference(mImsPhone.getRingingCall());
         }
-        Rlog.d(LOG_TAG, "isImsVideoCallOrConferencePresent: " + isPresent);
+        Rlog.d(mLogTag, "isImsVideoCallOrConferencePresent: " + isPresent);
         return isPresent;
     }
 
@@ -3119,7 +3120,7 @@
         int subId = getSubId();
         if (SubscriptionManager.isValidSubscriptionId(subId)) {
 
-            Rlog.d(LOG_TAG, "setVoiceMessageCount: Storing Voice Mail Count = " + countWaiting +
+            Rlog.d(mLogTag, "setVoiceMessageCount: Storing Voice Mail Count = " + countWaiting +
                     " for mVmCountKey = " + VM_COUNT + subId + " in preferences.");
 
             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
@@ -3127,16 +3128,16 @@
             editor.putInt(VM_COUNT + subId, countWaiting);
             editor.apply();
         } else {
-            Rlog.e(LOG_TAG, "setVoiceMessageCount in sharedPreference: invalid subId " + subId);
+            Rlog.e(mLogTag, "setVoiceMessageCount in sharedPreference: invalid subId " + subId);
         }
         // store voice mail count in SIM
         IccRecords records = UiccController.getInstance().getIccRecords(
                 mPhoneId, UiccController.APP_FAM_3GPP);
         if (records != null) {
-            Rlog.d(LOG_TAG, "setVoiceMessageCount: updating SIM Records");
+            Rlog.d(mLogTag, "setVoiceMessageCount: updating SIM Records");
             records.setVoiceMessageWaiting(1, countWaiting);
         } else {
-            Rlog.d(LOG_TAG, "setVoiceMessageCount: SIM Records not found");
+            Rlog.d(mLogTag, "setVoiceMessageCount: SIM Records not found");
         }
         // notify listeners of voice mail
         notifyMessageWaitingIndicator();
@@ -3152,7 +3153,7 @@
             int countFromSP = sp.getInt(VM_COUNT + subId, invalidCount);
             if (countFromSP != invalidCount) {
                 countVoiceMessages = countFromSP;
-                Rlog.d(LOG_TAG, "getStoredVoiceMessageCount: from preference for subId " + subId +
+                Rlog.d(mLogTag, "getStoredVoiceMessageCount: from preference for subId " + subId +
                         "= " + countVoiceMessages);
             } else {
                 // Check for old preference if count not found for current subId. This part of the
@@ -3165,10 +3166,10 @@
                         // get voice mail count from preferences
                         countVoiceMessages = sp.getInt(VM_COUNT, 0);
                         setVoiceMessageCount(countVoiceMessages);
-                        Rlog.d(LOG_TAG, "getStoredVoiceMessageCount: from preference = " +
+                        Rlog.d(mLogTag, "getStoredVoiceMessageCount: from preference = " +
                                 countVoiceMessages);
                     } else {
-                        Rlog.d(LOG_TAG, "getStoredVoiceMessageCount: returning 0 as count for " +
+                        Rlog.d(mLogTag, "getStoredVoiceMessageCount: returning 0 as count for " +
                                 "matching subscriberId not found");
 
                     }
@@ -3180,7 +3181,7 @@
                 }
             }
         } else {
-            Rlog.e(LOG_TAG, "getStoredVoiceMessageCount: invalid subId " + subId);
+            Rlog.e(mLogTag, "getStoredVoiceMessageCount: invalid subId " + subId);
         }
         return countVoiceMessages;
     }
@@ -3713,17 +3714,17 @@
                             }
                         }
                     } catch (NumberFormatException e) {
-                        Rlog.e(LOG_TAG, "Exception in getProvisioningUrlBaseFromFile: " + e);
+                        Rlog.e(mLogTag, "Exception in getProvisioningUrlBaseFromFile: " + e);
                     }
                 }
             }
             return null;
         } catch (FileNotFoundException e) {
-            Rlog.e(LOG_TAG, "Carrier Provisioning Urls file not found");
+            Rlog.e(mLogTag, "Carrier Provisioning Urls file not found");
         } catch (XmlPullParserException e) {
-            Rlog.e(LOG_TAG, "Xml parser exception reading Carrier Provisioning Urls file: " + e);
+            Rlog.e(mLogTag, "Xml parser exception reading Carrier Provisioning Urls file: " + e);
         } catch (IOException e) {
-            Rlog.e(LOG_TAG, "I/O exception reading Carrier Provisioning Urls file: " + e);
+            Rlog.e(mLogTag, "I/O exception reading Carrier Provisioning Urls file: " + e);
         }
         return null;
     }
@@ -3735,9 +3736,9 @@
         String url = getProvisioningUrlBaseFromFile();
         if (TextUtils.isEmpty(url)) {
             url = mContext.getResources().getString(R.string.mobile_provisioning_url);
-            Rlog.d(LOG_TAG, "getMobileProvisioningUrl: url from resource =" + url);
+            Rlog.d(mLogTag, "getMobileProvisioningUrl: url from resource =" + url);
         } else {
-            Rlog.d(LOG_TAG, "getMobileProvisioningUrl: url from File =" + url);
+            Rlog.d(mLogTag, "getMobileProvisioningUrl: url from File =" + url);
         }
         // Populate the iccid, imei and phone number in the provisioning url.
         if (!TextUtils.isEmpty(url)) {
@@ -3811,7 +3812,7 @@
      * version scoped to their packages
      */
     public void notifyNewRingingConnectionP(Connection cn) {
-        Rlog.i(LOG_TAG, String.format(
+        Rlog.i(mLogTag, String.format(
                 "notifyNewRingingConnection: phoneId=[%d], connection=[%s], registrants=[%s]",
                 getPhoneId(), cn, getNewRingingConnectionRegistrantsAsString()));
         if (!mIsVoiceCapable)
@@ -3867,12 +3868,12 @@
     private void sendIncomingCallRingNotification(int token) {
         if (mIsVoiceCapable && !mDoesRilSendMultipleCallRing &&
                 (token == mCallRingContinueToken)) {
-            Rlog.d(LOG_TAG, "Sending notifyIncomingRing");
+            Rlog.d(mLogTag, "Sending notifyIncomingRing");
             notifyIncomingRing();
             sendMessageDelayed(
                     obtainMessage(EVENT_CALL_RING_CONTINUE, token, 0), mCallRingDelay);
         } else {
-            Rlog.d(LOG_TAG, "Ignoring ring notification request,"
+            Rlog.d(mLogTag, "Ignoring ring notification request,"
                     + " mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing
                     + " token=" + token
                     + " mCallRingContinueToken=" + mCallRingContinueToken
@@ -3912,7 +3913,7 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public IsimRecords getIsimRecords() {
-        Rlog.e(LOG_TAG, "getIsimRecords() is only supported on LTE devices");
+        Rlog.e(mLogTag, "getIsimRecords() is only supported on LTE devices");
         return null;
     }
 
@@ -3945,7 +3946,7 @@
      */
     public void setVoiceMessageWaiting(int line, int countWaiting) {
         // This function should be overridden by class GsmCdmaPhone.
-        Rlog.e(LOG_TAG, "Error! This function should never be executed, inactive Phone.");
+        Rlog.e(mLogTag, "Error! This function should never be executed, inactive Phone.");
     }
 
     /**
@@ -4204,7 +4205,7 @@
                 isImsRegistered = sst.isImsRegistered();
             }
         }
-        Rlog.d(LOG_TAG, "isImsRegistered =" + isImsRegistered);
+        Rlog.d(mLogTag, "isImsRegistered =" + isImsRegistered);
         return isImsRegistered;
     }
 
@@ -4218,7 +4219,7 @@
         if (imsPhone != null) {
             isWifiCallingEnabled = imsPhone.isWifiCallingEnabled();
         }
-        Rlog.d(LOG_TAG, "isWifiCallingEnabled =" + isWifiCallingEnabled);
+        Rlog.d(mLogTag, "isWifiCallingEnabled =" + isWifiCallingEnabled);
         return isWifiCallingEnabled;
     }
 
@@ -4232,7 +4233,7 @@
         if (imsPhone != null) {
             isAvailable = imsPhone.isImsCapabilityAvailable(capability, regTech);
         }
-        Rlog.d(LOG_TAG, "isImsCapabilityAvailable, capability=" + capability + ", regTech="
+        Rlog.d(mLogTag, "isImsCapabilityAvailable, capability=" + capability + ", regTech="
                 + regTech + ", isAvailable=" + isAvailable);
         return isAvailable;
     }
@@ -4256,7 +4257,7 @@
         if (imsPhone != null) {
             isVolteEnabled = imsPhone.isVoiceOverCellularImsEnabled();
         }
-        Rlog.d(LOG_TAG, "isVoiceOverCellularImsEnabled=" + isVolteEnabled);
+        Rlog.d(mLogTag, "isVoiceOverCellularImsEnabled=" + isVolteEnabled);
         return isVolteEnabled;
     }
 
@@ -4270,7 +4271,7 @@
         if (imsPhone != null) {
             regTech = imsPhone.getImsRegistrationTech();
         }
-        Rlog.d(LOG_TAG, "getImsRegistrationTechnology =" + regTech);
+        Rlog.d(mLogTag, "getImsRegistrationTechnology =" + regTech);
         return regTech;
     }
 
@@ -4852,7 +4853,7 @@
     public boolean isDeviceIdle() {
         DeviceStateMonitor dsm = getDeviceStateMonitor();
         if (dsm == null) {
-            Rlog.e(LOG_TAG, "isDeviceIdle: DeviceStateMonitor is null");
+            Rlog.e(mLogTag, "isDeviceIdle: DeviceStateMonitor is null");
             return false;
         }
         return !dsm.shouldEnableHighPowerConsumptionIndications();
@@ -4866,7 +4867,7 @@
     public void notifyDeviceIdleStateChanged(boolean isIdle) {
         SignalStrengthController ssc = getSignalStrengthController();
         if (ssc == null) {
-            Rlog.e(LOG_TAG, "notifyDeviceIdleStateChanged: SignalStrengthController is null");
+            Rlog.e(mLogTag, "notifyDeviceIdleStateChanged: SignalStrengthController is null");
             return;
         }
         ssc.onDeviceIdleStateChanged(isIdle);
@@ -5298,7 +5299,7 @@
      * @param type for callback mode entry.
      */
     public void startCallbackMode(@TelephonyManager.EmergencyCallbackModeType int type) {
-        Rlog.d(LOG_TAG, "startCallbackMode:type=" + type);
+        Rlog.d(mLogTag, "startCallbackMode:type=" + type);
         mNotifier.notifyCallbackModeStarted(this, type);
     }
 
@@ -5309,7 +5310,7 @@
      */
     public void stopCallbackMode(@TelephonyManager.EmergencyCallbackModeType int type,
             @TelephonyManager.EmergencyCallbackModeStopReason int reason) {
-        Rlog.d(LOG_TAG, "stopCallbackMode:type=" + type + ", reason=" + reason);
+        Rlog.d(mLogTag, "stopCallbackMode:type=" + type + ", reason=" + reason);
         mNotifier.notifyCallbackModeStopped(this, type, reason);
     }
 
@@ -5347,7 +5348,7 @@
         pw.println(" isDnsCheckDisabled()=" + isDnsCheckDisabled());
         pw.println(" getUnitTestMode()=" + getUnitTestMode());
         pw.println(" getState()=" + getState());
-        pw.println(" getIccSerialNumber()=" + Rlog.pii(LOG_TAG, getIccSerialNumber()));
+        pw.println(" getIccSerialNumber()=" + Rlog.pii(mLogTag, getIccSerialNumber()));
         pw.println(" getIccRecordsLoaded()=" + getIccRecordsLoaded());
         pw.println(" getMessageWaitingIndicator()=" + getMessageWaitingIndicator());
         pw.println(" getCallForwardingIndicator()=" + getCallForwardingIndicator());
@@ -5532,18 +5533,14 @@
     }
 
     private void logd(String s) {
-        Rlog.d(LOG_TAG, "[" + mPhoneId + "] " + s);
+        Rlog.d(mLogTag, "[" + mPhoneId + "] " + s);
     }
 
     private void logi(String s) {
-        Rlog.i(LOG_TAG, "[" + mPhoneId + "] " + s);
+        Rlog.i(mLogTag, "[" + mPhoneId + "] " + s);
     }
 
     private void loge(String s) {
-        Rlog.e(LOG_TAG, "[" + mPhoneId + "] " + s);
-    }
-
-    private static String pii(String s) {
-        return Rlog.pii(LOG_TAG, s);
+        Rlog.e(mLogTag, "[" + mPhoneId + "] " + s);
     }
 }
diff --git a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
index ffa5b69..b96887c 100644
--- a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
+++ b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
@@ -391,9 +391,12 @@
                             }
                             mSlotsSupportingSimultaneousCellularCalls.add(i);
                         }
-                        // Ensure the slots supporting cellular DSDA does not exceed the phone count
-                        if (mSlotsSupportingSimultaneousCellularCalls.size() > getPhoneCount()) {
-                            loge("Invalid size of DSDA slots. Disabling cellular DSDA.");
+                        // Ensure the number of slots supporting cellular DSDA is valid:
+                        if (mSlotsSupportingSimultaneousCellularCalls.size() > getPhoneCount() ||
+                                mSlotsSupportingSimultaneousCellularCalls.size() < 2) {
+                            loge("Invalid size of DSDA slots. Disabling cellular DSDA. Size of "
+                                    + "mSlotsSupportingSimultaneousCellularCalls=" +
+                                    mSlotsSupportingSimultaneousCellularCalls.size());
                             mSlotsSupportingSimultaneousCellularCalls.clear();
                         }
                     } else {
diff --git a/src/java/com/android/internal/telephony/RadioSimProxy.java b/src/java/com/android/internal/telephony/RadioSimProxy.java
index 5265692..9bf9a50 100644
--- a/src/java/com/android/internal/telephony/RadioSimProxy.java
+++ b/src/java/com/android/internal/telephony/RadioSimProxy.java
@@ -530,6 +530,7 @@
             carrierRestrictions.allowedCarriersPrioritized =
                     (carrierRestrictionRules.getDefaultCarrierRestriction()
                             == CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED);
+            carrierRestrictions.status = carrierRestrictionRules.getCarrierRestrictionStatus();
             mSimProxy.setAllowedCarriers(serial, carrierRestrictions,
                     RILUtils.convertToHalSimLockMultiSimPolicyAidl(
                             carrierRestrictionRules.getMultiSimPolicy()));
diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java
index 20761e2..9f4fa11 100644
--- a/src/java/com/android/internal/telephony/data/DataConfigManager.java
+++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java
@@ -1503,6 +1503,14 @@
     }
 
     /**
+     * {@code True} enables mms to be attempted on iwlan if possible, even if existing cellular
+     *  networks already supports iwlan.
+     */
+    public boolean isForceIwlanMmsFeatureEnabled() {
+        return mResources.getBoolean(com.android.internal.R.bool.force_iwlan_mms_feature_enabled);
+    }
+
+    /**
      * Log debug messages.
      * @param s debug messages
      */
diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java
index 8369874..f47abfc 100644
--- a/src/java/com/android/internal/telephony/data/DataNetwork.java
+++ b/src/java/com/android/internal/telephony/data/DataNetwork.java
@@ -460,7 +460,10 @@
             // Dynamically add and remove MMTEL capability when network transition between VoPS
             // and non-VoPS network if the request is not MMTEL. For MMTEL, we retain the capability
             // to prevent immediate tear down.
-            NetworkCapabilities.NET_CAPABILITY_MMTEL
+            NetworkCapabilities.NET_CAPABILITY_MMTEL,
+            // Dynamically add and remove MMS capability depending on QNS's preference if there is
+            // a transport specific APN alternative.
+            NetworkCapabilities.NET_CAPABILITY_MMS
     );
 
     /** The parent state. Any messages not handled by the child state fallback to this. */
@@ -1263,7 +1266,7 @@
                         getHandler(), EVENT_VOICE_CALL_ENDED, null);
             }
 
-            if (mFlags.forceIwlanMms()) {
+            if (mFlags.forceIwlanMms() && mDataConfigManager.isForceIwlanMmsFeatureEnabled()) {
                 if (mDataProfile.canSatisfy(NetworkCapabilities.NET_CAPABILITY_MMS)) {
                     mAccessNetworksManagerCallback = new AccessNetworksManagerCallback(
                             getHandler()::post) {
@@ -1289,7 +1292,8 @@
         @Override
         public void exit() {
             logv("Unregistering all events.");
-            if (mFlags.forceIwlanMms() && mAccessNetworksManagerCallback != null) {
+            if (mFlags.forceIwlanMms() && mAccessNetworksManagerCallback != null
+                    && mDataConfigManager.isForceIwlanMmsFeatureEnabled()) {
                 mAccessNetworksManager.unregisterCallback(mAccessNetworksManagerCallback);
             }
 
@@ -2488,7 +2492,8 @@
         // will be attempted on IWLAN if possible, even if existing cellular networks already
         // supports IWLAN.
         if (mFlags.forceIwlanMms() && builder.build()
-                .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
+                && mDataConfigManager.isForceIwlanMmsFeatureEnabled()) {
             // If QNS sets MMS preferred on IWLAN, and it is possible to setup an MMS network on
             // IWLAN, then we need to remove the MMS capability on the cellular network. This will
             // allow the new MMS network to be brought up on IWLAN when MMS network request arrives.
diff --git a/src/java/com/android/internal/telephony/domainselection/DomainSelectionResolver.java b/src/java/com/android/internal/telephony/domainselection/DomainSelectionResolver.java
index 410f89b..1b66e54 100644
--- a/src/java/com/android/internal/telephony/domainselection/DomainSelectionResolver.java
+++ b/src/java/com/android/internal/telephony/domainselection/DomainSelectionResolver.java
@@ -64,8 +64,7 @@
      *                               to be bound to the domain selection controller.
      */
     public static void make(Context context, String flattenedComponentName) {
-        Log.i(TAG, "make flag=" + Flags.apDomainSelectionEnabled()
-                + ", useOem=" + Flags.useOemDomainSelectionService());
+        Log.i(TAG, "make useOem=" + Flags.useOemDomainSelectionService());
         if (sInstance == null) {
             sInstance = new DomainSelectionResolver(context, flattenedComponentName);
         }
diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
index 8478cff..167062f 100644
--- a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
+++ b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
@@ -564,6 +564,11 @@
         Rlog.i(TAG, "startEmergencyCall: phoneId=" + phone.getPhoneId()
                 + ", callId=" + c.getTelecomCallId());
 
+        if (needToSwitchPhone(phone)) {
+            Rlog.e(TAG, "startEmergencyCall failed. need to switch stacks.");
+            return CompletableFuture.completedFuture(DisconnectCause.EMERGENCY_PERM_FAILURE);
+        }
+
         if (mPhone != null) {
             // Create new future to return as to not interfere with any uncompleted futures.
             // Case1) When 2nd emergency call is initiated during an active call on the same phone.
@@ -2105,4 +2110,63 @@
             endNormalRoutingEmergencyCall(c);
         }
     }
+
+    /**
+     * Determines whether switching stacks is needed or not.
+     *
+     * @param phone the {@code Phone} on which to process the emergency call.
+     * @return true if switching stacks is needed.
+     */
+    @VisibleForTesting
+    public boolean needToSwitchPhone(Phone phone) {
+        int subId = phone.getSubId();
+        int phoneId = phone.getPhoneId();
+
+        if (isSimReady(phoneId, subId)) return false;
+
+        boolean switchPhone = false;
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            Rlog.i(TAG, "needToSwitchPhone SIM absent");
+            if (phoneId != 0 || isThereOtherPhone(phoneId, true)) {
+                // Prefer default Phone or other Phone with a SIM regardless of lock state.
+                switchPhone = true;
+            }
+        } else {
+            Rlog.i(TAG, "needToSwitchPhone SIM not ready");
+            if ((phoneId == 0 && isThereOtherPhone(phoneId, false))
+                    || (phoneId != 0 && isThereOtherPhone(phoneId, true))) {
+                // If there is another one with a SIM ready, switch Phones.
+                // Otherwise, prefer default Phone if both SIMs are locked.
+                switchPhone = true;
+            }
+        }
+        Rlog.i(TAG, "needToSwitchPhone " + switchPhone);
+        return switchPhone;
+    }
+
+    private boolean isThereOtherPhone(int skipPhoneId, boolean ignoreLockState) {
+        for (Phone phone : mPhoneFactoryProxy.getPhones()) {
+            int phoneId = phone.getPhoneId();
+            if (phoneId == skipPhoneId) {
+                continue;
+            }
+
+            int subId = phone.getSubId();
+            if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+                Rlog.i(TAG, "isThereOtherPhone phoneId=" + phoneId + ", subId=" + subId);
+                continue;
+            }
+            int simState = mTelephonyManagerProxy.getSimState(phoneId);
+            if ((simState == TelephonyManager.SIM_STATE_READY) || (ignoreLockState
+                    && simState != TelephonyManager.SIM_STATE_ABSENT
+                    && simState != TelephonyManager.SIM_STATE_NOT_READY)) {
+                Rlog.i(TAG, "isThereOtherPhone found, ignoreLockState=" + ignoreLockState
+                        + ", phoneId=" + phoneId + ", simState=" + simState);
+                return true;
+            }
+            Rlog.i(TAG, "isThereOtherPhone phoneId=" + phoneId + ", simState=" + simState);
+        }
+
+        return false;
+    }
 }
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index e4c5ae4..b2966b6 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -2878,6 +2878,14 @@
         ImsPhoneConnection conn = findConnection(imsCall);
         boolean rejectCall = false;
 
+        if (mFeatureFlags.preventHangupDuringCallMerge()) {
+            if (imsCall.isCallSessionMergePending()) {
+                if (DBG) log("hangup call failed during call merge");
+
+                throw new CallStateException("can not hangup during call merge");
+            }
+        }
+
         String logResult = "(undefined)";
         if (call == mRingingCall) {
             logResult = "(ringing) hangup incoming";
diff --git a/src/java/com/android/internal/telephony/satellite/NtnCapabilityResolver.java b/src/java/com/android/internal/telephony/satellite/NtnCapabilityResolver.java
index 65a25ea..dfc7919 100644
--- a/src/java/com/android/internal/telephony/satellite/NtnCapabilityResolver.java
+++ b/src/java/com/android/internal/telephony/satellite/NtnCapabilityResolver.java
@@ -47,7 +47,8 @@
         SatelliteController satelliteController = SatelliteController.getInstance();
         List<String> satellitePlmnList = satelliteController.getSatellitePlmnsForCarrier(subId);
         for (String satellitePlmn : satellitePlmnList) {
-            if (TextUtils.equals(satellitePlmn, registeredPlmn)) {
+            if (TextUtils.equals(satellitePlmn, registeredPlmn)
+                    && networkRegistrationInfo.isInService()) {
                 logd("Registered to satellite PLMN " + satellitePlmn);
                 networkRegistrationInfo.setIsNonTerrestrialNetwork(true);
                 networkRegistrationInfo.setAvailableServices(
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index 2e7465a..f5bc0a2 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -24,6 +24,7 @@
 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL;
 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT;
 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL;
+import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ESOS_SUPPORTED_BOOL;
 import static android.telephony.SubscriptionManager.SATELLITE_ATTACH_ENABLED_FOR_CARRIER;
 import static android.telephony.SubscriptionManager.SATELLITE_ENTITLEMENT_STATUS;
 import static android.telephony.SubscriptionManager.isValidSubscriptionId;
@@ -48,6 +49,7 @@
 import android.app.PendingIntent;
 import android.bluetooth.BluetoothAdapter;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -82,12 +84,14 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Telephony;
+import android.telephony.AccessNetworkConstants;
 import android.telephony.CarrierConfigManager;
 import android.telephony.DropBoxManagerLoggerBackend;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.PersistentLogger;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.satellite.INtnSignalStrengthCallback;
@@ -98,6 +102,7 @@
 import android.telephony.satellite.ISatelliteSupportedStateCallback;
 import android.telephony.satellite.ISatelliteTransmissionUpdateCallback;
 import android.telephony.satellite.NtnSignalStrength;
+import android.telephony.satellite.ProvisionSubscriberId;
 import android.telephony.satellite.SatelliteCapabilities;
 import android.telephony.satellite.SatelliteDatagram;
 import android.telephony.satellite.SatelliteManager;
@@ -124,6 +129,7 @@
 import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
 import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats;
 import com.android.internal.telephony.satellite.metrics.SessionMetricsStats;
+import com.android.internal.telephony.subscription.SubscriptionInfoInternal;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
 import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.internal.util.FunctionalUtils;
@@ -133,7 +139,6 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -220,6 +225,9 @@
     private static final int EVENT_SATELLITE_CONFIG_DATA_UPDATED = 40;
     private static final int EVENT_SATELLITE_SUPPORTED_STATE_CHANGED = 41;
     private static final int EVENT_NOTIFY_NTN_HYSTERESIS_TIMED_OUT = 42;
+    private static final int EVENT_EVALUATE_ESOS_PROFILES_PRIORITIZATION = 43;
+    private static final int CMD_PROVISION_SATELLITE_TOKEN_UPDATED = 44;
+    private static final int EVENT_PROVISION_SATELLITE_TOKEN_UPDATED = 45;
 
     @NonNull private static SatelliteController sInstance;
     @NonNull private final Context mContext;
@@ -318,6 +326,8 @@
     private final Object mIsSatelliteEnabledLock = new Object();
     @GuardedBy("mIsSatelliteEnabledLock")
     private Boolean mIsSatelliteEnabled = null;
+    private final Object mIsRadioOnLock = new Object();
+    @GuardedBy("mIsRadioOnLock")
     private boolean mIsRadioOn = false;
     private final Object mSatelliteViaOemProvisionLock = new Object();
     @GuardedBy("mSatelliteViaOemProvisionLock")
@@ -347,6 +357,8 @@
             mCarrierConfigChangeListener;
     @NonNull private final ConfigProviderAdaptor.Callback mConfigDataUpdatedCallback;
     @NonNull private final Object mCarrierConfigArrayLock = new Object();
+    @NonNull
+    private final SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionsChangedListener;
     @GuardedBy("mCarrierConfigArrayLock")
     @NonNull private final SparseArray<PersistableBundle> mCarrierConfigArray = new SparseArray<>();
     @GuardedBy("mIsSatelliteEnabledLock")
@@ -420,9 +432,24 @@
     @GuardedBy("mSupportedSatelliteServicesLock")
     private final SparseArray<List<String>> mMergedPlmnListPerCarrier = new SparseArray<>();
     private static AtomicLong sNextSatelliteEnableRequestId = new AtomicLong(0);
+    // key : subscriberId, value : provisioned or not.
+    @GuardedBy("mSatelliteTokenProvisionedLock")
+    private Map<String, Boolean> mProvisionedSubscriberId = new HashMap<>();
+    // key : subscriberId, value : subId
+    @GuardedBy("mSatelliteTokenProvisionedLock")
+    private Map<String, Integer> mSubscriberIdPerSub = new HashMap<>();
+    // key : priority, low value is high, value : List<SubscriptionInfo>
+    @GuardedBy("mSatelliteTokenProvisionedLock")
+    Map<Integer, List<SubscriptionInfo>> mSubsInfoListPerPriority = new HashMap<>();
+    @NonNull private final Object mSatelliteTokenProvisionedLock = new Object();
     private long mWaitTimeForSatelliteEnablingResponse;
     private long mDemoPointingAlignedDurationMillis;
     private long mDemoPointingNotAlignedDurationMillis;
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private long mLastEmergencyCallTime;
+    private long mSatelliteEmergencyModeDurationMillis;
+    private static final int DEFAULT_SATELLITE_EMERGENCY_MODE_DURATION_SECONDS = 300;
 
     /** Key used to read/write satellite system notification done in shared preferences. */
     private static final String SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY =
@@ -514,7 +541,10 @@
                 mContext, looper, mFeatureFlags, mPointingAppController);
 
         mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
-        mIsRadioOn = phone.isRadioOn();
+        synchronized (mIsRadioOnLock) {
+            mIsRadioOn = phone.isRadioOn();
+        }
+
         registerForSatelliteProvisionStateChanged();
         registerForPendingDatagramCount();
         registerForSatelliteModemStateChanged();
@@ -565,6 +595,30 @@
         mDemoPointingAlignedDurationMillis = getDemoPointingAlignedDurationMillisFromResources();
         mDemoPointingNotAlignedDurationMillis =
                 getDemoPointingNotAlignedDurationMillisFromResources();
+        mSatelliteEmergencyModeDurationMillis =
+                getSatelliteEmergencyModeDurationFromOverlayConfig(context);
+        sendMessageDelayed(obtainMessage(EVENT_EVALUATE_ESOS_PROFILES_PRIORITIZATION),
+                /* delayMillis= */ TimeUnit.MINUTES.toMillis(1));
+
+        SubscriptionManager subscriptionManager = mContext.getSystemService(
+                SubscriptionManager.class);
+        mSubscriptionsChangedListener = new SatelliteSubscriptionsChangedListener();
+        if (subscriptionManager != null) {
+            subscriptionManager.addOnSubscriptionsChangedListener(
+                    new HandlerExecutor(new Handler(looper)), mSubscriptionsChangedListener);
+        }
+    }
+
+    class SatelliteSubscriptionsChangedListener
+            extends SubscriptionManager.OnSubscriptionsChangedListener {
+
+        /**
+         * Callback invoked when there is any change to any SubscriptionInfo.
+         */
+        @Override
+        public void onSubscriptionsChanged() {
+            handleSubscriptionsChanged();
+        }
     }
 
     /**
@@ -997,6 +1051,7 @@
                     if (argument.enableSatellite) {
                         synchronized (mSatelliteEnabledRequestLock) {
                             mWaitingForRadioDisabled = true;
+                            setDemoModeEnabled(argument.enableDemoMode);
                         }
                         setSettingsKeyForSatelliteMode(SATELLITE_MODE_ENABLED_TRUE);
                         setSettingsKeyToAllowDeviceRotation(SATELLITE_MODE_ENABLED_TRUE);
@@ -1218,11 +1273,13 @@
             }
 
             case EVENT_RADIO_STATE_CHANGED: {
-                if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON) {
-                    mIsRadioOn = true;
-                } else if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_OFF) {
-                    mIsRadioOn = false;
-                    resetCarrierRoamingSatelliteModeParams();
+                synchronized (mIsRadioOnLock) {
+                    logd("EVENT_RADIO_STATE_CHANGED: radioState=" + mCi.getRadioState());
+                    if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON) {
+                        mIsRadioOn = true;
+                    } else if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_OFF) {
+                        resetCarrierRoamingSatelliteModeParams();
+                    }
                 }
 
                 if (mCi.getRadioState() != TelephonyManager.RADIO_POWER_UNAVAILABLE) {
@@ -1448,6 +1505,51 @@
                 break;
             }
 
+            case EVENT_EVALUATE_ESOS_PROFILES_PRIORITIZATION: {
+                evaluateESOSProfilesPrioritization();
+                break;
+            }
+
+            case CMD_PROVISION_SATELLITE_TOKEN_UPDATED: {
+                request = (SatelliteControllerHandlerRequest) msg.obj;
+                RequestProvisionSatelliteArgument argument =
+                        (RequestProvisionSatelliteArgument) request.argument;
+                onCompleted = obtainMessage(EVENT_PROVISION_SATELLITE_TOKEN_UPDATED, request);
+                // only pass to index 0.
+                int subId = -1;
+                synchronized (mSatelliteTokenProvisionedLock) {
+                    subId = mSubscriberIdPerSub.getOrDefault(
+                            argument.mProvisionSubscriberIdList.get(0).getSubscriberId(), -1);
+                }
+                String iccId = mSubscriptionManagerService.getSubscriptionInfo(subId).getIccId();
+                logd("CMD_PROVISION_SATELLITE_TOKEN_UPDATED: subId=" + subId + ", iccId=" + iccId);
+                mSatelliteModemInterface.updateSatelliteSubscription(iccId, onCompleted);
+                Consumer<Integer> result = new Consumer<Integer>() {
+                    @Override
+                    public void accept(Integer integer) {
+                        logd("invoke CMD_PROVISION_SATELLITE_SERVICE done.");
+                    }
+                };
+                ProvisionSatelliteServiceArgument internalArgument =
+                        new ProvisionSatelliteServiceArgument(iccId, null, result, subId);
+                sendMessage(obtainMessage(CMD_PROVISION_SATELLITE_SERVICE, internalArgument));
+                break;
+            }
+
+            case EVENT_PROVISION_SATELLITE_TOKEN_UPDATED: {
+                ar = (AsyncResult) msg.obj;
+                request = (SatelliteControllerHandlerRequest) ar.userObj;
+                RequestProvisionSatelliteArgument argument =
+                        (RequestProvisionSatelliteArgument) request.argument;
+                int error = SatelliteServiceUtils.getSatelliteError(ar,
+                        "updateSatelliteSubscription");
+                logd("EVENT_PROVISION_SATELLITE_TOKEN_UPDATED = " + error);
+                Bundle bundle = new Bundle();
+                bundle.putBoolean(SatelliteManager.KEY_PROVISION_SATELLITE_TOKENS, true);
+                argument.mResult.send(SATELLITE_RESULT_SUCCESS, bundle);
+                break;
+            }
+
             default:
                 Log.w(TAG, "SatelliteControllerHandler: unexpected message code: " +
                         msg.what);
@@ -1455,6 +1557,21 @@
         }
     }
 
+    private static final class RequestProvisionSatelliteArgument {
+        public List<ProvisionSubscriberId> mProvisionSubscriberIdList;
+        @NonNull
+        public ResultReceiver mResult;
+        public long mRequestId;
+
+        RequestProvisionSatelliteArgument(List<ProvisionSubscriberId> provisionSubscriberIdList,
+                ResultReceiver result) {
+            this.mProvisionSubscriberIdList = provisionSubscriberIdList;
+            this.mResult = result;
+            this.mRequestId = sNextSatelliteEnableRequestId.getAndUpdate(
+                    n -> ((n + 1) % Long.MAX_VALUE));
+        }
+    }
+
     private void handleEventConfigDataUpdated() {
         updateSupportedSatelliteServicesForActiveSubscriptions();
         int[] activeSubIds = mSubscriptionManagerService.getActiveSubIdList(true);
@@ -1498,11 +1615,13 @@
         }
 
         if (enableSatellite) {
-            if (!mIsRadioOn) {
-                ploge("Radio is not on, can not enable satellite");
-                sendErrorAndReportSessionMetrics(
-                        SatelliteManager.SATELLITE_RESULT_INVALID_MODEM_STATE, result);
-                return;
+            synchronized (mIsRadioOnLock) {
+                if (!mIsRadioOn) {
+                    ploge("Radio is not on, can not enable satellite");
+                    sendErrorAndReportSessionMetrics(
+                            SatelliteManager.SATELLITE_RESULT_INVALID_MODEM_STATE, result);
+                    return;
+                }
             }
         } else {
             /* if disable satellite, always assume demo is also disabled */
@@ -2644,12 +2763,15 @@
      * modem. {@link SatelliteController} will then power off the satellite modem.
      */
     public void onCellularRadioPowerOffRequested() {
+        logd("onCellularRadioPowerOffRequested()");
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
             plogd("onCellularRadioPowerOffRequested: oemEnabledSatelliteFlag is disabled");
             return;
         }
 
-        mIsRadioOn = false;
+        synchronized (mIsRadioOnLock) {
+            mIsRadioOn = false;
+        }
         requestSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
                 false /* enableSatellite */, false /* enableDemoMode */, false /* isEmergency */,
                 new IIntegerConsumer.Stub() {
@@ -2882,7 +3004,7 @@
             return true;
         }
 
-        if (serviceState.getState() == ServiceState.STATE_IN_SERVICE) {
+        if (getWwanIsInService(serviceState)) {
             // Device is connected to terrestrial network which has coverage
             resetCarrierRoamingSatelliteModeParams(subId);
             return false;
@@ -2981,6 +3103,29 @@
     }
 
     /**
+     * Register the handler for SIM Refresh notifications.
+     * @param handler Handler for notification message.
+     * @param what User-defined message code.
+     */
+    public void registerIccRefresh(Handler handler, int what) {
+        for (Phone phone : PhoneFactory.getPhones()) {
+            CommandsInterface ci = phone.mCi;
+            ci.registerForIccRefresh(handler, what, null);
+        }
+    }
+
+    /**
+     * Unregister the handler for SIM Refresh notifications.
+     * @param handler Handler for notification message.
+     */
+    public void unRegisterIccRefresh(Handler handler) {
+        for (Phone phone : PhoneFactory.getPhones()) {
+            CommandsInterface ci = phone.mCi;
+            ci.unregisterForIccRefresh(handler);
+        }
+    }
+
+    /**
      * To use the satellite service, update the EntitlementStatus and the PlmnAllowedList after
      * receiving the satellite configuration from the entitlement server. If satellite
      * entitlement is enabled, enable satellite for the carrier. Otherwise, disable satellite.
@@ -3711,7 +3856,6 @@
             if (areAllRadiosDisabled() && (mSatelliteEnabledRequest != null)
                     && mWaitingForRadioDisabled) {
                 plogd("Sending success to callback that sent enable satellite request");
-                setDemoModeEnabled(mSatelliteEnabledRequest.enableDemoMode);
                 mIsEmergency = mSatelliteEnabledRequest.isEmergency;
                 synchronized (mIsSatelliteEnabledLock) {
                     mIsSatelliteEnabled = mSatelliteEnabledRequest.enableSatellite;
@@ -3919,7 +4063,8 @@
                 KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL,
                 KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY,
                 KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL,
-                KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT);
+                KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT,
+                KEY_SATELLITE_ESOS_SUPPORTED_BOOL);
         if (config == null || config.isEmpty()) {
             config = CarrierConfigManager.getDefaultConfig();
         }
@@ -3936,10 +4081,19 @@
         }
 
         updateCarrierConfig(subId);
+        updateSatelliteESOSSupported(subId);
         updateEntitlementPlmnListPerCarrier(subId);
         updateSupportedSatelliteServicesForActiveSubscriptions();
         processNewCarrierConfigData(subId);
         resetCarrierRoamingSatelliteModeParams(subId);
+        sendMessageDelayed(obtainMessage(EVENT_EVALUATE_ESOS_PROFILES_PRIORITIZATION),
+                TimeUnit.MINUTES.toMillis(1));
+    }
+
+    // imsi, msisdn, default sms subId change
+    private void handleSubscriptionsChanged() {
+        sendMessageDelayed(obtainMessage(EVENT_EVALUATE_ESOS_PROFILES_PRIORITIZATION),
+                TimeUnit.MINUTES.toMillis(1));
     }
 
     private void processNewCarrierConfigData(int subId) {
@@ -3999,6 +4153,26 @@
         }
     }
 
+    /**
+     * Update the value of SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED stored in the database based
+     * on the value in the carrier config.
+     */
+    private void updateSatelliteESOSSupported(int subId) {
+        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+            return;
+        }
+
+        boolean isSatelliteESosSupportedFromDB =
+                mSubscriptionManagerService.getSatelliteESOSSupported(subId);
+        boolean isSatelliteESosSupportedFromCarrierConfig = getConfigForSubId(subId).getBoolean(
+                KEY_SATELLITE_ESOS_SUPPORTED_BOOL, false);
+        if (isSatelliteESosSupportedFromDB != isSatelliteESosSupportedFromCarrierConfig) {
+            mSubscriptionManagerService.setSatelliteESOSSupported(subId,
+                    isSatelliteESosSupportedFromCarrierConfig);
+            logd("updateSatelliteESOSSupported: " + isSatelliteESosSupportedFromCarrierConfig);
+        }
+    }
+
     @NonNull
     private String[] readStringArrayFromOverlayConfig(@ArrayRes int id) {
         String[] strArray = null;
@@ -4349,7 +4523,7 @@
                     }
                 } else {
                     Boolean connected = mWasSatelliteConnectedViaCarrier.get(subId);
-                    if (serviceState.getState() == ServiceState.STATE_IN_SERVICE) {
+                    if (getWwanIsInService(serviceState)) {
                         resetCarrierRoamingSatelliteModeParams(subId);
                     } else if (connected != null && connected) {
                         // The device just got disconnected from a satellite network
@@ -4586,15 +4760,7 @@
                 mSessionStartTimeStamp = 0;
                 mSessionProcessingTimeStamp = 0;
             } else {
-                /*
-                 * Unregister Importance Listener for Pointing UI when Satellite is disabled
-                 */
-                synchronized (mNeedsSatellitePointingLock) {
-                    if (mNeedsSatellitePointing) {
-                        mPointingAppController.removeListenerForPointingUI();
-                    }
-                }
-                moveSatelliteToOffStateAndCleanUpResources(SATELLITE_RESULT_MODEM_TIMEOUT, null);
+                notifyEnablementFailedToSatelliteSessionController();
                 mControllerMetricsStats.onSatelliteDisabled();
                 mWaitingForDisableSatelliteModemResponse = false;
                 mWaitingForSatelliteModemOff = false;
@@ -4858,6 +5024,25 @@
         return mDemoPointingNotAlignedDurationMillis;
     }
 
+    private boolean getWwanIsInService(ServiceState serviceState) {
+        List<NetworkRegistrationInfo> nriList = serviceState
+                .getNetworkRegistrationInfoListForTransportType(
+                        AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+        for (NetworkRegistrationInfo nri : nriList) {
+            if (nri.isInService()) {
+                logv("getWwanIsInService: return true");
+                return true;
+            }
+        }
+
+        logv("getWwanIsInService: return false");
+        return false;
+    }
+
+    private static void logv(@NonNull String log) {
+        Rlog.v(TAG, log);
+    }
+
     private static void logd(@NonNull String log) {
         Rlog.d(TAG, log);
     }
@@ -4926,4 +5111,253 @@
         // Also turn off persisted logging until new session is started
         loggerBackend.setLoggingEnabled(false);
     }
+
+    /**
+     * Set last emergency call time to the current time.
+     */
+    public void setLastEmergencyCallTime() {
+        synchronized (mLock) {
+            mLastEmergencyCallTime = getElapsedRealtime();
+            plogd("mLastEmergencyCallTime=" + mLastEmergencyCallTime);
+        }
+    }
+
+    /**
+     * Check if satellite is in emergency mode.
+     */
+    public boolean isInEmergencyMode() {
+        synchronized (mLock) {
+            if (mLastEmergencyCallTime == 0) return false;
+
+            long currentTime = getElapsedRealtime();
+            if ((currentTime - mLastEmergencyCallTime) <= mSatelliteEmergencyModeDurationMillis) {
+                plogd("Satellite is in emergency mode");
+                return true;
+            }
+            return false;
+        }
+    }
+
+    private long getSatelliteEmergencyModeDurationFromOverlayConfig(@NonNull Context context) {
+        Integer duration = DEFAULT_SATELLITE_EMERGENCY_MODE_DURATION_SECONDS;
+        try {
+            duration = context.getResources().getInteger(com.android.internal.R.integer
+                    .config_satellite_emergency_mode_duration);
+        } catch (Resources.NotFoundException ex) {
+            ploge("getSatelliteEmergencyModeDurationFromOverlayConfig: got ex=" + ex);
+        }
+        return TimeUnit.SECONDS.toMillis(duration);
+    }
+
+
+    /**
+     * Calculate priority
+     * 1. Active eSOS profiles are higher priority than inactive eSOS profiles.
+     * 2. Carrier Enabled eSOS profile is higher priority than OEM enabled eSOS profile.
+     * 3. Among active carrier eSOS profiles user selected(default SMS SIM) eSOS profile will be
+     * the highest priority.
+     */
+    private void evaluateESOSProfilesPrioritization() {
+        List<SubscriptionInfo> allSubInfos = mSubscriptionManagerService.getAllSubInfoList(
+                mContext.getOpPackageName(), mContext.getAttributionTag());
+        //key : priority, low value is high, value : List<SubscriptionInfo>
+        Map<Integer, List<SubscriptionInfo>> newSubsInfoListPerPriority = new HashMap<>();
+        for (SubscriptionInfo info : allSubInfos) {
+            int subId = info.getSubscriptionId();
+            boolean isActive = info.isActive();
+            boolean isDefaultSmsSubId = mSubscriptionManagerService.getDefaultSmsSubId() == subId;
+            boolean isNtnOnly = info.isOnlyNonTerrestrialNetwork();
+            boolean isESOSSupported = info.isSatelliteESOSSupported();
+            if (!isNtnOnly && !isESOSSupported) {
+                logd("evaluateESOSProfilesPrioritization: !isNtnOnly && !isESOS");
+                continue;
+            }
+
+            int keyPriority = (isESOSSupported && isActive && isDefaultSmsSubId) ? 0
+                    : (isESOSSupported && isActive) ? 1
+                            : (isNtnOnly) ? 2 : (isESOSSupported) ? 3 : -1;
+            if (keyPriority != -1) {
+                newSubsInfoListPerPriority.computeIfAbsent(keyPriority,
+                        k -> new ArrayList<>()).add(info);
+            }
+        }
+
+        if (newSubsInfoListPerPriority.size() == 0) {
+            logd("evaluateESOSProfilesPrioritization: no available");
+            return;
+        }
+
+        // if priority is changed, send broadcast for provisioned ESOS subs ids
+        synchronized (mSatelliteTokenProvisionedLock) {
+            if (isPriorityChanged(mSubsInfoListPerPriority, newSubsInfoListPerPriority)) {
+                mSubsInfoListPerPriority = newSubsInfoListPerPriority;
+                sendBroadCastForProvisionedESOSSubs();
+            }
+        }
+    }
+
+    // The subscriberId for ntnOnly SIMs is the Iccid, whereas for ESOS supported SIMs, the
+    // subscriberId is the Imsi prefix 6 digit + msisdn.
+    private String getSubscriberId(int subId, SubscriptionInfo info, boolean isNtnOnly) {
+        if (isNtnOnly) {
+            return info.getIccId();
+        }
+        return getSubscriberIdForCarrier(subId);
+    }
+
+    private String getSubscriberIdForCarrier(int subId) {
+        SubscriptionInfoInternal internal = mSubscriptionManagerService.getSubscriptionInfoInternal(
+                0);
+        String msisdn = "";
+        for (Phone phone : PhoneFactory.getPhones()) {
+            if (subId == phone.getSubId()) {
+                msisdn = phone.getMsisdn();
+            }
+        }
+        if (msisdn == null) {
+            logd("getSubscriberIdForCarrier: msisdn null");
+            return "";
+        }
+        return internal.getImsi().substring(0, 6) + msisdn;
+    }
+
+    private boolean isPriorityChanged(Map<Integer, List<SubscriptionInfo>> currentMap,
+            Map<Integer, List<SubscriptionInfo>> newMap) {
+        if (currentMap.size() == 0 || currentMap.size() != newMap.size()) {
+            return true;
+        }
+
+        for (Map.Entry<Integer, List<SubscriptionInfo>> entry : currentMap.entrySet()) {
+            List<SubscriptionInfo> currentList = entry.getValue();
+            List<SubscriptionInfo> newList = newMap.get(entry.getKey());
+            if (currentList == null || currentList.size() != newList.size()) {
+                return true;
+            }
+            logd("isPriorityChanged: current.size=" + currentList.size() + " , new.size="
+                    + newList.size());
+            for (int i = 0; i < currentList.size(); i++) {
+                if (!currentList.get(i).equals(newList.get(i))) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private void sendBroadCastForProvisionedESOSSubs() {
+        String packageName = getStringFromOverlayConfig(
+                R.string.config_satellite_gateway_service_package);
+        String className = getStringFromOverlayConfig(
+                R.string.config_satellite_carrier_roaming_esos_provisioned_class);
+        String action = getStringFromOverlayConfig(
+                R.string.config_satellite_carrier_roaming_esos_provisioned_intent_action);
+
+        Intent intent = new Intent(action);
+        intent.setComponent(new ComponentName(packageName, className));
+        mContext.sendBroadcast(intent);
+        logd("sendBroadCaseToProvisionedESOSSubs");
+    }
+
+    private String getStringFromOverlayConfig(int resourceId) {
+        String name;
+        try {
+            name = mContext.getResources().getString(resourceId);
+        } catch (Resources.NotFoundException ex) {
+            loge("getStringFromOverlayConfig: ex=" + ex);
+            name = null;
+        }
+        return name;
+    }
+
+    /**
+     * Request to get list of prioritized satellite tokens to be used for provision.
+     *
+     * @param result The result receiver, which returns the list of prioritized satellite tokens
+     * to be used for provision if the request is successful or an error code if the request failed.
+     */
+    public void requestProvisionSubscriberIds(@NonNull ResultReceiver result) {
+        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+            result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null);
+            return;
+        }
+
+        List<ProvisionSubscriberId> list = new ArrayList<>();
+        synchronized (mSatelliteTokenProvisionedLock) {
+            mSubscriberIdPerSub = new HashMap<>();
+            for (int i = 0; i < mSubsInfoListPerPriority.size(); i++) {
+                List<SubscriptionInfo> infoList = mSubsInfoListPerPriority.get(i);
+                for (SubscriptionInfo info : infoList) {
+                    String subscriberId = getSubscriberId(info.getSubscriptionId(), info,
+                            info.isOnlyNonTerrestrialNetwork());
+                    int carrierId = info.getCarrierId();
+                    logd("requestProvisionSubscriberIds: subscriberId:" + subscriberId
+                            + " , carrierId=" + carrierId);
+                    if (subscriberId.isEmpty()) {
+                        logd("requestProvisionSubscriberIds: getSubscriberId failed skip this "
+                                + "subscriberId.");
+                        continue;
+                    }
+                    list.add(new ProvisionSubscriberId(subscriberId, carrierId));
+                    mSubscriberIdPerSub.put(subscriberId, info.getSubscriptionId());
+                }
+            }
+        }
+
+        logd("requestProvisionSubscriberIds: size=" + list.size());
+        final Bundle bundle = new Bundle();
+        bundle.putParcelableList(SatelliteManager.KEY_REQUEST_PROVISION_SUBSCRIBER_ID_TOKEN, list);
+        result.send(SATELLITE_RESULT_SUCCESS, bundle);
+    }
+
+    /**
+     * Request to get provisioned status for given a satellite subscriber id.
+     *
+     * @param satelliteSubscriberId Satellite subscriber id requiring provisioned status check.
+     * @param result The result receiver, which returns the provisioned status of the token if the
+     * request is successful or an error code if the request failed.
+     */
+    public void requestIsProvisioned(String satelliteSubscriberId, @NonNull ResultReceiver result) {
+        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+            result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null);
+            return;
+        }
+
+        boolean isProvisioned = false;
+        synchronized (mSatelliteTokenProvisionedLock) {
+            if (mProvisionedSubscriberId.getOrDefault(satelliteSubscriberId, false)) {
+                isProvisioned = true;
+            }
+        }
+
+        logd("requestIsProvisioned: satelliteSubscriberId=" + satelliteSubscriberId
+                + " , isProvisioned=" + isProvisioned);
+        final Bundle bundle = new Bundle();
+        bundle.putBoolean(SatelliteManager.KEY_IS_SATELLITE_PROVISIONED, isProvisioned);
+        result.send(SATELLITE_RESULT_SUCCESS, bundle);
+    }
+
+    /**
+     * Deliver the list of provisioned satellite subscriber ids.
+     *
+     * @param list List of provisioned satellite subscriber ids.
+     * @param result The result receiver that returns whether deliver success or fail.
+     */
+    public void provisionSatellite(@NonNull List<ProvisionSubscriberId> list,
+            @NonNull ResultReceiver result) {
+        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+            result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null);
+            return;
+        }
+
+        logd("provisionSatellite: size=" + list.size());
+        for (ProvisionSubscriberId subscriberId : list) {
+            synchronized (mSatelliteTokenProvisionedLock) {
+                mProvisionedSubscriberId.put(subscriberId.getSubscriberId(), true);
+            }
+        }
+
+        RequestProvisionSatelliteArgument request = new RequestProvisionSatelliteArgument(list,
+                result);
+        sendMessage(obtainMessage(CMD_PROVISION_SATELLITE_TOKEN_UPDATED, request));
+    }
 }
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
index da4c69b..f0a96c2 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
@@ -1410,6 +1410,34 @@
     }
 
     /**
+     * Provision UUID with a satellite provider.
+     */
+    public void updateSatelliteSubscription(@NonNull String iccId, @NonNull Message message) {
+        if (mSatelliteService != null) {
+            try {
+                mSatelliteService.updateSatelliteSubscription(iccId,
+                        new IIntegerConsumer.Stub() {
+                            @Override
+                            public void accept(int result) {
+                                int error = SatelliteServiceUtils.fromSatelliteError(result);
+                                plogd("updateSatelliteSubscription: " + error);
+                                Binder.withCleanCallingIdentity(() ->
+                                        sendMessageWithResult(message, null, error));
+                            }
+                        });
+            } catch (RemoteException e) {
+                ploge("updateSatelliteSubscription: RemoteException " + e);
+                sendMessageWithResult(message, null,
+                        SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
+            }
+        } else {
+            ploge("updateSatelliteSubscription: Satellite service is unavailable.");
+            sendMessageWithResult(message, null,
+                    SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
+        }
+    }
+
+    /**
      * This API can be used by only CTS to update satellite vendor service package name.
      *
      * @param servicePackageName The package name of the satellite vendor service.
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
index aa87d39..7f3eb0f 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
@@ -43,7 +43,9 @@
 import android.os.SystemProperties;
 import android.provider.DeviceConfig;
 import android.telecom.Connection;
+import android.telephony.AccessNetworkConstants;
 import android.telephony.DropBoxManagerLoggerBackend;
+import android.telephony.NetworkRegistrationInfo;
 import android.telephony.PersistentLogger;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
@@ -68,6 +70,7 @@
 import com.android.internal.telephony.SmsApplication;
 import com.android.internal.telephony.metrics.SatelliteStats;
 
+import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 
@@ -195,8 +198,7 @@
      *                   call.
      */
     public void onEmergencyCallStarted(@NonNull Connection connection) {
-        if (!mSatelliteController.isSatelliteSupportedViaOem()
-                && !mSatelliteController.isSatelliteEmergencyMessagingSupportedViaCarrier()) {
+        if (!isSatelliteSupported()) {
             plogd("onEmergencyCallStarted: satellite is not supported");
             return;
         }
@@ -227,8 +229,7 @@
     public void onEmergencyCallConnectionStateChanged(
             String callId, @Connection.ConnectionState int state) {
         plogd("callId=" + callId + ", state=" + state);
-        if (!mSatelliteController.isSatelliteSupportedViaOem()
-                && !mSatelliteController.isSatelliteEmergencyMessagingSupportedViaCarrier()) {
+        if (!isSatelliteSupported()) {
             plogd("onEmergencyCallConnectionStateChanged: satellite is not supported");
             return;
         }
@@ -242,16 +243,19 @@
     }
 
     private void handleEmergencyCallStartedEvent(@NonNull Connection connection) {
+        mSatelliteController.setLastEmergencyCallTime();
+
         if (sendEventDisplayEmergencyMessageForcefully(connection)) {
             return;
         }
 
         selectEmergencyCallWaitForConnectionTimeoutDuration();
         if (mEmergencyConnection == null) {
-            handleStateChangedEventForHysteresisTimer();
             registerForInterestedStateChangedEvents();
         }
         mEmergencyConnection = connection;
+        handleStateChangedEventForHysteresisTimer();
+
         synchronized (mLock) {
             mCheckingAccessRestrictionInProgress = false;
             mIsSatelliteAllowedForCurrentLocation = false;
@@ -343,6 +347,7 @@
 
     private void handleEmergencyCallConnectionStateChangedEvent(
             @NonNull Pair<String, Integer> arg) {
+        mSatelliteController.setLastEmergencyCallTime();
         if (mEmergencyConnection == null) {
             // Either the call was not created or the timer already timed out.
             return;
@@ -409,7 +414,6 @@
         for (Phone phone : PhoneFactory.getPhones()) {
             phone.registerForServiceStateChanged(
                     this, EVENT_SERVICE_STATE_CHANGED, null);
-            registerForImsRegistrationStateChanged(phone);
         }
     }
 
@@ -429,7 +433,6 @@
                 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, mISatelliteProvisionStateCallback);
         for (Phone phone : PhoneFactory.getPhones()) {
             phone.unregisterForServiceStateChanged(this);
-            unregisterForImsRegistrationStateChanged(phone);
         }
     }
 
@@ -452,7 +455,7 @@
                 int state = serviceState.getState();
                 if ((state == STATE_IN_SERVICE || state == STATE_EMERGENCY_ONLY
                         || serviceState.isEmergencyOnly())
-                        && !serviceState.isUsingNonTerrestrialNetwork()) {
+                        && !isSatellitePlmn(phone.getSubId(), serviceState)) {
                     logv("isCellularAvailable true");
                     return true;
                 }
@@ -462,6 +465,34 @@
         return false;
     }
 
+    private boolean isSatellitePlmn(int subId, @NonNull ServiceState serviceState) {
+        List<String> satellitePlmnList =
+                mSatelliteController.getSatellitePlmnsForCarrier(subId);
+        if (satellitePlmnList.isEmpty()) {
+            logv("isSatellitePlmn: satellitePlmnList is empty");
+            return false;
+        }
+
+        for (NetworkRegistrationInfo nri :
+                serviceState.getNetworkRegistrationInfoListForTransportType(
+                        AccessNetworkConstants.TRANSPORT_TYPE_WWAN)) {
+            String registeredPlmn = nri.getRegisteredPlmn();
+            String mccmnc = nri.getCellIdentity().getMccString()
+                    + nri.getCellIdentity().getMncString();
+            for (String satellitePlmn : satellitePlmnList) {
+                if (TextUtils.equals(satellitePlmn, registeredPlmn)
+                        || TextUtils.equals(satellitePlmn, mccmnc)) {
+                    logv("isSatellitePlmn: return true, satellitePlmn:" + satellitePlmn
+                            + " registeredPlmn:" + registeredPlmn + " mccmnc:" + mccmnc);
+                    return true;
+                }
+            }
+        }
+
+        logv("isSatellitePlmn: return false");
+        return false;
+    }
+
     /**
      * @return {@link ServiceState#STATE_IN_SERVICE} if any subscription is in this state; else
      * {@link ServiceState#STATE_EMERGENCY_ONLY} if any subscription is in this state; else
@@ -493,7 +524,7 @@
     }
 
     private synchronized void handleStateChangedEventForHysteresisTimer() {
-        if (!isCellularAvailable()) {
+        if (!isCellularAvailable() && mEmergencyConnection != null) {
             startTimer();
         } else {
             logv("handleStateChangedEventForHysteresisTimer stopTimer");
@@ -760,6 +791,19 @@
                 || SystemProperties.getBoolean(BOOT_ALLOW_MOCK_MODEM_PROPERTY, false));
     }
 
+    private boolean isSatelliteSupported() {
+        if (mSatelliteController.isSatelliteEmergencyMessagingSupportedViaCarrier()) return true;
+        if (mSatelliteController.isSatelliteSupportedViaOem() && isSatelliteViaOemProvisioned()) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean isSatelliteViaOemProvisioned() {
+        Boolean provisioned = mSatelliteController.isSatelliteViaOemProvisioned();
+        return (provisioned != null) && provisioned;
+    }
+
     private static void logv(@NonNull String log) {
         Rlog.v(TAG, log);
     }
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
index d33fd73..4dc425d 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
@@ -327,8 +327,14 @@
     @NonNull
     public static List<String> mergeStrLists(List<String> strList1, List<String> strList2) {
         Set<String> mergedStrSet = new HashSet<>();
-        mergedStrSet.addAll(strList1);
-        mergedStrSet.addAll(strList2);
+        if (strList1 != null) {
+            mergedStrSet.addAll(strList1);
+        }
+
+        if (strList2 != null) {
+            mergedStrSet.addAll(strList2);
+        }
+
         return mergedStrSet.stream().toList();
     }
 
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java
index dde10a0..ac8f0b3 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java
@@ -41,7 +41,6 @@
 import android.os.SystemProperties;
 import android.telephony.DropBoxManagerLoggerBackend;
 import android.telephony.PersistentLogger;
-import android.telephony.Rlog;
 import android.telephony.satellite.ISatelliteModemStateCallback;
 import android.telephony.satellite.SatelliteManager;
 import android.telephony.satellite.stub.ISatelliteGateway;
@@ -139,6 +138,7 @@
     private long mSatelliteNbIotInactivityTimeoutMillis;
     private final ConcurrentHashMap<IBinder, ISatelliteModemStateCallback> mListeners;
     @SatelliteManager.SatelliteModemState private int mCurrentState;
+    @SatelliteManager.SatelliteModemState private int mPreviousState;
     final boolean mIsSatelliteSupported;
     private boolean mIsDemoMode = false;
     @GuardedBy("mLock")
@@ -147,7 +147,6 @@
     @NonNull private final DatagramController mDatagramController;
     @Nullable private PersistentLogger mPersistentLogger = null;
 
-
     /**
      * @return The singleton instance of SatelliteSessionController.
      */
@@ -215,6 +214,7 @@
                 getSatelliteNbIotInactivityTimeoutMillis();
         mListeners = new ConcurrentHashMap<>();
         mIsSendingTriggeredDuringTransferringState = new AtomicBoolean(false);
+        mPreviousState = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN;
         mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN;
         mIsSatelliteSupported = isSatelliteSupported;
         mExponentialBackoff = new ExponentialBackoff(REBIND_INITIAL_DELAY, REBIND_MAXIMUM_DELAY,
@@ -441,6 +441,7 @@
         @Override
         public void enter() {
             if (DBG) plogd("Entering UnavailableState");
+            mPreviousState = mCurrentState;
             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE;
             notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE);
         }
@@ -457,6 +458,7 @@
         public void enter() {
             if (DBG) plogd("Entering PowerOffState");
 
+            mPreviousState = mCurrentState;
             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_OFF;
             mIsSendingTriggeredDuringTransferringState.set(false);
             synchronized (mLock) {
@@ -501,6 +503,7 @@
         public void enter() {
             if (DBG) plogd("Entering EnablingState");
 
+            mPreviousState = mCurrentState;
             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_ENABLING_SATELLITE;
             notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_ENABLING_SATELLITE);
         }
@@ -554,6 +557,7 @@
         public void enter() {
             if (DBG) plogd("Entering DisablingState");
 
+            mPreviousState = mCurrentState;
             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_DISABLING_SATELLITE;
             notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_DISABLING_SATELLITE);
         }
@@ -570,6 +574,19 @@
                 case EVENT_SATELLITE_ENABLED_STATE_CHANGED:
                     handleSatelliteEnabledStateChanged((boolean) msg.obj);
                     break;
+                case EVENT_SATELLITE_ENABLEMENT_FAILED:
+                    if (mPreviousState == SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED
+                            || mPreviousState
+                            == SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING
+                            || mPreviousState == SatelliteManager.SATELLITE_MODEM_STATE_LISTENING) {
+                        transitionTo(mConnectedState);
+                    } else {
+                        transitionTo(mNotConnectedState);
+                    }
+                    break;
+                case EVENT_SATELLITE_MODEM_STATE_CHANGED:
+                    handleEventSatelliteModemStateChanged(msg.arg1);
+                    break;
             }
             // Ignore all unexpected events.
             return HANDLED;
@@ -582,12 +599,20 @@
                 transitionTo(mPowerOffState);
             }
         }
+
+        private void handleEventSatelliteModemStateChanged(
+                @SatelliteManager.SatelliteModemState int state) {
+            if (state == SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED) {
+                mPreviousState = state;
+            }
+        }
     }
 
     private class IdleState extends State {
         @Override
         public void enter() {
             if (DBG) plogd("Entering IdleState");
+            mPreviousState = mCurrentState;
             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_IDLE;
             mIsSendingTriggeredDuringTransferringState.set(false);
             stopNbIotInactivityTimer();
@@ -686,6 +711,7 @@
         public void enter() {
             if (DBG) plogd("Entering TransferringState");
             stopNbIotInactivityTimer();
+            mPreviousState = mCurrentState;
             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING;
             notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING);
         }
@@ -745,6 +771,7 @@
         public void enter() {
             if (DBG) plogd("Entering ListeningState");
 
+            mPreviousState = mCurrentState;
             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_LISTENING;
             long timeoutMillis = updateListeningMode(true);
             sendMessageDelayed(EVENT_LISTENING_TIMER_TIMEOUT, timeoutMillis);
@@ -808,6 +835,7 @@
         public void enter() {
             if (DBG) plogd("Entering NotConnectedState");
 
+            mPreviousState = mCurrentState;
             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED;
             notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED);
             startNbIotInactivityTimer();
@@ -873,6 +901,7 @@
         public void enter() {
             if (DBG) plogd("Entering ConnectedState");
 
+            mPreviousState = mCurrentState;
             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED;
             notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
             startNbIotInactivityTimer();
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java
index 7596754..cd6e6aa 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java
@@ -280,7 +280,7 @@
                     SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER,
                     SubscriptionInfoInternal::getSatelliteAttachEnabledForCarrier),
             new AbstractMap.SimpleImmutableEntry<>(
-                    SimInfo.COLUMN_IS_NTN,
+                    SimInfo.COLUMN_IS_ONLY_NTN,
                     SubscriptionInfoInternal::getOnlyNonTerrestrialNetwork),
             new AbstractMap.SimpleImmutableEntry<>(
                     SimInfo.COLUMN_SERVICE_CAPABILITIES,
@@ -293,7 +293,10 @@
                     SubscriptionInfoInternal::getSatelliteEntitlementStatus),
             new AbstractMap.SimpleImmutableEntry<>(
                     SimInfo.COLUMN_SATELLITE_ENTITLEMENT_PLMNS,
-                    SubscriptionInfoInternal::getSatelliteEntitlementPlmns)
+                    SubscriptionInfoInternal::getSatelliteEntitlementPlmns),
+            new AbstractMap.SimpleImmutableEntry<>(
+                    SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED,
+                    SubscriptionInfoInternal::getSatelliteESOSSupported)
     );
 
     /**
@@ -423,7 +426,7 @@
                     SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER,
                     SubscriptionDatabaseManager::setSatelliteAttachEnabledForCarrier),
             new AbstractMap.SimpleImmutableEntry<>(
-                    SimInfo.COLUMN_IS_NTN,
+                    SimInfo.COLUMN_IS_ONLY_NTN,
                     SubscriptionDatabaseManager::setNtn),
             new AbstractMap.SimpleImmutableEntry<>(
                     SimInfo.COLUMN_SERVICE_CAPABILITIES,
@@ -433,7 +436,10 @@
                     SubscriptionDatabaseManager::setTransferStatus),
             new AbstractMap.SimpleImmutableEntry<>(
                     SimInfo.COLUMN_SATELLITE_ENTITLEMENT_STATUS,
-                    SubscriptionDatabaseManager::setSatelliteEntitlementStatus)
+                    SubscriptionDatabaseManager::setSatelliteEntitlementStatus),
+            new AbstractMap.SimpleImmutableEntry<>(
+                    SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED,
+                    SubscriptionDatabaseManager::setSatelliteESOSSupported)
     );
 
     /**
@@ -2063,7 +2069,7 @@
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
             return;
         }
-        writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_NTN, isNtn,
+        writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_ONLY_NTN, isNtn,
                 SubscriptionInfoInternal.Builder::setOnlyNonTerrestrialNetwork);
     }
 
@@ -2162,6 +2168,23 @@
     }
 
     /**
+     * Set whether the carrier roaming to satellite is using ESOS for emergency messaging.
+     *
+     * @param subId Subscription id.
+     * @param isSatelliteESOSSupported whether the carrier roaming to satellite is using ESOS for
+     * emergency messaging.
+     * @throws IllegalArgumentException if the subscription does not exist.
+     */
+    public void setSatelliteESOSSupported(int subId, int isSatelliteESOSSupported) {
+        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+            return;
+        }
+        writeDatabaseAndCacheHelper(subId,
+                SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED, isSatelliteESOSSupported,
+                SubscriptionInfoInternal.Builder::setSatelliteESOSSupported);
+    }
+
+    /**
      * Reload the database from content provider to the cache. This must be a synchronous operation
      * to prevent cache/database out-of-sync. Callers should be cautious to call this method because
      * it might take longer time to complete.
@@ -2402,12 +2425,16 @@
                                 SimInfo.COLUMN_SATELLITE_ENTITLEMENT_PLMNS)));
         if (mFeatureFlags.oemEnabledSatelliteFlag()) {
             builder.setOnlyNonTerrestrialNetwork(cursor.getInt(cursor.getColumnIndexOrThrow(
-                    SimInfo.COLUMN_IS_NTN)));
+                    SimInfo.COLUMN_IS_ONLY_NTN)));
         }
         if (mFeatureFlags.supportPsimToEsimConversion()) {
             builder.setTransferStatus(cursor.getInt(cursor.getColumnIndexOrThrow(
                     SimInfo.COLUMN_TRANSFER_STATUS)));
         }
+        if (mFeatureFlags.carrierRoamingNbIotNtn()) {
+            builder.setSatelliteESOSSupported(cursor.getInt(
+                    cursor.getColumnIndexOrThrow(SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED)));
+        }
         return builder.build();
     }
 
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java
index c6dee7c..7684864 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java
@@ -492,6 +492,12 @@
     @NonNull private final String mSatelliteEntitlementPlmns;
 
     /**
+     * Whether the carrier roaming to satellite is using ESOS for emergency messaging.
+     * By default, its disabled. It is intended to use integer to fit the database format.
+     */
+    private final int mIsSatelliteESOSSupported;
+
+    /**
      * Constructor from builder.
      *
      * @param builder Builder of {@link SubscriptionInfoInternal}.
@@ -570,6 +576,7 @@
         this.mTransferStatus = builder.mTransferStatus;
         this.mIsSatelliteEntitlementStatus = builder.mIsSatelliteEntitlementStatus;
         this.mSatelliteEntitlementPlmns = builder.mSatelliteEntitlementPlmns;
+        this.mIsSatelliteESOSSupported = builder.mIsSatelliteESOSSupported;
     }
 
     /**
@@ -1266,6 +1273,13 @@
         return mSatelliteEntitlementPlmns;
     }
 
+    /**
+     * @return {@code 1} if the carrier roaming to satellite is using ESOS for emergency messaging.
+     */
+    public int getSatelliteESOSSupported() {
+        return mIsSatelliteESOSSupported;
+    }
+
     /** @return converted {@link SubscriptionInfo}. */
     @NonNull
     public SubscriptionInfo toSubscriptionInfo() {
@@ -1305,6 +1319,7 @@
                 .setServiceCapabilities(
                         SubscriptionManager.getServiceCapabilitiesSet(mServiceCapabilities))
                 .setTransferStatus(mTransferStatus)
+                .setSatelliteESOSSupported(mIsSatelliteESOSSupported == 1)
                 .build();
     }
 
@@ -1368,6 +1383,7 @@
                 + " transferStatus=" + mTransferStatus
                 + " satelliteEntitlementStatus=" + mIsSatelliteEntitlementStatus
                 + " satelliteEntitlementPlmns=" + mSatelliteEntitlementPlmns
+                + " isSatelliteESOSSupported=" + mIsSatelliteESOSSupported
                 + "]";
     }
 
@@ -1430,7 +1446,8 @@
                 && mServiceCapabilities == that.mServiceCapabilities
                 && mTransferStatus == that.mTransferStatus
                 && mIsSatelliteEntitlementStatus == that.mIsSatelliteEntitlementStatus
-                && mSatelliteEntitlementPlmns == that.mSatelliteEntitlementPlmns;
+                && mSatelliteEntitlementPlmns.equals(that.mSatelliteEntitlementPlmns)
+                && mIsSatelliteESOSSupported == that.mIsSatelliteESOSSupported;
     }
 
     @Override
@@ -1463,7 +1480,7 @@
                 mIsSatelliteEnabled, mCardId, mIsGroupDisabled,
                 mIsSatelliteAttachEnabledForCarrier, mIsOnlyNonTerrestrialNetwork,
                 mServiceCapabilities, mTransferStatus, mIsSatelliteEntitlementStatus,
-                mSatelliteEntitlementPlmns);
+                mSatelliteEntitlementPlmns, mIsSatelliteESOSSupported);
         result = 31 * result + Arrays.hashCode(mNativeAccessRules);
         result = 31 * result + Arrays.hashCode(mCarrierConfigAccessRules);
         result = 31 * result + Arrays.hashCode(mRcsConfig);
@@ -1872,6 +1889,11 @@
         private String mSatelliteEntitlementPlmns = "";
 
         /**
+         * Whether the carrier roaming to satellite is using ESOS for emergency messaging.
+         */
+        private int mIsSatelliteESOSSupported = 0;
+
+        /**
          * Default constructor.
          */
         public Builder() {
@@ -1953,6 +1975,7 @@
             mTransferStatus = info.mTransferStatus;
             mIsSatelliteEntitlementStatus = info.mIsSatelliteEntitlementStatus;
             mSatelliteEntitlementPlmns = info.mSatelliteEntitlementPlmns;
+            mIsSatelliteESOSSupported = info.mIsSatelliteESOSSupported;
         }
 
         /**
@@ -2923,6 +2946,19 @@
         }
 
         /**
+         * Set whether the carrier roaming to satellite is using ESOS for emergency messaging.
+         *
+         * @param isSatelliteESOSSupported {@code 1} if the carrier roaming to satellite is using
+         * ESOS for emergency messaging.
+         * @return The builder
+         */
+        @NonNull
+        public Builder setSatelliteESOSSupported(int isSatelliteESOSSupported) {
+            mIsSatelliteESOSSupported = isSatelliteESOSSupported;
+            return this;
+        }
+
+        /**
          * Build the {@link SubscriptionInfoInternal}.
          *
          * @return The {@link SubscriptionInfoInternal} instance.
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
index 0e98a9e..e6928b9 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
@@ -193,9 +193,10 @@
             SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED,
             SimInfo.COLUMN_SATELLITE_ENABLED,
             SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER,
-            SimInfo.COLUMN_IS_NTN,
+            SimInfo.COLUMN_IS_ONLY_NTN,
             SimInfo.COLUMN_SATELLITE_ENTITLEMENT_STATUS,
-            SimInfo.COLUMN_SATELLITE_ENTITLEMENT_PLMNS
+            SimInfo.COLUMN_SATELLITE_ENTITLEMENT_PLMNS,
+            SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED
     );
 
     /**
@@ -1540,6 +1541,9 @@
                             MccTable.updateMccMncConfiguration(mContext, mccMnc);
                         }
                         setMccMnc(subId, mccMnc);
+                        if (isSatelliteSpn(subInfo.getDisplayName()) || isSatellitePlmn(mccMnc)) {
+                            setNtn(subId, true);
+                        }
                     } else {
                         loge("updateSubscription: mcc/mnc is empty");
                     }
@@ -4591,6 +4595,43 @@
     }
 
     /**
+     * Set the satellite ESOS supported value in the subscription database.
+     *
+     * @param subId subscription id.
+     * @param isSatelliteESOSSupported {@code true} satellite ESOS supported true.
+     */
+    public void setSatelliteESOSSupported(int subId, @NonNull boolean isSatelliteESOSSupported) {
+        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+            return;
+        }
+        try {
+            mSubscriptionDatabaseManager.setSatelliteESOSSupported(subId,
+                    isSatelliteESOSSupported ? 1 : 0);
+        } catch (IllegalArgumentException e) {
+            loge("setSatelliteESOSSupported: invalid subId=" + subId);
+        }
+    }
+
+    /**
+     * Get the satellite ESOS supported value in the subscription database.
+     *
+     * @param subId subscription id.
+     * @return the satellite ESOS supported true or false.
+     */
+    public boolean getSatelliteESOSSupported(int subId) {
+        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+            return false;
+        }
+        SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager.getSubscriptionInfoInternal(
+                subId);
+        if (subInfo == null) {
+            return false;
+        }
+
+        return subInfo.getSatelliteESOSSupported() == 1;
+    }
+
+    /**
      * checks whether esim bootstrap is activated for any of the available active subscription info
      * list.
      *
diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java
index 84e84d9..a0ee2d1 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccController.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccController.java
@@ -780,9 +780,10 @@
         intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
         intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, state);
         intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
-        SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
+        int subId = SubscriptionManager.getSubscriptionId(phoneId);
+        SubscriptionManager.putPhoneIdAndMaybeSubIdExtra(intent, phoneId, subId);
         Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_STATE_CHANGED " + state + " reason "
-                + reason + " for phone: " + phoneId);
+                + reason + " for phone: " + phoneId + " sub: " + subId);
         IntentBroadcaster.getInstance().broadcastStickyIntent(mContext, intent, phoneId);
     }
 
@@ -798,7 +799,8 @@
             Intent intent = new Intent(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED);
             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
             intent.putExtra(TelephonyManager.EXTRA_SIM_STATE, state);
-            SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
+            int subId = SubscriptionManager.getSubscriptionId(phoneId);
+            SubscriptionManager.putPhoneIdAndMaybeSubIdExtra(intent, phoneId, subId);
             // TODO(b/130664115) we manually populate this intent with the slotId. In the future we
             // should do a review of whether to make this public
             UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId);
@@ -811,7 +813,7 @@
             }
             Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_CARD_STATE_CHANGED "
                     + TelephonyManager.simStateToString(state) + " for phone: " + phoneId
-                    + " slot: " + slotId + " port: " + portIndex);
+                    + " slot: " + slotId + " port: " + portIndex + " sub: " + subId);
             mContext.sendBroadcast(intent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
             TelephonyMetrics.getInstance().updateSimState(phoneId, state);
         }
@@ -838,7 +840,8 @@
             Intent intent = new Intent(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED);
             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
             intent.putExtra(TelephonyManager.EXTRA_SIM_STATE, state);
-            SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
+            int subId = SubscriptionManager.getSubscriptionId(phoneId);
+            SubscriptionManager.putPhoneIdAndMaybeSubIdExtra(intent, phoneId, subId);
             // TODO(b/130664115) we populate this intent with the actual slotId. In the future we
             // should do a review of whether to make this public
             UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId);
@@ -849,8 +852,8 @@
             }
             Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_APPLICATION_STATE_CHANGED "
                     + TelephonyManager.simStateToString(state)
-                    + " for phone: " + phoneId + " slot: " + slotId + "port: "
-                    + slot.getPortIndexFromPhoneId(phoneId));
+                    + " for phone: " + phoneId + " slot: " + slotId + " port: "
+                    + slot.getPortIndexFromPhoneId(phoneId) + " sub: " + subId);
             mContext.sendBroadcast(intent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
             TelephonyMetrics.getInstance().updateSimState(phoneId, state);
         }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
index a13a92c..4af6f7e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
@@ -131,11 +131,12 @@
                     + Telephony.SimInfo.COLUMN_SATELLITE_ENABLED + " INTEGER DEFAULT 0,"
                     + Telephony.SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER
                     + " INTEGER DEFAULT 1, "
-                    + Telephony.SimInfo.COLUMN_IS_NTN + " INTEGER DEFAULT 0,"
+                    + Telephony.SimInfo.COLUMN_IS_ONLY_NTN + " INTEGER DEFAULT 0,"
                     + Telephony.SimInfo.COLUMN_SERVICE_CAPABILITIES + " INTEGER DEFAULT 7,"
                     + Telephony.SimInfo.COLUMN_TRANSFER_STATUS + " INTEGER DEFAULT 0,"
                     + Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_STATUS + " INTEGER DEFAULT 0,"
-                    + Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_PLMNS + " TEXT"
+                    + Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_PLMNS + " TEXT,"
+                    + Telephony.SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED + " INTEGER DEFAULT 0"
                     + ");";
         }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java
index 0e04aff..b09d90d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java
@@ -203,26 +203,40 @@
         for (int i : enabledLogicalSlots) { expectedSlots.add(i); }
         assertEquals(expectedSlots, mPcm.getSlotsSupportingSimultaneousCellularCalls());
     }
+    @Test
+    @SmallTest
+    public void testUpdateSimultaneousCallingSupportBothInvalidSlotIds() throws Exception {
+        // Test case where both slot IDs are invalid (-1 and 5).
+        testUpdateSimultaneousCallingSupportWithInvalidSlots(Arrays.asList(-1, 5));
+    }
 
     @Test
     @SmallTest
-    public void testUpdateSimultaneousCallingSupport_invalidResponse_shouldFail() throws Exception {
-        doReturn(false).when(mFeatureFlags).simultaneousCallingIndications();
-        init(2);
-        mPcm.updateSimultaneousCallingSupport();
+    public void testUpdateSimultaneousCallingSupportOneInvalidSlotId() throws Exception {
+        // Test case where one slot ID is valid (1) and the other is invalid (2).
+        testUpdateSimultaneousCallingSupportWithInvalidSlots(Arrays.asList(1, 2));
+    }
 
-        // Have the modem send invalid phone slots -1 and 5:
-        List<Integer> invalidEnabledLogicalSlots = Arrays.asList(-1, 5);
-        ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
-        verify(mMockRadioConfig).updateSimultaneousCallingSupport(captor.capture());
-        Message msg = captor.getValue();
-        AsyncResult.forMessage(msg, invalidEnabledLogicalSlots, null);
-        msg.sendToTarget();
-        processAllMessages();
+    @Test
+    @SmallTest
+    public void testUpdateSimultaneousCallingSupportInvalidExtraSlotId() throws Exception {
+        // Test case where the number of slot IDs exceeds the phone count (2) and one slot ID is
+        // invalid (2).
+        testUpdateSimultaneousCallingSupportWithInvalidSlots(Arrays.asList(0, 1, 2));
+    }
 
-        // We would expect to DSDA to be disabled and mSlotsSupportingSimultaneousCellularCalls to
-        // have been cleared:
-        assertTrue(mPcm.getSlotsSupportingSimultaneousCellularCalls().isEmpty());
+    @Test
+    @SmallTest
+    public void testUpdateSimultaneousCallingSupportInvalidSingularSlotId() throws Exception {
+        // Test case where only a single, invalid slot ID (0) is provided.
+        testUpdateSimultaneousCallingSupportWithInvalidSlots(List.of(0));
+    }
+
+    @Test
+    @SmallTest
+    public void testUpdateSimultaneousCallingSupportInvalidEmptySlotIds() throws Exception {
+        // Test case where an empty list of slot IDs is provided.
+        testUpdateSimultaneousCallingSupportWithInvalidSlots(List.of());
     }
 
     /**
@@ -576,4 +590,28 @@
 
         assertEquals(capability, mPcm.getStaticPhoneCapability());
     }
+
+    private void testUpdateSimultaneousCallingSupportWithInvalidSlots(List<Integer> invalidSlots)
+            throws Exception {
+        doReturn(false).when(mFeatureFlags).simultaneousCallingIndications();
+        init(2);
+        mPcm.updateSimultaneousCallingSupport();
+
+        sendInvalidSlotsToModem(invalidSlots);
+        processAllMessages();
+
+        assertDsdaDisabledAndSlotsCleared();
+    }
+
+    private void sendInvalidSlotsToModem(List<Integer> invalidSlots) {
+        ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
+        verify(mMockRadioConfig).updateSimultaneousCallingSupport(captor.capture());
+        Message msg = captor.getValue();
+        AsyncResult.forMessage(msg, invalidSlots, null);
+        msg.sendToTarget();
+    }
+
+    private void assertDsdaDisabledAndSlotsCleared() {
+        assertTrue(mPcm.getSlotsSupportingSimultaneousCellularCalls().isEmpty());
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
index bf9ced3..7a30984 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -628,6 +628,7 @@
     public void testFormatSingaporeInternational() {
         // Disable feature flag.
         mSetFlagsRule.disableFlags(Flags.FLAG_REMOVE_COUNTRY_CODE_FROM_LOCAL_SINGAPORE_CALLS);
+        mSetFlagsRule.enableFlags(Flags.FLAG_NATIONAL_COUNTRY_CODE_FORMATTING_FOR_LOCAL_CALLS);
 
         // International call from a US iso
         assertEquals("+65 6521 8000", PhoneNumberUtils.formatNumber("+6565218000", "US"));
@@ -636,6 +637,7 @@
         assertEquals("+65 6521 8000", PhoneNumberUtils.formatNumber("+6565218000", "us"));
 
         // Enable feature flag
+        mSetFlagsRule.disableFlags(Flags.FLAG_NATIONAL_COUNTRY_CODE_FORMATTING_FOR_LOCAL_CALLS);
         mSetFlagsRule.enableFlags(Flags.FLAG_REMOVE_COUNTRY_CODE_FROM_LOCAL_SINGAPORE_CALLS);
 
         // Internal call from a US iso
@@ -644,6 +646,7 @@
         // Lowercase country iso
         assertEquals("+65 6521 8000", PhoneNumberUtils.formatNumber("+6565218000", "us"));
         mSetFlagsRule.disableFlags(Flags.FLAG_REMOVE_COUNTRY_CODE_FROM_LOCAL_SINGAPORE_CALLS);
+        mSetFlagsRule.disableFlags(Flags.FLAG_NATIONAL_COUNTRY_CODE_FORMATTING_FOR_LOCAL_CALLS);
     }
 
     /**
@@ -655,14 +658,16 @@
     public void testFormatSingaporeNational() {
         // Disable feature flag.
         mSetFlagsRule.disableFlags(Flags.FLAG_REMOVE_COUNTRY_CODE_FROM_LOCAL_SINGAPORE_CALLS);
+        mSetFlagsRule.enableFlags(Flags.FLAG_NATIONAL_COUNTRY_CODE_FORMATTING_FOR_LOCAL_CALLS);
 
         // Local call from a Singaporean number to a Singaporean number
-        assertEquals("+65 6521 8000", PhoneNumberUtils.formatNumber("+6565218000", "SG"));
+        assertEquals("6521 8000", PhoneNumberUtils.formatNumber("+6565218000", "SG"));
 
         // Lowercase country iso.
-        assertEquals("+65 6521 8000", PhoneNumberUtils.formatNumber("+6565218000", "sg"));
+        assertEquals("6521 8000", PhoneNumberUtils.formatNumber("+6565218000", "sg"));
 
         // Enable feature flag.
+        mSetFlagsRule.disableFlags(Flags.FLAG_NATIONAL_COUNTRY_CODE_FORMATTING_FOR_LOCAL_CALLS);
         mSetFlagsRule.enableFlags(Flags.FLAG_REMOVE_COUNTRY_CODE_FROM_LOCAL_SINGAPORE_CALLS);
 
         // Local call from a Singaporean number to a Singaporean number.
@@ -671,6 +676,44 @@
         // Lowercase country iso.
         assertEquals("6521 8000", PhoneNumberUtils.formatNumber("+6565218000", "sg"));
         mSetFlagsRule.disableFlags(Flags.FLAG_REMOVE_COUNTRY_CODE_FROM_LOCAL_SINGAPORE_CALLS);
+        mSetFlagsRule.disableFlags(Flags.FLAG_NATIONAL_COUNTRY_CODE_FORMATTING_FOR_LOCAL_CALLS);
+    }
+
+    @SmallTest
+    @Test
+    public void testFormatTaiwanNational() {
+        // Disable feature flag.
+        mSetFlagsRule.disableFlags(Flags.FLAG_NATIONAL_COUNTRY_CODE_FORMATTING_FOR_LOCAL_CALLS);
+        assertEquals("+886 2 8729 6000", PhoneNumberUtils.formatNumber("+886287296000", "TW"));
+        assertEquals("+886 2 8729 6000", PhoneNumberUtils.formatNumber("+886287296000", "tw"));
+        assertEquals("+886 988 102 544", PhoneNumberUtils.formatNumber("+886988102544", "TW"));
+        assertEquals("+886 988 102 544", PhoneNumberUtils.formatNumber("+886988102544", "tw"));
+
+        // Enable feature flag.
+        mSetFlagsRule.enableFlags(Flags.FLAG_NATIONAL_COUNTRY_CODE_FORMATTING_FOR_LOCAL_CALLS);
+        assertEquals("02 8729 6000", PhoneNumberUtils.formatNumber("+886287296000", "TW"));
+        assertEquals("02 8729 6000", PhoneNumberUtils.formatNumber("+886287296000", "tw"));
+        assertEquals("0988 102 544", PhoneNumberUtils.formatNumber("+886988102544", "TW"));
+        assertEquals("0988 102 544", PhoneNumberUtils.formatNumber("+886988102544", "tw"));
+        mSetFlagsRule.disableFlags(Flags.FLAG_NATIONAL_COUNTRY_CODE_FORMATTING_FOR_LOCAL_CALLS);
+    }
+
+    @SmallTest
+    @Test
+    public void testFormatTaiwanInternational() {
+        // Disable feature flag.
+        mSetFlagsRule.disableFlags(Flags.FLAG_NATIONAL_COUNTRY_CODE_FORMATTING_FOR_LOCAL_CALLS);
+        assertEquals("+886 2 8729 6000", PhoneNumberUtils.formatNumber("+886287296000", "US"));
+        assertEquals("+886 2 8729 6000", PhoneNumberUtils.formatNumber("+886287296000", "us"));
+        assertEquals("+886 988 102 544", PhoneNumberUtils.formatNumber("+886988102544", "US"));
+        assertEquals("+886 988 102 544", PhoneNumberUtils.formatNumber("+886988102544", "us"));
+
+        mSetFlagsRule.enableFlags(Flags.FLAG_NATIONAL_COUNTRY_CODE_FORMATTING_FOR_LOCAL_CALLS);
+        assertEquals("+886 2 8729 6000", PhoneNumberUtils.formatNumber("+886287296000", "US"));
+        assertEquals("+886 2 8729 6000", PhoneNumberUtils.formatNumber("+886287296000", "us"));
+        assertEquals("+886 988 102 544", PhoneNumberUtils.formatNumber("+886988102544", "US"));
+        assertEquals("+886 988 102 544", PhoneNumberUtils.formatNumber("+886988102544", "us"));
+        mSetFlagsRule.disableFlags(Flags.FLAG_NATIONAL_COUNTRY_CODE_FORMATTING_FOR_LOCAL_CALLS);
     }
 
     @SmallTest
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
index fd99ad0..e3da458 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
@@ -3471,9 +3471,12 @@
                         AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         assertEquals(2, nriList.size());
         for (NetworkRegistrationInfo nri : nriList) {
-            assertTrue(Arrays.equals(satelliteSupportedServices, nri.getAvailableServices().stream()
-                    .mapToInt(Integer::intValue)
-                    .toArray()));
+            if (nri.isInService()) {
+                assertTrue(Arrays.equals(satelliteSupportedServices,
+                        nri.getAvailableServices().stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
+            }
         }
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimultaneousCallingTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SimultaneousCallingTrackerTest.java
index 879b184..054df07 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SimultaneousCallingTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SimultaneousCallingTrackerTest.java
@@ -254,7 +254,7 @@
 
     /**
      * Test that simultaneous calling is not supported when IMS is not registered and cellular
-     * simultaneous calling is only supported for one SIM subscription.
+     * simultaneous calling is not supported for any SIM subscriptions.
      */
     @Test
     @SmallTest
@@ -264,8 +264,8 @@
         init(2);
         setAndVerifyStaticCapability(STATIC_DSDA_CAPABILITY);
 
-        // Have the modem inform telephony that only phone slot 0 supports DSDA:
-        List<Integer> enabledLogicalSlots = List.of(0);
+        // Have the modem inform telephony that no phone slots currently support DSDA:
+        List<Integer> enabledLogicalSlots = List.of();
         setAndVerifySlotsSupportingSimultaneousCellularCalling(enabledLogicalSlots);
 
         // Trigger onSubscriptionsChanged by updating the subscription ID of a phone slot:
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java
index ac92b8f..1e2b8ce 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java
@@ -69,6 +69,7 @@
                 .setServiceCapabilities(SubscriptionManager.getServiceCapabilitiesSet(
                     SubscriptionManager.SERVICE_CAPABILITY_DATA_BITMASK))
                 .setTransferStatus(1)
+                .setSatelliteESOSSupported(true)
                 .build();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java
index d4717dd..3b4f869 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java
@@ -37,9 +37,11 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.Process;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.permission.LegacyPermissionManager;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.telephony.SubscriptionManager;
@@ -50,11 +52,13 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.flags.Flags;
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.server.pm.permission.LegacyPermissionManagerService;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 
 import java.lang.reflect.Field;
@@ -71,6 +75,9 @@
     private static final String FEATURE = "com.example.feature";
     private static final String MSG = "message";
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     // Mocked classes
     private Context mMockContext;
     private AppOpsManager mMockAppOps;
@@ -90,6 +97,7 @@
 
     @Before
     public void setUp() throws Exception {
+        mSetFlagsRule.enableFlags(Flags.FLAG_SUPPORT_PHONE_UID_CHECK_FOR_MULTIUSER);
         mMockContext = mock(Context.class);
         mMockAppOps = mock(AppOpsManager.class);
         mMockSubscriptionManager = mock(SubscriptionManager.class);
@@ -558,6 +566,38 @@
                 UserHandle.SYSTEM));
     }
 
+    @Test
+    public void testIsSystemOrPhone_systemUser() {
+        assertTrue(TelephonyPermissions.isSystemOrPhone(Process.SYSTEM_UID));
+        assertTrue(TelephonyPermissions.isSystemOrPhone(Process.PHONE_UID));
+
+        assertFalse(TelephonyPermissions.isSystemOrPhone(1002));
+    }
+
+    @Test
+    public void testIsSystemOrPhone_nonSystemUser() {
+        assertTrue(TelephonyPermissions.isSystemOrPhone(1001000));
+        assertTrue(TelephonyPermissions.isSystemOrPhone(1001001));
+
+        assertFalse(TelephonyPermissions.isSystemOrPhone(1001002));
+    }
+
+    @Test
+    public void testIsRootOrShell_systemUser() {
+        assertTrue(TelephonyPermissions.isRootOrShell(Process.ROOT_UID));
+        assertTrue(TelephonyPermissions.isRootOrShell(Process.SHELL_UID));
+
+        assertFalse(TelephonyPermissions.isRootOrShell(1002));
+    }
+
+    @Test
+    public void testIsRootOrShell_nonSystemUser() {
+        assertTrue(TelephonyPermissions.isRootOrShell(1000000));
+        assertTrue(TelephonyPermissions.isRootOrShell(1002000));
+
+        assertFalse(TelephonyPermissions.isRootOrShell(1001002));
+    }
+
     // Put mMockTelephony into service cache so that TELEPHONY_SUPPLIER will get it.
     private void setTelephonyMockAsService() throws Exception {
         when(mMockTelephonyBinder.queryLocalInterface(anyString())).thenReturn(mMockTelephony);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
index 7795e42..1a5c1af 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
@@ -2419,8 +2419,13 @@
     @Test
     public void testMmsCapabilityRemovedWhenMmsPreferredOnIwlan() throws Exception {
         doReturn(true).when(mFeatureFlags).forceIwlanMms();
+        doReturn(true).when(mDataConfigManager).isForceIwlanMmsFeatureEnabled();
         setupDataNetwork();
 
+        TelephonyNetworkAgent mockNetworkAgent = Mockito.mock(TelephonyNetworkAgent.class);
+        replaceInstance(DataNetwork.class, "mNetworkAgent",
+                mDataNetworkUT, mockNetworkAgent);
+
         assertThat(mDataNetworkUT.getNetworkCapabilities()
                 .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)).isTrue();
 
@@ -2465,11 +2470,13 @@
                 .onPreferredTransportChanged(NetworkCapabilities.NET_CAPABILITY_MMS, false);
         processAllMessages();
 
-        // Check if MMS capability is removed.
+        // Check if MMS capability is removed, and we don't recreat network agent which triggers
+        // powering comsuming internet validation.
         assertThat(mDataNetworkUT.getNetworkCapabilities()
                 .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)).isFalse();
+        verify(mockNetworkAgent, never()).abandon();
 
-        // Now QNS prefers MMS on IWLAN
+        // Now QNS prefers MMS on WWAN
         doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager)
             .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
         accessNetworksManagerCallbackArgumentCaptor.getValue()
diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
index f05099d..0eb5c13 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
@@ -3171,6 +3171,207 @@
                 anyBoolean(), eq(0));
     }
 
+    /**
+     * Test Phone selection.
+     * SIM absent and SIM ready on the other Phone.
+     */
+    @Test
+    @SmallTest
+    public void testSwitchPhoneAbsentAndReady() {
+        EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
+                /* isSuplDdsSwitchRequiredForEmergencyCall= */ true);
+        Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true,
+                /* isRadioOn= */ true);
+        Phone phone1 = getPhone(1);
+
+        // Phone0
+        doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+                .when(phone0).getSubId();
+        doReturn(TelephonyManager.SIM_STATE_ABSENT)
+                .when(mTelephonyManagerProxy).getSimState(eq(0));
+
+        // Phone1
+        doReturn(2).when(phone1).getSubId();
+        doReturn(TelephonyManager.SIM_STATE_READY)
+                .when(mTelephonyManagerProxy).getSimState(eq(1));
+
+        CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall(
+                phone0, mTestConnection1, true);
+        processAllMessages();
+
+        assertTrue(future.isDone());
+        // Expect: DisconnectCause#EMERGENCY_PERM_FAILURE
+        assertEquals(future.getNow(DisconnectCause.NOT_DISCONNECTED),
+                Integer.valueOf(DisconnectCause.EMERGENCY_PERM_FAILURE));
+        verify(phone0, never()).setEmergencyMode(anyInt(), any(Message.class));
+    }
+
+    /**
+     * Test Phone selection.
+     * PIN locked and SIM ready on the other Phone.
+     */
+    @Test
+    @SmallTest
+    public void testSwitchPhonePinLockedAndReady() {
+        EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
+                /* isSuplDdsSwitchRequiredForEmergencyCall= */ true);
+        Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true,
+                /* isRadioOn= */ true);
+        Phone phone1 = getPhone(1);
+
+        // Phone0
+        doReturn(1).when(phone0).getSubId();
+        doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED)
+                .when(mTelephonyManagerProxy).getSimState(eq(0));
+
+        // Phone1
+        doReturn(2).when(phone1).getSubId();
+        doReturn(TelephonyManager.SIM_STATE_READY)
+                .when(mTelephonyManagerProxy).getSimState(eq(1));
+
+        CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall(
+                phone0, mTestConnection1, true);
+        processAllMessages();
+
+        assertTrue(future.isDone());
+        // Expect: DisconnectCause#EMERGENCY_PERM_FAILURE
+        assertEquals(future.getNow(DisconnectCause.NOT_DISCONNECTED),
+                Integer.valueOf(DisconnectCause.EMERGENCY_PERM_FAILURE));
+        verify(phone0, never()).setEmergencyMode(anyInt(), any(Message.class));
+    }
+
+    /**
+     * Test Phone selection.
+     * SIM ready and SIM ready on the other Phone.
+     */
+    @Test
+    @SmallTest
+    public void testSwitchPhoneReadyAndReady() {
+        EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
+                /* isSuplDdsSwitchRequiredForEmergencyCall= */ true);
+        Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true,
+                /* isRadioOn= */ true);
+        Phone phone1 = getPhone(1);
+
+        // Phone0
+        doReturn(1).when(phone0).getSubId();
+        doReturn(TelephonyManager.SIM_STATE_READY)
+                .when(mTelephonyManagerProxy).getSimState(eq(0));
+
+        // Phone1
+        doReturn(2).when(phone1).getSubId();
+        doReturn(TelephonyManager.SIM_STATE_READY)
+                .when(mTelephonyManagerProxy).getSimState(eq(1));
+
+        CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall(
+                phone0, mTestConnection1, true);
+        processAllMessages();
+
+        assertFalse(future.isDone());
+        verify(phone0).setEmergencyMode(anyInt(), any(Message.class));
+    }
+
+    /**
+     * Test Phone selection.
+     * PIN locked and PIN locked on the other Phone.
+     */
+    @Test
+    @SmallTest
+    public void testSwitchPhonePinLockedAndPinLocked() {
+        EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
+                /* isSuplDdsSwitchRequiredForEmergencyCall= */ true);
+        Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true,
+                /* isRadioOn= */ true);
+        Phone phone1 = getPhone(1);
+
+        // Phone0
+        doReturn(1).when(phone0).getSubId();
+        doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED)
+                .when(mTelephonyManagerProxy).getSimState(eq(0));
+
+        // Phone1
+        doReturn(2).when(phone1).getSubId();
+        doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED)
+                .when(mTelephonyManagerProxy).getSimState(eq(1));
+
+        CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall(
+                phone0, mTestConnection1, true);
+        processAllMessages();
+
+        assertFalse(future.isDone());
+        verify(phone0).setEmergencyMode(anyInt(), any(Message.class));
+    }
+
+    /**
+     * Test Phone selection.
+     * SIM absent and SIM absent on default Phone.
+     */
+    @Test
+    @SmallTest
+    public void testSwitchPhoneAbsentAndAbsentOnDefaultPhone() {
+        EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
+                /* isSuplDdsSwitchRequiredForEmergencyCall= */ true);
+        Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true,
+                /* isRadioOn= */ true);
+        Phone phone1 = getPhone(1);
+
+        // Phone0
+        doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+                .when(phone0).getSubId();
+        doReturn(TelephonyManager.SIM_STATE_ABSENT)
+                .when(mTelephonyManagerProxy).getSimState(eq(0));
+
+        // Phone1
+        doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+                .when(phone1).getSubId();
+        doReturn(TelephonyManager.SIM_STATE_ABSENT)
+                .when(mTelephonyManagerProxy).getSimState(eq(1));
+
+        CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall(
+                phone1, mTestConnection1, true);
+        processAllMessages();
+
+        assertTrue(future.isDone());
+        // Expect: DisconnectCause#EMERGENCY_PERM_FAILURE
+        assertEquals(future.getNow(DisconnectCause.NOT_DISCONNECTED),
+                Integer.valueOf(DisconnectCause.EMERGENCY_PERM_FAILURE));
+        verify(phone1, never()).setEmergencyMode(anyInt(), any(Message.class));
+    }
+
+    /**
+     * Test Phone selection.
+     * PIN locked and PIN locked on default Phone.
+     */
+    @Test
+    @SmallTest
+    public void testSwitchPhonePinLockedandPinLockedOnDefaultPhone() {
+        EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
+                /* isSuplDdsSwitchRequiredForEmergencyCall= */ true);
+        Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true,
+                /* isRadioOn= */ true);
+        Phone phone1 = getPhone(1);
+
+        // Phone0
+        doReturn(1).when(phone0).getSubId();
+        doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED)
+                .when(mTelephonyManagerProxy).getSimState(eq(0));
+
+        // Phone1
+        doReturn(2).when(phone1).getSubId();
+        doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED)
+                .when(mTelephonyManagerProxy).getSimState(eq(1));
+
+        CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall(
+                phone1, mTestConnection1, true);
+        processAllMessages();
+
+        assertTrue(future.isDone());
+        // Expect: DisconnectCause#EMERGENCY_PERM_FAILURE
+        assertEquals(future.getNow(DisconnectCause.NOT_DISCONNECTED),
+                Integer.valueOf(DisconnectCause.EMERGENCY_PERM_FAILURE));
+        verify(phone1, never()).setEmergencyMode(anyInt(), any(Message.class));
+    }
+
     private EmergencyStateTracker setupEmergencyStateTracker(
             boolean isSuplDdsSwitchRequiredForEmergencyCall) {
         doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
index 6056112..a525efa 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
@@ -2774,6 +2774,32 @@
         assertNetworkStatsEquals(expectedStats, uidStatsCaptor.getValue());
     }
 
+    @Test
+    public void testPreventHangupDuringCallMerge() {
+        // Enable feature flag
+        doReturn(true).when(mFeatureFlags).preventHangupDuringCallMerge();
+
+        // Change carrier config to allow call hold for 2nd call setup
+        PersistableBundle bundle = mContextFixture.getCarrierConfigBundle();
+        bundle.putBoolean(CarrierConfigManager.KEY_ALLOW_HOLD_VIDEO_CALL_BOOL, true);
+        mCTUT.updateCarrierConfigCache(bundle);
+
+        // Place a call.
+        placeCallAndMakeActive();
+        // Place a 2nd call
+        ImsPhoneConnection imsPhoneConnection = placeCallAndMakeActive();
+
+        // Try call merge
+        mCTUT.conference();
+
+        try {
+            mCTUT.hangup(imsPhoneConnection.getCall());
+            fail("Expect CallStateException but not");
+        } catch  (CallStateException e) {
+            // Expected exception
+        }
+    }
+
     private ImsPhoneConnection placeCallAndMakeActive() {
         ImsPhoneConnection connection = placeCall();
         ImsCall imsCall = connection.getImsCall();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
index da40c32..986e573 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
@@ -3434,7 +3434,8 @@
         assertEquals(SATELLITE_RESULT_MODEM_TIMEOUT, (long) mIIntegerConsumerResults.get(0));
         verify(mMockSatelliteModemInterface, never()).requestSatelliteEnabled(anyBoolean(),
                 anyBoolean(), anyBoolean(), any(Message.class));
-        verifySatelliteEnabled(false, SATELLITE_RESULT_SUCCESS);
+        // Satellite should state at enabled state since satellite disable request failed
+        verifySatelliteEnabled(true, SATELLITE_RESULT_SUCCESS);
 
         // Send the response for the above request to disable satellite. SatelliteController should
         // ignore the event
@@ -3442,7 +3443,7 @@
         AsyncResult.forMessage(response, null, null);
         response.sendToTarget();
         processAllMessages();
-        verifySatelliteEnabled(false, SATELLITE_RESULT_SUCCESS);
+        verifySatelliteEnabled(true, SATELLITE_RESULT_SUCCESS);
     }
 
     @Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
index 876fc51..f4fa48e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
@@ -16,7 +16,6 @@
 
 package com.android.internal.telephony.satellite;
 
-import static android.telephony.ServiceState.STATE_IN_SERVICE;
 import static android.telephony.ServiceState.STATE_OUT_OF_SERVICE;
 import static android.telephony.TelephonyManager.EXTRA_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE;
 import static android.telephony.TelephonyManager.EXTRA_EMERGENCY_CALL_TO_SATELLITE_LAUNCH_INTENT;
@@ -193,14 +192,25 @@
                 DEFAULT_HANDOVER_INTENT_ACTION);
     }
 
+    @Test
+    public void testStartTimer_emergencyCallNull() {
+        when(mServiceState.getState()).thenReturn(STATE_OUT_OF_SERVICE);
+        when(mServiceState2.getState()).thenReturn(STATE_OUT_OF_SERVICE);
+        mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
+        mTestSOSMessageRecommender.onEmergencyCallStarted(null);
+        processAllMessages();
+        assertFalse(mTestSOSMessageRecommender.isTimerStarted());
+        assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
+    }
+
     private void testTimeoutBeforeEmergencyCallEnd(int expectedHandoverType,
             String expectedPackageName, String expectedClassName, String expectedAction) {
         mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
         processAllMessages();
         assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone, 1,  1);
+        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 1);
         assertNull(mTestSOSMessageRecommender.isSatelliteAllowedCallback);
 
         // Move Location service to emergency mode
@@ -220,8 +230,8 @@
             assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
                     expectedHandoverType, expectedPackageName, expectedClassName, expectedAction));
         }
-        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
     }
 
     @Test
@@ -232,8 +242,8 @@
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
         processAllMessages();
         assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 1);
         assertNull(mTestSOSMessageRecommender.isSatelliteAllowedCallback);
 
         // Move Location service to emergency mode
@@ -247,8 +257,8 @@
         moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
         processAllMessages();
         assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE));
-        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
     }
 
     @Test
@@ -259,8 +269,8 @@
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
         processAllMessages();
         assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 1);
         assertNull(mTestSOSMessageRecommender.isSatelliteAllowedCallback);
 
         // Move Location service to emergency mode
@@ -277,8 +287,8 @@
                 EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911,
                 DEFAULT_SATELLITE_MESSAGING_PACKAGE, DEFAULT_SATELLITE_MESSAGING_CLASS,
                 DEFAULT_T911_HANDOVER_INTENT_ACTION));
-        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
         mTestSatelliteController.isOemEnabledSatelliteSupported = true;
     }
 
@@ -299,45 +309,8 @@
         processAllMessages();
         assertTrue(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
-        assertNull(mTestSOSMessageRecommender.isSatelliteAllowedCallback);
-
-        when(mPhone.isImsRegistered()).thenReturn(true);
-        when(mServiceState.getState()).thenReturn(STATE_IN_SERVICE);
-        mTestImsManager.sendImsRegistrationStateChangedEvent(0, true);
-        processAllMessages();
-
-        assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE));
-        assertFalse(mTestSOSMessageRecommender.isTimerStarted());
-        assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0);
-
-        when(mPhone.isImsRegistered()).thenReturn(false);
-        when(mServiceState.getState()).thenReturn(STATE_OUT_OF_SERVICE);
-        mTestImsManager.sendImsRegistrationStateChangedEvent(0, true);
-        processAllMessages();
-
-        assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE));
-        assertTrue(mTestSOSMessageRecommender.isTimerStarted());
-        assertEquals(2, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0);
-
-        when(mPhone.isImsRegistered()).thenReturn(false);
-        when(mPhone2.isImsRegistered()).thenReturn(true);
-        when(mServiceState.getState()).thenReturn(STATE_IN_SERVICE);
-        mTestImsManager.sendImsRegistrationStateChangedEvent(1, true);
-        processAllMessages();
-        assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE));
-        assertFalse(mTestSOSMessageRecommender.isTimerStarted());
-        assertEquals(2, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0);
-
-        when(mPhone2.isImsRegistered()).thenReturn(false);
-        when(mServiceState.getState()).thenReturn(STATE_OUT_OF_SERVICE);
-        mTestImsManager.sendImsRegistrationStateChangedEvent(1, false);
-        processAllMessages();
-        assertEquals(3, mTestSOSMessageRecommender.getCountOfTimerStarted());
+        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 1);
         assertNull(mTestSOSMessageRecommender.isSatelliteAllowedCallback);
 
         // Move Location service to emergency mode
@@ -354,8 +327,8 @@
         assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
                 EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE,
                 DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_T911_HANDOVER_INTENT_ACTION));
-        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
     }
 
@@ -366,8 +339,8 @@
 
         assertTrue(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 1);
 
         mTestSatelliteController.sendProvisionStateChangedEvent(
                 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false);
@@ -375,15 +348,15 @@
 
         assertFalse(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
 
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
         processAllMessages();
         assertTrue(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertRegisterForStateChangedEventsTriggered(mPhone, 2, 4, 2);
-        assertRegisterForStateChangedEventsTriggered(mPhone2, 2, 4, 2);
+        assertRegisterForStateChangedEventsTriggered(mPhone, 2, 2);
+        assertRegisterForStateChangedEventsTriggered(mPhone2, 2, 2);
 
         // Move Location service to emergency mode
         mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
@@ -405,8 +378,8 @@
                 DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_T911_HANDOVER_INTENT_ACTION));
         assertFalse(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertUnregisterForStateChangedEventsTriggered(mPhone, 2, 4, 2);
-        assertUnregisterForStateChangedEventsTriggered(mPhone2, 2, 4, 2);
+        assertUnregisterForStateChangedEventsTriggered(mPhone, 2, 2);
+        assertUnregisterForStateChangedEventsTriggered(mPhone2, 2, 2);
     }
 
     @Test
@@ -416,8 +389,8 @@
         processAllMessages();
         assertTrue(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 1);
         assertNull(mTestSOSMessageRecommender.isSatelliteAllowedCallback);
 
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
@@ -425,8 +398,8 @@
         assertNull(mTestSOSMessageRecommender.isSatelliteAllowedCallback);
         assertTrue(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 1);
 
         // Move Location service to emergency mode
         mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged(
@@ -442,8 +415,8 @@
         assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
                 EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE,
                 DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_T911_HANDOVER_INTENT_ACTION));
-        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
         assertFalse(mTestSOSMessageRecommender.isTimerStarted());
     }
@@ -479,8 +452,8 @@
 
         assertTrue(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 1);
 
         mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged(
                 WRONG_CALL_ID, Connection.STATE_ACTIVE);
@@ -489,8 +462,8 @@
         assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE));
         assertFalse(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
     }
 
     @Test
@@ -514,10 +487,10 @@
 
         assertFalse(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
-        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
     }
 
     @Test
@@ -586,8 +559,8 @@
 
         assertTrue(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 1);
 
         mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged(CALL_ID, connectionState);
         processAllMessages();
@@ -595,8 +568,8 @@
         assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE));
         assertFalse(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
     }
 
     private void testCellularServiceStateChangedBeforeTimeout(
@@ -608,8 +581,8 @@
         assertNull(mTestSOSMessageRecommender.isSatelliteAllowedCallback);
         assertTrue(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 1);
 
         when(mServiceState.getState()).thenReturn(availableServiceState);
         mTestSOSMessageRecommender.sendServiceStateChangedEvent();
@@ -617,8 +590,8 @@
         assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE));
         assertFalse(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
-        assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0);
-        assertUnregisterForStateChangedEventsTriggered(mPhone2, 0, 0, 0);
+        assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0);
+        assertUnregisterForStateChangedEventsTriggered(mPhone2, 0, 0);
 
         when(mServiceState.getState()).thenReturn(unavailableServiceState);
         when(mServiceState2.getState()).thenReturn(availableServiceState);
@@ -647,28 +620,24 @@
         assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
                 EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE,
                 DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_T911_HANDOVER_INTENT_ACTION));
-        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
-        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
+        assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
         assertFalse(mTestSOSMessageRecommender.isTimerStarted());
     }
 
-    private void assertRegisterForStateChangedEventsTriggered(
-            Phone phone, int registerForProvisionCount, int registerForImsCount,
-            int registerForCellularCount) {
+    private void assertRegisterForStateChangedEventsTriggered(Phone phone,
+            int registerForProvisionCount, int registerForCellularCount) {
         assertEquals(registerForProvisionCount,
                 mTestSatelliteController.getRegisterForSatelliteProvisionStateChangedCalls());
-        assertEquals(registerForImsCount, mTestImsManager.getAddRegistrationCallbackCalls());
         verify(phone, times(registerForCellularCount))
                 .registerForServiceStateChanged(any(), anyInt(), any());
     }
 
     private void assertUnregisterForStateChangedEventsTriggered(
-            Phone phone, int unregisterForProvisionCount, int unregisterForImsCount,
-            int unregisterForCellularCount) {
+            Phone phone, int unregisterForProvisionCount, int unregisterForCellularCount) {
         assertEquals(unregisterForProvisionCount,
                 mTestSatelliteController.getUnregisterForSatelliteProvisionStateChangedCalls());
-        assertEquals(unregisterForImsCount, mTestImsManager.getRemoveRegistrationListenerCalls());
         verify(phone, times(unregisterForCellularCount)).unregisterForServiceStateChanged(any());
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java
index 78763d1..fc9579f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java
@@ -936,28 +936,41 @@
         assertNotNull(mTestSatelliteSessionController);
         assertEquals(STATE_POWER_OFF, mTestSatelliteSessionController.getCurrentStateName());
 
-        // IDLE -> DISABLING
+        // IDLE -> DISABLING request failed -> NOT_CONNECTED
         moveToIdleState();
-        moveSatelliteToDisablingState();
+        moveSatelliteToDisablingRequestFailed(SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED,
+                STATE_NOT_CONNECTED);
 
-        // DISABLING -> POWER_OFF
+        // NOT_CONNECTED -> DISABLING -> POWER_OFF
+        moveSatelliteToDisablingState();
         moveToPowerOffState();
 
-        // TRANSFERRING -> DISABLING
+        // IDLE -> DISABLING -> POWER_OFF
+        moveToIdleState();
+        moveSatelliteToDisablingState();
+        moveToPowerOffState();
+
+        // TRANSFERRING -> DISABLING request failed -> CONNECTED
+        moveToIdleState();
+        moveIdleToTransferringState();
+        moveSatelliteToDisablingRequestFailed(
+                SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED, STATE_CONNECTED);
+
+        // CONNECTED -> DISABLING -> POWER_OFF
+        moveSatelliteToDisablingState();
+        moveToPowerOffState();
+
+        // TRANSFERRING -> DISABLING -> POWER_OFF
         moveToIdleState();
         moveIdleToTransferringState();
         moveSatelliteToDisablingState();
-
-        // DISABLING -> POWER_OFF
         moveToPowerOffState();
 
-        // LISTENING -> DISABLING
+        // LISTENING -> DISABLING -> POWER_OFF
         moveToIdleState();
         moveIdleToTransferringState();
         moveTransferringToListeningState();
         moveSatelliteToDisablingState();
-
-        // DISABLING -> POWER_OFF
         moveToPowerOffState();
     }
 
@@ -1112,6 +1125,18 @@
                 STATE_DISABLING_SATELLITE, mTestSatelliteSessionController.getCurrentStateName());
     }
 
+    private void moveSatelliteToDisablingRequestFailed(int state, String stateName) {
+        moveSatelliteToDisablingState();
+
+        // Satellite disabled request failed
+        mTestSatelliteSessionController.onSatelliteEnablementFailed();
+        processAllMessages();
+
+        // Satellite should stay in previous state as satellite disable request failed
+        assertSuccessfulModemStateChangedCallback(mTestSatelliteModemStateCallback, state);
+        assertEquals(stateName, mTestSatelliteSessionController.getCurrentStateName());
+    }
+
     private static class TestSatelliteModemInterface extends SatelliteModemInterface {
         private final AtomicInteger mListeningEnabledCount = new AtomicInteger(0);
         private final AtomicInteger mListeningDisabledCount = new AtomicInteger(0);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java
index 62b9def..5a0d0d8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java
@@ -122,8 +122,8 @@
     static final int FAKE_USER_ID2 = 11;
     static final int FAKE_SATELLITE_ATTACH_FOR_CARRIER_ENABLED = 1;
     static final int FAKE_SATELLITE_ATTACH_FOR_CARRIER_DISABLED = 0;
-    static final int FAKE_SATELLITE_IS_NTN_ENABLED = 1;
-    static final int FAKE_SATELLITE_IS_NTN_DISABLED = 0;
+    static final int FAKE_SATELLITE_IS_ONLY_NTN_ENABLED = 1;
+    static final int FAKE_SATELLITE_IS_ONLY_NTN_DISABLED = 0;
     static final int FAKE_SERVICE_CAPABILITIES_1 =
             SubscriptionManager.SERVICE_CAPABILITY_DATA_BITMASK;
     static final int FAKE_SERVICE_CAPABILITIES_2 =
@@ -132,6 +132,8 @@
     static final int FAKE_SATELLITE_ENTITLEMENT_STATUS_DISABLED = 0;
     static final String FAKE_SATELLITE_ENTITLEMENT_PLMNS1 = "123123,12310";
     static final String FAKE_SATELLITE_ENTITLEMENT_PLMNS2 = "";
+    static final int FAKE_SATELLITE_ESOS_SUPPORTED_ENABLED = 1;
+    static final int FAKE_SATELLITE_ESOS_SUPPORTED_DISABLED = 0;
 
     static final String FAKE_MAC_ADDRESS1 = "DC:E5:5B:38:7D:40";
     static final String FAKE_MAC_ADDRESS2 = "DC:B5:4F:47:F3:4C";
@@ -208,12 +210,13 @@
                     .setSatelliteEnabled(0)
                     .setSatelliteAttachEnabledForCarrier(
                             FAKE_SATELLITE_ATTACH_FOR_CARRIER_DISABLED)
-                    .setOnlyNonTerrestrialNetwork(FAKE_SATELLITE_IS_NTN_DISABLED)
+                    .setOnlyNonTerrestrialNetwork(FAKE_SATELLITE_IS_ONLY_NTN_DISABLED)
                     .setGroupDisabled(false)
                     .setServiceCapabilities(FAKE_SERVICE_CAPABILITIES_1)
                     .setTransferStatus(FAKE_TRANSFER_STATUS_TRANSFERRED_OUT)
                     .setSatelliteEntitlementStatus(FAKE_SATELLITE_ENTITLEMENT_STATUS_DISABLED)
                     .setSatelliteEntitlementPlmns(FAKE_SATELLITE_ENTITLEMENT_PLMNS2)
+                    .setSatelliteESOSSupported(FAKE_SATELLITE_ESOS_SUPPORTED_DISABLED)
                     .build();
 
     static final SubscriptionInfoInternal FAKE_SUBSCRIPTION_INFO2 =
@@ -283,12 +286,13 @@
                     .setSatelliteEnabled(1)
                     .setSatelliteAttachEnabledForCarrier(
                             FAKE_SATELLITE_ATTACH_FOR_CARRIER_ENABLED)
-                    .setOnlyNonTerrestrialNetwork(FAKE_SATELLITE_IS_NTN_ENABLED)
+                    .setOnlyNonTerrestrialNetwork(FAKE_SATELLITE_IS_ONLY_NTN_ENABLED)
                     .setGroupDisabled(false)
                     .setServiceCapabilities(FAKE_SERVICE_CAPABILITIES_2)
                     .setTransferStatus(FAKE_TRANSFER_STATUS_CONVERTED)
                     .setSatelliteEntitlementStatus(FAKE_SATELLITE_ENTITLEMENT_STATUS_ENABLED)
                     .setSatelliteEntitlementPlmns(FAKE_SATELLITE_ENTITLEMENT_PLMNS1)
+                    .setSatelliteESOSSupported(FAKE_SATELLITE_ESOS_SUPPORTED_ENABLED)
                     .build();
 
     private SubscriptionDatabaseManager mDatabaseManagerUT;
@@ -450,6 +454,7 @@
         when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
         when(mFeatureFlags.dataOnlyCellularService()).thenReturn(true);
         when(mFeatureFlags.supportPsimToEsimConversion()).thenReturn(true);
+        when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true);
         mDatabaseManagerUT = new SubscriptionDatabaseManager(mContext, Looper.myLooper(),
                 mFeatureFlags, mSubscriptionDatabaseManagerCallback);
         logd("SubscriptionDatabaseManagerTest -Setup!");
@@ -2010,28 +2015,28 @@
         // exception is expected if there is nothing in the database.
         assertThrows(IllegalArgumentException.class,
                 () -> mDatabaseManagerUT.setNtn(FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(),
-                        FAKE_SATELLITE_IS_NTN_ENABLED));
+                        FAKE_SATELLITE_IS_ONLY_NTN_ENABLED));
 
         SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1);
         mDatabaseManagerUT.setNtn(FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(),
-                FAKE_SATELLITE_IS_NTN_ENABLED);
+                FAKE_SATELLITE_IS_ONLY_NTN_ENABLED);
         processAllMessages();
 
         subInfo = new SubscriptionInfoInternal.Builder(subInfo)
-                .setOnlyNonTerrestrialNetwork(FAKE_SATELLITE_IS_NTN_ENABLED)
+                .setOnlyNonTerrestrialNetwork(FAKE_SATELLITE_IS_ONLY_NTN_ENABLED)
                 .build();
         verifySubscription(subInfo);
         verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1));
 
         assertThat(mDatabaseManagerUT.getSubscriptionProperty(
                 FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(),
-                SimInfo.COLUMN_IS_NTN)).isEqualTo(FAKE_SATELLITE_IS_NTN_ENABLED);
+                SimInfo.COLUMN_IS_ONLY_NTN)).isEqualTo(FAKE_SATELLITE_IS_ONLY_NTN_ENABLED);
 
         mDatabaseManagerUT.setSubscriptionProperty(FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(),
-                SimInfo.COLUMN_IS_NTN, FAKE_SATELLITE_IS_NTN_DISABLED);
+                SimInfo.COLUMN_IS_ONLY_NTN, FAKE_SATELLITE_IS_ONLY_NTN_DISABLED);
         assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(
                         FAKE_SUBSCRIPTION_INFO1.getSubscriptionId()).getOnlyNonTerrestrialNetwork())
-                .isEqualTo(FAKE_SATELLITE_IS_NTN_DISABLED);
+                .isEqualTo(FAKE_SATELLITE_IS_ONLY_NTN_DISABLED);
     }
 
     @Test
@@ -2074,13 +2079,13 @@
         SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1);
         mDatabaseManagerUT.setSatelliteAttachEnabledForCarrier(
                 FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(),
-                FAKE_SATELLITE_IS_NTN_DISABLED);
+                FAKE_SATELLITE_IS_ONLY_NTN_DISABLED);
         processAllMessages();
 
         when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false);
         reset(mSubscriptionDatabaseManagerCallback);
         subInfo = new SubscriptionInfoInternal.Builder(subInfo)
-                .setOnlyNonTerrestrialNetwork(FAKE_SATELLITE_IS_NTN_ENABLED)
+                .setOnlyNonTerrestrialNetwork(FAKE_SATELLITE_IS_ONLY_NTN_ENABLED)
                 .build();
 
         int subId = subInfo.getSubscriptionId();
@@ -2100,13 +2105,13 @@
 
         assertThat(mDatabaseManagerUT.getSubscriptionProperty(
                 FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(),
-                SimInfo.COLUMN_IS_NTN)).isNotEqualTo(FAKE_SATELLITE_IS_NTN_ENABLED);
+                SimInfo.COLUMN_IS_ONLY_NTN)).isNotEqualTo(FAKE_SATELLITE_IS_ONLY_NTN_ENABLED);
 
         mDatabaseManagerUT.setSubscriptionProperty(FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(),
-                SimInfo.COLUMN_IS_NTN, FAKE_SATELLITE_IS_NTN_ENABLED);
+                SimInfo.COLUMN_IS_ONLY_NTN, FAKE_SATELLITE_IS_ONLY_NTN_ENABLED);
         assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(
                 FAKE_SUBSCRIPTION_INFO1.getSubscriptionId()).getOnlyNonTerrestrialNetwork())
-                .isNotEqualTo(FAKE_SATELLITE_IS_NTN_ENABLED);
+                .isNotEqualTo(FAKE_SATELLITE_IS_ONLY_NTN_ENABLED);
     }
 
     @Test
@@ -2357,4 +2362,35 @@
                 .getSatelliteEntitlementPlmns())
                 .isEqualTo(FAKE_SATELLITE_ENTITLEMENT_PLMNS2);
     }
+
+    @Test
+    public void testUpdateSatelliteESOSSupported() throws Exception {
+        // exception is expected if there is nothing in the database.
+        assertThrows(IllegalArgumentException.class,
+                () -> mDatabaseManagerUT.setSatelliteESOSSupported(
+                        FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(),
+                        FAKE_SATELLITE_ESOS_SUPPORTED_ENABLED));
+
+        SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1);
+        mDatabaseManagerUT.setSatelliteESOSSupported(FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(),
+                FAKE_SATELLITE_ESOS_SUPPORTED_ENABLED);
+        processAllMessages();
+
+        subInfo = new SubscriptionInfoInternal.Builder(subInfo)
+                .setSatelliteESOSSupported(FAKE_SATELLITE_ESOS_SUPPORTED_ENABLED)
+                .build();
+        verifySubscription(subInfo);
+        verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1));
+
+        assertThat(mDatabaseManagerUT.getSubscriptionProperty(
+                FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(),
+                SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED)).isEqualTo(
+                FAKE_SATELLITE_ESOS_SUPPORTED_ENABLED);
+
+        mDatabaseManagerUT.setSubscriptionProperty(FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(),
+                SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED, FAKE_SATELLITE_ESOS_SUPPORTED_DISABLED);
+        assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(
+                        FAKE_SUBSCRIPTION_INFO1.getSubscriptionId())
+                .getSatelliteESOSSupported()).isEqualTo(FAKE_SATELLITE_ESOS_SUPPORTED_DISABLED);
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java
index de43b85..30a4d8e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java
@@ -110,7 +110,7 @@
                             SubscriptionDatabaseManagerTest
                                     .FAKE_SATELLITE_ATTACH_FOR_CARRIER_ENABLED)
                     .setOnlyNonTerrestrialNetwork(
-                            SubscriptionDatabaseManagerTest.FAKE_SATELLITE_IS_NTN_ENABLED)
+                            SubscriptionDatabaseManagerTest.FAKE_SATELLITE_IS_ONLY_NTN_ENABLED)
                     .setGroupDisabled(false)
                     .setOnlyNonTerrestrialNetwork(1)
                     .setServiceCapabilities(
@@ -122,6 +122,8 @@
                     .setSatelliteEntitlementPlmns(
                             SubscriptionDatabaseManagerTest
                                     .FAKE_SATELLITE_ENTITLEMENT_PLMNS1)
+                    .setSatelliteESOSSupported(
+                            SubscriptionDatabaseManagerTest.FAKE_SATELLITE_ESOS_SUPPORTED_ENABLED)
                     .build();
 
     private final SubscriptionInfoInternal mSubInfoNull =
@@ -240,7 +242,7 @@
                 .isEqualTo(SubscriptionDatabaseManagerTest
                         .FAKE_SATELLITE_ATTACH_FOR_CARRIER_ENABLED);
         assertThat(mSubInfo.getOnlyNonTerrestrialNetwork()).isEqualTo(
-                SubscriptionDatabaseManagerTest.FAKE_SATELLITE_IS_NTN_ENABLED);
+                SubscriptionDatabaseManagerTest.FAKE_SATELLITE_IS_ONLY_NTN_ENABLED);
         assertThat(mSubInfo.isGroupDisabled()).isFalse();
         assertThat(mSubInfo.getOnlyNonTerrestrialNetwork()).isEqualTo(1);
         assertThat(mSubInfo.getServiceCapabilities()).isEqualTo(
@@ -252,6 +254,8 @@
         assertThat(mSubInfo.getSatelliteEntitlementPlmns())
                 .isEqualTo(SubscriptionDatabaseManagerTest
                         .FAKE_SATELLITE_ENTITLEMENT_PLMNS1);
+        assertThat(mSubInfo.getSatelliteESOSSupported())
+                .isEqualTo(SubscriptionDatabaseManagerTest.FAKE_SATELLITE_ESOS_SUPPORTED_ENABLED);
     }
 
     @Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
index eb06ff1..acbf29b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
@@ -44,7 +44,7 @@
 import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_RCS_CONFIG1;
 import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_RCS_CONFIG2;
 import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_SATELLITE_ENTITLEMENT_PLMNS1;
-import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_SATELLITE_IS_NTN_DISABLED;
+import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_SATELLITE_IS_ONLY_NTN_DISABLED;
 import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_SUBSCRIPTION_INFO1;
 import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_SUBSCRIPTION_INFO2;
 import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_UUID1;
@@ -3255,7 +3255,7 @@
         SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT
                 .getSubscriptionInfoInternal(1);
         assertThat(subInfo.getOnlyNonTerrestrialNetwork())
-                .isEqualTo(FAKE_SATELLITE_IS_NTN_DISABLED);
+                .isEqualTo(FAKE_SATELLITE_IS_ONLY_NTN_DISABLED);
 
         mContextFixture.putResource(R.string.config_satellite_sim_spn_identifier,
                 FAKE_CARRIER_NAME1);
@@ -3282,7 +3282,7 @@
         subInfo = mSubscriptionManagerServiceUT
                 .getSubscriptionInfoInternal(2);
         assertThat(subInfo.getOnlyNonTerrestrialNetwork())
-                .isEqualTo(FAKE_SATELLITE_IS_NTN_DISABLED);
+                .isEqualTo(FAKE_SATELLITE_IS_ONLY_NTN_DISABLED);
 
         System.setProperty("persist.radio.allow_mock_modem", "false");
         doReturn(false).when(mFlags).oemEnabledSatelliteFlag();