Merge changes from topic "tc_change_22102807_16"

* changes:
  [automerged blank] Import translations. DO NOT MERGE ANYWHERE 2p: bdaf53bb24
  Import translations. DO NOT MERGE ANYWHERE
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index fd8a7ee..6cbc051 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -579,7 +579,7 @@
     <string name="onscreenEndCallText" msgid="6138725377654842757">"Finalizar"</string>
     <string name="onscreenShowDialpadText" msgid="658465753816164079">"Teclado"</string>
     <string name="onscreenMuteText" msgid="5470306116733843621">"Desativar som"</string>
-    <string name="onscreenAddCallText" msgid="9075675082903611677">"Adicionar chamada"</string>
+    <string name="onscreenAddCallText" msgid="9075675082903611677">"Adicionar ligação"</string>
     <string name="onscreenMergeCallsText" msgid="3692389519611225407">"Juntar chamadas"</string>
     <string name="onscreenSwapCallsText" msgid="2682542150803377991">"Trocar"</string>
     <string name="onscreenManageCallsText" msgid="1162047856081836469">"Gerenciar chamadas"</string>
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 88b4443..aa6f7f9 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -385,6 +385,7 @@
     private SharedPreferences mTelephonySharedPreferences;
     private PhoneConfigurationManager mPhoneConfigurationManager;
     private final RadioInterfaceCapabilityController mRadioInterfaceCapabilities;
+    private final Telephony2gUpdater mTelephony2gUpdater;
 
     /** User Activity */
     private AtomicBoolean mNotifyUserActivity;
@@ -2401,6 +2402,9 @@
         mRadioInterfaceCapabilities = RadioInterfaceCapabilityController.getInstance();
         mNotifyUserActivity = new AtomicBoolean(false);
         PropertyInvalidatedCache.invalidateCache(TelephonyManager.CACHE_KEY_PHONE_ACCOUNT_TO_SUBID);
+        mTelephony2gUpdater = new Telephony2gUpdater(
+                Executors.newSingleThreadExecutor(), mApp);
+        mTelephony2gUpdater.init();
         publish();
     }
 
@@ -6804,8 +6808,7 @@
             int phoneId = mSubscriptionController.getPhoneId(subId);
             Phone phone = PhoneFactory.getPhone(phoneId);
             if (phone != null) {
-                boolean retVal;
-                retVal = phone.getDataSettingsManager().isDataEnabled();
+                boolean retVal = phone.getDataSettingsManager().isDataEnabled();
                 if (DBG) log("isDataEnabled: " + retVal + ", subId=" + subId);
                 return retVal;
             } else {
diff --git a/src/com/android/phone/Telephony2gUpdater.java b/src/com/android/phone/Telephony2gUpdater.java
new file mode 100644
index 0000000..0919385
--- /dev/null
+++ b/src/com/android/phone/Telephony2gUpdater.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.UserManager;
+import android.telephony.RadioAccessFamily;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.RILConstants;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * A {@link BroadcastReceiver} that ensures that user restrictions are correctly applied to
+ * telephony.
+ * 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.
+ *
+ * Callers are expected to call {@code init()} and keep an instance of this class alive.
+ */
+public class Telephony2gUpdater extends BroadcastReceiver {
+    private static final String TAG = "TelephonyUserManagerReceiver";
+
+    // 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.
+    private final Executor mExecutor;
+    private final Context mContext;
+    private final long mBaseAllowedNetworks;
+
+    public Telephony2gUpdater(Executor executor, Context context) {
+        this(executor, context,
+                RadioAccessFamily.getRafFromNetworkType(RILConstants.PREFERRED_NETWORK_MODE));
+    }
+
+    public Telephony2gUpdater(Executor executor, Context context,
+            long baseAllowedNetworks) {
+        mExecutor = executor;
+        mContext = context;
+        mBaseAllowedNetworks = baseAllowedNetworks;
+    }
+
+    /**
+     * Register the given instance as a {@link BroadcastReceiver} and a {@link
+     * SubscriptionManager.OnSubscriptionsChangedListener}.
+     */
+    public void init() {
+        mContext.getSystemService(SubscriptionManager.class).addOnSubscriptionsChangedListener(
+                mExecutor, new SubscriptionListener());
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED);
+        mContext.registerReceiver(this, filter);
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (context == null || intent == null) return;
+        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();
+        });
+    }
+
+    /**
+     * Update all active subscriptions with allowed network types depending on the current state
+     * of the {@link UserManager.DISALLOW_2G}.
+     */
+    @VisibleForTesting
+    public void handleUserRestrictionsChanged(Context context) {
+        UserManager um = context.getSystemService(UserManager.class);
+        TelephonyManager tm = context.getSystemService(TelephonyManager.class);
+        SubscriptionManager sm = context.getSystemService(SubscriptionManager.class);
+        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) {
+                allowedNetworkTypes &= ~twoGBitmask;
+            } else {
+                allowedNetworkTypes |= twoGBitmask;
+            }
+            telephonyManager.setAllowedNetworkTypesForReason(
+                    TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS,
+                    allowedNetworkTypes);
+        }
+    }
+
+    private class SubscriptionListener extends SubscriptionManager.OnSubscriptionsChangedListener {
+        @Override
+        public void onSubscriptionsChanged() {
+            Log.i(TAG, "Running handler for subscription change.");
+            handleUserRestrictionsChanged(mContext);
+        }
+    }
+
+}
diff --git a/src/com/android/phone/settings/RadioInfo.java b/src/com/android/phone/settings/RadioInfo.java
index 7c2c829..c6dbfc6 100644
--- a/src/com/android/phone/settings/RadioInfo.java
+++ b/src/com/android/phone/settings/RadioInfo.java
@@ -72,13 +72,6 @@
 import android.telephony.TelephonyDisplayInfo;
 import android.telephony.TelephonyManager;
 import android.telephony.data.NetworkSlicingConfig;
-import android.telephony.ims.ImsException;
-import android.telephony.ims.ImsManager;
-import android.telephony.ims.ImsMmTelManager;
-import android.telephony.ims.ImsRcsManager;
-import android.telephony.ims.ProvisioningManager;
-import android.telephony.ims.feature.MmTelFeature;
-import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.Menu;
@@ -99,6 +92,9 @@
 import androidx.appcompat.app.AlertDialog.Builder;
 import androidx.appcompat.app.AppCompatActivity;
 
+import com.android.ims.ImsConfig;
+import com.android.ims.ImsException;
+import com.android.ims.ImsManager;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.euicc.EuiccConnector;
@@ -181,6 +177,18 @@
      */
     private static final int ALWAYS_ON_DSDS_MODE = 1;
 
+    private static final int IMS_VOLTE_PROVISIONED_CONFIG_ID =
+            ImsConfig.ConfigConstants.VLT_SETTING_ENABLED;
+
+    private static final int IMS_VT_PROVISIONED_CONFIG_ID =
+            ImsConfig.ConfigConstants.LVC_SETTING_ENABLED;
+
+    private static final int IMS_WFC_PROVISIONED_CONFIG_ID =
+            ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED;
+
+    private static final int EAB_PROVISIONED_CONFIG_ID =
+            ImsConfig.ConfigConstants.EAB_SETTING_ENABLED;
+
     //Values in must match CELL_INFO_REFRESH_RATES
     private static final String[] CELL_INFO_REFRESH_RATE_LABELS = {
             "Disabled",
@@ -285,7 +293,6 @@
     private TelephonyManager mTelephonyManager;
     private ImsManager mImsManager = null;
     private Phone mPhone = null;
-    private ProvisioningManager mProvisioningManager = null;
 
     private String mPingHostnameResultV4;
     private String mPingHostnameResultV6;
@@ -419,9 +426,8 @@
         mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId);
 
         // update the phoneId
+        mImsManager = ImsManager.getInstance(getApplicationContext(), phoneIndex);
         mPhone = PhoneFactory.getPhone(phoneIndex);
-        mImsManager = new ImsManager(mPhone.getContext());
-        mProvisioningManager = ProvisioningManager.createForSubscriptionId(mPhone.getSubId());
 
         updateAllFields();
     }
@@ -481,8 +487,7 @@
         mTelephonyManager = ((TelephonyManager) getSystemService(TELEPHONY_SERVICE))
                 .createForSubscriptionId(mPhone.getSubId());
 
-        mImsManager = new ImsManager(mPhone.getContext());
-        mProvisioningManager = ProvisioningManager.createForSubscriptionId(mPhone.getSubId());
+        mImsManager = ImsManager.getInstance(getApplicationContext(), mPhone.getPhoneId());
 
         sPhoneIndexLabels = getPhoneIndexLabels(mTelephonyManager);
 
@@ -550,7 +555,7 @@
         mImsWfcProvisionedSwitch = (Switch) findViewById(R.id.wfc_provisioned_switch);
         mEabProvisionedSwitch = (Switch) findViewById(R.id.eab_provisioned_switch);
 
