Merge "CarrierRestrictionStatus API AIDL implementation"
diff --git a/assets/CarrierRestrictionOperatorDetails.json b/assets/CarrierRestrictionOperatorDetails.json
new file mode 100644
index 0000000..166cc39
--- /dev/null
+++ b/assets/CarrierRestrictionOperatorDetails.json
@@ -0,0 +1,4 @@
+{
+  "_comment": "Operator should register with its application package name, carrierId and all the corresponding  SHAIDs",
+  "_comment": "Example format :: << \"packageName\" : {\"carrierId\":<int>, \"callerSHA1Id\":[<SHAID1>, <SHAID2>]} >>"
+}
\ No newline at end of file
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index cbe88e0..b205fc8 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -615,7 +615,7 @@
     <string name="ota_title_activate" msgid="4049645324841263423">"Aktibatu telefonoa"</string>
     <string name="ota_touch_activate" msgid="838764494319694754">"Telefono-zerbitzua aktibatzeko, dei berezi bat egin behar da.\n\n\"Aktibatu\" sakatu ondoren, telefonoa aktibatzeko, entzun ematen zaizkizun argibideak."</string>
     <string name="ota_hfa_activation_title" msgid="3300556778212729671">"Aktibatzen…"</string>
-    <string name="ota_hfa_activation_dialog_message" msgid="7921718445773342996">"Telefonoa datu-konexioaren zerbitzua aktibatzen ari da.\n\nEragiketa 5 minutura arte luza daiteke."</string>
+    <string name="ota_hfa_activation_dialog_message" msgid="7921718445773342996">"Telefonoa mugikorretarako datu-zerbitzua aktibatzen ari da.\n\nEragiketa gehienez 5 minutu luza daiteke."</string>
     <string name="ota_skip_activation_dialog_title" msgid="7666611236789203797">"Aktibazioa saltatu nahi duzu?"</string>
     <string name="ota_skip_activation_dialog_message" msgid="6691722887019708713">"Aktibazioa saltatzen baduzu, ezingo duzu deirik egin, ez eta datu-konexioaren sareetara konektatu ere, baina Wi-Fi sareetara konektatu ahal izango duzu. Telefonoa aktibatzen duzun arte, pizten duzun bakoitzean eskatuko zaizu aktibatzeko."</string>
     <string name="ota_skip_activation_dialog_skip_label" msgid="5908029466817825633">"Saltatu"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 9443c12..17ef040 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -68,7 +68,7 @@
     <string name="phone_accounts_make_sip_calls_with" msgid="4691221006731847255">"SIP чалууларын төмөнкү менен жасоо"</string>
     <string name="phone_accounts_ask_every_time" msgid="6192347582666047168">"Биринчи сурасын"</string>
     <string name="phone_accounts_default_account_label" msgid="5107598881335931101">"Тармак жок"</string>
-    <string name="phone_accounts_settings_header" msgid="6296501692964706536">"Жөндөөлөр"</string>
+    <string name="phone_accounts_settings_header" msgid="6296501692964706536">"Параметрлер"</string>
     <string name="phone_accounts_choose_accounts" msgid="4748805293314824974">"Аккаунттарды тандоо"</string>
     <string name="phone_accounts_selection_header" msgid="2945830843104108440">"Телефон каттоо эсептери"</string>
     <string name="phone_accounts_add_sip_account" msgid="1437634802033309305">"SIP аккаунтун кошуу"</string>
@@ -93,7 +93,7 @@
     <string name="sum_cdma_call_settings" msgid="3185825305136993636">"CDMA менен гана чалуунун кошумча жөндөөлөрү"</string>
     <string name="labelNwService" msgid="6015891883487125120">"Тармак кызматынын жөндөөлөрү"</string>
     <string name="labelCallerId" msgid="2090540744550903172">"Чалуучуну аныктоо"</string>
-    <string name="sum_loading_settings" msgid="434063780286688775">"Жөндөөлөр жүктөлүүдө…"</string>
+    <string name="sum_loading_settings" msgid="434063780286688775">"Параметрлер жүктөлүүдө…"</string>
     <string name="sum_hide_caller_id" msgid="131100328602371933">"Чыгуучу чалууларда номер жашырылган"</string>
     <string name="sum_show_caller_id" msgid="3571854755324664591">"Чыгуучу чалууларда көрсөтүлчү номер"</string>
     <string name="sum_default_caller_id" msgid="1767070797135682959">"Кимдир-бирөөгө чалып жатканда ага номерим көрүнүшү үчүн байланыш операторунун стандарттуу жөндөөлөрү колдонулат."</string>
@@ -133,11 +133,11 @@
     <string name="cdma_call_waiting_in_ims_off" msgid="1099246114368636334">"IMS платформасында CDMA чалуу күтүүcү өчүрүлгөн"</string>
     <string name="updating_title" msgid="6130548922615719689">"Чалуу жөндөөлөрү"</string>
     <string name="call_settings_admin_user_only" msgid="7238947387649986286">"Чалуу жөндөөлөрүн администратор гана өзгөртө алат."</string>
-    <string name="call_settings_with_label" msgid="8460230435361579511">"Жөндөөлөр (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+    <string name="call_settings_with_label" msgid="8460230435361579511">"Параметрлер (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
     <string name="error_updating_title" msgid="2024290892676808965">"Чалуу жөндөөлөрүндө ката кетти"</string>
-    <string name="reading_settings" msgid="1605904432450871183">"Жөндөөлөр окулууда…"</string>
-    <string name="updating_settings" msgid="3650396734816028808">"Жөндөөлөр жаңыртылууда…"</string>
-    <string name="reverting_settings" msgid="7378668837291012205">"Жөндөөлөр артка кайтарылууда…"</string>
+    <string name="reading_settings" msgid="1605904432450871183">"Параметрлер окулууда…"</string>
+    <string name="updating_settings" msgid="3650396734816028808">"Параметрлер жаңыртылууда…"</string>
+    <string name="reverting_settings" msgid="7378668837291012205">"Параметрлер артка кайтарылууда…"</string>
     <string name="response_error" msgid="3904481964024543330">"Тармактан күтүлбөгөн жооп алынды."</string>
     <string name="exception_error" msgid="330994460090467">"Тармак же SIM карта катасы."</string>
     <string name="stk_cc_ss_to_dial_error" msgid="5147693491690618704">"SS сурамы демейки чалууга өзгөртүлдү"</string>
@@ -903,7 +903,7 @@
     <string name="radio_info_smsc_update_label" msgid="5141996256097115753">"Жаңыртуу"</string>
     <string name="radio_info_smsc_refresh_label" msgid="8409923721451604560">"Жаңылоо"</string>
     <string name="radio_info_toggle_dns_check_label" msgid="1394078554927787350">"DNS текшерүүнү которуштуруу"</string>
-    <string name="oem_radio_info_label" msgid="2914167475119997456">"OEM\'ге тиешелүү Маалымат/Жөндөөлөр"</string>
+    <string name="oem_radio_info_label" msgid="2914167475119997456">"OEM\'ге тиешелүү Маалымат/Параметрлер"</string>
     <string name="radio_info_endc_available" msgid="2983767110681230019">"EN-DC жеткиликтүү (NSA):"</string>
     <string name="radio_info_dcnr_restricted" msgid="7147511536420148173">"DCNR чектелген (NSA):"</string>
     <string name="radio_info_nr_available" msgid="3383388088451237182">"NR жеткиликтүү (NSA):"</string>
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 79bda6c..ccef4d8 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -31,6 +31,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
 import android.app.PropertyInvalidatedCache;
@@ -492,13 +493,11 @@
 
     private static final class PurchasePremiumCapabilityArgument {
         public @TelephonyManager.PremiumCapability int capability;
-        public @NonNull String appName;
         public @NonNull IIntegerConsumer callback;
 
         PurchasePremiumCapabilityArgument(@TelephonyManager.PremiumCapability int capability,
-                @NonNull String appName, @NonNull IIntegerConsumer callback) {
+                @NonNull IIntegerConsumer callback) {
             this.capability = capability;
-            this.appName = appName;
             this.callback = callback;
         }
     }
@@ -2214,7 +2213,7 @@
                     PurchasePremiumCapabilityArgument arg =
                             (PurchasePremiumCapabilityArgument) request.argument;
                     SlicePurchaseController.getInstance(request.phone).purchasePremiumCapability(
-                            arg.capability, arg.appName, onCompleted);
+                            arg.capability, onCompleted);
                     break;
                 }
 
@@ -2459,8 +2458,7 @@
         mRadioInterfaceCapabilities = RadioInterfaceCapabilityController.getInstance();
         mNotifyUserActivity = new AtomicBoolean(false);
         PropertyInvalidatedCache.invalidateCache(TelephonyManager.CACHE_KEY_PHONE_ACCOUNT_TO_SUBID);
-        mTelephony2gUpdater = new Telephony2gUpdater(
-                Executors.newSingleThreadExecutor(), mApp);
+        mTelephony2gUpdater = new Telephony2gUpdater(mApp);
         mTelephony2gUpdater.init();
         publish();
         CarrierAllowListInfo.loadInstance(mApp);
@@ -2502,6 +2500,20 @@
                 ? getDefaultPhone() : getPhone(subId);
     }
 
