Merge "Check the preferred scan type in limited service state" into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 074de4a..5c8504a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -169,6 +169,9 @@
     <!-- Needed to register for UWB state changes for satellite communication -->
     <uses-permission android:name="android.permission.UWB_PRIVILEGED"/>
 
+    <!-- Needed to initiate configuration update -->
+    <uses-permission android:name="android.permission.UPDATE_CONFIG"/>
+
     <!-- Needed to bind the domain selection service. -->
     <uses-permission android:name="android.permission.BIND_DOMAIN_SELECTION_SERVICE" />
 
@@ -577,6 +580,16 @@
             </intent-filter>
         </receiver>
 
+        <!-- Update configuration data file -->
+        <receiver android:name="com.android.internal.telephony.configupdate.TelephonyConfigUpdateInstallReceiver"
+            android:exported="true"
+            android:permission="android.permission.UPDATE_CONFIG">
+            <intent-filter>
+                <action android:name="android.os.action.UPDATE_CONFIG" />
+                <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+            </intent-filter>
+        </receiver>
+
         <receiver
             android:name="com.android.internal.telephony.uicc.ShowInstallAppNotificationReceiver"
             android:exported="false"/>
diff --git a/assets/CarrierRestrictionOperatorDetails.json b/assets/CarrierRestrictionOperatorDetails.json
index f3da100..8602d4e 100644
--- a/assets/CarrierRestrictionOperatorDetails.json
+++ b/assets/CarrierRestrictionOperatorDetails.json
@@ -1,5 +1,6 @@
 {
   "_comment": "Operator should register with its application package name, carrierId and all the corresponding  SHAIDs",
   "_comment": "Example format :: << \"packageName\" : {\"carrierId\":<int>, \"callerSHA1Id\":[<SHAID1>, <SHAID2>]} >>",
-  "com.vzw.hss.myverizon":{"carrierId":1839,"callerSHA1Id":["C58EE7871896786F8BF70EBDB137DE10074043E9","AE23A03436DF07B0CD70FE881CDA2EC1D21215D7B7B0CC68E67B67F5DF89526A"]}
+  "com.vzw.hss.myverizon":{"carrierId":1839,"callerSHA1Id":["C58EE7871896786F8BF70EBDB137DE10074043E9","AE23A03436DF07B0CD70FE881CDA2EC1D21215D7B7B0CC68E67B67F5DF89526A"]},
+  "com.google.android.apps.tycho":{"carrierId":1989,"callerSHA1Id":["B9CFCE1C47A6AC713442718F15EF55B00B3A6D1A6D48CB46249FA8EB51465350","4C36AF4A5BDAD97C1F3D8B283416D244496C2AC5EAFE8226079EF6F676FD1859"]}
 }
\ No newline at end of file
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index a51c72d..78e4cfc 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -321,9 +321,9 @@
     <string name="throttle_help" msgid="2624535757028809735">"למידע נוסף"</string>
     <string name="throttle_status_subtext" msgid="1110276415078236687">"<xliff:g id="USED_0">%1$s</xliff:g> (<xliff:g id="USED_1">%2$d</xliff:g>%%) מתוך התקופה המרבית של <xliff:g id="USED_2">%3$s</xliff:g>\nהתקופה הבאה מתחילה בעוד <xliff:g id="USED_3">%4$d</xliff:g> ימים (<xliff:g id="USED_4">%5$s</xliff:g>)"</string>
     <string name="throttle_data_usage_subtext" msgid="3185429653996709840">"<xliff:g id="USED_0">%1$s</xliff:g> (<xliff:g id="USED_1">%2$d</xliff:g>??)  מתוך התקופה המרבית של<xliff:g id="USED_2">%3$s</xliff:g>"</string>
-    <string name="throttle_data_rate_reduced_subtext" msgid="8369839346277847725">"‏<xliff:g id="USED_0">%1$s</xliff:g> חריגה מהמקסימום\nקצב הנתונים ירד ל-‏‎<xliff:g id="USED_1">%2$d</xliff:g> Kb לשנייה"</string>
+    <string name="throttle_data_rate_reduced_subtext" msgid="8369839346277847725">"‏<xliff:g id="USED_0">%1$s</xliff:g> חריגה מהמקסימום\nקצב הנתונים ירד ל-‏‎<xliff:g id="USED_1">%2$d</xliff:g>Kb לשנייה"</string>
     <string name="throttle_time_frame_subtext" msgid="6462089615392402127">"<xliff:g id="USED_0">%1$d</xliff:g>?? מהמחזור חלפו\nהתקופה הבאה מתחילה בעוד <xliff:g id="USED_1">%2$d</xliff:g> ימים (<xliff:g id="USED_2">%3$s</xliff:g>)"</string>
-    <string name="throttle_rate_subtext" msgid="7221971817325779535">"‏קצב הנתונים יורד ל-‏‎<xliff:g id="USED">%1$d</xliff:g> Kb לשנייה במקרה של חריגה ממגבלת השימוש בנתונים"</string>
+    <string name="throttle_rate_subtext" msgid="7221971817325779535">"‏קצב הנתונים יורד ל-‏‎<xliff:g id="USED">%1$d</xliff:g>Kb לשנייה במקרה של חריגה ממגבלת השימוש בנתונים"</string>
     <string name="throttle_help_subtext" msgid="2817114897095534807">"למידע נוסף על מדיניות השימוש בנתונים ברשת הסלולרית של הספק שלך"</string>
     <string name="cell_broadcast_sms" msgid="4053449797289031063">"‏SMS בשידור סלולרי"</string>
     <string name="enable_disable_cell_bc_sms" msgid="4759958924031721350">"‏SMS בשידור סלולרי"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 76dee50..1201657 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -296,7 +296,7 @@
     <string name="limited_sim_function_with_phone_num_notification_message" msgid="5928988883403677610">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> चे कॉल आणि डेटा सेवा <xliff:g id="PHONE_NUMBER">%2$s</xliff:g> वापरताना ब्लॉक केले जाऊ शकतात."</string>
     <string name="limited_sim_function_notification_message" msgid="5338638075496721160">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> चे कॉल आणि डेटा सेवा दुसरे सिम वापरताना ब्लॉक केले जाऊ शकतात."</string>
     <string name="sip_accounts_removed_notification_title" msgid="3528076957535736095">"आढळलेली आणि काढून टाकलेली कालबाह्य झालेली SIP खाती"</string>
-    <string name="sip_accounts_removed_notification_message" msgid="1916856744869791592">"Android प्लॅटफॉर्मवर आता SIP कॉलिंगला सपोर्ट नाही.\nतुमची अस्तित्वात असलेली SIP खाती <xliff:g id="REMOVED_SIP_ACCOUNTS">%s</xliff:g> काढून टाकली आहेत.\nकृपया तुमच्या कॉलिंगसंबंधित डीफॉल्ट खात्याचे सेटिंग कंफर्म करा."</string>
+    <string name="sip_accounts_removed_notification_message" msgid="1916856744869791592">"Android प्लॅटफॉर्मवर आता SIP कॉलिंगला सपोर्ट नाही.\nतुमची अस्तित्वात असलेली SIP खाती <xliff:g id="REMOVED_SIP_ACCOUNTS">%s</xliff:g> काढून टाकली आहेत.\nकृपया तुमच्या कॉलिंगसंबंधित डीफॉल्ट खात्याचे सेटिंग कन्फर्म करा."</string>
     <string name="sip_accounts_removed_notification_action" msgid="3772778402370555562">"सेटिंग्जवर जा"</string>
     <string name="data_usage_title" msgid="8438592133893837464">"अ‍ॅप डेटा वापर"</string>
     <string name="data_usage_template" msgid="6287906680674061783">"<xliff:g id="ID_2">%2$s</xliff:g> दरम्यान <xliff:g id="ID_1">%1$s</xliff:g> मोबाइल डेटा वापरला गेला"</string>