-        if (!isImsSupportedOnDevice(mPhone.getContext())) {
+        if (!ImsManager.isImsSupportedOnDevice(mPhone.getContext())) {
             mImsVolteProvisionedSwitch.setVisibility(View.GONE);
             mImsVtProvisionedSwitch.setVisibility(View.GONE);
             mImsWfcProvisionedSwitch.setVisibility(View.GONE);
@@ -781,8 +786,7 @@
                 R.string.radioInfo_menu_viewFDN).setOnMenuItemClickListener(mViewFDNCallback);
         menu.add(1, MENU_ITEM_VIEW_SDN, 0,
                 R.string.radioInfo_menu_viewSDN).setOnMenuItemClickListener(mViewSDNCallback);
-
-        if (isImsSupportedOnDevice(mPhone.getContext())) {
+        if (ImsManager.isImsSupportedOnDevice(mPhone.getContext())) {
             menu.add(1, MENU_ITEM_GET_IMS_STATUS,
                     0, R.string.radioInfo_menu_getIMS).setOnMenuItemClickListener(mGetImsStatus);
         }
@@ -1510,38 +1514,34 @@
         mRadioPowerOnSwitch.setOnCheckedChangeListener(mRadioPowerOnChangeListener);
     }
 
-    private void setImsVolteProvisionedState(boolean state) {
+    void setImsVolteProvisionedState(boolean state) {
         Log.d(TAG, "setImsVolteProvisioned state: " + ((state) ? "on" : "off"));
-        setImsConfigProvisionedState(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE, state);
+        setImsConfigProvisionedState(IMS_VOLTE_PROVISIONED_CONFIG_ID, state);
     }
 
-    private void setImsVtProvisionedState(boolean state) {
+    void setImsVtProvisionedState(boolean state) {
         Log.d(TAG, "setImsVtProvisioned() state: " + ((state) ? "on" : "off"));
-        setImsConfigProvisionedState(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO,
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE, state);
+        setImsConfigProvisionedState(IMS_VT_PROVISIONED_CONFIG_ID, state);
     }
 
-    private void setImsWfcProvisionedState(boolean state) {
+    void setImsWfcProvisionedState(boolean state) {
         Log.d(TAG, "setImsWfcProvisioned() state: " + ((state) ? "on" : "off"));
-        setImsConfigProvisionedState(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
-                ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN, state);
+        setImsConfigProvisionedState(IMS_WFC_PROVISIONED_CONFIG_ID, state);
     }
 
-    private void setEabProvisionedState(boolean state) {
+    void setEabProvisionedState(boolean state) {
         Log.d(TAG, "setEabProvisioned() state: " + ((state) ? "on" : "off"));
-        setRcsConfigProvisionedState(ImsRcsManager.CAPABILITY_TYPE_PRESENCE_UCE,
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE, state);
+        setImsConfigProvisionedState(EAB_PROVISIONED_CONFIG_ID, state);
     }
 
-    private void setImsConfigProvisionedState(int capability, int tech, boolean state) {
-        if (mProvisioningManager != null) {
+    void setImsConfigProvisionedState(int configItem, boolean state) {
+        if (mPhone != null && mImsManager != null) {
             mQueuedWork.execute(new Runnable() {
                 public void run() {
                     try {
-                        mProvisioningManager.setProvisioningStatusForCapability(
-                                capability, tech, state);
-                    } catch (RuntimeException e) {
+                        mImsManager.getConfigInterface().setProvisionedValue(
+                                configItem, state ? 1 : 0);
+                    } catch (ImsException e) {
                         Log.e(TAG, "setImsConfigProvisioned() exception:", e);
                     }
                 }
@@ -1549,71 +1549,6 @@
         }
     }
 
-    private void setRcsConfigProvisionedState(int capability, int tech, boolean state) {
-        if (mProvisioningManager != null) {
-            mQueuedWork.execute(new Runnable() {
-                public void run() {
-                    try {
-                        mProvisioningManager.setRcsProvisioningStatusForCapability(
-                                capability, tech, state);
-                    } catch (RuntimeException e) {
-                        Log.e(TAG, "setRcsConfigProvisioned() exception:", e);
-                    }
-                }
-            });
-        }
-    }
-
-    private boolean isImsVolteProvisioningRequired() {
-        return isImsConfigProvisioningRequired(
-                MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
-    }
-
-    private boolean isImsVtProvisioningRequired() {
-        return isImsConfigProvisioningRequired(
-                MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO,
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
-    }
-
-    private boolean isImsWfcProvisioningRequired() {
-        return isImsConfigProvisioningRequired(
-                MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
-                ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN);
-    }
-
-    private boolean isEabProvisioningRequired() {
-        return isRcsConfigProvisioningRequired(
-                ImsRcsManager.CAPABILITY_TYPE_PRESENCE_UCE,
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
-    }
-
-    private boolean isImsConfigProvisioningRequired(int capability, int tech) {
-        if (mProvisioningManager != null) {
-            try {
-                return mProvisioningManager.isProvisioningRequiredForCapability(
-                        capability, tech);
-            } catch (RuntimeException e) {
-                Log.e(TAG, "isImsConfigProvisioningRequired() exception:", e);
-            }
-        }
-
-        return false;
-    }
-
-    private boolean isRcsConfigProvisioningRequired(int capability, int tech) {
-        if (mProvisioningManager != null) {
-            try {
-                return mProvisioningManager.isRcsProvisioningRequiredForCapability(
-                        capability, tech);
-            } catch (RuntimeException e) {
-                Log.e(TAG, "isRcsConfigProvisioningRequired() exception:", e);
-            }
-        }
-
-        return false;
-    }
-
     OnCheckedChangeListener mRadioPowerOnChangeListener = new OnCheckedChangeListener() {
         @Override
         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
@@ -1649,8 +1584,11 @@
     };
 
     private boolean isImsVolteProvisioned() {
-        return getImsConfigProvisionedState(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        if (mImsManager != null) {
+            return mImsManager.isVolteEnabledByPlatform()
+                && mImsManager.isVolteProvisionedOnDevice();
+        }
+        return false;
     }
 
     OnCheckedChangeListener mImsVolteCheckedChangeListener = new OnCheckedChangeListener() {
@@ -1661,8 +1599,11 @@
     };
 
     private boolean isImsVtProvisioned() {
-        return getImsConfigProvisionedState(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO,
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        if (mImsManager != null) {
+            return mImsManager.isVtEnabledByPlatform()
+                && mImsManager.isVtProvisionedOnDevice();
+        }
+        return false;
     }
 
     OnCheckedChangeListener mImsVtCheckedChangeListener = new OnCheckedChangeListener() {
@@ -1673,8 +1614,11 @@
     };
 
     private boolean isImsWfcProvisioned() {
-        return getImsConfigProvisionedState(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
-                ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN);
+        if (mImsManager != null) {
+            return mImsManager.isWfcEnabledByPlatform()
+                && mImsManager.isWfcProvisionedOnDevice();
+        }
+        return false;
     }
 
     OnCheckedChangeListener mImsWfcCheckedChangeListener = new OnCheckedChangeListener() {
@@ -1685,8 +1629,7 @@
     };
 
     private boolean isEabProvisioned() {
-        return getRcsConfigProvisionedState(ImsRcsManager.CAPABILITY_TYPE_PRESENCE_UCE,
-                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        return isFeatureProvisioned(EAB_PROVISIONED_CONFIG_ID, false);
     }
 
     OnCheckedChangeListener mEabCheckedChangeListener = new OnCheckedChangeListener() {
@@ -1696,30 +1639,23 @@
         }
     };
 
-    private boolean getImsConfigProvisionedState(int capability, int tech) {
-        if (mProvisioningManager != null) {
+    private boolean isFeatureProvisioned(int featureId, boolean defaultValue) {
+        boolean provisioned = defaultValue;
+        if (mImsManager != null) {
             try {
-                return mProvisioningManager.getProvisioningStatusForCapability(
-                        capability, tech);
-            } catch (RuntimeException e) {
-                Log.e(TAG, "getImsConfigProvisionedState() exception:", e);
+                ImsConfig imsConfig = mImsManager.getConfigInterface();
+                if (imsConfig != null) {
+                    provisioned =
+                            (imsConfig.getProvisionedValue(featureId)
+                                    == ImsConfig.FeatureValueConstants.ON);
+                }
+            } catch (ImsException ex) {
+                Log.e(TAG, "isFeatureProvisioned() exception:", ex);
             }
         }
 
-        return false;
-    }
-
-    private boolean getRcsConfigProvisionedState(int capability, int tech) {
-        if (mProvisioningManager != null) {
-            try {
-                return mProvisioningManager.getRcsProvisioningStatusForCapability(
-                        capability, tech);
-            } catch (RuntimeException e) {
-                Log.e(TAG, "getRcsConfigProvisionedState() exception:", e);
-            }
-        }
-
-        return false;
+        log("isFeatureProvisioned() featureId=" + featureId + " provisioned=" + provisioned);
+        return provisioned;
     }
 
     private boolean isEabEnabledByPlatform() {
@@ -1738,56 +1674,35 @@
     }
 
     private void updateImsProvisionedState() {
-        if (!isImsSupportedOnDevice(mPhone.getContext())) {
+        if (!ImsManager.isImsSupportedOnDevice(mPhone.getContext())) {
             return;
         }
-
-        updateServiceEnabledByPlatform();
-
-        updateEabProvisionedSwitch(isEabEnabledByPlatform());
-    }
-
-    private void updateVolteProvisionedSwitch(boolean isEnabledByPlatform) {
-        boolean isProvisioned = isEnabledByPlatform && isImsVolteProvisioned();
-        log("updateImsProvisionedState isProvisioned" + isProvisioned);
-
+        log("updateImsProvisionedState isImsVolteProvisioned()=" + isImsVolteProvisioned());
+        //delightful hack to prevent on-checked-changed calls from
+        //actually forcing the ims provisioning to its transient/current value.
         mImsVolteProvisionedSwitch.setOnCheckedChangeListener(null);
-        mImsVolteProvisionedSwitch.setChecked(isProvisioned);
+        mImsVolteProvisionedSwitch.setChecked(isImsVolteProvisioned());
         mImsVolteProvisionedSwitch.setOnCheckedChangeListener(mImsVolteCheckedChangeListener);
         mImsVolteProvisionedSwitch.setEnabled(!IS_USER_BUILD
-                && isEnabledByPlatform && isImsVolteProvisioningRequired());
-    }
-
-    private void updateVtProvisionedSwitch(boolean isEnabledByPlatform) {
-        boolean isProvisioned = isEnabledByPlatform && isImsVtProvisioned();
-        log("updateVtProvisionedSwitch isProvisioned" + isProvisioned);
+                && mImsManager.isVolteEnabledByPlatform());
 
         mImsVtProvisionedSwitch.setOnCheckedChangeListener(null);
-        mImsVtProvisionedSwitch.setChecked(isProvisioned);
+        mImsVtProvisionedSwitch.setChecked(isImsVtProvisioned());
         mImsVtProvisionedSwitch.setOnCheckedChangeListener(mImsVtCheckedChangeListener);
         mImsVtProvisionedSwitch.setEnabled(!IS_USER_BUILD
-                && isEnabledByPlatform && isImsVtProvisioningRequired());
-    }
-
-    private void updateWfcProvisionedSwitch(boolean isEnabledByPlatform) {
-        boolean isProvisioned = isEnabledByPlatform && isImsWfcProvisioned();
-        log("updateWfcProvisionedSwitch isProvisioned" + isProvisioned);
+                && mImsManager.isVtEnabledByPlatform());
 
         mImsWfcProvisionedSwitch.setOnCheckedChangeListener(null);
-        mImsWfcProvisionedSwitch.setChecked(isProvisioned);
+        mImsWfcProvisionedSwitch.setChecked(isImsWfcProvisioned());
         mImsWfcProvisionedSwitch.setOnCheckedChangeListener(mImsWfcCheckedChangeListener);
         mImsWfcProvisionedSwitch.setEnabled(!IS_USER_BUILD
-                && isEnabledByPlatform && isImsWfcProvisioningRequired());
-    }
-
-    private void updateEabProvisionedSwitch(boolean isEnabledByPlatform) {
-        log("updateEabProvisionedSwitch isEabWfcProvisioned()=" + isEabProvisioned());
+                && mImsManager.isWfcEnabledByPlatform());
 
         mEabProvisionedSwitch.setOnCheckedChangeListener(null);
         mEabProvisionedSwitch.setChecked(isEabProvisioned());
         mEabProvisionedSwitch.setOnCheckedChangeListener(mEabCheckedChangeListener);
         mEabProvisionedSwitch.setEnabled(!IS_USER_BUILD
-                && isEnabledByPlatform && isEabProvisioningRequired());
+                && isEabEnabledByPlatform());
     }
 
     OnClickListener mDnsCheckButtonHandler = new OnClickListener() {
@@ -2026,28 +1941,4 @@
         intent.putExtra("isDefault", isChecked);
         sendBroadcast(intent);
     }
-
-    private boolean isImsSupportedOnDevice(Context context) {
-        return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS);
-    }
-
-    private void updateServiceEnabledByPlatform() {
-        ImsMmTelManager imsMmTelManager = mImsManager.getImsMmTelManager(mPhone.getSubId());
-        try {
-            imsMmTelManager.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
-                    AccessNetworkConstants.TRANSPORT_TYPE_WWAN, getMainExecutor(), (result) -> {
-                        updateVolteProvisionedSwitch(result);
-                    });
-            imsMmTelManager.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO,
-                    AccessNetworkConstants.TRANSPORT_TYPE_WWAN, getMainExecutor(), (result) -> {
-                        updateVtProvisionedSwitch(result);
-                    });
-            imsMmTelManager.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
-                    AccessNetworkConstants.TRANSPORT_TYPE_WLAN, getMainExecutor(), (result) -> {
-                        updateWfcProvisionedSwitch(result);
-                    });
-        } catch (ImsException e) {
-            e.printStackTrace();
-        }
-    }
 }
diff --git a/src/com/android/phone/slicestore/SliceStore.java b/src/com/android/phone/slicestore/SliceStore.java
index 20245f6..bb66973 100644
--- a/src/com/android/phone/slicestore/SliceStore.java
+++ b/src/com/android/phone/slicestore/SliceStore.java
@@ -16,6 +16,7 @@
 
 package com.android.phone.slicestore;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.PendingIntent;
@@ -27,7 +28,6 @@
 import android.net.ConnectivityManager;
 import android.os.AsyncResult;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Message;
 import android.os.PersistableBundle;
 import android.telephony.AnomalyReporter;
@@ -42,6 +42,8 @@
 
 import com.android.internal.telephony.Phone;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.Arrays;
@@ -68,6 +70,29 @@
 public class SliceStore extends Handler {
     @NonNull private static final String TAG = "SliceStore";
 
+    /** Unknown failure code. */
+    public static final int FAILURE_CODE_UNKNOWN = 0;
+    /** Network boost purchase failed because the carrier URL is unavailable. */
+    public static final int FAILURE_CODE_CARRIER_URL_UNAVAILABLE = 1;
+    /** Network boost purchase failed because the server is unreachable. */
+    public static final int FAILURE_CODE_SERVER_UNREACHABLE = 2;
+    /** Network boost purchase failed because user authentication failed. */
+    public static final int FAILURE_CODE_AUTHENTICATION_FAILED = 3;
+    /** Network boost purchase failed because the payment failed. */
+    public static final int FAILURE_CODE_PAYMENT_FAILED = 4;
+
+    /**
+     * Failure codes that the carrier website can return when a premium capability purchase fails.
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "FAILURE_CODE_" }, value = {
+            FAILURE_CODE_UNKNOWN,
+            FAILURE_CODE_CARRIER_URL_UNAVAILABLE,
+            FAILURE_CODE_SERVER_UNREACHABLE,
+            FAILURE_CODE_AUTHENTICATION_FAILED,
+            FAILURE_CODE_PAYMENT_FAILED})
+    public @interface FailureCode {}
+
     /** Value for an invalid premium capability. */
     public static final int PREMIUM_CAPABILITY_INVALID = -1;
 
@@ -77,8 +102,16 @@
     private static final int EVENT_SLICING_CONFIG_CHANGED = 2;
     /** Display booster notification. */
     private static final int EVENT_DISPLAY_BOOSTER_NOTIFICATION = 3;
-    /** Boost was not purchased within the timeout specified by carrier configs. */
+    /**
+     * Premium capability was not purchased within the timeout specified by
+     * {@link CarrierConfigManager#KEY_PREMIUM_CAPABILITY_NOTIFICATION_DISPLAY_TIMEOUT_MILLIS_LONG}.
+     */
     private static final int EVENT_PURCHASE_TIMEOUT = 4;
+    /**
+     * Network did not set up the slicing configuration within the timeout specified by
+     * {@link CarrierConfigManager#KEY_PREMIUM_CAPABILITY_NETWORK_SETUP_TIME_MILLIS_LONG}.
+     */
+    private static final int EVENT_SETUP_TIMEOUT = 5;
 
     /** UUID to report an anomaly when a premium capability is throttled twice in a row. */
     private static final String UUID_CAPABILITY_THROTTLED_TWICE =
@@ -87,6 +120,13 @@
     private static final String UUID_INVALID_PHONE_ID = "ced79f1a-8ac0-4260-8cf3-08b54c0494f3";
     /** UUID to report an anomaly when receiving an unknown action. */
     private static final String UUID_UNKNOWN_ACTION = "0197efb0-dab1-4b0a-abaf-ac9336ec7923";
+    /** UUID to report an anomaly when receiving an unknown failure code with a non-empty reason. */
+    private static final String UUID_UNKNOWN_FAILURE_CODE = "76943b23-4415-400c-9855-b534fc4fc62c";
+    /**
+     * UUID to report an anomaly when the network fails to set up a slicing configuration after
+     * the user purchases a premium capability.
+     */
+    private static final String UUID_NETWORK_SETUP_FAILED = "12eeffbf-08f8-40ed-9a00-d344199552fc";
 
     /** Action to start the SliceStore application and display the network boost notification. */
     public static final String ACTION_START_SLICE_STORE =
@@ -106,6 +146,9 @@
     /** Action indicating the purchase request was not made on the default data subscription. */
     private static final String ACTION_SLICE_STORE_RESPONSE_NOT_DEFAULT_DATA =
             "com.android.phone.slicestore.action.SLICE_STORE_RESPONSE_NOT_DEFAULT_DATA";
+    /** Action indicating the purchase request was successful. */
+    private static final String ACTION_SLICE_STORE_RESPONSE_SUCCESS =
+            "com.android.phone.slicestore.action.SLICE_STORE_RESPONSE_SUCCESS";
 
     /** Extra for the phone index to send to the SliceStore application. */
     public static final String EXTRA_PHONE_ID = "com.android.phone.slicestore.extra.PHONE_ID";
@@ -114,6 +157,15 @@
     /** Extra for the requested premium capability to purchase from the SliceStore application. */
     public static final String EXTRA_PREMIUM_CAPABILITY =
             "com.android.phone.slicestore.extra.PREMIUM_CAPABILITY";
+    /** Extra for the duration of the purchased premium capability. */
+    public static final String EXTRA_PURCHASE_DURATION =
+            "com.android.phone.slicestore.extra.PURCHASE_DURATION";
+    /** Extra for the {@link FailureCode} why the premium capability purchase failed. */
+    public static final String EXTRA_FAILURE_CODE =
+            "com.android.phone.slicestore.extra.FAILURE_CODE";
+    /** Extra for the human-readable reason why the premium capability purchase failed. */
+    public static final String EXTRA_FAILURE_REASON =
+            "com.android.phone.slicestore.extra.FAILURE_REASON";
     /**
      * Extra for the application name requesting to purchase the premium capability
      * from the SliceStore application.
@@ -131,6 +183,8 @@
      * Extra for the carrier error PendingIntent that the SliceStore application can send as a
      * response if the premium capability purchase request failed due to a carrier error.
      * Sends {@link #ACTION_SLICE_STORE_RESPONSE_CARRIER_ERROR}.
+     * Sender can modify the intent to specify the failure code and reason for failure with
+     * {@link #EXTRA_FAILURE_CODE} and {@link #EXTRA_FAILURE_REASON}.
      */
     public static final String EXTRA_INTENT_CARRIER_ERROR =
             "com.android.phone.slicestore.extra.INTENT_CARRIER_ERROR";
@@ -150,6 +204,15 @@
      */
     public static final String EXTRA_INTENT_NOT_DEFAULT_DATA =
             "com.android.phone.slicestore.extra.INTENT_NOT_DEFAULT_DATA";
+    /**
+     * Extra for the success PendingIntent that the SliceStore application can send as a response
+     * if the premium capability purchase request was successful.
+     * Sends {@link #ACTION_SLICE_STORE_RESPONSE_SUCCESS}.
+     * Sender can modify the intent to specify a purchase duration with
+     * {@link #EXTRA_PURCHASE_DURATION}.
+     */
+    public static final String EXTRA_INTENT_SUCCESS =
+            "com.android.phone.slicestore.extra.INTENT_SUCCESS";
 
     /** Component name to send an explicit broadcast to SliceStoreBroadcastReceiver. */
     private static final ComponentName SLICE_STORE_COMPONENT_NAME =
@@ -161,8 +224,8 @@
 
     /** The Phone instance used to create the SliceStore */
     @NonNull private final Phone mPhone;
-    /** The set of purchased capabilities. */
-    @NonNull private final Set<Integer> mPurchasedCapabilities = new HashSet<>();
+    /** The set of capabilities that are pending network setup. */
+    @NonNull private final Set<Integer> mPendingSetupCapabilities = new HashSet<>();
     /** The set of throttled capabilities. */
     @NonNull private final Set<Integer> mThrottledCapabilities = new HashSet<>();
     /** A map of pending capabilities to the onComplete message for the purchase request. */
@@ -174,7 +237,7 @@
     @Nullable private NetworkSlicingConfig mSlicingConfig;
 
     private class SliceStoreBroadcastReceiver extends BroadcastReceiver {
-        private final @TelephonyManager.PremiumCapability int mCapability;
+        @TelephonyManager.PremiumCapability private final int mCapability;
 
         SliceStoreBroadcastReceiver(@TelephonyManager.PremiumCapability int capability) {
             mCapability = capability;
@@ -191,11 +254,9 @@
             int capability = intent.getIntExtra(EXTRA_PREMIUM_CAPABILITY,
                     PREMIUM_CAPABILITY_INVALID);
             if (SliceStore.getInstance(phoneId) == null) {
-                String logStr = "SliceStoreBroadcastReceiver( "
+                reportAnomaly(UUID_INVALID_PHONE_ID, "SliceStoreBroadcastReceiver( "
                         + TelephonyManager.convertPremiumCapabilityToString(mCapability)
-                        + ") received invalid phoneId: " + phoneId;
-                loge(logStr);
-                AnomalyReporter.reportAnomaly(UUID.fromString(UUID_INVALID_PHONE_ID), logStr);
+                        + ") received invalid phoneId: " + phoneId);
                 return;
             } else if (capability != mCapability) {
                 logd("SliceStoreBroadcastReceiver("
@@ -214,11 +275,10 @@
                     break;
                 }
                 case ACTION_SLICE_STORE_RESPONSE_CARRIER_ERROR: {
-                    logd("Carrier error for capability: "
-                            + TelephonyManager.convertPremiumCapabilityToString(capability));
-                    SliceStore.getInstance(phoneId).sendPurchaseResultFromSliceStore(capability,
-                            TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_ERROR,
-                            true);
+                    int failureCode = intent.getIntExtra(EXTRA_FAILURE_CODE, FAILURE_CODE_UNKNOWN);
+                    String failureReason = intent.getStringExtra(EXTRA_FAILURE_REASON);
+                    SliceStore.getInstance(phoneId).onCarrierError(
+                            capability, failureCode, failureReason);
                     break;
                 }
                 case ACTION_SLICE_STORE_RESPONSE_REQUEST_FAILED: {
@@ -238,12 +298,15 @@
                             false);
                     break;
                 }
+                case ACTION_SLICE_STORE_RESPONSE_SUCCESS: {
+                    long duration = intent.getLongExtra(EXTRA_PURCHASE_DURATION, 0);
+                    SliceStore.getInstance(phoneId).onCarrierSuccess(capability, duration);
+                    break;
+                }
                 default:
-                    String logStr = "SliceStoreBroadcastReceiver("
+                    reportAnomaly(UUID_UNKNOWN_ACTION, "SliceStoreBroadcastReceiver("
                             + TelephonyManager.convertPremiumCapabilityToString(mCapability)
-                            + ") received unknown action: " + action;
-                    loge(logStr);
-                    AnomalyReporter.reportAnomaly(UUID.fromString(UUID_UNKNOWN_ACTION), logStr);
+                            + ") received unknown action: " + action);
                     break;
             }
         }
@@ -276,7 +339,7 @@
     }
 
     private SliceStore(@NonNull Phone phone) {
-        super(Looper.myLooper());
+        super(phone.getLooper());
         mPhone = phone;
         // TODO: Create a cached value for slicing config in DataIndication and initialize here
         mPhone.mCi.registerForSlicingConfigChanged(this, EVENT_SLICING_CONFIG_CHANGED, null);
@@ -297,6 +360,7 @@
                 NetworkSlicingConfig config = (NetworkSlicingConfig) ar.result;
                 logd("EVENT_SLICING_CONFIG_CHANGED: from " + mSlicingConfig + " to " + config);
                 mSlicingConfig = config;
+                onSlicingConfigChanged();
                 break;
             }
             case EVENT_DISPLAY_BOOSTER_NOTIFICATION: {
@@ -314,6 +378,12 @@
                 onTimeout(capability);
                 break;
             }
+            case EVENT_SETUP_TIMEOUT:
+                int capability = (int) msg.obj;
+                logd("EVENT_SETUP_TIMEOUT: for capability "
+                        + TelephonyManager.convertPremiumCapabilityToString(capability));
+                onSetupTimeout(capability);
+                break;
             default:
                 loge("Unknown event: " + msg.obj);
         }
@@ -380,13 +450,18 @@
                     onComplete);
             return;
         }
-        if (mPurchasedCapabilities.contains(capability) || isSlicingConfigActive(capability)) {
-            // TODO (b/245882601): Handle capability expiry
+        if (isSlicingConfigActive(capability)) {
             sendPurchaseResult(capability,
                     TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED,
                     onComplete);
             return;
         }
+        if (mPendingSetupCapabilities.contains(capability)) {
+            sendPurchaseResult(capability,
+                    TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP,
+                    onComplete);
+            return;
+        }
         if (mThrottledCapabilities.contains(capability)) {
             sendPurchaseResult(capability,
                     TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED,
@@ -456,10 +531,20 @@
                         throttleDuration);
             }
         } else {
-            String logStr = TelephonyManager.convertPremiumCapabilityToString(capability)
-                    + " is already throttled.";
-            loge(logStr);
-            AnomalyReporter.reportAnomaly(UUID.fromString(UUID_CAPABILITY_THROTTLED_TWICE), logStr);
+            reportAnomaly(UUID_CAPABILITY_THROTTLED_TWICE,
+                    TelephonyManager.convertPremiumCapabilityToString(capability)
+                            + " is already throttled.");
+        }
+    }
+
+    private void onSlicingConfigChanged() {
+        for (int capability : new int[] {TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY}) {
+            if (isSlicingConfigActive(capability) && hasMessages(EVENT_SETUP_TIMEOUT, capability)) {
+                logd("Successfully set up slicing configuration for "
+                        + TelephonyManager.convertPremiumCapabilityToString(capability));
+                mPendingSetupCapabilities.remove(capability);
+                removeMessages(EVENT_SETUP_TIMEOUT, capability);
+            }
         }
     }
 
@@ -481,13 +566,16 @@
         intent.putExtra(EXTRA_PREMIUM_CAPABILITY, capability);
         intent.putExtra(EXTRA_REQUESTING_APP_NAME, appName);
         intent.putExtra(EXTRA_INTENT_CANCELED,
-                createPendingIntent(ACTION_SLICE_STORE_RESPONSE_CANCELED, capability));
+                createPendingIntent(ACTION_SLICE_STORE_RESPONSE_CANCELED, capability, false));
         intent.putExtra(EXTRA_INTENT_CARRIER_ERROR,
-                createPendingIntent(ACTION_SLICE_STORE_RESPONSE_CARRIER_ERROR, capability));
+                createPendingIntent(ACTION_SLICE_STORE_RESPONSE_CARRIER_ERROR, capability, true));
         intent.putExtra(EXTRA_INTENT_REQUEST_FAILED,
-                createPendingIntent(ACTION_SLICE_STORE_RESPONSE_REQUEST_FAILED, capability));
+                createPendingIntent(ACTION_SLICE_STORE_RESPONSE_REQUEST_FAILED, capability, false));
         intent.putExtra(EXTRA_INTENT_NOT_DEFAULT_DATA,
-                createPendingIntent(ACTION_SLICE_STORE_RESPONSE_NOT_DEFAULT_DATA, capability));
+                createPendingIntent(ACTION_SLICE_STORE_RESPONSE_NOT_DEFAULT_DATA, capability,
+                        false));
+        intent.putExtra(EXTRA_INTENT_SUCCESS,
+                createPendingIntent(ACTION_SLICE_STORE_RESPONSE_SUCCESS, capability, true));
         logd("Broadcasting start intent to SliceStoreBroadcastReceiver.");
         mPhone.getContext().sendBroadcast(intent);
 