+    /**
+     * Get phone object associated with a subscription.
+     * Return default phone if phone object associated with subscription is null
+     * @param subId - subscriptionId
+     * @return phone object associated with a subscription or default phone if null.
+     */
+    private Phone getPhoneFromSubIdOrDefault(int subId) {
+        Phone phone = getPhoneFromSubId(subId);
+        if (phone == null) {
+            phone = getDefaultPhone();
+        }
+        return phone;
+    }
+
     @Nullable
     private UiccPort getUiccPortFromRequest(@NonNull MainThreadRequest request) {
         Phone phone = getPhoneFromRequest(request);
@@ -4431,7 +4443,18 @@
         try {
             int slotId = getSlotIndexOrException(subId);
             verifyImsMmTelConfiguredOrThrow(slotId);
-            ImsManager.getInstance(mApp, slotId).addCapabilitiesCallbackForSubscription(c, subId);
+
+            ImsStateCallbackController controller = ImsStateCallbackController.getInstance();
+            if (controller != null) {
+                ImsManager imsManager = controller.getImsManager(subId);
+                if (imsManager != null) {
+                    imsManager.addCapabilitiesCallbackForSubscription(c, subId);
+                } else {
+                    throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+                }
+            } else {
+                throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
+            }
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4454,13 +4477,18 @@
 
         final long token = Binder.clearCallingIdentity();
         try {
-            ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
-                        .removeCapabilitiesCallbackForSubscription(c, subId);
-        } catch (ImsException e) {
-            Log.i(LOG_TAG, "unregisterMmTelCapabilityCallback: " + subId
-                     + "is inactive, ignoring unregister.");
-             // If the subscription is no longer active, just return, since the callback
-             // will already have been removed internally.
+            ImsStateCallbackController controller = ImsStateCallbackController.getInstance();
+            if (controller != null) {
+                ImsManager imsManager = controller.getImsManager(subId);
+                if (imsManager != null) {
+                    imsManager.removeCapabilitiesCallbackForSubscription(c, subId);
+                } else {
+                    Log.i(LOG_TAG, "unregisterMmTelCapabilityCallback: " + subId
+                            + " is inactive, ignoring unregister.");
+                    // If the ImsManager is not valid, just return, since the callback
+                    // will already have been removed internally.
+                }
+            }
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -4871,8 +4899,18 @@
             }
             int slotId = getSlotIndexOrException(subId);
             verifyImsMmTelConfiguredOrThrow(slotId);
-            ImsManager.getInstance(mApp, slotId)
-                    .addProvisioningCallbackForSubscription(callback, subId);
+
+            ImsStateCallbackController controller = ImsStateCallbackController.getInstance();
+            if (controller != null) {
+                ImsManager imsManager = controller.getImsManager(subId);
+                if (imsManager != null) {
+                    imsManager.addProvisioningCallbackForSubscription(callback, subId);
+                } else {
+                    throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+                }
+            } else {
+                throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
+            }
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4889,13 +4927,18 @@
             throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
         }
         try {
-            ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
-                    .removeProvisioningCallbackForSubscription(callback, subId);
-        } catch (ImsException e) {
-            Log.i(LOG_TAG, "unregisterImsProvisioningChangedCallback: " + subId
-                    + "is inactive, ignoring unregister.");
-            // If the subscription is no longer active, just return, since the callback will already
-            // have been removed internally.
+            ImsStateCallbackController controller = ImsStateCallbackController.getInstance();
+            if (controller != null) {
+                ImsManager imsManager = controller.getImsManager(subId);
+                if (imsManager != null) {
+                    imsManager.removeProvisioningCallbackForSubscription(callback, subId);
+                } else {
+                    Log.i(LOG_TAG, "unregisterImsProvisioningChangedCallback: " + subId
+                            + " is inactive, ignoring unregister.");
+                    // If the ImsManager is not valid, just return, since the callback will already
+                    // have been removed internally.
+                }
+            }
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -10272,8 +10315,9 @@
             throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
         }
         if (!isImsAvailableOnDevice()) {
-            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
-                    "IMS not available on device.");
+            // ProvisioningManager can not handle ServiceSpecificException.
+            // Throw the IllegalStateException and annotate ProvisioningManager.
+            throw new IllegalStateException("IMS not available on device.");
         }
 
         final long identity = Binder.clearCallingIdentity();
@@ -10872,8 +10916,9 @@
             throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
         }
         if (!isImsAvailableOnDevice()) {
-            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
-                    "IMS not available on device.");
+            // operation failed silently
+            Rlog.w(LOG_TAG, "IMS not available on device.");
+            return;
         }
 
         final long identity = Binder.clearCallingIdentity();
@@ -10897,8 +10942,9 @@
             throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
         }
         if (!isImsAvailableOnDevice()) {
-            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
-                    "IMS not available on device.");
+            // ProvisioningManager can not handle ServiceSpecificException.
+            // Throw the IllegalStateException and annotate ProvisioningManager.
+            throw new IllegalStateException("IMS not available on device.");
         }
 
         final long identity = Binder.clearCallingIdentity();
@@ -11528,6 +11574,12 @@
                     + " failed due to missing permissions.");
             throw new SecurityException("purchasePremiumCapability requires permission "
                     + "READ_BASIC_PHONE_STATE.");
+        } else if (!TelephonyPermissions.checkInternetPermissionNoThrow(
+                mApp, "purchasePremiumCapability")) {
+            log("purchasePremiumCapability "
+                    + TelephonyManager.convertPremiumCapabilityToString(capability)
+                    + " failed due to missing permissions.");
+            throw new SecurityException("purchasePremiumCapability requires permission INTERNET.");
         }
 
         Phone phone = getPhone(subId);
@@ -11546,15 +11598,50 @@
             }
             return;
         }
-        String appName;
+
+        String callingProcess;
         try {
-            appName = mApp.getPackageManager().getApplicationLabel(mApp.getPackageManager()
-                    .getApplicationInfo(getCurrentPackageName(), 0)).toString();
+            callingProcess = mApp.getPackageManager().getApplicationInfo(
+                    getCurrentPackageName(), 0).processName;
         } catch (PackageManager.NameNotFoundException e) {
-            appName = "An application";
+            callingProcess = getCurrentPackageName();
         }