@@ -876,7 +876,7 @@
     <string name="radio_info_dds" msgid="1122593144425697126">"डीफॉल्ट डेटा सिम SubId:"</string>
     <string name="radio_info_dl_kbps" msgid="2382922659525318726">"DL बँडविड्थ (kbps):"</string>
     <string name="radio_info_ul_kbps" msgid="2102225400904799036">"UL बँडविड्थ (kbps):"</string>
-    <string name="radio_info_phy_chan_config" msgid="608045501232211303">"प्रत्यक्ष चॅनलची कॉंफिगरेशन:"</string>
+    <string name="radio_info_phy_chan_config" msgid="608045501232211303">"प्रत्यक्ष चॅनलची कॉन्फिगरेशन:"</string>
     <string name="radio_info_cell_info_refresh_rate" msgid="670511448975997340">"सेल माहिती रिफ्रेश रेट:"</string>
     <string name="radio_info_cellinfo_label" msgid="8199062974670377659">"सर्व सेल परिमाण माहिती:"</string>
     <string name="radio_info_gprs_service_label" msgid="6819204246355412952">"डेटा सर्व्हिस:"</string>
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index ef71016..9b71919 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -52,6 +52,7 @@
 import android.service.carrier.CarrierIdentifier;
 import android.service.carrier.CarrierService;
 import android.service.carrier.ICarrierService;
+import android.telephony.AnomalyReporter;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyFrameworkInitializer;
@@ -94,6 +95,7 @@
 import java.util.Locale;
 import java.util.Objects;
 import java.util.Set;
+import java.util.UUID;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -218,6 +220,10 @@
             CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL
     };
 
+    // UUID to report anomaly when config changed reported with subId that map to invalid phone
+    private static final String UUID_NOTIFY_CONFIG_CHANGED_WITH_INVALID_PHONE =
+            "d81cef11-c2f1-4d76-955d-7f50e8590c48";
+
     // Handler to process various events.
     //
     // For each phoneId, the event sequence should be:
@@ -1483,9 +1489,14 @@
 
         int phoneId = SubscriptionManager.getPhoneId(subscriptionId);
         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
-            logd("Ignore invalid phoneId: " + phoneId + " for subId: " + subscriptionId);
-            throw new IllegalArgumentException(
-                    "Invalid phoneId " + phoneId + " for subId " + subscriptionId);
+            final String msg =
+                    "Ignore invalid phoneId: " + phoneId + " for subId: " + subscriptionId;
+            if (mFeatureFlags.addAnomalyWhenNotifyConfigChangedWithInvalidPhone()) {
+                AnomalyReporter.reportAnomaly(
+                        UUID.fromString(UUID_NOTIFY_CONFIG_CHANGED_WITH_INVALID_PHONE), msg);
+            }
+            logd(msg);
+            throw new IllegalArgumentException(msg);
         }
 
         enforceTelephonyFeatureWithException(getCurrentPackageName(),
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 839d8cb..e18818c 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -8504,7 +8504,8 @@
                 setNetworkSelectionModeAutomatic(subId);
                 Phone phone = getPhone(subId);
                 cleanUpAllowedNetworkTypes(phone, subId);
-                setDataRoamingEnabled(subId, getDefaultDataRoamingEnabled(subId));
+                setDataRoamingEnabled(subId, phone == null ? false
+                        : phone.getDataSettingsManager().isDefaultDataRoamingEnabled());
                 getPhone(subId).resetCarrierKeysForImsiEncryption();
             }
             // There has been issues when Sms raw table somehow stores orphan
@@ -10107,20 +10108,6 @@
     }
 
     /**
-     * Returns true if the data roaming is enabled by default, i.e the system property
-     * of {@link #DEFAULT_DATA_ROAMING_PROPERTY_NAME} is true or the config of
-     * {@link CarrierConfigManager#KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL} is true.
-     */
-    private boolean getDefaultDataRoamingEnabled(int subId) {
-        final CarrierConfigManager configMgr = (CarrierConfigManager)
-                mApp.getSystemService(Context.CARRIER_CONFIG_SERVICE);
-        boolean isDataRoamingEnabled = TelephonyProperties.data_roaming().orElse(false);
-        isDataRoamingEnabled |= configMgr.getConfigForSubId(subId).getBoolean(
-                CarrierConfigManager.KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL);
-        return isDataRoamingEnabled;
-    }
-
-    /**
      * Returns the default network type for the given {@code subId}, if the default network type is
      * not set, return {@link Phone#PREFERRED_NT_MODE}.
      */
diff --git a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
index 76032f8..36280e9 100644
--- a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
+++ b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
@@ -51,6 +51,7 @@
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.TelephonyCountryDetector;
 import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.satellite.SatelliteConfig;
 import com.android.internal.telephony.satellite.SatelliteController;
 import com.android.phone.PhoneGlobals;
 
@@ -106,6 +107,7 @@
     private static final int CMD_IS_SATELLITE_COMMUNICATION_ALLOWED = 1;
     protected static final int EVENT_WAIT_FOR_CURRENT_LOCATION_TIMEOUT = 2;
     protected static final int EVENT_KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT = 3;
+    protected static final int EVENT_CONFIG_DATA_UPDATED = 4;
 
     private static SatelliteAccessController sInstance;
 
@@ -176,6 +178,8 @@
         mCountryDetector = TelephonyCountryDetector.getInstance(context);
         mSatelliteController = SatelliteController.getInstance();
         loadOverlayConfigs(context);
+        mSatelliteController.registerForConfigUpdateChanged(this, EVENT_CONFIG_DATA_UPDATED,
+                context);
         if (s2CellFile != null) {
             mSatelliteS2CellFile = s2CellFile;
         }
@@ -215,6 +219,9 @@
             case EVENT_KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT:
                 cleanupOnDeviceAccessControllerResources();
                 break;
+            case EVENT_CONFIG_DATA_UPDATED:
+                updateSatelliteConfigData((Context) msg.obj);
+                break;
             default:
                 logw("SatelliteAccessControllerHandler: unexpected message code: " + msg.what);
                 break;
@@ -338,6 +345,59 @@
         return SystemClock.elapsedRealtimeNanos();
     }
 