@@ -498,6 +586,7 @@
         filter.addAction(ACTION_SLICE_STORE_RESPONSE_CARRIER_ERROR);
         filter.addAction(ACTION_SLICE_STORE_RESPONSE_REQUEST_FAILED);
         filter.addAction(ACTION_SLICE_STORE_RESPONSE_NOT_DEFAULT_DATA);
+        filter.addAction(ACTION_SLICE_STORE_RESPONSE_SUCCESS);
         mPhone.getContext().registerReceiver(mSliceStoreBroadcastReceivers.get(capability), filter);
     }
 
@@ -506,15 +595,18 @@
      *
      * @param action The action that will be sent for this PendingIntent
      * @param capability The premium capability that was requested.
+     * @param mutable {@code true} if the PendingIntent should be mutable and
+     *                {@code false} if it should be immutable.
      * @return The PendingIntent for the given action and capability.
      */
     @NonNull private PendingIntent createPendingIntent(@NonNull String action,
-            @TelephonyManager.PremiumCapability int capability) {
+            @TelephonyManager.PremiumCapability int capability, boolean mutable) {
         Intent intent = new Intent(action);
         intent.putExtra(EXTRA_PHONE_ID, mPhone.getPhoneId());
         intent.putExtra(EXTRA_PREMIUM_CAPABILITY, capability);
-        return PendingIntent.getBroadcast(mPhone.getContext(), 0, intent,
-                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE);
+        return PendingIntent.getBroadcast(mPhone.getContext(), capability, intent,
+                PendingIntent.FLAG_CANCEL_CURRENT
+                        | (mutable ? PendingIntent.FLAG_MUTABLE : PendingIntent.FLAG_IMMUTABLE));
     }
 
     private void onTimeout(@TelephonyManager.PremiumCapability int capability) {
@@ -531,9 +623,43 @@
                 capability, TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_TIMEOUT, true);
     }
 