+
+        boolean isVisible = false;
+        ActivityManager am = mApp.getSystemService(ActivityManager.class);
+        if (am != null) {
+            List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
+            if (processes != null) {
+                for (ActivityManager.RunningAppProcessInfo process : processes) {
+                    log("purchasePremiumCapability: process " + process.processName
+                            + "has importance " + process.importance);
+                    if (process.processName.equals(callingProcess) && process.importance
+                            <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
+                        isVisible = true;
+                        break;
+                    }
+                }
+            }
+        }
+
+        if (!isVisible) {
+            try {
+                int result = TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_FOREGROUND;
+                callback.accept(result);
+                loge("purchasePremiumCapability: " + callingProcess + " is not in the foreground.");
+            } catch (RemoteException e) {
+                String logStr = "Purchase premium capability "
+                        + TelephonyManager.convertPremiumCapabilityToString(capability)
+                        + " failed due to RemoteException handling background application: " + e;
+                if (DBG) log(logStr);
+                AnomalyReporter.reportAnomaly(
+                        UUID.fromString(PURCHASE_PREMIUM_CAPABILITY_ERROR_UUID), logStr);
+            }
+            return;
+        }
+
         sendRequestAsync(CMD_PURCHASE_PREMIUM_CAPABILITY,
-                new PurchasePremiumCapabilityArgument(capability, appName, callback), phone, null);
+                new PurchasePremiumCapabilityArgument(capability, callback), phone, null);
     }
 
     /**
@@ -11775,7 +11862,8 @@
             boolean updateIfNeeded) {
         enforceInteractAcrossUsersPermission("getDefaultRespondViaMessageApplication");
 
-        Context context = getPhone(subId).getContext();
+        Context context = getPhoneFromSubIdOrDefault(subId).getContext();
+
         UserHandle userHandle = null;
         final long identity = Binder.clearCallingIdentity();
         try {
diff --git a/src/com/android/phone/Telephony2gUpdater.java b/src/com/android/phone/Telephony2gUpdater.java
index 0919385..baaa684 100644
--- a/src/com/android/phone/Telephony2gUpdater.java
+++ b/src/com/android/phone/Telephony2gUpdater.java
@@ -30,8 +30,13 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.RILConstants;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
 
 /**
  * A {@link BroadcastReceiver} that ensures that user restrictions are correctly applied to
@@ -39,27 +44,50 @@
  * This includes handling broadcasts from user restriction state changes, as well as ensuring that
  * SIM-specific settings are correctly applied when new subscriptions become active.
  *
+ * <p>
  * Callers are expected to call {@code init()} and keep an instance of this class alive.
+ * </p>
  */
 public class Telephony2gUpdater extends BroadcastReceiver {
-    private static final String TAG = "TelephonyUserManagerReceiver";
+    private static final String TAG = "Telephony2gUpdater";
 
     // We can't interact with the HAL on the main thread of the phone process (where
     // receivers are run by default), so we execute our logic from a separate thread.
+    // The correctness of this implementation relies heavily on this executor ensuring
+    // tasks are serially executed i.e. ExecutorService.newSingleThreadExecutor()
     private final Executor mExecutor;
     private final Context mContext;
     private final long mBaseAllowedNetworks;
 
-    public Telephony2gUpdater(Executor executor, Context context) {
-        this(executor, context,
+    private UserManager mUserManager;
+    private TelephonyManager mTelephonyManager;
+    private SubscriptionManager mSubscriptionManager;
+
+    // The current subscription ids
+    // Ensure this value is never accessed concurrently
+    private Set<Integer> mCurrentSubscriptions;
+    // We keep track of the last value to avoid updating when unrelated user restrictions change
+    // Ensure this value is never accessed concurrently
+    private boolean mDisallowCellular2gRestriction;
+
+    public Telephony2gUpdater(Context context) {
+        this(Executors.newSingleThreadExecutor(), context,
                 RadioAccessFamily.getRafFromNetworkType(RILConstants.PREFERRED_NETWORK_MODE));
     }
 
-    public Telephony2gUpdater(Executor executor, Context context,
-            long baseAllowedNetworks) {
+    @VisibleForTesting
+    public Telephony2gUpdater(Executor executor, Context context, long baseAllowedNetworks) {
         mExecutor = executor;
         mContext = context;
         mBaseAllowedNetworks = baseAllowedNetworks;
+
+        mUserManager = mContext.getSystemService(UserManager.class);
+        mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+        mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+
+        // All user restrictions are false by default
+        mDisallowCellular2gRestriction = false;
+        mCurrentSubscriptions = new HashSet<>();
     }
 
     /**
@@ -80,41 +108,42 @@
         Log.i(TAG, "Received callback for action " + intent.getAction());
         final PendingResult result = goAsync();
         mExecutor.execute(() -> {
-            Log.i(TAG, "Running handler for action " + intent.getAction());
-            handleUserRestrictionsChanged(context);
-            result.finish();
+            boolean disallow2g = mUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G);
+            if (mDisallowCellular2gRestriction == disallow2g) {
+                Log.i(TAG, "No update to DISALLOW_CELLULAR_2G restriction.");
+                return;
+            }
+
+            mDisallowCellular2gRestriction = disallow2g;
+
+            Log.i(TAG, "Running handler for all subscriptions based on DISALLOW_CELLULAR_2G change."
+                    + " Restriction value: " + mDisallowCellular2gRestriction);
+            handleUserRestrictionsChanged(mCurrentSubscriptions);
+            if (result != null) {
+                result.finish();
+            }
         });
     }
 
     /**
-     * Update all active subscriptions with allowed network types depending on the current state
-     * of the {@link UserManager.DISALLOW_2G}.
+     * Update subscriptions with allowed network types depending on the current state
+     * of the {@link UserManager#DISALLOW_CELLULAR_2G}.
+     *
+     * @param subIds A list of subIds to update.
      */
-    @VisibleForTesting
-    public void handleUserRestrictionsChanged(Context context) {
-        UserManager um = context.getSystemService(UserManager.class);
-        TelephonyManager tm = context.getSystemService(TelephonyManager.class);
-        SubscriptionManager sm = context.getSystemService(SubscriptionManager.class);
+    private void handleUserRestrictionsChanged(Collection<Integer> subIds) {
         final long twoGBitmask = TelephonyManager.NETWORK_CLASS_BITMASK_2G;
 
-        boolean shouldDisable2g = um.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G);
-
-        // This is expected when subscription info cannot be determined. We'll get another
-        // callback in the future from our SubscriptionListener once we have valid subscriptions.
-        List<SubscriptionInfo> subscriptionInfoList = sm.getAvailableSubscriptionInfoList();
-        if (subscriptionInfoList == null) {
-            return;
-        }
-
         long allowedNetworkTypes = mBaseAllowedNetworks;
 
         // 2G device admin controls are global
-        for (SubscriptionInfo info : subscriptionInfoList) {
-            TelephonyManager telephonyManager = tm.createForSubscriptionId(
-                    info.getSubscriptionId());
-            if (shouldDisable2g) {
+        for (Integer subId : subIds) {
+            TelephonyManager telephonyManager = mTelephonyManager.createForSubscriptionId(subId);
+            if (mDisallowCellular2gRestriction) {
+                Log.i(TAG, "Disabling 2g based on user restriction for subId: " + subId);
                 allowedNetworkTypes &= ~twoGBitmask;
             } else {
+                Log.i(TAG, "Enabling 2g based on user restriction for subId: " + subId);
                 allowedNetworkTypes |= twoGBitmask;
             }
             telephonyManager.setAllowedNetworkTypesForReason(
@@ -126,8 +155,30 @@
     private class SubscriptionListener extends SubscriptionManager.OnSubscriptionsChangedListener {
         @Override
         public void onSubscriptionsChanged() {
-            Log.i(TAG, "Running handler for subscription change.");
-            handleUserRestrictionsChanged(mContext);
+            // Note that this entire callback gets invoked in the single threaded executor
+            List<SubscriptionInfo> allSubscriptions =
+                    mSubscriptionManager.getCompleteActiveSubscriptionInfoList();
+
+            HashSet<Integer> updatedSubIds = new HashSet<>(allSubscriptions.size());
+            List<Integer> newSubIds = new ArrayList<>();
+
+            for (SubscriptionInfo info : allSubscriptions) {
+                updatedSubIds.add(info.getSubscriptionId());
+                if (!mCurrentSubscriptions.contains(info.getSubscriptionId())) {
+                    newSubIds.add(info.getSubscriptionId());
+                }
+            }
+
+            mCurrentSubscriptions = updatedSubIds;
+
+            if (newSubIds.isEmpty()) {
+                Log.d(TAG, "No new subIds. Skipping update.");
+                return;
+            }
+
+            Log.i(TAG, "New subscriptions found. Running handler to update 2g restrictions with "
+                    + "subIds " + newSubIds.toString());
+            handleUserRestrictionsChanged(newSubIds);
         }
     }
 
diff --git a/src/com/android/phone/slice/SlicePurchaseController.java b/src/com/android/phone/slice/SlicePurchaseController.java
index 3864119..e36325e 100644
--- a/src/com/android/phone/slice/SlicePurchaseController.java
+++ b/src/com/android/phone/slice/SlicePurchaseController.java
@@ -40,6 +40,7 @@
 import android.os.Message;
 import android.os.PersistableBundle;
 import android.provider.DeviceConfig;
+import android.sysprop.TelephonyProperties;
 import android.telephony.AnomalyReporter;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
@@ -204,11 +205,9 @@
     public static final String EXTRA_FAILURE_REASON =
             "com.android.phone.slice.extra.FAILURE_REASON";
     /**
-     * Extra for the application name requesting to purchase the premium capability
-     * from the slice purchase application.
+     * Extra for the user's carrier.
      */
-    public static final String EXTRA_REQUESTING_APP_NAME =
-            "com.android.phone.slice.extra.REQUESTING_APP_NAME";
+    public static final String EXTRA_CARRIER = "com.android.phone.slice.extra.CARRIER";
     /**
      * Extra for the canceled PendingIntent that the slice purchase application can send as a
      * response if the performance boost notification or WebView was canceled by the user.
@@ -497,11 +496,10 @@
                 break;
             }
             case EVENT_START_SLICE_PURCHASE_APP: {
-                int capability = msg.arg1;
-                String appName = (String) msg.obj;
-                logd("EVENT_START_SLICE_PURCHASE_APP: " + appName + " requests capability "
+                int capability = (int) msg.obj;
+                logd("EVENT_START_SLICE_PURCHASE_APP: "
                         + TelephonyManager.convertPremiumCapabilityToString(capability));
-                onStartSlicePurchaseApplication(capability, appName);
+                onStartSlicePurchaseApplication(capability);
                 break;
             }
             case EVENT_PURCHASE_TIMEOUT: {
@@ -565,13 +563,11 @@
      * Purchase the given premium capability from the carrier.
      *
      * @param capability The premium capability to purchase.
-     * @param appName The name of the application requesting premium capabilities.
      * @param onComplete The callback message to send when the purchase request is complete.
      */
     public synchronized void purchasePremiumCapability(
-            @TelephonyManager.PremiumCapability int capability, @NonNull String appName,
-            @NonNull Message onComplete) {
-        logd("purchasePremiumCapability: " + appName + " requests capability "
+            @TelephonyManager.PremiumCapability int capability, @NonNull Message onComplete) {
+        logd("purchasePremiumCapability: "
                 + TelephonyManager.convertPremiumCapabilityToString(capability));
         // Check whether the premium capability can be purchased.
         if (!arePremiumCapabilitiesSupportedByDevice()) {
@@ -627,8 +623,7 @@
         // All state checks passed. Mark purchase pending and start the slice purchase application.
         // Process through the handler since this method is synchronized.
         mPendingPurchaseCapabilities.put(capability, onComplete);
-        sendMessage(obtainMessage(EVENT_START_SLICE_PURCHASE_APP, capability, 0 /* unused */,
-                appName));
+        sendMessage(obtainMessage(EVENT_START_SLICE_PURCHASE_APP, capability));
     }
 
     private void sendPurchaseResult(@TelephonyManager.PremiumCapability int capability,
@@ -687,8 +682,8 @@
         }
     }
 
-    private void onStartSlicePurchaseApplication(@TelephonyManager.PremiumCapability int capability,
-            @NonNull String appName) {
+    private void onStartSlicePurchaseApplication(
+            @TelephonyManager.PremiumCapability int capability) {
         PremiumNetworkEntitlementResponse premiumNetworkEntitlementResponse =
                 mPremiumNetworkEntitlementApi.checkEntitlementStatus(capability);
 
@@ -721,7 +716,8 @@
         }
 
         String purchaseUrl = getPurchaseUrl(premiumNetworkEntitlementResponse);
-        if (TextUtils.isEmpty(purchaseUrl)) {
+        String carrier = getSimOperator();
+        if (TextUtils.isEmpty(purchaseUrl) || TextUtils.isEmpty(carrier)) {
             handlePurchaseResult(capability,
                     PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED, false);
             return;
@@ -753,7 +749,7 @@
         intent.putExtra(EXTRA_SUB_ID, mPhone.getSubId());
         intent.putExtra(EXTRA_PREMIUM_CAPABILITY, capability);
         intent.putExtra(EXTRA_PURCHASE_URL, purchaseUrl);
-        intent.putExtra(EXTRA_REQUESTING_APP_NAME, appName);
+        intent.putExtra(EXTRA_CARRIER, carrier);
         intent.putExtra(EXTRA_INTENT_CANCELED, createPendingIntent(
                 ACTION_SLICE_PURCHASE_APP_RESPONSE_CANCELED, capability, false));
         intent.putExtra(EXTRA_INTENT_CARRIER_ERROR, createPendingIntent(
@@ -805,6 +801,20 @@
     }
 
     /**
+     * Get the SIM operator. This is the carrier name from the SIM rather than from the network,
+     * which will be the same regardless of whether the user is roaming or not.
+     *
+     * @return The operator name from the SIM.
+     */
+    @VisibleForTesting
+    @Nullable public String getSimOperator() {
+        if (mPhone.getPhoneId() < TelephonyProperties.icc_operator_alpha().size()) {
+            return TelephonyProperties.icc_operator_alpha().get(mPhone.getPhoneId());
+        }
+        return null;
+    }
+
+    /**
      * Create the PendingIntent to allow the slice purchase application to send back responses.
      *
      * @param action The action that will be sent for this PendingIntent
@@ -819,6 +829,7 @@
         Intent intent = new Intent(action);
         intent.putExtra(EXTRA_PHONE_ID, mPhone.getPhoneId());
         intent.putExtra(EXTRA_PREMIUM_CAPABILITY, capability);
+        intent.setPackage(mPhone.getContext().getPackageName());
         return PendingIntent.getBroadcast(mPhone.getContext(), capability, intent,
                 PendingIntent.FLAG_CANCEL_CURRENT
                         | (mutable ? PendingIntent.FLAG_MUTABLE : PendingIntent.FLAG_IMMUTABLE));
@@ -1028,6 +1039,11 @@
     }
 
     private boolean isNetworkAvailable() {
+        if (mPhone.getServiceState().getDataRoaming()) {
+            logd("Network unavailable because it is roaming.");
+            return false;
+        }
+
         // TODO (b/251558673): Create a listener for data network type changed to dismiss
         //  notification and activity when the network is no longer available.
         switch (mPhone.getServiceState().getDataNetworkType()) {
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 7d7d949..68956bd 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -557,13 +557,22 @@
                         Connection connection, @Connection.ConnectionState int state) {
                     TelephonyConnection c = (TelephonyConnection) connection;
                     if (c != null) {
-                        if (c.getState() == Connection.STATE_ACTIVE) {
-                            Log.d(LOG_TAG, "Call State->ACTIVE."
-                                    + "Clearing DomainSelectionConnection");
-                            c.removeTelephonyConnectionListener(mNormalCallConnectionListener);
-                            mDomainSelectionConnection.finishSelection();
-                            mDomainSelectionConnection = null;
-                            mNormalCallConnection = null;
+                        switch(c.getState()) {
+                            case Connection.STATE_ACTIVE: {
+                                Log.d(LOG_TAG, "Call State->ACTIVE."
+                                        + "Clearing DomainSelectionConnection");
+                                if (mDomainSelectionConnection != null) {
+                                    mDomainSelectionConnection.finishSelection();
+                                    mDomainSelectionConnection = null;
+                                }
+                                mNormalCallConnection = null;
+                            }
+                            break;
+
+                            case Connection.STATE_DISCONNECTED: {
+                                c.removeTelephonyConnectionListener(mNormalCallConnectionListener);
+                            }
+                            break;
                         }
                     }
                 }
@@ -598,7 +607,6 @@
                             if (mDomainSelectionConnection != null) {
                                 mDomainSelectionConnection = null;
                             }
-
                             if (mNormalCallConnection != null) {
                                 // TODO: To support ShowPreciseFailedCause, TelephonyConnection
                                 //  .getShowPreciseFailedCause API should be added.
@@ -2048,8 +2056,10 @@
                             e.getMessage(), phone.getPhoneId()));
             mNormalCallConnection.close();
         }
-        mDomainSelectionConnection.finishSelection();
-        mDomainSelectionConnection = null;
+        if (mDomainSelectionConnection != null) {
+            mDomainSelectionConnection.finishSelection();
+            mDomainSelectionConnection = null;
+        }
         mNormalCallConnection = null;
     }
 
@@ -2060,6 +2070,10 @@
             return false;
         }
 
+        if (phone == null) {
+            return false;
+        }
+
         String dialPart = PhoneNumberUtils.extractNetworkPortionAlt(
                 PhoneNumberUtils.stripSeparators(number));
         boolean isMmiCode = (dialPart.startsWith("*") || dialPart.startsWith("#"))
@@ -2072,6 +2086,16 @@
             return false;
         }
 
+        // Check and select same domain as ongoing call on the same subscription (if exists)
+        int activeCallDomain = getActiveCallDomain(phone.getSubId());
+        if (activeCallDomain != NetworkRegistrationInfo.DOMAIN_UNKNOWN) {
+            Log.d(LOG_TAG, "Selecting same domain as ongoing call on same subId");
+            mNormalCallConnection = connection;
+            handleOutgoingCallConnectionByCallDomainSelection(
+                    activeCallDomain, phone, number, videoState);
+            return true;
+        }
+
         mDomainSelectionConnection = mDomainSelectionResolver
                 .getDomainSelectionConnection(phone, SELECTOR_TYPE_CALLING, false);
         if (mDomainSelectionConnection == null) {
@@ -2313,6 +2337,7 @@
                             callFailCause, reasonInfo);
 
             Log.d(LOG_TAG, "Reselecting the domain for call");
+            mNormalCallConnection = c;
             CompletableFuture<Integer> future = mDomainSelectionConnection
                     .reselectDomain(selectionAttributes);
             if (future != null) {
@@ -2329,7 +2354,7 @@
             mDomainSelectionConnection = null;
         }
         mNormalCallConnection = null;
-        Log.d(LOG_TAG, "Reselecting the domain for call failed");
+        Log.d(LOG_TAG, "Reselect call domain not triggered.");
         return false;
     }
 
@@ -3459,4 +3484,25 @@
                     }
                 });
     }
+
+    private @NetworkRegistrationInfo.Domain int getActiveCallDomain(int subId) {
+        for (Connection c: getAllConnections()) {
+            if ((c instanceof TelephonyConnection)) {
+                TelephonyConnection connection = (TelephonyConnection) c;
+                Phone phone = connection.getPhone();
+                if (phone == null) {
+                    continue;
+                }
+
+                if (phone.getSubId() == subId) {
+                    if (phone instanceof GsmCdmaPhone) {
+                        return NetworkRegistrationInfo.DOMAIN_CS;
+                    } else if (phone instanceof ImsPhone) {
+                        return NetworkRegistrationInfo.DOMAIN_PS;
+                    }
+                }
+            }
+        }
+        return NetworkRegistrationInfo.DOMAIN_UNKNOWN;
+    }
 }
diff --git a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
index dcb1de7..53a60af 100644
--- a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
@@ -41,14 +41,22 @@
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_SCAN_TIMER_SEC_INT;
+import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL;
 import static android.telephony.CarrierConfigManager.ImsEmergency.SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_SETTING_ENABLED;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_VALID_EID;
+import static android.telephony.CarrierConfigManager.ImsWfc.KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL;
 import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME;
 import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING;
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
 import android.os.CancellationSignal;
 import android.os.Looper;
 import android.os.Message;
@@ -69,6 +77,7 @@
 import android.telephony.TransportSelectorCallback;
 import android.telephony.ims.ImsManager;
 import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ProvisioningManager;
 import android.text.TextUtils;
 import android.util.LocalLog;
 
@@ -97,6 +106,30 @@
 
     private static final LocalLog sLocalLog = new LocalLog(LOG_SIZE);
 
+    /**
+     * Network callback used to determine whether Wi-Fi is connected or not.
+     */
+    private ConnectivityManager.NetworkCallback mNetworkCallback =
+            new ConnectivityManager.NetworkCallback() {
+                @Override
+                public void onAvailable(Network network) {
+                    logi("onAvailable: " + network);
+                    mWiFiAvailable = true;
+                }
+
+                @Override
+                public void onLost(Network network) {
+                    logi("onLost: " + network);
+                    mWiFiAvailable = false;
+                }
+
+                @Override
+                public void onUnavailable() {
+                    logi("onUnavailable");
+                    mWiFiAvailable = false;
+                }
+            };
+
     private boolean mIsEmergencyBarred;
     private boolean mImsRegistered;
     private boolean mIsVoiceCapable;
@@ -122,10 +155,14 @@
     private @CarrierConfigManager.ImsEmergency.EmergencyDomain int[] mDomainPreferenceRoam;
     private List<String> mCdmaPreferredNumbers;
     private boolean mPreferImsWhenCallsOnCs;
+    private int mVoWifiRequiresCondition;
+    private boolean mIsMonitoringConnectivity;
+    private boolean mWiFiAvailable;
     private int mScanTimeout;
     private int mMaxNumOfVoWifiTries;
+    private boolean mVoWifiOverEmergencyPdn;
     private @CarrierConfigManager.ImsEmergency.EmergencyScanType int mPreferredNetworkScanType;
-    private int mCallSetupTimerOnCurrentRatSec;
+    private int mCallSetupTimerOnCurrentRat;
     private boolean mRequiresImsRegistration;
     private boolean mRequiresVoLteEnabled;
     private boolean mLtePreferredAfterNrFailure;
@@ -353,11 +390,13 @@
         mDomainPreferenceRoam = b.getIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_ROAMING_INT_ARRAY);
         mPreferImsWhenCallsOnCs = b.getBoolean(
                 KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL);
-        mScanTimeout = b.getInt(KEY_EMERGENCY_SCAN_TIMER_SEC_INT);
+        mVoWifiRequiresCondition = b.getInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT);
+        mScanTimeout = b.getInt(KEY_EMERGENCY_SCAN_TIMER_SEC_INT) * 1000;
         mMaxNumOfVoWifiTries = b.getInt(KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT);
+        mVoWifiOverEmergencyPdn = b.getBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL);
         mPreferredNetworkScanType = b.getInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT);
-        mCallSetupTimerOnCurrentRatSec = b.getInt(
-                KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT);
+        mCallSetupTimerOnCurrentRat = b.getInt(
+                KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT) * 1000;
         mRequiresImsRegistration = b.getBoolean(KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL);
         mRequiresVoLteEnabled = b.getBoolean(KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL);
         mLtePreferredAfterNrFailure = b.getBoolean(
@@ -386,11 +425,13 @@
                 + ", domainPrefRoam=" + arrayToString(mDomainPreferenceRoam,
                         EmergencyCallDomainSelector::domainPreferenceToString)
                 + ", preferImsOnCs=" + mPreferImsWhenCallsOnCs
+                + ", voWifiRequiresCondition=" + mVoWifiRequiresCondition
                 + ", scanTimeout=" + mScanTimeout
                 + ", maxNumOfVoWifiTries=" + mMaxNumOfVoWifiTries
+                + ", voWifiOverEmergencyPdn=" + mVoWifiOverEmergencyPdn
                 + ", preferredScanType=" + carrierConfigNetworkScanTypeToString(
                         mPreferredNetworkScanType)
-                + ", callSetupTimer=" + mCallSetupTimerOnCurrentRatSec
+                + ", callSetupTimer=" + mCallSetupTimerOnCurrentRat
                 + ", requiresImsReg=" + mRequiresImsRegistration
                 + ", requiresVoLteEnabled=" + mRequiresVoLteEnabled
                 + ", ltePreferredAfterNr=" + mLtePreferredAfterNrFailure
@@ -560,6 +601,7 @@
                 // remove any pending timers.
                 removeMessages(MSG_NETWORK_SCAN_TIMEOUT);
                 sendEmptyMessageDelayed(MSG_NETWORK_SCAN_TIMEOUT, mScanTimeout);
+                registerForConnectivityChanges();
             }
         }
     }
@@ -639,8 +681,33 @@
     }
 
     private void handleNetworkScanTimeout() {
-        if (isImsRegisteredWithVoiceCapability()
-                && isImsRegisteredOverWifi()) {
+        logi("handleNetworkScanTimeout overEmergencyPdn=" + mVoWifiOverEmergencyPdn
+                + ", wifiAvailable=" + mWiFiAvailable);
+        boolean available = mWiFiAvailable;
+        if (mVoWifiOverEmergencyPdn) {
+            // SOS APN
+            if (!available && isImsRegisteredOverCrossSim()) {
+                available = true;
+            }
+            if (available) {
+                switch (mVoWifiRequiresCondition) {
+                    case VOWIFI_REQUIRES_SETTING_ENABLED:
+                        available = isWifiCallingSettingEnabled();
+                        break;
+                    case VOWIFI_REQUIRES_VALID_EID:
+                        available = isWifiCallingActivated();
+                        break;
+                    default:
+                        break;
+                }
+            }
+        } else {
+            // IMS APN. When IMS is already registered over Wi-Fi.
+            available = isImsRegisteredWithVoiceCapability() && isImsRegisteredOverWifi();
+        }
+
+        logi("handleNetworkScanTimeout VoWi-Fi available=" + available);
+        if (available) {
             if (mCancelSignal != null) {
                 mCancelSignal.cancel();
                 mCancelSignal = null;
@@ -811,6 +878,41 @@
         return true;
     }
 
+    private boolean isWifiCallingActivated() {
+        try {
+            ImsManager imsMngr = mContext.getSystemService(ImsManager.class);
+            ProvisioningManager pm = imsMngr.getProvisioningManager(getSubId());
+            String eid = pm.getProvisioningStringValue(
+                    ProvisioningManager.KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID);
+            boolean activated = (!TextUtils.isEmpty(eid)) && (!TextUtils.equals("0", eid));
+            logi("isWifiCallingActivated " + activated);
+            return activated;
+        } catch (Exception e) {
+            logi("isWifiCallingActivated e=" + e);
+        }
+        return false;
+    }
+
+    private boolean isWifiCallingSettingEnabled() {
+        boolean result = false;
+        try {
+            if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
+                ImsManager imsMngr = mContext.getSystemService(ImsManager.class);
+                ImsMmTelManager mmTelManager = imsMngr.getImsMmTelManager(getSubId());
+                if (isInRoaming()) {
+                    result = mmTelManager.isVoWiFiRoamingSettingEnabled();
+                } else {
+                    result = mmTelManager.isVoWiFiSettingEnabled();
+                }
+                logi("isWifiCallingSettingEnabled " + result);
+                return result;
+            }
+        } catch (Exception e) {
+            logi("isWifiCallingSettingEnabled e=" + e);
+        }
+        return result;
+    }
+
     private @NonNull List<Integer> getImsNetworkTypeConfiguration() {
         int[] rats = mImsRatsConfig;
         if (isInRoaming()) rats = mImsRoamRatsConfig;
@@ -897,6 +999,21 @@
     }
 
     /**
+     * Determines whether IMS is registered over the mobile data of another subscription.
+     *
+     * @return {@code true} if IMS is registered over the mobile data of another subscription.
+     */
+    private boolean isImsRegisteredOverCrossSim() {
+        boolean ret = false;
+        if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
+            ret = mImsStateTracker.isImsRegisteredOverCrossSim();
+        }
+
+        logi("isImsRegisteredOverCrossSim " + ret);
+        return ret;
+    }
+
+    /**
      * Determines whether IMS is registered with voice capability.
      *
      * @return {@code true} if IMS is registered with voice capability.
@@ -952,6 +1069,40 @@
         mWwanSelectorCallback.onDomainSelected(domain);
     }
 
+    /**
+     * Registers for changes to network connectivity.
+     */
+    private void registerForConnectivityChanges() {
+        if (mIsMonitoringConnectivity) {
+            return;
+        }
+
+        ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+        if (cm != null) {
+            logi("registerForConnectivityChanges");
+            NetworkRequest.Builder builder = new NetworkRequest.Builder();
+            builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+            cm.registerNetworkCallback(builder.build(), mNetworkCallback);
+            mIsMonitoringConnectivity = true;
+        }
+    }
+
+    /**
+     * Unregisters for connectivity changes.
+     */
+    private void unregisterForConnectivityChanges() {
+        if (!mIsMonitoringConnectivity) {
+            return;
+        }
+
+        ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+        if (cm != null) {
+            logi("unregisterForConnectivityChanges");
+            cm.unregisterNetworkCallback(mNetworkCallback);
+            mIsMonitoringConnectivity = false;
+        }
+    }
+
     private static String arrayToString(int[] intArray, IntFunction<String> func) {
         int length = intArray.length;
         StringBuilder sb = new StringBuilder("{");
@@ -1027,6 +1178,7 @@
         mDestroyed = true;
         mImsStateTracker.removeBarringInfoListener(this);
         mImsStateTracker.removeImsStateListener(this);
+        unregisterForConnectivityChanges();
 
         super.destroy();
     }
diff --git a/src/com/android/services/telephony/domainselection/ImsStateTracker.java b/src/com/android/services/telephony/domainselection/ImsStateTracker.java
index 95c81a0..fc3f811 100644
--- a/src/com/android/services/telephony/domainselection/ImsStateTracker.java
+++ b/src/com/android/services/telephony/domainselection/ImsStateTracker.java
@@ -130,6 +130,7 @@
     /** The IMS registration state and the network type that performed IMS registration. */
     private Boolean mImsRegistered;
     private @RadioAccessNetworkType int mImsAccessNetworkType = AccessNetworkType.UNKNOWN;
+    private Boolean mImsRegisteredOverCrossSim;
     /** The MMTEL capabilities - Voice, Video, SMS, and Ut. */
     private MmTelCapabilities mMmTelCapabilities;
     private final Runnable mMmTelFeatureUnavailableRunnable = new Runnable() {
@@ -361,6 +362,13 @@
     }
 
     /**
+     * Returns {@code true} if IMS is registered over the mobile data of another subscription.
+     */
+    public boolean isImsRegisteredOverCrossSim() {
+        return mImsRegisteredOverCrossSim != null && mImsRegisteredOverCrossSim;
+    }
+
+    /**
      * Returns {@code true} if IMS voice call is capable, {@code false} otherwise.
      */
     public boolean isImsVoiceCapable() {
@@ -406,6 +414,7 @@
         mMmTelFeatureAvailable = null;
         mImsRegistered = null;
         mImsAccessNetworkType = AccessNetworkType.UNKNOWN;
+        mImsRegisteredOverCrossSim = null;
         mMmTelCapabilities = null;
     }
 
@@ -418,6 +427,7 @@
         setMmTelFeatureAvailable(false);
         setImsRegistered(false);
         setImsAccessNetworkType(AccessNetworkType.UNKNOWN);
+        setImsRegisteredOverCrossSim(false);
         setMmTelCapabilities(new MmTelCapabilities());
     }
 
@@ -450,6 +460,13 @@
         }
     }
 
+    private void setImsRegisteredOverCrossSim(boolean crossSim) {
+        if (!Objects.equals(mImsRegisteredOverCrossSim, Boolean.valueOf(crossSim))) {
+            logi("setImsRegisteredOverCrossSim: " + mImsRegisteredOverCrossSim + " >> " + crossSim);
+            mImsRegisteredOverCrossSim = Boolean.valueOf(crossSim);
+        }
+    }
+
     /**
      * Notifies the specified listener of the current IMS state if it's valid.
      *
@@ -548,6 +565,8 @@
             setImsStateAsUnavailable();
             unregisterImsRegistrationCallback();
             unregisterMmTelCapabilityCallback();
+            // ImsStateCallback has already been removed after calling onUnavailable.
+            mImsStateCallback = null;
             notifyImsMmTelFeatureAvailableChanged();
         } else {
             logw("onMmTelFeatureUnavailable: unexpected reason=" + reason);
@@ -563,6 +582,8 @@
         setImsRegistered(true);
         setImsAccessNetworkType(
                 imsRegTechToAccessNetworkType(attributes.getRegistrationTechnology()));
+        setImsRegisteredOverCrossSim(attributes.getRegistrationTechnology()
+                == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM);
         notifyImsRegistrationStateChanged();
     }
 
@@ -573,6 +594,7 @@
         logd("onImsUnregistered: " + info);
         setImsRegistered(false);
         setImsAccessNetworkType(AccessNetworkType.UNKNOWN);
+        setImsRegisteredOverCrossSim(false);
         setMmTelCapabilities(new MmTelCapabilities());
         notifyImsRegistrationStateChanged();
     }
diff --git a/testapps/GbaTestApp/res/values-ky/strings.xml b/testapps/GbaTestApp/res/values-ky/strings.xml
index bf5cd30..00383d5 100644
--- a/testapps/GbaTestApp/res/values-ky/strings.xml
+++ b/testapps/GbaTestApp/res/values-ky/strings.xml
@@ -2,7 +2,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     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_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>
diff --git a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java
index 0f120f4..a74e7f0 100644
--- a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java
+++ b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java
@@ -23,7 +23,7 @@
 import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED;
 import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE;
 import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION;
-import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_OVERRIDDEN;
+import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_FOREGROUND;
 import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP;
 import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_SUCCESS;
 import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED;
@@ -271,8 +271,8 @@
                 return "Already purchased";
             case PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS:
                 return "Already in progress";
-            case PURCHASE_PREMIUM_CAPABILITY_RESULT_OVERRIDDEN:
-                return "Overridden";
+            case PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_FOREGROUND:
+                return "Not foreground";
             case PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_CANCELED:
                 return "User canceled";
             case PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED:
diff --git a/tests/src/com/android/phone/Telephony2gUpdaterTest.java b/tests/src/com/android/phone/Telephony2gUpdaterTest.java
index 3443767..3684f30 100644
--- a/tests/src/com/android/phone/Telephony2gUpdaterTest.java
+++ b/tests/src/com/android/phone/Telephony2gUpdaterTest.java
@@ -16,13 +16,17 @@
 
 package com.android.phone;
 
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.content.Intent;
 import android.os.UserManager;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -35,22 +39,33 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 
 @RunWith(AndroidJUnit4.class)
 public class Telephony2gUpdaterTest extends TelephonyTestBase {
+    private static final long DRAIN_TIMEOUT = 10;
     private Telephony2gUpdater mTelephony2gUpdater;
+    private SubscriptionManager.OnSubscriptionsChangedListener mChangedListener;
     private Executor mExecutor;
+    private CountDownLatch mLatch;
 
     private UserManager mMockUserManager;
     private TelephonyManager mMockTelephonyManager;
     private SubscriptionManager mMockSubscriptionManager;
 
+    // Set up to be returned from mMockSubscriptionManager.getCompleteActiveSubscriptionInfoList()
+    // Updates will be reflected in subsequent calls to the mock method.
+    private List<SubscriptionInfo> mCurrentSubscriptions;
+
     // 2G Bitmask is 0b10000000_01001011
     private static final long BASE_NETWORK = 0b11111111_11111111;
     private static final long EXPECTED_DISABLED = 0b01111111_10110100;
@@ -65,89 +80,247 @@
         mMockUserManager = mContext.getSystemService(UserManager.class);
         mMockSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
 
+        mCurrentSubscriptions = new ArrayList<>();
+        setupMutableSubscriptionInfoMock();
+
         mExecutor = Executors.newSingleThreadExecutor();
-        mTelephony2gUpdater = new Telephony2gUpdater(mExecutor,
-                getTestContext(), BASE_NETWORK);
+        mTelephony2gUpdater = new Telephony2gUpdater(mExecutor, getTestContext(), BASE_NETWORK);
+        mTelephony2gUpdater.init();
+        ArgumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener> argument =
+                ArgumentCaptor.forClass(SubscriptionManager.OnSubscriptionsChangedListener.class);
+        verify(mMockSubscriptionManager).addOnSubscriptionsChangedListener(any(Executor.class),
+                argument.capture());
+        mChangedListener = argument.getValue();
     }
 
     @Test
-    public void handleUserRestrictionsChanged_noSubscriptions_noAllowedNetworksChanged() {
-        when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
-                new ArrayList<>());
-        mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
+    public void onSubscriptionsChanged_noSubscriptions_noAllowedNetworksChanged() {
+        triggerOnSubscriptionChangedAndWait();
         verify(mMockTelephonyManager, never()).setAllowedNetworkTypesForReason(anyInt(), anyInt());
     }
 
     @Test
-    public void handleUserRestrictionsChanged_nullSubscriptions_noAllowedNetworksChanged() {
-        when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(null);
-        mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
-        verify(mMockTelephonyManager, never()).setAllowedNetworkTypesForReason(anyInt(), anyInt());
-    }
+    public void onSubscriptionsChanged_oneSubscription_allowedNetworksUpdated() {
+        TelephonyManager tmSubscription1 = addSubscriptionAndGetMock(1001);
+        triggerOnSubscriptionChangedAndWait();
 
-    @Test
-    public void handleUserRestrictionsChanged_oneSubscription_allowedNetworksUpdated() {
-        TelephonyManager tmSubscription1 = mock(TelephonyManager.class);
-        when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
-                Collections.singletonList(getSubInfo(1)));
-        when(mMockTelephonyManager.createForSubscriptionId(1)).thenReturn(tmSubscription1);
-        when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
-                true);
-
-        mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
-
-        System.out.println(TelephonyManager.convertNetworkTypeBitmaskToString(11L));
         verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
-                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
     }
 
     @Test
-    public void handleUserRestrictionsChanged_manySubscriptionsDisallow2g_allowedNetworkUpdated() {
-
-        // Two subscriptions are available
-        when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
-                Arrays.asList(getSubInfo(1), getSubInfo(2)));
-        TelephonyManager tmSubscription1 = mock(TelephonyManager.class);
-        TelephonyManager tmSubscription2 = mock(TelephonyManager.class);
-        when(mMockTelephonyManager.createForSubscriptionId(1)).thenReturn(tmSubscription1);
-        when(mMockTelephonyManager.createForSubscriptionId(2)).thenReturn(tmSubscription2);
+    public void onSubscriptionsChanged_manySubscriptionsDisallow2g_allowedNetworkUpdated() {
         // 2g is disallowed
         when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
                 true);
+        triggerBroadcastReceiverAndWait();
 
-        mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
+        TelephonyManager tmSubscription1 = addSubscriptionAndGetMock(1001);
+        TelephonyManager tmSubscription2 = addSubscriptionAndGetMock(1002);
+
+        triggerOnSubscriptionChangedAndWait();
 
         verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
                 TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+        verify(tmSubscription2, times(1)).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+    }
+
+    @Test
+    public void onSubscriptionsChanged_noNewSubscriptions_noAllowedNetworksChanged() {
+        when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
+                true);
+        triggerBroadcastReceiverAndWait();
+
+        TelephonyManager tmSubscription1 = addSubscriptionAndGetMock(1001);
+
+        triggerOnSubscriptionChangedAndWait();
+        triggerOnSubscriptionChangedAndWait();
+
+        // subscriptions were updated twice, but we have no new subIds so we only expect one update
         verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
                 TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
     }
 
     @Test
-    public void handleUserRestrictionsChanged_manySubscriptionsAllow2g_allowedNetworkUpdated() {
+    public void onSubscriptionsChanged_removeSubscription_noAdditionalNetworkChanges() {
+        // We start with 2 subIds
+        TelephonyManager tmSubscription1 = addSubscriptionAndGetMock(1001);
+        TelephonyManager tmSubscription2 = addSubscriptionAndGetMock(1002);
 
-        // Two subscriptions are available
-        when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
-                Arrays.asList(getSubInfo(1), getSubInfo(2)));
-        TelephonyManager tmSubscription1 = mock(TelephonyManager.class);
-        TelephonyManager tmSubscription2 = mock(TelephonyManager.class);
-        when(mMockTelephonyManager.createForSubscriptionId(1)).thenReturn(tmSubscription1);
-        when(mMockTelephonyManager.createForSubscriptionId(2)).thenReturn(tmSubscription2);
+        triggerOnSubscriptionChangedAndWait();
 
-        // 2g is allowed
+        // 2g is still enabled since the default is to not set the user restriction
+        verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+        verify(tmSubscription2, times(1)).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+
+
+        mCurrentSubscriptions.remove(1);
+        triggerOnSubscriptionChangedAndWait();
+
+        // Subscriptions have changed, but we've only removed a subscription so there should be no
+        // extra updates to allowed network types
+        verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+        verify(tmSubscription2, times(1)).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+    }
+
+    @Test
+    public void onSubscriptionsChanged_removeSubscriptionAndReAdd() {
+        when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
+                true);
+        triggerBroadcastReceiverAndWait();
+
+        TelephonyManager tmSubscription1 = addSubscriptionAndGetMock(1001);
+        triggerOnSubscriptionChangedAndWait();
+        mCurrentSubscriptions.remove(0);
+        triggerOnSubscriptionChangedAndWait();
+        mCurrentSubscriptions.add(getSubInfo(1001));
+        triggerOnSubscriptionChangedAndWait();
+
+        // subscriptions were updated thrice, but one of those updates removed a subscription
+        // such that the sub list was empty, so we only expect an update on the first and last
+        // updates.
+        verify(tmSubscription1, times(2)).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+    }
+
+    @Test
+    public void onSubscriptionsChanged_addSubscription_updateAllowedNetworks() {
+        // We start with 2 subIds and update subscriptions
+        TelephonyManager tmSubscription1 = addSubscriptionAndGetMock(1001);
+        TelephonyManager tmSubscription2 = addSubscriptionAndGetMock(1002);
+        triggerOnSubscriptionChangedAndWait();
+
+        // Then add a subId and update subscriptions again
+        TelephonyManager tmSubscription3 = addSubscriptionAndGetMock(1003);
+        triggerOnSubscriptionChangedAndWait();
+
+        // we only need to update the new subscription
+        verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+        verify(tmSubscription2, times(1)).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+        verify(tmSubscription3, times(1)).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+    }
+
+    @Test
+    public void onUserRestrictionUnchanged_noChangeToRestriction_noAllowedNetworksUpdated() {
+        TelephonyManager tmSubscription = addSubscriptionAndGetMock(1001);
+        triggerOnSubscriptionChangedAndWait();
+        // precondition: we've updated allowed networks to the default (2g enabled)
+        verify(tmSubscription, times(1)).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+        verify(tmSubscription, never()).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+
+        when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
+                true);
+        triggerBroadcastReceiverAndWait();
+        triggerBroadcastReceiverAndWait();
+
+        // expect we only updated once even though we got two broadcasts for user restriction
+        // updates
+        verify(tmSubscription, times(1)).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+        // extra check to ensure we haven't also somehow updated back to enabled along the way
+        verify(tmSubscription, times(1)).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+    }
+
+    @Test
+    public void onUserRestrictionChanged_restrictionChanged_allowedNetworksUpdated() {
+        // precondition: we've updated allowed networks to the default (2g enabled)
+        TelephonyManager tmSubscription = addSubscriptionAndGetMock(1001);
+        triggerOnSubscriptionChangedAndWait();
+        verify(tmSubscription, times(1)).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+        verify(tmSubscription, never()).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+
+        // update the user restriction to disallow 2g
+        reset(tmSubscription);
+        when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
+                true);
+        triggerBroadcastReceiverAndWait();
+        verify(tmSubscription, never()).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+        verify(tmSubscription, times(1)).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+
+
+        // update the user restriction to allow 2g again
+        reset(tmSubscription);
         when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
                 false);
-
-        mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
-
-        verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
+        triggerBroadcastReceiverAndWait();
+        verify(tmSubscription, times(1)).setAllowedNetworkTypesForReason(
                 TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
-        verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
-                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+        verify(tmSubscription, never()).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+
     }
 
     private SubscriptionInfo getSubInfo(int id) {
         return new SubscriptionInfo(id, "890126042XXXXXXXXXXX", 0, "T-mobile", "T-mobile", 0, 255,
                 "12345", 0, null, "310", "260", "156", false, null, null);
     }
+
+    private void triggerOnSubscriptionChangedAndWait() {
+        mExecutor.execute(() -> mChangedListener.onSubscriptionsChanged());
+        drainSingleThreadedExecutor();
+    }
+
+    private void triggerBroadcastReceiverAndWait() {
+        mTelephony2gUpdater.onReceive(mContext, new Intent());
+        drainSingleThreadedExecutor();
+    }
+
+    /**
+     * Wait for all tasks on executor up to the point of invocation to drain, then return.
+     *
+     * This helper takes advantage of the fact that we're using an immutable single threaded
+     * executor that guarantees tasks are executed in the order they are enqueued. It enqueues a
+     * task that decrements a latch and then waits on that task to finish. By definition, once the
+     * test task finishes, all previously enqueued tasks will have also completed.
+     */
+    private void drainSingleThreadedExecutor() {
+        resetExecutorLatch();
+        mExecutor.execute(() -> mLatch.countDown());
+        try {
+            mLatch.await(DRAIN_TIMEOUT, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    private void resetExecutorLatch() {
+        mLatch = new CountDownLatch(1);
+    }
+
+    /**
+     * Helper that allows you to update subInfo and have that change reflected on subsequent calls
+     * to {@link SubscriptionManager#getCompleteActiveSubscriptionInfoList()}
+     */
+    private void setupMutableSubscriptionInfoMock() {
+        var answer = new Answer<List<SubscriptionInfo>>() {
+            @Override
+            public List<SubscriptionInfo> answer(InvocationOnMock invocation) throws Throwable {
+                return mCurrentSubscriptions;
+            }
+        };
+        when(mMockSubscriptionManager.getCompleteActiveSubscriptionInfoList()).thenAnswer(answer);
+    }
+
+    private TelephonyManager addSubscriptionAndGetMock(int subId) {
+        mCurrentSubscriptions.add(getSubInfo(subId));
+        TelephonyManager tmSubscription = mock(TelephonyManager.class);
+        when(mMockTelephonyManager.createForSubscriptionId(subId)).thenReturn(tmSubscription);
+        return tmSubscription;
+    }
+
 }
diff --git a/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java b/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
index e2ebac0..921babb 100644
--- a/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
+++ b/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
@@ -70,7 +70,7 @@
 
 @RunWith(AndroidJUnit4.class)
 public class SlicePurchaseControllerTest extends TelephonyTestBase {
-    private static final String TAG = "SlicePurchaseControllerTest";
+    private static final String CARRIER = "Some Carrier";
     private static final String DAILY_NOTIFICATION_COUNT_KEY = "daily_notification_count0";
     private static final String MONTHLY_NOTIFICATION_COUNT_KEY = "monthly_notification_count0";
     private static final int YEAR = 2000;
@@ -148,6 +148,7 @@
         mSlicePurchaseController = spy(slicePurchaseController);
         doReturn(null).when(mSlicePurchaseController).createPendingIntent(
                 anyString(), anyInt(), anyBoolean());
+        doReturn(CARRIER).when(mSlicePurchaseController).getSimOperator();
         replaceInstance(SlicePurchaseController.class, "sInstances", mSlicePurchaseController,
                 Map.of(PHONE_ID, mSlicePurchaseController));
         replaceInstance(SlicePurchaseController.class, "mPremiumNetworkEntitlementApi",
@@ -272,8 +273,7 @@
     @Test
     public void testPurchasePremiumCapabilityResultFeatureNotSupported() {
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED,
                 mResult);
@@ -283,8 +283,7 @@
                 .getCachedAllowedNetworkTypesBitmask();
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertNotEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED,
                 mResult);
@@ -296,8 +295,7 @@
                 .getCachedAllowedNetworkTypesBitmask();
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED, mResult);
 
@@ -308,8 +306,7 @@
                 SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertNotEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED,
                 mResult);
@@ -325,8 +322,7 @@
                 SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(
                 TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION,
@@ -336,8 +332,7 @@
         doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mPhone).getSubId();
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertNotEquals(
                 TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION,
@@ -355,8 +350,7 @@
         doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mPhone).getSubId();
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE,
                 mResult);
@@ -365,8 +359,7 @@
         doReturn(TelephonyManager.NETWORK_TYPE_NR).when(mServiceState).getDataNetworkType();
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertNotEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE,
                 mResult);
@@ -385,8 +378,7 @@
         doReturn(null).when(mPremiumNetworkEntitlementApi).checkEntitlementStatus(anyInt());
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ENTITLEMENT_CHECK_FAILED,
                 mResult);
@@ -398,8 +390,7 @@
                 .checkEntitlementStatus(anyInt());
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED,
                 mResult);
@@ -409,8 +400,7 @@
                 PremiumNetworkEntitlementResponse.PREMIUM_NETWORK_PROVISION_STATUS_IN_PROGRESS;
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS,
                 mResult);
@@ -425,16 +415,14 @@
                 PURCHASE_CONDITION_TIMEOUT);
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ENTITLEMENT_CHECK_FAILED,
                 mResult);
 
         // retry to verify throttled
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
 