+    /**
+     * Update country codes, S2CellFile and satellite region allowed by ConfigUpdater
+     * or CarrierConfig
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    public void updateSatelliteConfigData(Context context) {
+        logd("updateSatelliteConfigData");
+
+        SatelliteConfig satelliteConfig = mSatelliteController.getSatelliteConfig();
+        if (satelliteConfig != null  && satelliteConfig.getSatelliteS2CellFile(context) != null) {
+            logd("Check mSatelliteS2CellFile from ConfigUpdater");
+            Path pathSatelliteS2CellFile = satelliteConfig.getSatelliteS2CellFile(context);
+            mSatelliteS2CellFile = pathSatelliteS2CellFile.toFile();
+            if (mSatelliteS2CellFile != null && !mSatelliteS2CellFile.exists()) {
+                loge("The satellite S2 cell file " + mSatelliteS2CellFile.getName()
+                        + " does not exist");
+                mSatelliteS2CellFile = null;
+            }
+        }
+
+        if (mSatelliteS2CellFile == null) {
+            logd("Check mSatelliteS2CellFile from CarrierConfig");
+            String satelliteS2CellFileName = getSatelliteS2CellFileFromOverlayConfig(context);
+            mSatelliteS2CellFile = TextUtils.isEmpty(satelliteS2CellFileName)
+                    ? null : new File(satelliteS2CellFileName);
+            if (mSatelliteS2CellFile != null && !mSatelliteS2CellFile.exists()) {
+                loge("The satellite S2 cell file " + mSatelliteS2CellFile.getName()
+                        + " does not exist");
+                mSatelliteS2CellFile = null;
+            }
+        }
+
+        if (mSatelliteS2CellFile == null) {
+            logd("Since mSatelliteS2CellFile is null, don't need to refer other configurations");
+            return;
+        }
+
+        if (satelliteConfig != null
+                && !satelliteConfig.getDeviceSatelliteCountryCodes().isEmpty()) {
+            logd("update mSatelliteCountryCodes by ConfigUpdater");
+            mSatelliteCountryCodes = satelliteConfig.getDeviceSatelliteCountryCodes();
+        } else {
+            mSatelliteCountryCodes = getSatelliteCountryCodesFromOverlayConfig(context);
+        }
+
+        if (satelliteConfig != null && satelliteConfig.isSatelliteDataForAllowedRegion() != null) {
+            logd("update mIsSatelliteAllowAccessControl by ConfigUpdater");
+            mIsSatelliteAllowAccessControl = satelliteConfig.isSatelliteDataForAllowedRegion();
+        } else {
+            mIsSatelliteAllowAccessControl = getSatelliteAccessAllowFromOverlayConfig(context);
+        }
+    }
+
     private void loadOverlayConfigs(@NonNull Context context) {
         mSatelliteCountryCodes = getSatelliteCountryCodesFromOverlayConfig(context);
         mIsSatelliteAllowAccessControl = getSatelliteAccessAllowFromOverlayConfig(context);
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index 91ecb93..c00adef 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -119,16 +119,20 @@
             FlagsAdapter featureFlags) {
         Context context = PhoneGlobals.getInstance();
 
-        return new DisconnectCause(
-                toTelecomDisconnectCauseCode(telephonyDisconnectCause, carrierConfig),
-                toTelecomDisconnectCauseLabel(context, telephonyDisconnectCause,
-                        telephonyPreciseDisconnectCause, carrierConfig, featureFlags),
-                toTelecomDisconnectCauseDescription(context, telephonyDisconnectCause, phoneId),
-                toTelecomDisconnectReason(context, telephonyDisconnectCause, reason, phoneId),
-                toTelecomDisconnectCauseTone(telephonyDisconnectCause, carrierConfig, featureFlags),
-                telephonyDisconnectCause,
-                telephonyPreciseDisconnectCause,
-                imsReasonInfo);
+        return new DisconnectCause.Builder()
+                .setCode(toTelecomDisconnectCauseCode(telephonyDisconnectCause, carrierConfig))
+                .setLabel(toTelecomDisconnectCauseLabel(context, telephonyDisconnectCause,
+                        telephonyPreciseDisconnectCause, carrierConfig, featureFlags))
+                .setDescription(toTelecomDisconnectCauseDescription(
+                        context, telephonyDisconnectCause, phoneId))
+                .setReason(toTelecomDisconnectReason(
+                        context, telephonyDisconnectCause, reason, phoneId))
+                .setTone(toTelecomDisconnectCauseTone(
+                        telephonyDisconnectCause, carrierConfig, featureFlags))
+                .setTelephonyDisconnectCause(telephonyDisconnectCause)
+                .setTelephonyPreciseDisconnectCause(telephonyPreciseDisconnectCause)
+                .setImsReasonInfo(imsReasonInfo)
+                .build();
     }
 
     /**
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index a510e51..67b32df 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -141,6 +141,9 @@
     // existing call.
     private static final int DEFAULT_DSDA_OUTGOING_CALL_HOLD_TIMEOUT_MS = 2000;
 
+    // Timeout to wait for the termination of incoming call before continue with the emergency call.
+    private static final int DEFAULT_REJECT_INCOMING_CALL_TIMEOUT_MS = 10 * 1000; // 10 seconds.
+
     // If configured, reject attempts to dial numbers matching this pattern.
     private static final Pattern CDMA_ACTIVATION_CODE_REGEX_PATTERN =
             Pattern.compile("\\*228[0-9]{0,2}");
@@ -706,6 +709,20 @@
         }
     }
 
+    private static class OnDisconnectListener extends
+            com.android.internal.telephony.Connection.ListenerBase {
+        private final CompletableFuture<Boolean> mFuture;
+
+        OnDisconnectListener(CompletableFuture<Boolean> future) {
+            mFuture = future;
+        }
+
+        @Override
+        public void onDisconnect(int cause) {
+            mFuture.complete(true);
+        }
+    };
+
     private final DomainSelectionConnection.DomainSelectionConnectionCallback
             mEmergencyDomainSelectionConnectionCallback =
                     new DomainSelectionConnection.DomainSelectionConnectionCallback() {
@@ -1252,27 +1269,9 @@
                 final Connection resultConnection = getTelephonyConnection(request, numberToDial,
                         true, handle, phone);
 
-                CompletableFuture<Void> maybeHoldFuture = CompletableFuture.completedFuture(null);
-                if (mTelephonyManagerProxy.isConcurrentCallsPossible()
-                        && shouldHoldForEmergencyCall(phone)) {
-                    // If the PhoneAccountHandle was adjusted on building the TelephonyConnection,
-                    // the relevant PhoneAccountHandle will be updated in resultConnection.
-                    PhoneAccountHandle phoneAccountHandle =
-                            resultConnection.getPhoneAccountHandle() == null
-                            ? request.getAccountHandle() : resultConnection.getPhoneAccountHandle();
-                    Conferenceable c = maybeHoldCallsOnOtherSubs(phoneAccountHandle);
-                    if (c != null) {
-                        maybeHoldFuture = delayDialForOtherSubHold(phone, c, (success) -> {
-                            Log.i(this, "onCreateOutgoingConn emergency-"
-                                    + " delayDialForOtherSubHold success = " + success);
-                            if (!success) {
-                                // Terminates the existing call to make way for the emergency call.
-                                hangup(c, android.telephony.DisconnectCause
-                                        .OUTGOING_EMERGENCY_CALL_PLACED);
-                            }
-                        });
-                    }
-                }
+                CompletableFuture<Void> maybeHoldFuture =
+                        checkAndHoldCallsOnOtherSubsForEmergencyCall(request,
+                                resultConnection, phone);
                 Consumer<Boolean> ddsSwitchConsumer = (result) -> {
                     Log.i(this, "onCreateOutgoingConn emergency-"
                             + " delayDialForDdsSwitch result = " + result);
@@ -1284,6 +1283,32 @@
         }
     }
 
+    private CompletableFuture<Void> checkAndHoldCallsOnOtherSubsForEmergencyCall(
+            ConnectionRequest request, Connection resultConnection, Phone phone) {
+        CompletableFuture<Void> maybeHoldFuture = CompletableFuture.completedFuture(null);
+        if (mTelephonyManagerProxy.isConcurrentCallsPossible()
+                && shouldHoldForEmergencyCall(phone)) {
+            // If the PhoneAccountHandle was adjusted on building the TelephonyConnection,
+            // the relevant PhoneAccountHandle will be updated in resultConnection.
+            PhoneAccountHandle phoneAccountHandle =
+                    resultConnection.getPhoneAccountHandle() == null
+                    ? request.getAccountHandle() : resultConnection.getPhoneAccountHandle();
+            Conferenceable c = maybeHoldCallsOnOtherSubs(phoneAccountHandle);
+            if (c != null) {
+                maybeHoldFuture = delayDialForOtherSubHold(phone, c, (success) -> {
+                    Log.i(this, "checkAndHoldCallsOnOtherSubsForEmergencyCall"
+                            + " delayDialForOtherSubHold success = " + success);
+                    if (!success) {
+                        // Terminates the existing call to make way for the emergency call.
+                        hangup(c, android.telephony.DisconnectCause
+                                .OUTGOING_EMERGENCY_CALL_PLACED);
+                    }
+                });
+            }
+        }
+        return maybeHoldFuture;
+    }
+
     private Connection placeOutgoingConnection(ConnectionRequest request,
             Connection resultConnection, Phone phone) {
         // If there was a failure, the resulting connection will not be a TelephonyConnection,
@@ -2303,11 +2328,15 @@
                     // On GSM phones, null connection means that we dialed an MMI code
                     int telephonyDisconnectCause = handleMmiCode(
                             phone, android.telephony.DisconnectCause.OUTGOING_FAILURE);
-                    mNormalCallConnection.setTelephonyConnectionDisconnected(mDisconnectCauseFactory
-                            .toTelecomDisconnectCause(telephonyDisconnectCause,
-                                    "Connection is null", phone.getPhoneId()));
+                    if (mNormalCallConnection.getState() != Connection.STATE_DISCONNECTED) {
+                        mNormalCallConnection.setTelephonyConnectionDisconnected(
+                                mDisconnectCauseFactory.toTelecomDisconnectCause(
+                                        telephonyDisconnectCause,
+                                        "Connection is null",
+                                        phone.getPhoneId()));
+                        mNormalCallConnection.close();
+                    }
                     clearNormalCallDomainSelectionConnection();
-                    mNormalCallConnection.close();
                     return;
                 }
 
@@ -2354,6 +2383,7 @@
         boolean isMmiCode = (dialPart.startsWith("*") || dialPart.startsWith("#"))
                 && dialPart.endsWith("#");
         boolean isSuppServiceCode = ImsPhoneMmiCode.isSuppServiceCodes(dialPart, phone);
+        boolean isPotentialUssdCode = isMmiCode && !isSuppServiceCode;
 
         // If the number is both an MMI code and a supplementary service code,
         // it shall be treated as UT. In this case, domain selection is not performed.
@@ -2362,6 +2392,10 @@
             return false;
         }
 
+        /* For USSD codes, connection is closed and MMIDialogActivity is started.
+           To avoid connection close and return false. isPotentialUssdCode is handled after
+            all condition checks. */
+
         // Check and select same domain as ongoing call on the same subscription (if exists)
         int activeCallDomain = getActiveCallDomain(phone.getSubId());
         if (activeCallDomain != NetworkRegistrationInfo.DOMAIN_UNKNOWN
@@ -2397,6 +2431,15 @@
         mNormalCallConnection = connection;
         future.thenAcceptAsync((domain) -> handleOutgoingCallConnectionByCallDomainSelection(
                 domain, phone, number, videoState), mDomainSelectionMainExecutor);
+
+        if (isPotentialUssdCode) {
+            Log.v(LOG_TAG, "PotentialUssdCode. Closing connection with DisconnectCause.DIALED_MMI");
+            connection.setTelephonyConnectionDisconnected(
+                    mDisconnectCauseFactory.toTelecomDisconnectCause(
+                            android.telephony.DisconnectCause.DIALED_MMI,
+                            "Dialing USSD", phone.getPhoneId()));
+            connection.close();
+        }
         return true;
     }
 