-    private void onCarrierSuccess(@TelephonyManager.PremiumCapability int capability) {
-        // TODO(b/245882601): Process and return success.
-        //  Probably need to handle capability expiry as well
+    private void onCarrierError(@TelephonyManager.PremiumCapability int capability,
+            @FailureCode int failureCode, @Nullable String failureReason) {
+        logd("Carrier error for capability: "
+                + TelephonyManager.convertPremiumCapabilityToString(capability) + " with code: "
+                + convertFailureCodeToString(failureCode) + " and reason: " + failureReason);
+        if (failureCode == FAILURE_CODE_UNKNOWN && !TextUtils.isEmpty(failureReason)) {
+            reportAnomaly(UUID_UNKNOWN_FAILURE_CODE,
+                    "Failure code needs to be added for: " + failureReason);
+        }
+        sendPurchaseResultFromSliceStore(capability,
+                TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_ERROR, true);
+    }
+
+    private void onCarrierSuccess(@TelephonyManager.PremiumCapability int capability,
+            long duration) {
+        logd("Successfully purchased premium capability "
+                + TelephonyManager.convertPremiumCapabilityToString(capability)
+                + " for " + TimeUnit.MILLISECONDS.toMinutes(duration) + " minutes.");
+        mPendingSetupCapabilities.add(capability);
+        long setupDuration = getCarrierConfigs().getLong(
+                CarrierConfigManager.KEY_PREMIUM_CAPABILITY_NETWORK_SETUP_TIME_MILLIS_LONG);
+        logd("Waiting " + TimeUnit.MILLISECONDS.toMinutes(setupDuration) + " minutes for the "
+                + "network to set up the slicing configuration.");
+        sendMessageDelayed(obtainMessage(EVENT_SETUP_TIMEOUT, capability), setupDuration);
+        sendPurchaseResultFromSliceStore(
+                capability, TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_SUCCESS, false);
+    }
+
+    private void onSetupTimeout(@TelephonyManager.PremiumCapability int capability) {
+        logd("onSetupTimeout: " + TelephonyManager.convertPremiumCapabilityToString(capability));
+        mPendingSetupCapabilities.remove(capability);
+        if (!isSlicingConfigActive(capability)) {
+            reportAnomaly(UUID_NETWORK_SETUP_FAILED,
+                    "Failed to set up slicing configuration for capability "
+                            + TelephonyManager.convertPremiumCapabilityToString(capability)
+                            + " within the time specified.");
+        }
     }
 
     @Nullable private PersistableBundle getCarrierConfigs() {
@@ -628,6 +754,29 @@
         return true;
     }
 
+    /**
+     * Returns the failure code {@link FailureCode} as a String.
+     *
+     * @param failureCode The failure code.
+     * @return The failure code as a String.
+     */
+    @NonNull public static String convertFailureCodeToString(@FailureCode int failureCode) {
+        switch (failureCode) {
+            case FAILURE_CODE_UNKNOWN: return "UNKNOWN";
+            case FAILURE_CODE_CARRIER_URL_UNAVAILABLE: return "CARRIER_URL_UNAVAILABLE";
+            case FAILURE_CODE_SERVER_UNREACHABLE: return "SERVER_UNREACHABLE";
+            case FAILURE_CODE_AUTHENTICATION_FAILED: return "AUTHENTICATION_FAILED";
+            case FAILURE_CODE_PAYMENT_FAILED: return "PAYMENT_FAILED";
+            default:
+                return "UNKNOWN(" + failureCode + ")";
+        }
+    }
+
+    private void reportAnomaly(@NonNull String uuid, @NonNull String log) {
+        loge(log);
+        AnomalyReporter.reportAnomaly(UUID.fromString(uuid), log);
+    }
+
     private void logd(String s) {
         Log.d(TAG + "-" + mPhone.getPhoneId(), s);
     }
diff --git a/tests/src/com/android/TelephonyTestBase.java b/tests/src/com/android/TelephonyTestBase.java
index ffda81b..d72d85e 100644
--- a/tests/src/com/android/TelephonyTestBase.java
+++ b/tests/src/com/android/TelephonyTestBase.java
@@ -24,10 +24,16 @@
 
 import com.android.internal.telephony.PhoneConfigurationManager;
 
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Rule;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
@@ -40,6 +46,10 @@
 
     protected TestContext mContext;
 
+    private final HashMap<InstanceKey, Object> mOldInstances = new HashMap<>();
+    private final LinkedList<InstanceKey> mInstanceKeys = new LinkedList<>();
+
+    @Before
     public void setUp() throws Exception {
         mContext = spy(new TestContext());
         // Set up the looper if it does not exist on the test thread.
@@ -56,9 +66,11 @@
         }
     }
 