@@ -450,16 +438,14 @@
         sendValidPurchaseRequest();
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS,
                 mResult);
 
         // retry to verify same result
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS,
                 mResult);
@@ -487,8 +473,7 @@
         testPurchasePremiumCapabilityResultSuccess();
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP,
                 mResult);
@@ -507,16 +492,14 @@
         sendNetworkSlicingConfig(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, true);
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED,
                 mResult);
 
         // retry to verify same result
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED,
                 mResult);
@@ -537,8 +520,7 @@
 
         // retry to verify throttled
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
 
@@ -565,8 +547,7 @@
 
         // retry to verify throttled
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
 
@@ -596,8 +577,7 @@
 
         // retry to verify throttled
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
 
@@ -660,8 +640,7 @@
 
         // retry to verify throttled
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
 
@@ -678,8 +657,7 @@
 
         // retry to verify throttled
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
     }
@@ -741,8 +719,7 @@
 
         // send purchase request
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
 
         // verify that the purchase request was sent successfully
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
index 3f6ce98..7a01004 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
@@ -35,9 +35,14 @@
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_SCAN_TIMER_SEC_INT;
+import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL;
 import static android.telephony.CarrierConfigManager.ImsEmergency.SCAN_TYPE_NO_PREFERENCE;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_NONE;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_SETTING_ENABLED;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_VALID_EID;