@@ -2413,6 +2456,32 @@
             Log.i(this, "placeEmergencyConnection");
 
             mIsEmergencyCallPending = true;
+            mEmergencyConnection = (TelephonyConnection) resultConnection;
+        }
+
+        CompletableFuture<Void> maybeHoldFuture =
+                checkAndHoldCallsOnOtherSubsForEmergencyCall(request, resultConnection, phone);
+        maybeHoldFuture.thenRun(() -> placeEmergencyConnectionInternal(resultConnection,
+                phone, request, numberToDial, isTestEmergencyNumber, needToTurnOnRadio));
+
+        // Non TelephonyConnection type instance means dialing failure.
+        return resultConnection;
+    }
+
+    @SuppressWarnings("FutureReturnValueIgnored")
+    private void placeEmergencyConnectionInternal(final Connection resultConnection,
+            final Phone phone, final ConnectionRequest request,
+            final String numberToDial, final boolean isTestEmergencyNumber,
+            final boolean needToTurnOnRadio) {
+
+        if (mEmergencyConnection == null) {
+            Log.i(this, "placeEmergencyConnectionInternal dialing canceled");
+            return;
+        }
+
+        if (resultConnection instanceof TelephonyConnection) {
+            Log.i(this, "placeEmergencyConnectionInternal");
+
             ((TelephonyConnection) resultConnection).addTelephonyConnectionListener(
                     mEmergencyConnectionListener);
 
@@ -2420,7 +2489,6 @@
                 mEmergencyStateTracker = EmergencyStateTracker.getInstance();
             }
 
-            mEmergencyConnection = (TelephonyConnection) resultConnection;
             CompletableFuture<Integer> future = mEmergencyStateTracker.startEmergencyCall(
                     phone, resultConnection, isTestEmergencyNumber);
             future.thenAccept((result) -> {
@@ -2446,8 +2514,6 @@
                 }
             });
         }
-        // Non TelephonyConnection type instance means dialing failure.
-        return resultConnection;
     }
 
     @SuppressWarnings("FutureReturnValueIgnored")
@@ -2509,8 +2575,13 @@
             }
             Bundle extras = request.getExtras();
             extras.putInt(PhoneConstants.EXTRA_DIAL_DOMAIN, result);
-            placeOutgoingConnection(request, resultConnection, phone);
-            mIsEmergencyCallPending = false;
+            CompletableFuture<Void> rejectFuture = checkAndRejectIncomingCall(phone, (ret) -> {
+                if (!ret) {
+                    Log.i(this, "createEmergencyConnection reject incoming call failed");
+                }
+            });
+            rejectFuture.thenRun(() -> placeEmergencyConnectionOnSelectedDomain(request,
+                    resultConnection, phone));
         }, mDomainSelectionMainExecutor);
     }
 
@@ -2525,10 +2596,26 @@
                         Log.i(this, "dialCsEmergencyCall dialing canceled");
                         return;
                     }
-                    placeOutgoingConnection(request, resultConnection, phone);
+                    CompletableFuture<Void> future = checkAndRejectIncomingCall(phone, (ret) -> {
+                        if (!ret) {
+                            Log.i(this, "dialCsEmergencyCall reject incoming call failed");
+                        }
+                    });
+                    future.thenRun(() -> placeEmergencyConnectionOnSelectedDomain(request,
+                            resultConnection, phone));
                 });
     }
 