+    @After
     public void tearDown() throws Exception {
         // Ensure there are no static references to handlers after test completes.
         PhoneConfigurationManager.unregisterAllMultiSimConfigChangeRegistrants();
+        restoreInstances();
     }
 
     protected final boolean waitForExecutorAction(Executor executor, long timeoutMillis) {
@@ -108,6 +120,61 @@
         }
     }
 
+    protected synchronized void replaceInstance(final Class c, final String instanceName,
+            final Object obj, final Object newValue)
+            throws Exception {
+        Field field = c.getDeclaredField(instanceName);
+        field.setAccessible(true);
+
+        InstanceKey key = new InstanceKey(c, instanceName, obj);
+        if (!mOldInstances.containsKey(key)) {
+            mOldInstances.put(key, field.get(obj));
+            mInstanceKeys.add(key);
+        }
+        field.set(obj, newValue);
+    }
+
+    private synchronized void restoreInstances() throws Exception {
+        Iterator<InstanceKey> it = mInstanceKeys.descendingIterator();
+
+        while (it.hasNext()) {
+            InstanceKey key = it.next();
+            Field field = key.mClass.getDeclaredField(key.mInstName);
+            field.setAccessible(true);
+            field.set(key.mObj, mOldInstances.get(key));
+        }
+
+        mInstanceKeys.clear();
+        mOldInstances.clear();
+    }
+
+    private static class InstanceKey {
+        public final Class mClass;
+        public final String mInstName;
+        public final Object mObj;
+        InstanceKey(final Class c, final String instName, final Object obj) {
+            mClass = c;
+            mInstName = instName;
+            mObj = obj;
+        }
+
+        @Override
+        public int hashCode() {
+            return (mClass.getName().hashCode() * 31 + mInstName.hashCode()) * 31;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null || obj.getClass() != getClass()) {
+                return false;
+            }
+
+            InstanceKey other = (InstanceKey) obj;
+            return (other.mClass == mClass && other.mInstName.equals(mInstName)
+                    && other.mObj == mObj);
+        }
+    }
+
     protected TestContext getTestContext() {
         return mContext;
     }