+import static android.telephony.CarrierConfigManager.ImsWfc.KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL;
 import static android.telephony.DomainSelectionService.SELECTOR_TYPE_CALLING;
 import static android.telephony.NetworkRegistrationInfo.DOMAIN_CS;
 import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS;
@@ -62,6 +67,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkRequest;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IPowerManager;
@@ -82,6 +89,7 @@
 import android.telephony.WwanSelectorCallback;
 import android.telephony.ims.ImsManager;
 import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ProvisioningManager;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.TestableLooper;
 import android.util.Log;
@@ -111,12 +119,14 @@
     private static final int SLOT_0_SUB_ID = 1;
 
     @Mock private CarrierConfigManager mCarrierConfigManager;
+    @Mock private ConnectivityManager mConnectivityManager;
     @Mock private TelephonyManager mTelephonyManager;
     @Mock private WwanSelectorCallback mWwanSelectorCallback;
     @Mock private TransportSelectorCallback mTransportSelectorCallback;
     @Mock private ImsMmTelManager mMmTelManager;
     @Mock private ImsStateTracker mImsStateTracker;
     @Mock private DomainSelectorBase.DestroyListener mDestroyListener;
+    @Mock private ProvisioningManager mProvisioningManager;
 
     private Context mContext;
 
@@ -126,6 +136,7 @@
     private SelectionAttributes mSelectionAttributes;
     private @AccessNetworkConstants.RadioAccessNetworkType List<Integer> mAccessNetwork;
     private PowerManager mPowerManager;