+    private void placeEmergencyConnectionOnSelectedDomain(ConnectionRequest request,
+            TelephonyConnection resultConnection, Phone phone) {
+        if (mEmergencyConnection == null) {
+            Log.i(this, "placeEmergencyConnectionOnSelectedDomain dialing canceled");
+            return;
+        }
+        placeOutgoingConnection(request, resultConnection, phone);
+        mIsEmergencyCallPending = false;
+    }
+
     private void releaseEmergencyCallDomainSelection(boolean cancel, boolean isActive) {
         if (mEmergencyCallDomainSelectionConnection != null) {
             if (cancel) mEmergencyCallDomainSelectionConnection.cancelSelection();
@@ -2778,11 +2865,29 @@
         return false;
     }
 
-    private void onEmergencyRedialOnDomain(TelephonyConnection connection,
+    private void onEmergencyRedialOnDomain(final TelephonyConnection connection,
             final Phone phone, @NetworkRegistrationInfo.Domain int domain) {
         Log.i(this, "onEmergencyRedialOnDomain phoneId=" + phone.getPhoneId()
                 + ", domain=" + DomainSelectionService.getDomainName(domain));
 
+        final Bundle extras = new Bundle();
+        extras.putInt(PhoneConstants.EXTRA_DIAL_DOMAIN, domain);
+
+        CompletableFuture<Void> future = checkAndRejectIncomingCall(phone, (ret) -> {
+            if (!ret) {
+                Log.i(this, "onEmergencyRedialOnDomain reject incoming call failed");
+            }
+        });
+        future.thenRun(() -> onEmergencyRedialOnDomainInternal(connection, phone, extras));
+    }
+
+    private void onEmergencyRedialOnDomainInternal(TelephonyConnection connection,
+            Phone phone, Bundle extras) {
+        if (mEmergencyConnection == null) {
+            Log.i(this, "onEmergencyRedialOnDomainInternal dialing canceled");
+            return;
+        }
+
         String number = connection.getAddress().getSchemeSpecificPart();
 
         // Indicates undetectable emergency number with DialArgs
@@ -2791,12 +2896,9 @@
         if (connection.getEmergencyServiceCategory() != null) {
             isEmergency = true;
             eccCategory = connection.getEmergencyServiceCategory();
-            Log.i(this, "onEmergencyRedialOnDomain eccCategory=" + eccCategory);
+            Log.i(this, "onEmergencyRedialOnDomainInternal eccCategory=" + eccCategory);
         }
 
-        Bundle extras = new Bundle();
-        extras.putInt(PhoneConstants.EXTRA_DIAL_DOMAIN, domain);
-
         com.android.internal.telephony.Connection originalConnection =
                 connection.getOriginalConnection();
         try {
@@ -2811,14 +2913,20 @@
                         connection::registerForCallEvents);
             }
         } catch (CallStateException e) {
-            Log.e(this, e, "onEmergencyRedialOnDomain, exception: " + e);
+            Log.e(this, e, "onEmergencyRedialOnDomainInternal, exception: " + e);
+            onLocalHangup(connection);
+            connection.unregisterForCallEvents();
+            handleCallStateException(e, connection, phone);
+            return;
         }
         if (originalConnection == null) {
-            Log.d(this, "onEmergencyRedialOnDomain, phone.dial returned null");
-            connection.setDisconnected(
+            Log.d(this, "onEmergencyRedialOnDomainInternal, phone.dial returned null");
+            onLocalHangup(connection);
+            connection.setTelephonyConnectionDisconnected(
                     mDisconnectCauseFactory.toTelecomDisconnectCause(
                                 android.telephony.DisconnectCause.ERROR_UNSPECIFIED,
                                 "unknown error"));
+            connection.close();
         } else {
             connection.setOriginalConnection(originalConnection);
         }
@@ -3366,6 +3474,52 @@
     }
 
     /**
+     * If needed, block until an incoming call is disconnected for outgoing emergency call,
+     * or timeout expires.
+     * @param phone The Phone to reject the incoming call
+     * @param completeConsumer The consumer to call once rejecting incoming call has been
+     *        completed. {@code true} result if the operation commpletes successfully, or
+     *        {@code false} if the operation timed out/failed.
+     */
+    private CompletableFuture<Void> checkAndRejectIncomingCall(Phone phone,
+            Consumer<Boolean> completeConsumer) {
+        if (phone == null) {
+            // Unexpected inputs
+            Log.i(this, "checkAndRejectIncomingCall phone is null");
+            completeConsumer.accept(false);
+            return CompletableFuture.completedFuture(null);
+        }
+
+        Call ringingCall = phone.getRingingCall();
+        if (ringingCall == null || !ringingCall.isRinging()) {
+            completeConsumer.accept(true);
+            return CompletableFuture.completedFuture(null);
+        }
+        Log.i(this, "checkAndRejectIncomingCall found a ringing call");
+
+        try {
+            ringingCall.hangup();
+            CompletableFuture<Boolean> future = new CompletableFuture<>();
+            com.android.internal.telephony.Connection cn = ringingCall.getLatestConnection();
+            cn.addListener(new OnDisconnectListener(future));
+            // A timeout that will complete the future to not block the outgoing call indefinitely.
+            CompletableFuture<Boolean> timeout = new CompletableFuture<>();
+            phone.getContext().getMainThreadHandler().postDelayed(
+                    () -> timeout.complete(false), DEFAULT_REJECT_INCOMING_CALL_TIMEOUT_MS);
+            // Ensure that the Consumer is completed on the main thread.
+            return future.acceptEitherAsync(timeout, completeConsumer,
+                    phone.getContext().getMainExecutor()).exceptionally((ex) -> {
+                        Log.w(this, "checkAndRejectIncomingCall - exceptionally= " + ex);
+                        return null;
+                    });
+        } catch (Exception e) {
+            Log.w(this, "checkAndRejectIncomingCall - exception= " + e.getMessage());
+            completeConsumer.accept(false);
+            return CompletableFuture.completedFuture(null);
+        }
+    }
+
+    /**
      * Get the Phone to use for an emergency call of the given emergency number address:
      *  a) If there are multiple Phones with the Subscriptions that support the emergency number
      *     address, and one of them is the default voice Phone, consider the default voice phone
diff --git a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
index ac68599..53b3659 100644
--- a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
@@ -85,6 +85,7 @@
 import android.telephony.TransportSelectorCallback;
 import android.telephony.ims.ImsManager;
 import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.ProvisioningManager;
 import android.text.TextUtils;
 import android.util.LocalLog;
@@ -335,11 +336,11 @@
     private void reselectDomain() {
         logi("reselectDomain tryCsWhenPsFails=" + mTryCsWhenPsFails);
 
-        int cause = mSelectionAttributes.getCsDisconnectCause();
+        int cause = getDisconnectCause();
         mCrossSimRedialingController.notifyCallFailure(cause);
 
-        if (cause == EMERGENCY_PERM_FAILURE
-                || cause == EMERGENCY_TEMP_FAILURE) {
+        if ((cause == EMERGENCY_PERM_FAILURE || cause == EMERGENCY_TEMP_FAILURE)
+                && mCrossSimRedialingController.isThereOtherSlot()) {
             logi("reselectDomain should redial on the other subscription");
             terminateSelectionForCrossSimRedialing(cause == EMERGENCY_PERM_FAILURE);
             return;
@@ -394,6 +395,25 @@
         mDomainSelected = false;
     }
 
+    private int getDisconnectCause() {
+        int cause = mSelectionAttributes.getCsDisconnectCause();
+
+        ImsReasonInfo reasonInfo = mSelectionAttributes.getPsDisconnectCause();
+        if (reasonInfo != null) {
+            switch (reasonInfo.getCode()) {
+                case ImsReasonInfo.CODE_EMERGENCY_TEMP_FAILURE:
+                    cause = EMERGENCY_TEMP_FAILURE;
+                    break;
+                case ImsReasonInfo.CODE_EMERGENCY_PERM_FAILURE:
+                    cause = EMERGENCY_PERM_FAILURE;
+                    break;
+                default:
+                    break;
+            }
+        }
+        return cause;
+    }
+
     private void reselectDomainInternal() {
         post(() -> {
             if (mDestroyed) return;
@@ -657,6 +677,13 @@
     private void selectDomainFromInitialState() {
         if (mDestroyed) return;
 
+        if (isInEmergencyCallbackModeOnPsWwan()) {
+            logi("selectDomain PS cellular connected in ECBM");
+            mPsNetworkType = EUTRAN;
+            onWwanNetworkTypeSelected(mPsNetworkType);
+            return;
+        }
+
         boolean csInService = isCsInService();
         boolean psInService = isPsInService();
 
@@ -1610,6 +1637,12 @@
                 && mEcbmHelper.getDataConnectionState(getSlotId()) == DATA_CONNECTED;
     }
 
+    private boolean isInEmergencyCallbackModeOnPsWwan() {
+        return mEcbmHelper.isInEmergencyCallbackMode(getSlotId())
+                && mEcbmHelper.getTransportType(getSlotId()) == TRANSPORT_TYPE_WWAN
+                && mEcbmHelper.getDataConnectionState(getSlotId()) == DATA_CONNECTED;
+    }
+
     @Override
     protected void logi(String msg) {
         super.logi(msg);
diff --git a/src/com/android/services/telephony/domainselection/EmergencyCallbackModeHelper.java b/src/com/android/services/telephony/domainselection/EmergencyCallbackModeHelper.java
index e42dfe7..cdf2225 100644
--- a/src/com/android/services/telephony/domainselection/EmergencyCallbackModeHelper.java
+++ b/src/com/android/services/telephony/domainselection/EmergencyCallbackModeHelper.java
@@ -68,7 +68,7 @@
                 @NonNull PreciseDataConnectionState dataConnectionState) {
             ApnSetting apnSetting = dataConnectionState.getApnSetting();
             if ((apnSetting == null)
-                    || ((apnSetting.getApnTypeBitmask() | ApnSetting.TYPE_EMERGENCY) == 0)) {
+                    || ((apnSetting.getApnTypeBitmask() & ApnSetting.TYPE_EMERGENCY) == 0)) {
                 return;
             }
             mTransportType = dataConnectionState.getTransportType();
diff --git a/testapps/GbaTestApp/res/values-mr/strings.xml b/testapps/GbaTestApp/res/values-mr/strings.xml
index 75aaf5f..f8e8992 100644
--- a/testapps/GbaTestApp/res/values-mr/strings.xml
+++ b/testapps/GbaTestApp/res/values-mr/strings.xml
@@ -3,9 +3,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="2922839697457005451">"GbaTestApp"</string>
     <string name="label_settings" msgid="8030871890526865502">"सेटिंग्ज"</string>
-    <string name="label_carrier" msgid="1470455313066422804">"वाहक कॉंफिगरेशन"</string>
-    <string name="label_service" msgid="2668963955237345578">"सेवा कॉंफिगरेशन"</string>
-    <string name="label_test" msgid="8425079572898571918">"चाचणी कॉंफिगरेशन"</string>
+    <string name="label_carrier" msgid="1470455313066422804">"वाहकाचे कॉन्फिगरेशन"</string>
+    <string name="label_service" msgid="2668963955237345578">"सेवेचे कॉन्फिगरेशन"</string>
+    <string name="label_test" msgid="8425079572898571918">"चाचणीचे कॉन्फिगरेशन"</string>
     <string name="button_name_running" msgid="4557363091224858010">"रन करत आहे"</string>
     <string name="button_name_exit" msgid="8025683733431538975">"बाहेर पडा"</string>
     <string name="label_test_result" msgid="892984695972956196">"चाचणी परिणाम"</string>
diff --git a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
index c44b347..e6f70aa 100644
--- a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
+++ b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
@@ -23,6 +23,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
@@ -31,7 +32,11 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -57,6 +62,8 @@
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.TelephonyCountryDetector;
 import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.satellite.SatelliteConfig;
+import com.android.internal.telephony.satellite.SatelliteConfigParser;
 import com.android.internal.telephony.satellite.SatelliteController;
 
 import org.junit.After;
@@ -70,6 +77,8 @@
 
 import java.io.File;
 import java.lang.reflect.Field;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -531,6 +540,42 @@
         assertTrue(mQueriedSatelliteAllowed);
     }
 
+    @Test
+    public void testUpdateSatelliteConfigData() {
+        // Verify the case when the configParser is not exist.
+        SatelliteConfigParser spyConfigParserNull =
+                spy(new SatelliteConfigParser((byte[]) null));
+        doReturn(spyConfigParserNull).when(mMockSatelliteController).getSatelliteConfigParser();
+        mSatelliteAccessControllerUT.updateSatelliteConfigData(mMockContext);
+
+        assertNull(spyConfigParserNull.getConfig());
+
+        // Verify the case when the configParser is exist but empty.
+        SatelliteConfigParser spyConfigParserEmpty =
+                spy(new SatelliteConfigParser("test".getBytes()));
+        doReturn(spyConfigParserEmpty).when(mMockSatelliteController).getSatelliteConfigParser();
+        mSatelliteAccessControllerUT.updateSatelliteConfigData(mMockContext);
+
+        assertNull(spyConfigParserEmpty.getConfig());
+
+        // Verify the case when the configParser is exist and valid data
+        SatelliteConfig mockSatelliteConfig = mock(SatelliteConfig.class);
+        final String filePath = "/data/user_de/0/com.android.phone/app_satellite/s2_cell_file";
+        Path targetSatS2FilePath = Paths.get(filePath);
+        doReturn(false).when(mockSatelliteConfig).isFileExist(any());
+        doReturn(targetSatS2FilePath).when(mockSatelliteConfig)
+                .copySatS2FileToPhoneDirectory(any(), any());
+        doReturn(Arrays.asList("US")).when(mockSatelliteConfig).getDeviceSatelliteCountryCodes();
+        doReturn(false).when(mockSatelliteConfig).isSatelliteDataForAllowedRegion();
+        doReturn(targetSatS2FilePath).when(mockSatelliteConfig).getSatelliteS2CellFile(any());
+        doReturn(mockSatelliteConfig).when(mMockSatelliteController).getSatelliteConfig();
+
+        mSatelliteAccessControllerUT.updateSatelliteConfigData(mMockContext);
+        verify(mockSatelliteConfig, times(0)).getDeviceSatelliteCountryCodes();
+        verify(mockSatelliteConfig, times(0)).isSatelliteDataForAllowedRegion();
+        verify(mockSatelliteConfig, times(2)).getSatelliteS2CellFile(any());
+    }
+
     private void clearAllInvocations() {
         clearInvocations(mMockSatelliteController);
         clearInvocations(mMockSatelliteOnDeviceAccessController);
diff --git a/tests/src/com/android/phone/security/SafetySourceReceiverTest.java b/tests/src/com/android/phone/security/SafetySourceReceiverTest.java
index de1f101..305e698 100644
--- a/tests/src/com/android/phone/security/SafetySourceReceiverTest.java
+++ b/tests/src/com/android/phone/security/SafetySourceReceiverTest.java
@@ -60,12 +60,16 @@
         MockitoAnnotations.initMocks(this);
         SafetySourceReceiver receiver = new SafetySourceReceiver();
         mSafetySourceReceiver = spy(receiver);
+
+        when(mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY)).thenReturn(true);
     }
 
     @Test
     public void testOnReceive() {
         mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY_UNSOL_EVENTS,
-                Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY_UNSOL_EVENTS);
+                Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY_UNSOL_EVENTS,
+                Flags.FLAG_ENFORCE_TELEPHONY_FEATURE_MAPPING_FOR_PUBLIC_APIS);
         Phone mockPhone = mock(Phone.class);
         when(mSafetySourceReceiver.getDefaultPhone()).thenReturn(mockPhone);
 
@@ -80,7 +84,8 @@
     public void testOnReceive_featureFlagsOff() {
         mSetFlagsRule.disableFlags(
                 Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY_UNSOL_EVENTS,
-                Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY_UNSOL_EVENTS);
+                Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY_UNSOL_EVENTS,
+                Flags.FLAG_ENFORCE_TELEPHONY_FEATURE_MAPPING_FOR_PUBLIC_APIS);
 
         Intent intent = new Intent(ACTION_REFRESH_SAFETY_SOURCES);
         intent.putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, "aBroadcastId");
@@ -96,9 +101,6 @@
                 Flags.FLAG_ENFORCE_TELEPHONY_FEATURE_MAPPING_FOR_PUBLIC_APIS);
         when(mSafetySourceReceiver.getDefaultPhone()).thenReturn(null);
 
-        when(mContext.getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_TELEPHONY)).thenReturn(true);
-
         Intent intent = new Intent(ACTION_REFRESH_SAFETY_SOURCES);
         intent.putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, "aBroadcastId");
 
@@ -125,5 +127,4 @@
 
         verify(mockPhone, never()).refreshSafetySources(any());
     }
-
 }
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index f0e900a..e791d3c 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -325,6 +325,10 @@
 
     @After
     public void tearDown() throws Exception {
+        if (mTestConnectionService != null
+                && mTestConnectionService.getEmergencyConnection() != null) {
+            mTestConnectionService.onLocalHangup(mTestConnectionService.getEmergencyConnection());
+        }
         mTestConnectionService = null;
         super.tearDown();
     }
@@ -1990,6 +1994,27 @@
     }
 
     /**
+     * For DSDA devices with AP domain selection service enabled, placing an outgoing call
+     * on a 2nd sub will hold the existing ACTIVE connection on the first sub.
+     */
+    @Test
+    @SmallTest
+    public void testHoldOnOtherSubForVirtualDsdaDeviceWithDomainSelectionEnabled() {
+        when(mTelephonyManagerProxy.isConcurrentCallsPossible()).thenReturn(true);
+        doReturn(true).when(mDomainSelectionResolver).isDomainSelectionSupported();
+
+        ArrayList<android.telecom.Connection> tcs = new ArrayList<>();
+        SimpleTelephonyConnection tc1 = createTestConnection(SUB1_HANDLE, 0, false);
+        tc1.setTelephonyConnectionActive();
+        tcs.add(tc1);
+
+        Conferenceable c = TelephonyConnectionService.maybeHoldCallsOnOtherSubs(
+                tcs, new ArrayList<>(), SUB2_HANDLE, mTelephonyManagerProxy);
+        assertTrue(c.equals(tc1));
+        assertTrue(tc1.wasHeld);
+    }
+
+    /**
      * For DSDA devices, if the existing connection was already held, placing an outgoing call on a
      * 2nd sub will not attempt to hold the existing connection on the first sub.
      */
@@ -2267,8 +2292,7 @@
 
         ArgumentCaptor<DialArgs> argsCaptor = ArgumentCaptor.forClass(DialArgs.class);
 
-        Connection nc = Mockito.mock(Connection.class);
-        doReturn(nc).when(mPhone0).dial(anyString(), any(), any());
+        doReturn(mInternalConnection).when(mPhone0).dial(anyString(), any(), any());
 
         verify(mPhone0).dial(anyString(), argsCaptor.capture(), any());
         DialArgs dialArgs = argsCaptor.getValue();
@@ -2296,8 +2320,131 @@
 
         ArgumentCaptor<DialArgs> argsCaptor = ArgumentCaptor.forClass(DialArgs.class);
 
-        Connection nc = Mockito.mock(Connection.class);
-        doReturn(nc).when(mPhone0).dial(anyString(), any(), any());
+        doReturn(mInternalConnection).when(mPhone0).dial(anyString(), any(), any());
+
+        verify(mPhone0).dial(anyString(), argsCaptor.capture(), any());
+        DialArgs dialArgs = argsCaptor.getValue();
+        assertNotNull("DialArgs param is null", dialArgs);
+        assertNotNull("intentExtras is null", dialArgs.intentExtras);
+        assertTrue(dialArgs.intentExtras.containsKey(PhoneConstants.EXTRA_DIAL_DOMAIN));
+        assertEquals(selectedDomain,
+                dialArgs.intentExtras.getInt(PhoneConstants.EXTRA_DIAL_DOMAIN, -1));
+    }
+
+    @Test
+    public void testDomainSelectionRedialFailedWithException() throws Exception {
+        setupForCallTest();
+
+        int preciseDisconnectCause = com.android.internal.telephony.CallFailCause.ERROR_UNSPECIFIED;
+        int disconnectCause = android.telephony.DisconnectCause.ERROR_UNSPECIFIED;
+        int selectedDomain = DOMAIN_CS;
+
+        TestTelephonyConnection c = setupForReDialForDomainSelection(
+                mPhone0, selectedDomain, preciseDisconnectCause, disconnectCause, true);
+
+        CallStateException cse = new CallStateException(CallStateException.ERROR_CALLING_DISABLED,
+                "Calling disabled via ro.telephony.disable-call property");
+        doThrow(cse).when(mPhone0).dial(anyString(), any(), any());
+
+        assertTrue(mTestConnectionService.maybeReselectDomain(c, null, true,
+                android.telephony.DisconnectCause.NOT_VALID));
+        verify(mEmergencyCallDomainSelectionConnection).reselectDomain(any());
+        verify(mEmergencyCallDomainSelectionConnection).cancelSelection();
+        verify(mEmergencyStateTracker).endCall(any());
+    }
+
+    @Test
+    public void testDomainSelectionRejectIncoming() throws Exception {
+        setupForCallTest();
+
+        int selectedDomain = DOMAIN_CS;
+
+        setupForDialForDomainSelection(mPhone0, selectedDomain, true);
+
+        doReturn(mInternalConnection2).when(mCall).getLatestConnection();
+        doReturn(true).when(mCall).isRinging();
+        doReturn(mCall).when(mPhone0).getRingingCall();
+
+        mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
+                createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
+                        TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+
+        ArgumentCaptor<android.telecom.Connection> connectionCaptor =
+                ArgumentCaptor.forClass(android.telecom.Connection.class);
+
+        verify(mDomainSelectionResolver)
+                .getDomainSelectionConnection(eq(mPhone0), eq(SELECTOR_TYPE_CALLING), eq(true));
+        verify(mEmergencyStateTracker)
+                .startEmergencyCall(eq(mPhone0), connectionCaptor.capture(), eq(false));
+        verify(mEmergencyCallDomainSelectionConnection).createEmergencyConnection(any(), any());
+
+        android.telecom.Connection tc = connectionCaptor.getValue();
+
+        assertNotNull(tc);
+        assertEquals(TELECOM_CALL_ID1, tc.getTelecomCallId());
+        assertEquals(mTestConnectionService.getEmergencyConnection(), tc);
+
+        ArgumentCaptor<Connection.Listener> listenerCaptor =
+                ArgumentCaptor.forClass(Connection.Listener.class);
+
+        verify(mInternalConnection2).addListener(listenerCaptor.capture());
+        verify(mCall).hangup();
+        verify(mPhone0, never()).dial(anyString(), any(), any());
+
+        Connection.Listener listener = listenerCaptor.getValue();
+
+        assertNotNull(listener);
+
+        listener.onDisconnect(0);
+
+        verify(mSatelliteSOSMessageRecommender).onEmergencyCallStarted(any());
+
+        ArgumentCaptor<DialArgs> argsCaptor = ArgumentCaptor.forClass(DialArgs.class);
+
+        verify(mPhone0).dial(anyString(), argsCaptor.capture(), any());
+
+        DialArgs dialArgs = argsCaptor.getValue();
+
+        assertNotNull("DialArgs param is null", dialArgs);
+        assertNotNull("intentExtras is null", dialArgs.intentExtras);
+        assertTrue(dialArgs.intentExtras.containsKey(PhoneConstants.EXTRA_DIAL_DOMAIN));
+        assertEquals(selectedDomain,
+                dialArgs.intentExtras.getInt(PhoneConstants.EXTRA_DIAL_DOMAIN, -1));
+    }
+
+    @Test
+    public void testDomainSelectionRedialRejectIncoming() throws Exception {
+        setupForCallTest();
+
+        int preciseDisconnectCause = com.android.internal.telephony.CallFailCause.ERROR_UNSPECIFIED;
+        int disconnectCause = android.telephony.DisconnectCause.ERROR_UNSPECIFIED;
+        int selectedDomain = DOMAIN_CS;
+
+        TestTelephonyConnection c = setupForReDialForDomainSelection(
+                mPhone0, selectedDomain, preciseDisconnectCause, disconnectCause, true);
+
+        doReturn(mInternalConnection2).when(mCall).getLatestConnection();
+        doReturn(true).when(mCall).isRinging();
+        doReturn(mCall).when(mPhone0).getRingingCall();
+
+        assertTrue(mTestConnectionService.maybeReselectDomain(c, null, true,
+                android.telephony.DisconnectCause.NOT_VALID));
+        verify(mEmergencyCallDomainSelectionConnection).reselectDomain(any());
+
+        ArgumentCaptor<Connection.Listener> listenerCaptor =
+                ArgumentCaptor.forClass(Connection.Listener.class);
+
+        verify(mInternalConnection2).addListener(listenerCaptor.capture());
+        verify(mCall).hangup();
+        verify(mPhone0, never()).dial(anyString(), any(), any());
+
+        Connection.Listener listener = listenerCaptor.getValue();
+
+        assertNotNull(listener);
+
+        listener.onDisconnect(0);
+
+        ArgumentCaptor<DialArgs> argsCaptor = ArgumentCaptor.forClass(DialArgs.class);
 
         verify(mPhone0).dial(anyString(), argsCaptor.capture(), any());
         DialArgs dialArgs = argsCaptor.getValue();
@@ -2621,6 +2768,7 @@
 
         setupForDialForDomainSelection(mPhone0, selectedDomain, true);
         doReturn(mPhone0).when(mImsPhone).getDefaultPhone();
+        doReturn(mInternalConnection).when(mPhone0).dial(anyString(), any(), any());
 
         TestTelephonyConnection c = setupForReDialForDomainSelection(
                 mImsPhone, selectedDomain, preciseDisconnectCause, disconnectCause, false);
@@ -2671,6 +2819,7 @@
 
         setupForDialForDomainSelection(mPhone0, selectedDomain, true);
         doReturn(mPhone0).when(mImsPhone).getDefaultPhone();
+        doReturn(mInternalConnection).when(mPhone0).dial(anyString(), any(), any());
 
         TestTelephonyConnection c = setupForReDialForDomainSelection(
                 mImsPhone, selectedDomain, preciseDisconnectCause, disconnectCause, false);
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
index f7b249a..50085e7 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
@@ -280,6 +280,8 @@
                 any(), anyInt(), anyBoolean(), any(), any());
 
         when(mResources.getStringArray(anyInt())).thenReturn(null);