diff --git a/tests/src/com/android/TestContext.java b/tests/src/com/android/TestContext.java
index 7edbed9..7c3a842 100644
--- a/tests/src/com/android/TestContext.java
+++ b/tests/src/com/android/TestContext.java
@@ -31,6 +31,7 @@
 import android.os.Looper;
 import android.os.PersistableBundle;
 import android.os.Process;
+import android.os.UserManager;
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
@@ -58,6 +59,7 @@
     @Mock TelephonyManager mMockTelephonyManager;
     @Mock SubscriptionManager mMockSubscriptionManager;
     @Mock ImsManager mMockImsManager;
+    @Mock UserManager mMockUserManager;
 
     private SparseArray<PersistableBundle> mCarrierConfigs = new SparseArray<>();
 
@@ -147,6 +149,9 @@
             case(Context.TELEPHONY_IMS_SERVICE) : {
                 return mMockImsManager;
             }
+            case(Context.USER_SERVICE) : {
+                return mMockUserManager;
+            }
         }
         return null;
     }
@@ -165,6 +170,9 @@
         if (serviceClass == SubscriptionManager.class) {
             return Context.TELEPHONY_SUBSCRIPTION_SERVICE;
         }
+        if (serviceClass == UserManager.class) {
+            return Context.USER_SERVICE;
+        }
         return null;
     }
 
diff --git a/tests/src/com/android/phone/ImsStateCallbackControllerTest.java b/tests/src/com/android/phone/ImsStateCallbackControllerTest.java
index 60374bc..2bd87be 100644
--- a/tests/src/com/android/phone/ImsStateCallbackControllerTest.java
+++ b/tests/src/com/android/phone/ImsStateCallbackControllerTest.java
@@ -52,6 +52,7 @@
 import android.testing.TestableLooper;
 import android.util.Log;
 
+import com.android.TelephonyTestBase;
 import com.android.ims.FeatureConnector;
 import com.android.ims.ImsManager;
 import com.android.ims.RcsFeatureManager;
@@ -70,13 +71,12 @@
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
-import java.lang.reflect.Field;
 import java.util.concurrent.Executor;
 
 /**
  * Unit tests for RcsProvisioningMonitor
  */
-public class ImsStateCallbackControllerTest {
+public class ImsStateCallbackControllerTest extends TelephonyTestBase {
     private static final String TAG = "ImsStateCallbackControllerTest";
     private static final int FAKE_SUB_ID_BASE = 0x0FFFFFF0;
 
@@ -189,6 +189,7 @@
             mLooper.destroy();
             mLooper = null;
         }
+        super.tearDown();
     }
 
     @Test
@@ -952,13 +953,6 @@
         }
     }
 