+    private ConnectivityManager.NetworkCallback mNetworkCallback;
 
     @Before
     public void setUp() throws Exception {
@@ -141,6 +152,8 @@
                     return Context.CARRIER_CONFIG_SERVICE;
                 } else if (serviceClass == PowerManager.class) {
                     return Context.POWER_SERVICE;
+                } else if (serviceClass == ConnectivityManager.class) {
+                    return Context.CONNECTIVITY_SERVICE;
                 }
                 return super.getSystemServiceName(serviceClass);
             }
@@ -151,6 +164,9 @@
                     case (Context.POWER_SERVICE) : {
                         return mPowerManager;
                     }
+                    case (Context.CONNECTIVITY_SERVICE) : {
+                        return mConnectivityManager;
+                    }
                 }
                 return super.getSystemService(name);
             }
@@ -183,6 +199,17 @@
         when(mCarrierConfigManager.getConfigForSubId(anyInt()))
             .thenReturn(getDefaultPersistableBundle());
 
+        mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                mNetworkCallback = (ConnectivityManager.NetworkCallback)
+                        invocation.getArguments()[1];
+                return null;
+            }
+        }).when(mConnectivityManager).registerNetworkCallback(
+                any(NetworkRequest.class), any(ConnectivityManager.NetworkCallback.class));
+
         IPowerManager powerManager = mock(IPowerManager.class);
         mPowerManager = new PowerManager(mContext, powerManager, mock(IThermalService.class),
                 new Handler(mHandlerThread.getLooper()));