+
+        doReturn(false).when(mCsrdCtrl).isThereOtherSlot();
     }
 
     @After
@@ -2219,6 +2221,7 @@
     public void testCrossStackTimerTempFailure() throws Exception {
         createSelector(SLOT_0_SUB_ID);
         unsolBarringInfoChanged(false);
+        doReturn(true).when(mCsrdCtrl).isThereOtherSlot();
 
         EmergencyRegistrationResult regResult = getEmergencyRegResult(UTRAN,
                 REGISTRATION_STATE_HOME,
@@ -2243,12 +2246,48 @@
         processAllMessages();
 
         verify(mCsrdCtrl).notifyCallFailure(eq(PreciseDisconnectCause.EMERGENCY_TEMP_FAILURE));
+        verify(mTransportSelectorCallback)
+                .onSelectionTerminated(eq(DisconnectCause.EMERGENCY_TEMP_FAILURE));
+    }
+
+    @Test
+    public void testCrossStackTimerTempFailureNoValidSubscription() throws Exception {
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+        doReturn(false).when(mCsrdCtrl).isThereOtherSlot();
+
+        EmergencyRegistrationResult regResult = getEmergencyRegResult(UTRAN,
+                REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_CS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+
+        verifyCsDialed();
+
+        attr = new SelectionAttributes.Builder(SLOT_0, SLOT_0_SUB_ID, SELECTOR_TYPE_CALLING)
+                .setAddress(TEST_URI)
+                .setEmergency(true)
+                .setEmergencyRegistrationResult(regResult)
+                .setCsDisconnectCause(PreciseDisconnectCause.EMERGENCY_TEMP_FAILURE)
+                .build();
+
+        mDomainSelector.reselectDomain(attr);
+        processAllMessages();
+
+        verify(mCsrdCtrl).notifyCallFailure(eq(PreciseDisconnectCause.EMERGENCY_TEMP_FAILURE));
+        verify(mTransportSelectorCallback, never())
+                .onSelectionTerminated(eq(DisconnectCause.EMERGENCY_TEMP_FAILURE));
     }
 
     @Test
     public void testCrossStackTimerPermFailure() throws Exception {
         createSelector(SLOT_0_SUB_ID);
         unsolBarringInfoChanged(false);
+        doReturn(true).when(mCsrdCtrl).isThereOtherSlot();
 
         EmergencyRegistrationResult regResult = getEmergencyRegResult(UTRAN,
                 REGISTRATION_STATE_HOME,
@@ -2273,6 +2312,41 @@
         processAllMessages();
 
         verify(mCsrdCtrl).notifyCallFailure(eq(PreciseDisconnectCause.EMERGENCY_PERM_FAILURE));
+        verify(mTransportSelectorCallback)
+                .onSelectionTerminated(eq(DisconnectCause.EMERGENCY_PERM_FAILURE));
+    }
+
+    @Test
+    public void testCrossStackTimerPermFailureNoValidSubscription() throws Exception {
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+        doReturn(false).when(mCsrdCtrl).isThereOtherSlot();
+
+        EmergencyRegistrationResult regResult = getEmergencyRegResult(UTRAN,
+                REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_CS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+
+        verifyCsDialed();
+
+        attr = new SelectionAttributes.Builder(SLOT_0, SLOT_0_SUB_ID, SELECTOR_TYPE_CALLING)
+                .setAddress(TEST_URI)
+                .setEmergency(true)
+                .setEmergencyRegistrationResult(regResult)
+                .setCsDisconnectCause(PreciseDisconnectCause.EMERGENCY_PERM_FAILURE)
+                .build();
+
+        mDomainSelector.reselectDomain(attr);
+        processAllMessages();
+
+        verify(mCsrdCtrl).notifyCallFailure(eq(PreciseDisconnectCause.EMERGENCY_PERM_FAILURE));
+        verify(mTransportSelectorCallback, never())
+                .onSelectionTerminated(eq(DisconnectCause.EMERGENCY_PERM_FAILURE));
     }
 
     @Test
@@ -2898,6 +2972,16 @@
         doReturn(TRANSPORT_TYPE_WWAN).when(mEcbmHelper).getTransportType(anyInt());
         doReturn(DATA_CONNECTED).when(mEcbmHelper).getDataConnectionState(anyInt());
 
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                Consumer<WwanSelectorCallback> consumer =
+                        (Consumer<WwanSelectorCallback>) invocation.getArguments()[0];
+                consumer.accept(mWwanSelectorCallback);
+                return null;
+            }
+        }).when(mTransportSelectorCallback).onWwanSelected(any());
+
         EmergencyRegistrationResult regResult = getEmergencyRegResult(UNKNOWN,
                 REGISTRATION_STATE_UNKNOWN,
                 0, false, false, 0, 0, "", "");
@@ -2910,6 +2994,7 @@
 
         verify(mTransportSelectorCallback, never()).onWlanSelected(anyBoolean());
         verify(mTransportSelectorCallback).onWwanSelected(any());
+        verify(mWwanSelectorCallback).onDomainSelected(eq(DOMAIN_PS), eq(true));
     }
 
     @Test