-    private static void replaceInstance(final Class c,
-            final String instanceName, final Object obj, final Object newValue) throws Exception {
-        Field field = c.getDeclaredField(instanceName);
-        field.setAccessible(true);
-        field.set(obj, newValue);
-    }
-
     private void makeFakeActiveSubIds(int count) {
         final int[] subIds = new int[count];
         for (int i = 0; i < count; i++) {
diff --git a/tests/src/com/android/phone/NotificationMgrTest.java b/tests/src/com/android/phone/NotificationMgrTest.java
index a6ee276..6d979d6 100644
--- a/tests/src/com/android/phone/NotificationMgrTest.java
+++ b/tests/src/com/android/phone/NotificationMgrTest.java
@@ -69,9 +69,13 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import com.android.TelephonyTestBase;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.data.DataConfigManager;
+import com.android.internal.telephony.data.DataNetworkController;
+import com.android.internal.telephony.data.DataSettingsManager;
 import com.android.internal.telephony.util.NotificationChannelController;
 
 import org.junit.Before;
@@ -81,15 +85,14 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import java.lang.reflect.Field;
+import java.util.Collections;
 
 /**
  * Unit Test for NotificationMgr
  */
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
-public class NotificationMgrTest {
-
+public class NotificationMgrTest extends TelephonyTestBase {
     private static final int TEST_SUB_ID = 1;
     private static final long SERIAL_NUMBER_OF_USER = 1234567L;
     private static final String TEST_LABEL_CF = "test_call_forwarding";
@@ -111,8 +114,12 @@
     @Mock NotificationManager mNotificationManager;
     @Mock SubscriptionInfo mSubscriptionInfo;
     @Mock Resources mResources;
+    @Mock Context mMockedContext;
     @Mock ServiceState mServiceState;
     @Mock CarrierConfigManager mCarrierConfigManager;
+    @Mock DataNetworkController mDataNetworkController;
+    @Mock DataSettingsManager mDataSettingsManager;
+    @Mock DataConfigManager mDataConfigManager;
 
     private Phone[] mPhones;
     private NotificationMgr mNotificationMgr;
@@ -123,6 +130,15 @@
         mPhones = new Phone[]{mPhone};
         replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
         when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM);
+        when(mPhone.getContext()).thenReturn(mMockedContext);
+        when(mMockedContext.getResources()).thenReturn(mResources);
+        when(mPhone.getServiceState()).thenReturn(mServiceState);
+        when(mPhone.getDataNetworkController()).thenReturn(mDataNetworkController);
+        when(mDataNetworkController.getInternetDataDisallowedReasons()).thenReturn(
+                Collections.emptyList());
+        when(mDataNetworkController.getDataConfigManager()).thenReturn(mDataConfigManager);
+        when(mPhone.getDataSettingsManager()).thenReturn(mDataSettingsManager);
+        when(mDataSettingsManager.isDataEnabledForReason(anyInt())).thenReturn(true);
         when(mApp.getSharedPreferences(anyString(), anyInt())).thenReturn(mSharedPreferences);
 
         when(mApp.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
@@ -157,8 +173,7 @@
     }
 
     @Test
-    public void testUpdateCfi_visible_noActiveSubscription_notificationNeverSent()
-            throws Exception {
+    public void testUpdateCfi_visible_noActiveSubscription_notificationNeverSent() {
         // Given no active subscription available
         when(mSubscriptionManager.getActiveSubscriptionInfo(eq(TEST_SUB_ID))).thenReturn(null);
 
@@ -170,7 +185,7 @@
     }
 
     @Test
-    public void testUpdateCfi_visible_hasActiveSub_singleSIM_notificationSent() throws Exception {
+    public void testUpdateCfi_visible_hasActiveSub_singleSIM_notificationSent() {
         when(mTelephonyManager.getPhoneCount()).thenReturn(1);
         when(mSubscriptionManager.getActiveSubscriptionInfo(eq(TEST_SUB_ID))).thenReturn(
                 mSubscriptionInfo);
@@ -181,8 +196,7 @@
     }
 
     @Test
-    public void testUpdateCfi_visible_hasActiveSub_multiSIM_notificationSentWithoutDisplayName()
-            throws Exception {
+    public void testUpdateCfi_visible_hasActiveSub_multiSIM_notificationSentWithoutDisplayName() {
         when(mTelephonyManager.getPhoneCount()).thenReturn(2);
         when(mSubscriptionManager.getActiveSubscriptionInfo(eq(TEST_SUB_ID))).thenReturn(
                 mSubscriptionInfo);
@@ -194,8 +208,7 @@
     }
 
     @Test
-    public void testUpdateCfi_visible_hasActiveSub_multiSIM_notificationSentWithDisplayName()
-            throws Exception {
+    public void testUpdateCfi_visible_hasActiveSub_multiSIM_notificationSentWithDisplayName() {
         when(mTelephonyManager.getPhoneCount()).thenReturn(2);
         when(mSubscriptionManager.getActiveSubscriptionInfo(eq(TEST_SUB_ID))).thenReturn(
                 mSubscriptionInfo);
@@ -207,8 +220,7 @@
     }
 
     @Test
-    public void testUpdateCfi_invisible_hasUnmanagedProfile_notificationCanceled()
-            throws Exception {
+    public void testUpdateCfi_invisible_hasUnmanagedProfile_notificationCanceled() {
         when(mUserManager.isManagedProfile(anyInt())).thenReturn(false);
 
         mNotificationMgr.updateCfi(TEST_SUB_ID, /*visible=*/false, /*isFresh=*/false);
@@ -217,8 +229,7 @@
     }
 
     @Test
-    public void testUpdateCfi_invisible_allProfilesAreManaged_notificationNeverCanceled()
-            throws Exception {
+    public void testUpdateCfi_invisible_allProfilesAreManaged_notificationNeverCanceled() {
         when(mUserManager.isManagedProfile(anyInt())).thenReturn(true);
 
         mNotificationMgr.updateCfi(TEST_SUB_ID, /*visible=*/false, /*isFresh=*/false);
@@ -227,7 +238,7 @@
     }
 
     @Test
-    public void testShowDataRoamingNotification_roamingOn() throws Exception {
+    public void testShowDataRoamingNotification_roamingOn() {
         mNotificationMgr.showDataRoamingNotification(TEST_SUB_ID, /*roamingOn=*/true);
 
         verifyNotificationSentWithChannelId(
@@ -235,7 +246,7 @@
     }
 
     @Test
-    public void testShowDataRoamingNotification_roamingOff() throws Exception {
+    public void testShowDataRoamingNotification_roamingOff() {
         mNotificationMgr.showDataRoamingNotification(TEST_SUB_ID, /*roamingOn=*/false);
 
         verifyNotificationSentWithChannelId(
@@ -250,8 +261,7 @@
     }
 
     @Test
-    public void testUpdateNetworkSelection_justOutOfService_notificationNeverSent()
-            throws Exception {
+    public void testUpdateNetworkSelection_justOutOfService_notificationNeverSent() {
         prepareResourcesForNetworkSelection();
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
@@ -265,8 +275,7 @@
     }
 
     @Test
-    public void testUpdateNetworkSelection_oosEnoughTime_selectionVisibleToUser_notificationSent()
-            throws Exception {
+    public void testUpdateNetworkSelection_oosEnoughTime_selectionVisibleToUser_notificationSent() {
         prepareResourcesForNetworkSelection();
         when(mTelephonyManager.isManualNetworkSelectionAllowed()).thenReturn(true);
         PersistableBundle config = new PersistableBundle();
@@ -288,8 +297,7 @@
     }
 
     @Test
-    public void testUpdateNetworkSelection_invalidSubscription_notificationNotSent()
-            throws Exception {
+    public void testUpdateNetworkSelection_invalidSubscription_notificationNotSent() {
         prepareResourcesForNetworkSelection();
         when(mTelephonyManager.isManualNetworkSelectionAllowed()).thenReturn(true);
         PersistableBundle config = new PersistableBundle();
@@ -312,8 +320,7 @@
     }
 
     @Test
-    public void testUpdateNetworkSelection_nullCarrierConfig_notificationNotSent()
-            throws Exception {
+    public void testUpdateNetworkSelection_nullCarrierConfig_notificationNotSent() {
         prepareResourcesForNetworkSelection();
 
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(null);
@@ -329,8 +336,7 @@
     }
 
     @Test
-    public void testUpdateNetworkSelection_userNotAllowedToChooseOperator_notificationNotSent()
-            throws Exception {
+    public void testUpdateNetworkSelection_userNotAllowedToChooseOperator_notificationNotSent() {
         prepareResourcesForNetworkSelection();
 
         PersistableBundle config = new PersistableBundle();
@@ -353,8 +359,8 @@
     }
 
     @Test
-    public void testUpdateNetworkSelection_OverrideHideCarrierNetworkSelection_notificationNotSent()
-            throws Exception {
+    public void
+            testUpdateNetworkSelection_OverrideHideCarrierNetworkSelection_notificationNotSent() {
         prepareResourcesForNetworkSelection();
 
         PersistableBundle config = new PersistableBundle();
@@ -401,8 +407,7 @@
     }
 
     @Test
-    public void testUpdateNetworkSelection_worldMode_userSetLTE_notificationNotSent()
-            throws Exception {
+    public void testUpdateNetworkSelection_worldMode_userSetLTE_notificationNotSent() {
         prepareResourcesForNetworkSelection();
 
         PersistableBundle config = new PersistableBundle();
@@ -431,8 +436,7 @@
     }
 
     @Test
-    public void testUpdateNetworkSelection_worldMode_userSetTDSCDMA_notSupported_notifNotSent()
-            throws Exception {
+    public void testUpdateNetworkSelection_worldMode_userSetTDSCDMA_notSupported_notifNotSent() {
         prepareResourcesForNetworkSelection();
 
         PersistableBundle config = new PersistableBundle();
@@ -462,8 +466,7 @@
     }
 
     @Test
-    public void testUpdateNetworkSelection_worldMode_userSetWCDMA_notificationSent()
-            throws Exception {
+    public void testUpdateNetworkSelection_worldMode_userSetWCDMA_notificationSent() {
         prepareResourcesForNetworkSelection();
 
         PersistableBundle config = new PersistableBundle();
@@ -494,8 +497,7 @@
     }
 
     @Test
-    public void testUpdateNetworkSelection_worldPhone_networkSelectionNotHide_notificationSent()
-            throws Exception {
+    public void testUpdateNetworkSelection_worldPhone_networkSelectionNotHide_notificationSent() {
         prepareResourcesForNetworkSelection();
 
         PersistableBundle config = new PersistableBundle();
@@ -519,8 +521,7 @@
     }
 
     @Test
-    public void testUpdateNetworkSelection_gsmBasicOptionOn_notificationSent()
-            throws Exception {
+    public void testUpdateNetworkSelection_gsmBasicOptionOn_notificationSent() {
         prepareResourcesForNetworkSelection();
 
         PersistableBundle config = new PersistableBundle();
@@ -545,8 +546,7 @@
     }
 
     @Test
-    public void testUpdateNetworkSelection_gsmBasicOptionOff_notificationNotSent()
-            throws Exception {
+    public void testUpdateNetworkSelection_gsmBasicOptionOff_notificationNotSent() {
         prepareResourcesForNetworkSelection();
 
         PersistableBundle config = new PersistableBundle();
@@ -569,8 +569,7 @@
     }
 
     @Test
-    public void testShowLimitedSimFunctionWarningNotification_forTheFirstTime_notificationSent()
-            throws Exception {
+    public void testShowLimitedSimFunctionWarningNotification_forTheFirstTime_notificationSent() {
         when(mResources.getText(R.string.limited_sim_function_notification_message)).thenReturn(
                 CARRIER_NAME);
         when(mResources.getText(
@@ -584,8 +583,8 @@
     }
 
     @Test
-    public void testShowLimitedSimFunctionWarningNotification_consecutiveCall_notificationSentOnce()
-            throws Exception {
+    public void
+            testShowLimitedSimFunctionWarningNotification_consecutiveCall_notificationSentOnce() {
         when(mResources.getText(R.string.limited_sim_function_notification_message)).thenReturn(
                 CARRIER_NAME);
         when(mResources.getText(
@@ -602,8 +601,7 @@
     }
 
     @Test
-    public void testDismissLimitedSimFunctionWarningNotification_noShowCalledBefore_noCancelSent()
-            throws Exception {
+    public void testDismissLimitedSimFunctionWarningNotification_noShowCalledBefore_noCancelSent() {
         // showLimitedSimFunctionWarningNotification was never called before
 
         mNotificationMgr.dismissLimitedSimFunctionWarningNotification(TEST_SUB_ID);
@@ -612,8 +610,7 @@
     }
 
     @Test
-    public void testDismissLimitedSimFunctionWarningNotification_showCalledBefore_cancelSent()
-            throws Exception {
+    public void testDismissLimitedSimFunctionWarningNotification_showCalledBefore_cancelSent() {
         when(mResources.getText(R.string.limited_sim_function_notification_message)).thenReturn(
                 CARRIER_NAME);
         when(mResources.getText(
@@ -651,11 +648,4 @@
         when(mApp.getString(R.string.mobile_network_settings_class)).thenReturn(
                 MOBILE_NETWORK_SELECTION_CLASS);
     }
-
-    private static void replaceInstance(final Class c,
-            final String instanceName, final Object obj, final Object newValue) throws Exception {
-        Field field = c.getDeclaredField(instanceName);
-        field.setAccessible(true);
-        field.set(obj, newValue);
-    }
 }
diff --git a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
index ffc0177..08bdb9b 100644
--- a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
+++ b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
@@ -33,6 +33,7 @@
 import com.android.internal.telephony.RILConstants;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -90,6 +91,7 @@
     }
 
     @Test
+    @Ignore("b/254731907")
     public void matchLocaleFromSupportedLocaleList_inputLocaleChangeToSupportedLocale() {
         // Input zh-TW, then look up the matched supported locale, zh-Hant-TW, instead.
         String result1 = mPhoneInterfaceManager.matchLocaleFromSupportedLocaleList(
diff --git a/tests/src/com/android/phone/PhoneUtilsTest.java b/tests/src/com/android/phone/PhoneUtilsTest.java
index eb4c248..521a0bb 100644
--- a/tests/src/com/android/phone/PhoneUtilsTest.java
+++ b/tests/src/com/android/phone/PhoneUtilsTest.java
@@ -28,23 +28,19 @@
 
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.TelephonyTestBase;
 import com.android.internal.telephony.GsmCdmaPhone;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.HashMap;
-
 @RunWith(AndroidJUnit4.class)
-public class PhoneUtilsTest {
+public class PhoneUtilsTest extends TelephonyTestBase {
     @Mock
     private SubscriptionManager mMockSubscriptionManager;
     @Mock
@@ -59,37 +55,6 @@
     private PhoneAccountHandle mPhoneAccountHandleTest = new PhoneAccountHandle(
             PSTN_CONNECTION_SERVICE_COMPONENT, mPhoneAccountHandleIdString);
 
-    private HashMap<InstanceKey, Object> mOldInstances = new HashMap<InstanceKey, Object>();
-
-    private ArrayList<InstanceKey> mInstanceKeys = new ArrayList<InstanceKey>();
-
-    private static class InstanceKey {
-        public final Class mClass;
-        public final String mInstName;
-        public final Object mObj;
-        InstanceKey(final Class c, final String instName, final Object obj) {
-            mClass = c;
-            mInstName = instName;
-            mObj = obj;
-        }
-
-        @Override
-        public int hashCode() {
-            return (mClass.getName().hashCode() * 31 + mInstName.hashCode()) * 31;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj == null || !(obj instanceof InstanceKey)) {
-                return false;
-            }
-
-            InstanceKey other = (InstanceKey) obj;
-            return (other.mClass == mClass && other.mInstName.equals(mInstName)
-                    && other.mObj == mObj);
-        }
-    }
-
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
@@ -100,37 +65,6 @@
         replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
     }
 
-    @After
-    public void tearDown() throws Exception {
-        restoreInstance(PhoneFactory.class, "sPhones", null);
-    }
-
-    protected synchronized void replaceInstance(final Class c, final String instanceName,
-            final Object obj, final Object newValue)
-            throws Exception {
-        Field field = c.getDeclaredField(instanceName);
-        field.setAccessible(true);
-
-        InstanceKey key = new InstanceKey(c, instanceName, obj);
-        if (!mOldInstances.containsKey(key)) {
-            mOldInstances.put(key, field.get(obj));
-            mInstanceKeys.add(key);
-        }
-        field.set(obj, newValue);
-    }
-
-    protected synchronized void restoreInstance(final Class c, final String instanceName,
-            final Object obj) throws Exception {
-        InstanceKey key = new InstanceKey(c, instanceName, obj);
-        if (mOldInstances.containsKey(key)) {
-            Field field = c.getDeclaredField(instanceName);
-            field.setAccessible(true);
-            field.set(obj, mOldInstances.get(key));
-            mOldInstances.remove(key);
-            mInstanceKeys.remove(key);
-        }
-    }
-
     @Test
     public void testIsPhoneAccountActive() throws Exception {
         assertTrue(PhoneUtils.isPhoneAccountActive(
diff --git a/tests/src/com/android/phone/Telephony2gUpdaterTest.java b/tests/src/com/android/phone/Telephony2gUpdaterTest.java
new file mode 100644
index 0000000..3443767
--- /dev/null
+++ b/tests/src/com/android/phone/Telephony2gUpdaterTest.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.UserManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.TelephonyTestBase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+@RunWith(AndroidJUnit4.class)
+public class Telephony2gUpdaterTest extends TelephonyTestBase {
+    private Telephony2gUpdater mTelephony2gUpdater;
+    private Executor mExecutor;
+
+    private UserManager mMockUserManager;
+    private TelephonyManager mMockTelephonyManager;
+    private SubscriptionManager mMockSubscriptionManager;
+
+    // 2G Bitmask is 0b10000000_01001011
+    private static final long BASE_NETWORK = 0b11111111_11111111;
+    private static final long EXPECTED_DISABLED = 0b01111111_10110100;
+    private static final long EXPECTED_ENABLED = 0b11111111_11111111;
+
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mMockTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+        mMockUserManager = mContext.getSystemService(UserManager.class);
+        mMockSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+
+        mExecutor = Executors.newSingleThreadExecutor();
+        mTelephony2gUpdater = new Telephony2gUpdater(mExecutor,
+                getTestContext(), BASE_NETWORK);
+    }
+
+    @Test
+    public void handleUserRestrictionsChanged_noSubscriptions_noAllowedNetworksChanged() {
+        when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
+                new ArrayList<>());
+        mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
+        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());
+    }
+
+    @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);
+    }
+
+    @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);
+        // 2g is disallowed
+        when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
+                true);
+
+        mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
+
+        verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+        verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
+                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+    }
+
+    @Test
+    public void handleUserRestrictionsChanged_manySubscriptionsAllow2g_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);
+
+        // 2g is allowed
+        when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
+                false);
+
+        mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
+
+        verify(tmSubscription1, 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);
+    }
+
+    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);
+    }
+}
diff --git a/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java b/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java
index 28a7b02..969622a 100644
--- a/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java
+++ b/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java
@@ -38,19 +38,14 @@
 import com.android.internal.telephony.PhoneFactory;
 import com.android.phone.common.R;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.Locale;
 
-
 @RunWith(AndroidJUnit4.class)
 public class DisconnectCauseUtilTest extends TelephonyTestBase {
 
@@ -60,42 +55,11 @@
 
     // dynamic
     private Context mContext;
-    private HashMap<InstanceKey, Object> mOldInstances = new HashMap<InstanceKey, Object>();
-    private ArrayList<InstanceKey> mInstanceKeys = new ArrayList<InstanceKey>();
 
     //Mocks
     @Mock
     private GsmCdmaPhone mMockPhone;
 
-    // inner classes
-    private static class InstanceKey {
-        public final Class mClass;
-        public final String mInstName;
-        public final Object mObj;
-
-        InstanceKey(final Class c, final String instName, final Object obj) {
-            mClass = c;
-            mInstName = instName;
-            mObj = obj;
-        }
-
-        @Override
-        public int hashCode() {
-            return (mClass.getName().hashCode() * 31 + mInstName.hashCode()) * 31;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj == null || !(obj instanceof InstanceKey)) {
-                return false;
-            }
-
-            InstanceKey other = (InstanceKey) obj;
-            return (other.mClass == mClass && other.mInstName.equals(mInstName)
-                    && other.mObj == mObj);
-        }
-    }
-
     @Before
     public void setUp() throws Exception {
         super.setUp();
@@ -106,15 +70,6 @@
         setSinglePhone();
     }
 
-    @After
-    public void tearDown() throws Exception {
-        // restoreInstance.
-        // Not doing so will potentially "confuse" other tests with the mocked instance
-        restoreInstance(PhoneFactory.class, "sPhones", null);
-        super.tearDown();
-    }
-
-
     /**
      * Verifies that a call drop due to loss of WIFI results in a disconnect cause of error and that
      * the label, description and tone are all present.
@@ -176,33 +131,6 @@
         replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
     }
 
-
-    protected synchronized void replaceInstance(final Class c, final String instanceName,
-            final Object obj, final Object newValue)
-            throws Exception {
-        Field field = c.getDeclaredField(instanceName);
-        field.setAccessible(true);
-
-        InstanceKey key = new InstanceKey(c, instanceName, obj);
-        if (!mOldInstances.containsKey(key)) {
-            mOldInstances.put(key, field.get(obj));
-            mInstanceKeys.add(key);
-        }
-        field.set(obj, newValue);
-    }
-
-    protected synchronized void restoreInstance(final Class c, final String instanceName,
-            final Object obj) throws Exception {
-        InstanceKey key = new InstanceKey(c, instanceName, obj);
-        if (mOldInstances.containsKey(key)) {
-            Field field = c.getDeclaredField(instanceName);
-            field.setAccessible(true);
-            field.set(obj, mOldInstances.get(key));
-            mOldInstances.remove(key);
-            mInstanceKeys.remove(key);
-        }
-    }
-
     private Resources getResourcesForLocale(Context context, Locale locale) {
         Configuration config = new Configuration();
         config.setToDefaults();