@@ -190,6 +217,8 @@
         ImsManager imsManager = mContext.getSystemService(ImsManager.class);
         when(imsManager.getImsMmTelManager(anyInt())).thenReturn(mMmTelManager);
         when(mMmTelManager.isAdvancedCallingSettingEnabled()).thenReturn(true);
+        doReturn(mProvisioningManager).when(imsManager).getProvisioningManager(anyInt());
+        doReturn(null).when(mProvisioningManager).getProvisioningStringValue(anyInt());
 
         when(mTransportSelectorCallback.onWwanSelected()).thenReturn(mWwanSelectorCallback);
         doAnswer(new Answer<Void>() {
@@ -882,6 +911,10 @@
 
     @Test
     public void testDefaultEpsImsRegisteredBarredScanTimeoutWifi() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
         createSelector(SLOT_0_SUB_ID);
         unsolBarringInfoChanged(true);
 
@@ -898,6 +931,121 @@
 
         assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
 
+        // Wi-Fi is not connected.
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // Wi-Fi is connected.
+        mNetworkCallback.onAvailable(null);
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+    }
+
+    @Test
+    public void testVoWifiSosPdnRequiresSettingEnabled() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+        bundle.putInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT, VOWIFI_REQUIRES_SETTING_ENABLED);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(true);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_PS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        bindImsServiceUnregistered();
+        processAllMessages();
+
+        assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        // Wi-Fi is not connected.
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // Wi-Fi is connected. But Wi-Fi calling setting is disabled.
+        mNetworkCallback.onAvailable(null);
+        when(mMmTelManager.isVoWiFiRoamingSettingEnabled()).thenReturn(false);
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // Wi-Fi is connected and Wi-Fi calling setting is enabled.
+        when(mMmTelManager.isVoWiFiSettingEnabled()).thenReturn(true);
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+    }
+
+    @Test
+    public void testVoWifiSosPdnRequiresValidEid() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+        bundle.putInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT, VOWIFI_REQUIRES_VALID_EID);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(true);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_PS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        bindImsServiceUnregistered();
+        processAllMessages();
+
+        assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        // Wi-Fi is not connected.
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // Wi-Fi is connected. But Wi-Fi calling s not activated.
+        mNetworkCallback.onAvailable(null);
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // Wi-Fi is connected and Wi-Fi calling is activated.
+        doReturn("1").when(mProvisioningManager).getProvisioningStringValue(anyInt());
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+    }
+
+    @Test
+    public void testVoWifiImsPdnRequiresNone() throws Exception {
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(true);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_PS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        bindImsServiceUnregistered();
+        processAllMessages();
+
+        assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        // Wi-Fi is not connected.
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // Wi-Fi is connected but IMS is not registered over Wi-Fi.
+        mNetworkCallback.onAvailable(null);
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // IMS is registered over Wi-Fi.
+        bindImsService(true);
         mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
 
         verify(mTransportSelectorCallback, times(1)).onWlanSelected();
@@ -1025,8 +1173,10 @@
                 CarrierConfigManager.ImsEmergency.DOMAIN_PS_NON_3GPP
                 };
         boolean imsWhenVoiceOnCs = false;