@@ -2980,6 +3065,42 @@
         verify(mTransportSelectorCallback).onWwanSelected(any());
     }
 
+    @Test
+    public void testNotInEcbmOnWwanConnected() throws Exception {
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        doReturn(false).when(mEcbmHelper).isInEmergencyCallbackMode(anyInt());
+        doReturn(TRANSPORT_TYPE_WLAN).when(mEcbmHelper).getTransportType(anyInt());
+        doReturn(DATA_CONNECTED).when(mEcbmHelper).getDataConnectionState(anyInt());
+
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                Consumer<WwanSelectorCallback> consumer =
+                        (Consumer<WwanSelectorCallback>) invocation.getArguments()[0];
+                consumer.accept(mWwanSelectorCallback);
+                return null;
+            }
+        }).when(mTransportSelectorCallback).onWwanSelected(any());
+
+        EmergencyRegistrationResult regResult = getEmergencyRegResult(UNKNOWN,
+                REGISTRATION_STATE_UNKNOWN,
+                0, false, false, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+        processAllMessages();
+
+        verify(mTransportSelectorCallback, never()).onWlanSelected(anyBoolean());
+        verify(mTransportSelectorCallback).onWwanSelected(any());
+        verify(mWwanSelectorCallback, never()).onDomainSelected(anyInt(), anyBoolean());
+        verify(mWwanSelectorCallback).onRequestEmergencyNetworkScan(
+                any(), anyInt(), anyBoolean(), any(), any());
+    }
+
     private void setupForScanListTest(PersistableBundle bundle) throws Exception {
         setupForScanListTest(bundle, false);
     }