+        int voWifiRequiresCondition = VOWIFI_REQUIRES_NONE;
         int maxRetriesOverWiFi = 1;
         int cellularScanTimerSec = 10;
+        boolean voWifiOverEmergencyPdn = false;
         int scanType = SCAN_TYPE_NO_PREFERENCE;
         boolean requiresImsRegistration = false;
         boolean requiresVoLteEnabled = false;
@@ -1034,17 +1184,19 @@
         String[] cdmaPreferredNumbers = new String[] {};
 
         return getPersistableBundle(imsRats, csRats, imsRoamRats, csRoamRats,
-                domainPreference, roamDomainPreference, imsWhenVoiceOnCs, maxRetriesOverWiFi,
-                cellularScanTimerSec, scanType, requiresImsRegistration, requiresVoLteEnabled,
-                ltePreferredAfterNrFailed, cdmaPreferredNumbers);
+                domainPreference, roamDomainPreference, imsWhenVoiceOnCs,
+                voWifiRequiresCondition, maxRetriesOverWiFi, cellularScanTimerSec,
+                scanType, voWifiOverEmergencyPdn, requiresImsRegistration,
+                requiresVoLteEnabled, ltePreferredAfterNrFailed, cdmaPreferredNumbers);
     }
 
     private static PersistableBundle getPersistableBundle(
             @Nullable int[] imsRats, @Nullable int[] csRats,
             @Nullable int[] imsRoamRats, @Nullable int[] csRoamRats,
             @Nullable int[] domainPreference, @Nullable int[] roamDomainPreference,
-            boolean imsWhenVoiceOnCs, int maxRetriesOverWiFi,
-            int cellularScanTimerSec, int scanType, boolean requiresImsRegistration,
+            boolean imsWhenVoiceOnCs, int voWifiRequiresCondition,
+            int maxRetriesOverWiFi, int cellularScanTimerSec, int scanType,
+            boolean voWifiOverEmergencyPdn, boolean requiresImsRegistration,
             boolean requiresVoLteEnabled, boolean ltePreferredAfterNrFailed,
             @Nullable String[] cdmaPreferredNumbers) {
 
@@ -1075,8 +1227,10 @@
                     roamDomainPreference);
         }
         bundle.putBoolean(KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL, imsWhenVoiceOnCs);
+        bundle.putInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT, voWifiRequiresCondition);
         bundle.putInt(KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT, maxRetriesOverWiFi);
         bundle.putInt(KEY_EMERGENCY_SCAN_TIMER_SEC_INT, cellularScanTimerSec);
+        bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, voWifiOverEmergencyPdn);
         bundle.putInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT, scanType);
         bundle.putBoolean(KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL, requiresImsRegistration);
         bundle.putBoolean(KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL, requiresVoLteEnabled);
diff --git a/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java b/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java
index 3551593..430adea 100644
--- a/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java
@@ -210,6 +210,23 @@
 
     @Test
     @SmallTest
+    public void testStartAfterUnavailableWithReasonSubscriptionInactive() throws ImsException {
+        ImsStateCallback callback = setUpImsStateCallback();
+        callback.onUnavailable(ImsStateCallback.REASON_SUBSCRIPTION_INACTIVE);
+
+        mImsStateTracker.start(SUB_1);
+
+        assertTrue(isImsStateInit());
+        // One is invoked in setUpImsStateCallback and the other is invoked in start(int).
+        verify(mMmTelManager, times(2)).registerImsStateCallback(
+                any(Executor.class), any(ImsStateCallback.class));
+        // ImsStateCallback has already been set to null when onUnavailable is called.
+        verify(mMmTelManager, never()).unregisterImsStateCallback(
+                any(ImsStateCallback.class));
+    }
+
+    @Test
+    @SmallTest
     public void testUpdateServiceStateBeforeAddingListener() {
         mImsStateTracker.updateServiceState(mServiceState);
         mImsStateTracker.addServiceStateListener(mServiceStateListener);
@@ -509,6 +526,7 @@
         assertFalse(mImsStateTracker.isImsStateReady());
         assertTrue(mImsStateTracker.isImsRegistered());
         assertFalse(mImsStateTracker.isImsRegisteredOverWlan());
+        assertFalse(mImsStateTracker.isImsRegisteredOverCrossSim());
         assertEquals(AccessNetworkType.EUTRAN, mImsStateTracker.getImsAccessNetworkType());
 
         callback.onRegistered(new ImsRegistrationAttributes.Builder(
@@ -517,6 +535,7 @@
         assertFalse(mImsStateTracker.isImsStateReady());
         assertTrue(mImsStateTracker.isImsRegistered());
         assertFalse(mImsStateTracker.isImsRegisteredOverWlan());
+        assertFalse(mImsStateTracker.isImsRegisteredOverCrossSim());
         assertEquals(AccessNetworkType.NGRAN, mImsStateTracker.getImsAccessNetworkType());
 
         callback.onRegistered(new ImsRegistrationAttributes.Builder(
@@ -525,6 +544,7 @@
         assertFalse(mImsStateTracker.isImsStateReady());
         assertTrue(mImsStateTracker.isImsRegistered());
         assertTrue(mImsStateTracker.isImsRegisteredOverWlan());
+        assertFalse(mImsStateTracker.isImsRegisteredOverCrossSim());
         assertEquals(AccessNetworkType.IWLAN, mImsStateTracker.getImsAccessNetworkType());
 
         callback.onRegistered(new ImsRegistrationAttributes.Builder(
@@ -533,6 +553,7 @@
         assertFalse(mImsStateTracker.isImsStateReady());
         assertTrue(mImsStateTracker.isImsRegistered());
         assertTrue(mImsStateTracker.isImsRegisteredOverWlan());
+        assertTrue(mImsStateTracker.isImsRegisteredOverCrossSim());
         assertEquals(AccessNetworkType.IWLAN, mImsStateTracker.getImsAccessNetworkType());
 
         callback.onRegistered(new ImsRegistrationAttributes.Builder(
@@ -541,6 +562,7 @@
         assertFalse(mImsStateTracker.isImsStateReady());
         assertTrue(mImsStateTracker.isImsRegistered());
         assertFalse(mImsStateTracker.isImsRegisteredOverWlan());
+        assertFalse(mImsStateTracker.isImsRegisteredOverCrossSim());
         assertEquals(AccessNetworkType.UNKNOWN, mImsStateTracker.getImsAccessNetworkType());
 
         verify(mImsStateListener, times(5)).onImsRegistrationStateChanged();