[automerger skipped] Import translations. DO NOT MERGE ANYWHERE am: 4704c8b9c6 -s ours

am skip reason: subject contains skip directive

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/services/Telephony/+/19394038

Change-Id: Ief2ed9e6064d4bd40ae92f87aa6ee0d72640a4d3
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 8218a84..d0f427c 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -207,8 +207,6 @@
     <style name="DialerAlertDialogTheme"
         parent="@android:style/Theme.Material.Light.Dialog">
         <item name="android:forceDarkAllowed">true</item>
-        <item name="android:colorAccent">@color/dialer_theme_color</item>
-        <item name="android:textColor">?android:attr/textColorPrimaryInverseDisableOnly</item>
     </style>
 
     <style name="Empty" parent="@android:style/Theme.Material.Light">
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 307170a..cb774c7 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -1321,7 +1321,6 @@
             boolean persistent) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.MODIFY_PHONE_STATE, null);
-        //TODO: Also check for SHELL UID to restrict this method to testing only (b/131326259)
         int phoneId = SubscriptionManager.getPhoneId(subscriptionId);
         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
             logd("Ignore invalid phoneId: " + phoneId + " for subId: " + subscriptionId);
diff --git a/src/com/android/phone/ImsRcsController.java b/src/com/android/phone/ImsRcsController.java
index bf55764..d4a0f1e 100644
--- a/src/com/android/phone/ImsRcsController.java
+++ b/src/com/android/phone/ImsRcsController.java
@@ -252,7 +252,7 @@
         } catch (ImsException e) {
             Log.e(TAG, "isCapable: sudId=" + subId
                     + ", capability=" + capability + ", " + e.getMessage());
-            return false;
+            throw new ServiceSpecificException(e.getCode(), e.getMessage());
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -278,7 +278,7 @@
         } catch (ImsException e) {
             Log.e(TAG, "isAvailable: sudId=" + subId
                     + ", capability=" + capability + ", " + e.getMessage());
-            return false;
+            throw new ServiceSpecificException(e.getCode(), e.getMessage());
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -786,16 +786,43 @@
         int slotId = phone.getPhoneId();
         if (!skipVerifyingConfig) {
             verifyImsRcsConfiguredOrThrow(slotId);
+            verifyRcsSubIdActiveOrThrow(slotId, subId);
         }
         RcsFeatureController c = mRcsService.getFeatureController(slotId);
         if (c == null) {
+            // If we hit this case, we have verified that TelephonyRcsService has processed any
+            // subId changes for the associated slot and applied configs. In this case, the configs
+            // do not have the RCS feature enabled.
             throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
                     "The requested operation is not supported for subId " + subId);
         }
+        if (!skipVerifyingConfig && c.getAssociatedSubId() != subId) {
+            // If we hit this case, the ImsFeature has not finished setting up the RCS feature yet
+            // or the RCS feature has crashed and is being set up again.
+            Log.w(TAG, "getRcsFeatureController: service unavailable on slot " + slotId
+                    + " for subId " + subId);
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
+                    "The ImsService is not currently available for subid " + subId
+                            + ", please try again");
+        }
         return c;
     }
 
     /**
+     * Ensure the TelephonyRcsService is tracking the supplied subId for the supplied slotId and has
+     * set up the stack.
+     */
+    private void verifyRcsSubIdActiveOrThrow(int slotId, int subId) {
+        if (mRcsService.verifyActiveSubId(slotId, subId)) return;
+
+        Log.w(TAG, "verifyRcsSubIdActiveOrThrow: verify failed, service not set up yet on "
+                + "slot " + slotId + " for subId " + subId);
+        throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
+                "ImsService set up in progress for subId " + subId
+                        + ", please try again");
+    }
+
+    /**
      * Throw an ImsException if the IMS resolver does not have an ImsService configured for RCS
      * for the given slot ID or no ImsResolver instance has been created.
      * @param slotId The slot ID that the IMS service is created for.
diff --git a/src/com/android/phone/PhoneDisplayMessage.java b/src/com/android/phone/PhoneDisplayMessage.java
index be7fc7f..c487cba 100644
--- a/src/com/android/phone/PhoneDisplayMessage.java
+++ b/src/com/android/phone/PhoneDisplayMessage.java
@@ -80,7 +80,8 @@
         sDisplayMessageDialog.getWindow().addFlags(
                 WindowManager.LayoutParams.FLAG_DIM_BEHIND
                 | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
-                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
 
         sDisplayMessageDialog.show();
     }
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index 695a4a4..d0aad4a 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -469,7 +469,7 @@
 
                 // build the dialog
                 final AlertDialog newDialog =
-                        FrameworksUtils.makeAlertDialogBuilder(contextThemeWrapper)
+                        new AlertDialog.Builder(contextThemeWrapper)
                         .setMessage(text)
                         .setView(dialogView)
                         .setPositiveButton(R.string.send_button, mUSSDDialogListener)
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index 669e830..97676fc 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -1646,7 +1646,7 @@
         String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUES_FROM_XML + ": ";
 
         // Parse all options
-        CcOptionParseResult options = parseCcOptions(tag, false);
+        CcOptionParseResult options = parseCcOptions(tag, true);
         if (options == null) {
             return -1;
         }
diff --git a/src/com/android/phone/settings/RadioInfo.java b/src/com/android/phone/settings/RadioInfo.java
index 2058d2d..d4367ca 100644
--- a/src/com/android/phone/settings/RadioInfo.java
+++ b/src/com/android/phone/settings/RadioInfo.java
@@ -72,6 +72,13 @@
 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;
@@ -92,9 +99,6 @@
 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;
@@ -176,18 +180,6 @@
      */
     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",
@@ -291,6 +283,7 @@
     private TelephonyManager mTelephonyManager;
     private ImsManager mImsManager = null;
     private Phone mPhone = null;
+    private ProvisioningManager mProvisioningManager = null;
 
     private String mPingHostnameResultV4;
     private String mPingHostnameResultV6;
@@ -423,8 +416,9 @@
         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();
     }
@@ -484,7 +478,8 @@
         mTelephonyManager = ((TelephonyManager) getSystemService(TELEPHONY_SERVICE))
                 .createForSubscriptionId(mPhone.getSubId());
 
-        mImsManager = ImsManager.getInstance(getApplicationContext(), mPhone.getPhoneId());
+        mImsManager = new ImsManager(mPhone.getContext());
+        mProvisioningManager = ProvisioningManager.createForSubscriptionId(mPhone.getSubId());
 
         sPhoneIndexLabels = getPhoneIndexLabels(mTelephonyManager);
 
@@ -552,7 +547,7 @@
         mImsWfcProvisionedSwitch = (Switch) findViewById(R.id.wfc_provisioned_switch);
         mEabProvisionedSwitch = (Switch) findViewById(R.id.eab_provisioned_switch);
 
-        if (!ImsManager.isImsSupportedOnDevice(mPhone.getContext())) {
+        if (!isImsSupportedOnDevice(mPhone.getContext())) {
             mImsVolteProvisionedSwitch.setVisibility(View.GONE);
             mImsVtProvisionedSwitch.setVisibility(View.GONE);
             mImsWfcProvisionedSwitch.setVisibility(View.GONE);
@@ -774,7 +769,8 @@
                 R.string.radioInfo_menu_viewFDN).setOnMenuItemClickListener(mViewFDNCallback);
         menu.add(1, MENU_ITEM_VIEW_SDN, 0,
                 R.string.radioInfo_menu_viewSDN).setOnMenuItemClickListener(mViewSDNCallback);
-        if (ImsManager.isImsSupportedOnDevice(mPhone.getContext())) {
+
+        if (isImsSupportedOnDevice(mPhone.getContext())) {
             menu.add(1, MENU_ITEM_GET_IMS_STATUS,
                     0, R.string.radioInfo_menu_getIMS).setOnMenuItemClickListener(mGetImsStatus);
         }
@@ -1502,34 +1498,38 @@
         mRadioPowerOnSwitch.setOnCheckedChangeListener(mRadioPowerOnChangeListener);
     }
 
-    void setImsVolteProvisionedState(boolean state) {
+    private void setImsVolteProvisionedState(boolean state) {
         Log.d(TAG, "setImsVolteProvisioned state: " + ((state) ? "on" : "off"));
-        setImsConfigProvisionedState(IMS_VOLTE_PROVISIONED_CONFIG_ID, state);
+        setImsConfigProvisionedState(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+                ImsRegistrationImplBase.REGISTRATION_TECH_LTE, state);
     }
 
-    void setImsVtProvisionedState(boolean state) {
+    private void setImsVtProvisionedState(boolean state) {
         Log.d(TAG, "setImsVtProvisioned() state: " + ((state) ? "on" : "off"));
-        setImsConfigProvisionedState(IMS_VT_PROVISIONED_CONFIG_ID, state);
+        setImsConfigProvisionedState(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO,
+                ImsRegistrationImplBase.REGISTRATION_TECH_LTE, state);
     }
 
-    void setImsWfcProvisionedState(boolean state) {
+    private void setImsWfcProvisionedState(boolean state) {
         Log.d(TAG, "setImsWfcProvisioned() state: " + ((state) ? "on" : "off"));
-        setImsConfigProvisionedState(IMS_WFC_PROVISIONED_CONFIG_ID, state);
+        setImsConfigProvisionedState(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+                ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN, state);
     }
 
-    void setEabProvisionedState(boolean state) {
+    private void setEabProvisionedState(boolean state) {
         Log.d(TAG, "setEabProvisioned() state: " + ((state) ? "on" : "off"));
-        setImsConfigProvisionedState(EAB_PROVISIONED_CONFIG_ID, state);
+        setRcsConfigProvisionedState(ImsRcsManager.CAPABILITY_TYPE_PRESENCE_UCE,
+                ImsRegistrationImplBase.REGISTRATION_TECH_LTE, state);
     }
 
-    void setImsConfigProvisionedState(int configItem, boolean state) {
-        if (mPhone != null && mImsManager != null) {
+    private void setImsConfigProvisionedState(int capability, int tech, boolean state) {
+        if (mProvisioningManager != null) {
             mQueuedWork.execute(new Runnable() {
                 public void run() {
                     try {
-                        mImsManager.getConfigInterface().setProvisionedValue(
-                                configItem, state ? 1 : 0);
-                    } catch (ImsException e) {
+                        mProvisioningManager.setProvisioningStatusForCapability(
+                                capability, tech, state);
+                    } catch (RuntimeException e) {
                         Log.e(TAG, "setImsConfigProvisioned() exception:", e);
                     }
                 }
@@ -1537,6 +1537,71 @@
         }
     }
 
+    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) {
@@ -1556,11 +1621,8 @@
     };
 
     private boolean isImsVolteProvisioned() {
-        if (mImsManager != null) {
-            return mImsManager.isVolteEnabledByPlatform()
-                && mImsManager.isVolteProvisionedOnDevice();
-        }
-        return false;
+        return getImsConfigProvisionedState(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
     }
 
     OnCheckedChangeListener mImsVolteCheckedChangeListener = new OnCheckedChangeListener() {
@@ -1571,11 +1633,8 @@
     };
 
     private boolean isImsVtProvisioned() {
-        if (mImsManager != null) {
-            return mImsManager.isVtEnabledByPlatform()
-                && mImsManager.isVtProvisionedOnDevice();
-        }
-        return false;
+        return getImsConfigProvisionedState(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO,
+                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
     }
 
     OnCheckedChangeListener mImsVtCheckedChangeListener = new OnCheckedChangeListener() {
@@ -1586,11 +1645,8 @@
     };
 
     private boolean isImsWfcProvisioned() {
-        if (mImsManager != null) {
-            return mImsManager.isWfcEnabledByPlatform()
-                && mImsManager.isWfcProvisionedOnDevice();
-        }
-        return false;
+        return getImsConfigProvisionedState(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+                ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN);
     }
 
     OnCheckedChangeListener mImsWfcCheckedChangeListener = new OnCheckedChangeListener() {
@@ -1601,7 +1657,8 @@
     };
 
     private boolean isEabProvisioned() {
-        return isFeatureProvisioned(EAB_PROVISIONED_CONFIG_ID, false);
+        return getRcsConfigProvisionedState(ImsRcsManager.CAPABILITY_TYPE_PRESENCE_UCE,
+                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
     }
 
     OnCheckedChangeListener mEabCheckedChangeListener = new OnCheckedChangeListener() {
@@ -1611,23 +1668,30 @@
         }
     };
 
-    private boolean isFeatureProvisioned(int featureId, boolean defaultValue) {
-        boolean provisioned = defaultValue;
-        if (mImsManager != null) {
+    private boolean getImsConfigProvisionedState(int capability, int tech) {
+        if (mProvisioningManager != null) {
             try {
-                ImsConfig imsConfig = mImsManager.getConfigInterface();
-                if (imsConfig != null) {
-                    provisioned =
-                            (imsConfig.getProvisionedValue(featureId)
-                                    == ImsConfig.FeatureValueConstants.ON);
-                }
-            } catch (ImsException ex) {
-                Log.e(TAG, "isFeatureProvisioned() exception:", ex);
+                return mProvisioningManager.getProvisioningStatusForCapability(
+                        capability, tech);
+            } catch (RuntimeException e) {
+                Log.e(TAG, "getImsConfigProvisionedState() exception:", e);
             }
         }
 
-        log("isFeatureProvisioned() featureId=" + featureId + " provisioned=" + provisioned);
-        return provisioned;
+        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;
     }
 
     private boolean isEabEnabledByPlatform() {
@@ -1646,35 +1710,56 @@
     }
 
     private void updateImsProvisionedState() {
-        if (!ImsManager.isImsSupportedOnDevice(mPhone.getContext())) {
+        if (!isImsSupportedOnDevice(mPhone.getContext())) {
             return;
         }
-        log("updateImsProvisionedState isImsVolteProvisioned()=" + isImsVolteProvisioned());
-        //delightful hack to prevent on-checked-changed calls from
-        //actually forcing the ims provisioning to its transient/current value.
+
+        updateServiceEnabledByPlatform();
+
+        updateEabProvisionedSwitch(isEabEnabledByPlatform());
+    }
+
+    private void updateVolteProvisionedSwitch(boolean isEnabledByPlatform) {
+        boolean isProvisioned = isEnabledByPlatform && isImsVolteProvisioned();
+        log("updateImsProvisionedState isProvisioned" + isProvisioned);
+
         mImsVolteProvisionedSwitch.setOnCheckedChangeListener(null);
-        mImsVolteProvisionedSwitch.setChecked(isImsVolteProvisioned());
+        mImsVolteProvisionedSwitch.setChecked(isProvisioned);
         mImsVolteProvisionedSwitch.setOnCheckedChangeListener(mImsVolteCheckedChangeListener);
         mImsVolteProvisionedSwitch.setEnabled(!IS_USER_BUILD
-                && mImsManager.isVolteEnabledByPlatform());
+                && isEnabledByPlatform && isImsVolteProvisioningRequired());
+    }
+
+    private void updateVtProvisionedSwitch(boolean isEnabledByPlatform) {
+        boolean isProvisioned = isEnabledByPlatform && isImsVtProvisioned();
+        log("updateVtProvisionedSwitch isProvisioned" + isProvisioned);
 
         mImsVtProvisionedSwitch.setOnCheckedChangeListener(null);
-        mImsVtProvisionedSwitch.setChecked(isImsVtProvisioned());
+        mImsVtProvisionedSwitch.setChecked(isProvisioned);
         mImsVtProvisionedSwitch.setOnCheckedChangeListener(mImsVtCheckedChangeListener);
         mImsVtProvisionedSwitch.setEnabled(!IS_USER_BUILD
-                && mImsManager.isVtEnabledByPlatform());
+                && isEnabledByPlatform && isImsVtProvisioningRequired());
+    }
+
+    private void updateWfcProvisionedSwitch(boolean isEnabledByPlatform) {
+        boolean isProvisioned = isEnabledByPlatform && isImsWfcProvisioned();
+        log("updateWfcProvisionedSwitch isProvisioned" + isProvisioned);
 
         mImsWfcProvisionedSwitch.setOnCheckedChangeListener(null);
-        mImsWfcProvisionedSwitch.setChecked(isImsWfcProvisioned());
+        mImsWfcProvisionedSwitch.setChecked(isProvisioned);
         mImsWfcProvisionedSwitch.setOnCheckedChangeListener(mImsWfcCheckedChangeListener);
         mImsWfcProvisionedSwitch.setEnabled(!IS_USER_BUILD
-                && mImsManager.isWfcEnabledByPlatform());
+                && isEnabledByPlatform && isImsWfcProvisioningRequired());
+    }
+
+    private void updateEabProvisionedSwitch(boolean isEnabledByPlatform) {
+        log("updateEabProvisionedSwitch isEabWfcProvisioned()=" + isEabProvisioned());
 
         mEabProvisionedSwitch.setOnCheckedChangeListener(null);
         mEabProvisionedSwitch.setChecked(isEabProvisioned());
         mEabProvisionedSwitch.setOnCheckedChangeListener(mEabCheckedChangeListener);
         mEabProvisionedSwitch.setEnabled(!IS_USER_BUILD
-                && isEabEnabledByPlatform());
+                && isEnabledByPlatform && isEabProvisioningRequired());
     }
 
     OnClickListener mDnsCheckButtonHandler = new OnClickListener() {
@@ -1913,4 +1998,28 @@
         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/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index 9321e1e..587ac43 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -25,6 +25,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.ims.ImsReasonInfo;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.CallFailCause;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
@@ -101,14 +102,29 @@
     public static DisconnectCause toTelecomDisconnectCause(
             int telephonyDisconnectCause, int telephonyPreciseDisconnectCause, String reason,
             int phoneId, ImsReasonInfo imsReasonInfo) {
+        return toTelecomDisconnectCause(telephonyDisconnectCause, telephonyPreciseDisconnectCause,
+                reason, phoneId, imsReasonInfo, getCarrierConfigBundle(phoneId));
+    }
+
+    /**
+     * Final pre-processing method in creating a DisconnectCause.  This method should NOT be called
+     * from another class directly.  It only has private-package visibility for testing.
+     *
+     * @param carrierConfig
+     */
+    @VisibleForTesting
+    static DisconnectCause toTelecomDisconnectCause(
+            int telephonyDisconnectCause, int telephonyPreciseDisconnectCause, String reason,
+            int phoneId, ImsReasonInfo imsReasonInfo, PersistableBundle carrierConfig) {
         Context context = PhoneGlobals.getInstance();
+
         return new DisconnectCause(
-                toTelecomDisconnectCauseCode(telephonyDisconnectCause),
+                toTelecomDisconnectCauseCode(telephonyDisconnectCause, carrierConfig),
                 toTelecomDisconnectCauseLabel(context, telephonyDisconnectCause,
-                        telephonyPreciseDisconnectCause),
+                        telephonyPreciseDisconnectCause, carrierConfig),
                 toTelecomDisconnectCauseDescription(context, telephonyDisconnectCause, phoneId),
-                toTelecomDisconnectReason(context,telephonyDisconnectCause, reason, phoneId),
-                toTelecomDisconnectCauseTone(telephonyDisconnectCause, phoneId),
+                toTelecomDisconnectReason(context, telephonyDisconnectCause, reason, phoneId),
+                toTelecomDisconnectCauseTone(telephonyDisconnectCause, carrierConfig),
                 telephonyDisconnectCause,
                 telephonyPreciseDisconnectCause,
                 imsReasonInfo);
@@ -119,7 +135,16 @@
      * {@link android.telecom.DisconnectCause} disconnect code.
      * @return The disconnect code as defined in {@link android.telecom.DisconnectCause}.
      */
-    private static int toTelecomDisconnectCauseCode(int telephonyDisconnectCause) {
+    private static int toTelecomDisconnectCauseCode(int telephonyDisconnectCause,
+            PersistableBundle carrierConfig) {
+
+        // special case: some carriers determine what disconnect causes play the BUSY tone.
+        // hence, must adjust the disconnectCause CODE to match the tone.
+        if (doesCarrierClassifyDisconnectCauseAsBusyCause(telephonyDisconnectCause,
+                carrierConfig)) {
+            return DisconnectCause.BUSY;
+        }
+
         switch (telephonyDisconnectCause) {
             case android.telephony.DisconnectCause.LOCAL:
             //  The call was still disconnected locally, so this is not an error condition.
@@ -237,8 +262,17 @@
      * Returns a label for to the disconnect cause to be shown to the user.
      */
     private static CharSequence toTelecomDisconnectCauseLabel(
-            Context context, int telephonyDisconnectCause, int telephonyPreciseDisconnectCause) {
+            Context context, int telephonyDisconnectCause, int telephonyPreciseDisconnectCause,
+            PersistableBundle carrierConfig) {
         CharSequence label;
+
+        // special case: some carriers determine what disconnect causes play the BUSY tone.
+        // hence, must adjust the disconnectCause LABEL to match the tone.
+        if (doesCarrierClassifyDisconnectCauseAsBusyCause(telephonyDisconnectCause,
+                carrierConfig)) {
+            return context.getResources().getString(R.string.callFailed_userBusy);
+        }
+
         if (telephonyPreciseDisconnectCause != CallFailCause.NOT_VALID) {
             label = getLabelFromPreciseDisconnectCause(context, telephonyPreciseDisconnectCause,
                     telephonyDisconnectCause);
@@ -695,6 +729,10 @@
                 resourceId = R.string.incall_error_emergency_only;
                 break;
 
+            case android.telephony.DisconnectCause.ICC_ERROR:
+                resourceId = R.string.callFailed_simError;
+                break;
+
             case android.telephony.DisconnectCause.OUT_OF_SERVICE:
                 // No network connection.
                 if (ImsUtil.shouldPromoteWfc(context, phoneId)) {
@@ -840,21 +878,15 @@
     /**
      * Returns the tone to play for the disconnect cause, or UNKNOWN if none should be played.
      */
-    private static int toTelecomDisconnectCauseTone(int telephonyDisconnectCause, int phoneId) {
-        Phone phone = PhoneFactory.getPhone(phoneId);
-        PersistableBundle config;
-        if (phone != null) {
-            config = PhoneGlobals.getInstance().getCarrierConfigForSubId(phone.getSubId());
-        } else {
-            config = PhoneGlobals.getInstance().getCarrierConfig();
+    private static int toTelecomDisconnectCauseTone(int telephonyDisconnectCause,
+            PersistableBundle carrierConfig) {
+
+        // special case: some carriers determine what disconnect causes play the BUSY tone.
+        if (doesCarrierClassifyDisconnectCauseAsBusyCause(telephonyDisconnectCause,
+                carrierConfig)) {
+            return ToneGenerator.TONE_SUP_BUSY;
         }
-        int[] busyToneArray = config.getIntArray(
-                CarrierConfigManager.KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY);
-        for (int busyTone : busyToneArray) {
-            if (busyTone == telephonyDisconnectCause) {
-                return ToneGenerator.TONE_SUP_BUSY;
-            }
-        }
+
         switch (telephonyDisconnectCause) {
             case android.telephony.DisconnectCause.CONGESTION:
                 return ToneGenerator.TONE_SUP_CONGESTION;
@@ -886,4 +918,37 @@
                 return ToneGenerator.TONE_PROP_PROMPT;
         }
     }
+
+    /**
+     * Helper method that examines the carrierConfig KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY
+     * containing the DisconnectCauses that are classified as DisconnectCause.BUSY
+     * @param telephonyDisconnectCause
+     * @param carrierConfig object that holds all the carrier specific settings
+     * @return whether the cause is in the carrier config busy tone array
+     */
+    private static boolean doesCarrierClassifyDisconnectCauseAsBusyCause(
+            int telephonyDisconnectCause, PersistableBundle carrierConfig) {
+        int[] busyToneArray = carrierConfig.getIntArray(
+                CarrierConfigManager.KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY);
+        for (int busyTone : busyToneArray) {
+            if (busyTone == telephonyDisconnectCause) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static PersistableBundle getCarrierConfigBundle(int phoneId) {
+        Phone phone = PhoneFactory.getPhone(phoneId);
+        PersistableBundle config;
+
+        if (phone != null) {
+            config = PhoneGlobals.getInstance().getCarrierConfigForSubId(phone.getSubId());
+        } else {
+            config = PhoneGlobals.getInstance().getCarrierConfig();
+        }
+
+        return config;
+    }
+
 }
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index ed07726..684e03a 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -2016,32 +2016,47 @@
     }
 
     @VisibleForTesting
-    public PersistableBundle getCarrierConfig() {
+    public @NonNull PersistableBundle getCarrierConfig() {
         Phone phone = getPhone();
         if (phone == null) {
-            return null;
+            Log.w(this,
+                    "getCarrierConfig: phone is null. Returning CarrierConfigManager"
+                            + ".getDefaultConfig()");
+            return CarrierConfigManager.getDefaultConfig();
         }
-        return PhoneGlobals.getInstance().getCarrierConfigForSubId(phone.getSubId());
+
+        // potential null returned from .getCarrierConfigForSubId() and method guarantees non-null.
+        // hence, need for try/finally block
+        PersistableBundle pb = null;
+        try {
+            pb = PhoneGlobals.getInstance().getCarrierConfigForSubId(phone.getSubId());
+        } catch (Exception e) {
+            Log.e(this, e,
+                    "getCarrierConfig: caught Exception when calling "
+                            + "PhoneGlobals.getCarrierConfigForSubId(phone.getSubId()). Returning "
+                            + "CarrierConfigManager.getDefaultConfig()");
+        } finally {
+            if (pb == null) {
+                pb = CarrierConfigManager.getDefaultConfig();
+            }
+        }
+        return pb;
+    }
+
+    @VisibleForTesting
+    public boolean isRttMergeSupported(@NonNull PersistableBundle pb) {
+        return pb.getBoolean(CarrierConfigManager.KEY_ALLOW_MERGING_RTT_CALLS_BOOL);
     }
 
     private boolean canDeflectImsCalls() {
-        PersistableBundle b = getCarrierConfig();
-        // Return false if the CarrierConfig is unavailable
-        if (b != null) {
-            return b.getBoolean(
-                    CarrierConfigManager.KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL) &&
-                    isValidRingingCall();
-        }
-        return false;
+        return getCarrierConfig().getBoolean(
+                CarrierConfigManager.KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL)
+                && isValidRingingCall();
     }
 
     private boolean isCallTransferSupported() {
-        PersistableBundle b = getCarrierConfig();
-        // Return false if the CarrierConfig is unavailable
-        if (b != null) {
-            return b.getBoolean(CarrierConfigManager.KEY_CARRIER_ALLOW_TRANSFER_IMS_CALL_BOOL);
-        }
-        return false;
+        return getCarrierConfig().getBoolean(
+                CarrierConfigManager.KEY_CARRIER_ALLOW_TRANSFER_IMS_CALL_BOOL);
     }
 
     private boolean canTransfer(TelephonyConnection c) {
@@ -3038,8 +3053,6 @@
         if (isIms) {
             isVoWifiEnabled = isWfcEnabled(phone);
         }
-        boolean isRttMergeSupported = getCarrierConfig()
-                .getBoolean(CarrierConfigManager.KEY_ALLOW_MERGING_RTT_CALLS_BOOL);
         PhoneAccountHandle phoneAccountHandle = isIms ? PhoneUtils
                 .makePstnPhoneAccountHandle(phone.getDefaultPhone())
                 : PhoneUtils.makePstnPhoneAccountHandle(phone);
@@ -3077,7 +3090,7 @@
         if (mTreatAsEmergencyCall) {
             isConferenceSupported = false;
             Log.d(this, "refreshConferenceSupported = false; emergency call");
-        } else if (isRtt() && !isRttMergeSupported) {
+        } else if (isRtt() && !isRttMergeSupported(getCarrierConfig())) {
             isConferenceSupported = false;
             Log.d(this, "refreshConferenceSupported = false; rtt call");
         } else if (!isConferencingSupported || isIms && !isImsConferencingSupported) {
@@ -3134,12 +3147,9 @@
         Phone phone = getPhone();
         if (phone != null && (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA)
                 && !mOriginalConnection.isIncoming()) {
-            PersistableBundle pb = getCarrierConfig();
-            if (pb != null) {
-                showOrigDialString = pb.getBoolean(CarrierConfigManager
-                        .KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL);
-                Log.d(this, "showOrigDialString: " + showOrigDialString);
-            }
+            showOrigDialString = getCarrierConfig().getBoolean(CarrierConfigManager
+                    .KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL);
+            Log.d(this, "showOrigDialString: " + showOrigDialString);
         }
         return showOrigDialString;
     }
@@ -3716,8 +3726,7 @@
         if (mOriginalConnection.isIncoming()
                 && !TextUtils.isEmpty(mOriginalConnection.getAddress())
                 && mOriginalConnection.getAddress().startsWith(JAPAN_COUNTRY_CODE_WITH_PLUS_SIGN)) {
-            PersistableBundle b = getCarrierConfig();
-            return b != null && b.getBoolean(
+            return getCarrierConfig().getBoolean(
                     CarrierConfigManager.KEY_FORMAT_INCOMING_NUMBER_TO_NATIONAL_FOR_JP_BOOL);
         }
         return false;
@@ -3742,8 +3751,7 @@
      * otherwise.
      */
     private boolean supportsD2DUsingRtp() {
-        PersistableBundle b = getCarrierConfig();
-        return b != null && b.getBoolean(
+        return getCarrierConfig().getBoolean(
                 CarrierConfigManager.KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL);
     }
 
@@ -3751,8 +3759,7 @@
      * @return {@code true} if the carrier supports D2D using DTMF digits, {@code false} otherwise.
      */
     private boolean supportsD2DUsingDtmf() {
-        PersistableBundle b = getCarrierConfig();
-        return b != null && b.getBoolean(
+        return getCarrierConfig().getBoolean(
                 CarrierConfigManager.KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_DTMF_BOOL);
     }
 
@@ -3761,8 +3768,7 @@
      * extensions used in D2D comms, {@code false} otherwise.
      */
     private boolean supportsSdpNegotiationOfRtpHeaderExtensions() {
-        PersistableBundle b = getCarrierConfig();
-        return b != null && b.getBoolean(
+        return getCarrierConfig().getBoolean(
                 CarrierConfigManager
                         .KEY_SUPPORTS_SDP_NEGOTIATION_OF_D2D_RTP_HEADER_EXTENSIONS_BOOL);
     }
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 071376d..f1c0383 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -181,18 +181,27 @@
      */
     private static class SlotStatus {
         public int slotId;
+        public int activeSubId;
         // RAT capabilities
         public int capabilities;
         // By default, we will assume that the slots are not locked.
         public boolean isLocked = false;
         // Is the emergency number associated with the slot
         public boolean hasDialedEmergencyNumber = false;
-        //SimState
+        //SimState.
         public int simState;
 
-        public SlotStatus(int slotId, int capabilities) {
+        //helper to check if sim is really 'present' in the traditional sense.
+        // since eSIM always reports SIM_STATE_READY
+        public boolean isSubActiveAndSimPresent() {
+            return (simState != TelephonyManager.SIM_STATE_ABSENT
+                && activeSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        }
+
+        public SlotStatus(int slotId, int capabilities, int activeSubId) {
             this.slotId = slotId;
             this.capabilities = capabilities;
+            this.activeSubId = activeSubId;
         }
     }
 
@@ -221,6 +230,7 @@
         public int getPhoneId(int subId) {
             return SubscriptionManager.getPhoneId(subId);
         }
+
     };
 
     /**
@@ -229,9 +239,9 @@
     @VisibleForTesting
     public interface TelephonyManagerProxy {
         int getPhoneCount();
-        boolean hasIccCard(int slotId);
         boolean isCurrentEmergencyNumber(String number);
         Map<Integer, List<EmergencyNumber>> getCurrentEmergencyNumberList();
+        boolean isConcurrentCallsPossible();
     }
 
     private TelephonyManagerProxy mTelephonyManagerProxy;
@@ -250,11 +260,6 @@
         }
 
         @Override
-        public boolean hasIccCard(int slotId) {
-            return mTelephonyManager.hasIccCard(slotId);
-        }
-
-        @Override
         public boolean isCurrentEmergencyNumber(String number) {
             try {
                 return mTelephonyManager.isEmergencyNumber(number);
@@ -271,6 +276,12 @@
                 return new HashMap<>();
             }
         }
+
+        @Override
+        public boolean isConcurrentCallsPossible() {
+            // Under DSDA, need to be determined by voice capabilities
+            return mTelephonyManager.getMaxNumberOfSimultaneouslyActiveSims() > 1;
+        }
     }
 
     /**
@@ -1636,7 +1647,13 @@
             Bundle connExtras = c.getExtras();
             Log.i(this, "retryOutgoingOriginalConnection, redialing on Phone Id: " + newPhoneToUse);
             c.clearOriginalConnection();
-            if (phoneId != newPhoneToUse.getPhoneId()) updatePhoneAccount(c, newPhoneToUse);
+            if (phoneId != newPhoneToUse.getPhoneId()) {
+                if (!mTelephonyManagerProxy.isConcurrentCallsPossible()) {
+                    disconnectAllCallsOnOtherSubs(
+                            mPhoneUtilsProxy.makePstnPhoneAccountHandle(newPhoneToUse));
+                }
+                updatePhoneAccount(c, newPhoneToUse);
+            }
             placeOutgoingConnection(c, newPhoneToUse, videoState, connExtras);
         } else {
             // We have run out of Phones to use. Disconnect the call and destroy the connection.
@@ -1834,6 +1851,9 @@
             case CallStateException.ERROR_OTASP_PROVISIONING_IN_PROCESS:
                  cause = android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS;
                  break;
+            case CallStateException.ERROR_FDN_BLOCKED:
+                 cause = android.telephony.DisconnectCause.FDN_BLOCKED;
+                 break;
         }
         connection.setTelephonyConnectionDisconnected(
                 DisconnectCauseUtil.toTelecomDisconnectCause(cause, e.getMessage(),
@@ -2161,10 +2181,11 @@
             // 5)
             // Store the RAF Capabilities for sorting later.
             int radioAccessFamily = phone.getRadioAccessFamily();
-            SlotStatus status = new SlotStatus(i, radioAccessFamily);
+            SlotStatus status = new SlotStatus(i, radioAccessFamily, phone.getSubId());
             phoneSlotStatus.add(status);
             Log.i(this, "getFirstPhoneForEmergencyCall, RAF:" +
-                    Integer.toHexString(radioAccessFamily) + " saved for Phone Id:" + i);
+                Integer.toHexString(radioAccessFamily) + " saved for Phone Id:" + i + " subId:"
+                + phone.getSubId());
             // 4)
             // Report Slot's PIN/PUK lock status for sorting later.
             int simState = mSubscriptionManagerProxy.getSimStateForSlotIdx(i);
@@ -2174,6 +2195,7 @@
                     simState == TelephonyManager.SIM_STATE_PUK_REQUIRED) {
                 status.isLocked = true;
             }
+
             // 3) Store if the Phone has the corresponding emergency number
             if (phonesWithEmergencyNumber != null) {
                 for (Phone phoneWithEmergencyNumber : phonesWithEmergencyNumber) {
@@ -2184,13 +2206,15 @@
                 }
             }
             // 6)
-            if (firstPhoneWithSim == null && mTelephonyManagerProxy.hasIccCard(i)) {
-                // The slot has a SIM card inserted, but is not in service, so keep track of this
-                // Phone. Do not return because we want to make sure that none of the other Phones
+            if (firstPhoneWithSim == null &&
+                (phone.getSubId() != SubscriptionManager.INVALID_SIM_SLOT_INDEX)) {
+                // The slot has a SIM card inserted (and an active subscription), but is not in
+                // service, so keep track of this Phone.
+                // Do not return because we want to make sure that none of the other Phones
                 // are in service (because that is always faster).
                 firstPhoneWithSim = phone;
-                Log.i(this, "getFirstPhoneForEmergencyCall, SIM card inserted, Phone Id:" +
-                        firstPhoneWithSim.getPhoneId());
+                Log.i(this, "getFirstPhoneForEmergencyCall, SIM with active sub, Phone Id:" +
+                    firstPhoneWithSim.getPhoneId());
             }
         }
         // 7)
@@ -2206,18 +2230,19 @@
             final int defaultPhoneId = mPhoneFactoryProxy.getDefaultPhone().getPhoneId();
             final Phone firstOccupiedSlot = firstPhoneWithSim;
             if (!phoneSlotStatus.isEmpty()) {
+                Log.i(this, "getFirstPhoneForEmergencyCall, list size: " + phoneSlotStatus.size()
+                    + " defaultPhoneId: " + defaultPhoneId + " firstOccupiedSlot: "
+                    + firstOccupiedSlot);
                 // Only sort if there are enough elements to do so.
                 if (phoneSlotStatus.size() > 1) {
                     Collections.sort(phoneSlotStatus, (o1, o2) -> {
-                        // Sort by non-absent SIM.
-                        if (o1.simState == TelephonyManager.SIM_STATE_ABSENT
-                                && o2.simState != TelephonyManager.SIM_STATE_ABSENT) {
-                            return -1;
-                        }
-                        if (o2.simState == TelephonyManager.SIM_STATE_ABSENT
-                                && o1.simState != TelephonyManager.SIM_STATE_ABSENT) {
+                        // Sort by non-absent SIM (SIM without active sub is considered absent).
+                        if (o1.isSubActiveAndSimPresent() && !o2.isSubActiveAndSimPresent()) {
                             return 1;
                         }
+                        if (o2.isSubActiveAndSimPresent() && !o1.isSubActiveAndSimPresent()) {
+                            return -1;
+                        }
                         // First start by seeing if either of the phone slots are locked. If they
                         // are, then sort by non-locked SIM first. If they are both locked, sort
                         // by capability instead.
@@ -2645,4 +2670,23 @@
                     }
                 });
     }
+
+    private void disconnectAllCallsOnOtherSubs (@NonNull PhoneAccountHandle handle) {
+        Collection<Connection>connections = getAllConnections();
+        connections.stream()
+                .filter(c ->
+                        (c.getState() == Connection.STATE_ACTIVE
+                                || c.getState() == Connection.STATE_HOLDING)
+                                // Include any calls not on same sub as current connection.
+                                && !Objects.equals(c.getPhoneAccountHandle(), handle))
+                .forEach(c -> {
+                    if (c instanceof TelephonyConnection) {
+                        TelephonyConnection tc = (TelephonyConnection) c;
+                        Log.i(LOG_TAG, "disconnectAllCallsOnOtherSubs: disconnect" +
+                                " %s due to redial happened on other sub.",
+                                tc.getTelecomCallId());
+                        tc.hangup(android.telephony.DisconnectCause.LOCAL);
+                    }
+                });
+    }
 }
diff --git a/src/com/android/services/telephony/rcs/RcsFeatureController.java b/src/com/android/services/telephony/rcs/RcsFeatureController.java
index 0e1cb4b..48c84b1 100644
--- a/src/com/android/services/telephony/rcs/RcsFeatureController.java
+++ b/src/com/android/services/telephony/rcs/RcsFeatureController.java
@@ -19,6 +19,7 @@
 import android.annotation.AnyThread;
 import android.content.Context;
 import android.net.Uri;
+import android.telephony.SubscriptionManager;
 import android.telephony.ims.ImsException;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
@@ -402,6 +403,17 @@
         callback.accept(mImsRcsRegistrationHelper.getImsRegistrationState());
     }
 
+    /**
+     * @return the subscription ID that is currently associated with this RCS feature.
+     */
+    public int getAssociatedSubId() {
+        RcsFeatureManager manager = getFeatureManager();
+        if (manager != null) {
+            return manager.getSubId();
+        }
+        return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+    }
+
     private void updateCapabilities() {
         RcsFeatureManager manager = getFeatureManager();
         if (manager != null) {
diff --git a/src/com/android/services/telephony/rcs/TelephonyRcsService.java b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
index dfcea74..13b3a7d 100644
--- a/src/com/android/services/telephony/rcs/TelephonyRcsService.java
+++ b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
@@ -244,6 +244,22 @@
     }
 
     /**
+     * Verifies the subId supplied is the active subId for the slotId specified.
+     * If we have not processed a CARRIER_CONFIG_CHANGED indication for this subscription yet,
+     * either the subscription is not active or we have not finished setting up the feature yet.
+     * @param slotId The slotId we are verifying
+     * @param subId The subId we are verifying
+     * @return true if the subId is the active subId we are tracking for the slotId specified.
+     */
+    public boolean verifyActiveSubId(int slotId, int subId) {
+        synchronized (mLock) {
+            int currId = mSlotToAssociatedSubIds.get(slotId,
+                    SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+            return subId == currId;
+        }
+    }
+
+    /**
      * ACTION_CARRIER_CONFIG_CHANGED was received by this service for a specific slot.
      * @param slotId The slotId associated with the event.
      * @param subId The subId associated with the event. May cause the subId associated with the
diff --git a/testapps/TelephonyManagerTestApp/AndroidManifest.xml b/testapps/TelephonyManagerTestApp/AndroidManifest.xml
index 40fc549..6392c26 100644
--- a/testapps/TelephonyManagerTestApp/AndroidManifest.xml
+++ b/testapps/TelephonyManagerTestApp/AndroidManifest.xml
@@ -26,7 +26,6 @@
     <uses-permission android:name="android.permission.CALL_PRIVILEGED"/>
     <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
 
-            android.Manifest.permission.ACCESS_FINE_LOCATION
     <application android:label="TelephonyManagerTestApp">
         <activity android:name=".TelephonyManagerTestApp"
              android:label="TelephonyManagerTestApp"
diff --git a/testapps/TestSliceApp/.idea/.gitignore b/testapps/TestSliceApp/.idea/.gitignore
deleted file mode 100644
index 26d3352..0000000
--- a/testapps/TestSliceApp/.idea/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
diff --git a/testapps/TestSliceApp/.idea/compiler.xml b/testapps/TestSliceApp/.idea/compiler.xml
deleted file mode 100644
index fb7f4a8..0000000
--- a/testapps/TestSliceApp/.idea/compiler.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="CompilerConfiguration">
-    <bytecodeTargetLevel target="11" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/testapps/TestSliceApp/.idea/gradle.xml b/testapps/TestSliceApp/.idea/gradle.xml
deleted file mode 100644
index 526b4c2..0000000
--- a/testapps/TestSliceApp/.idea/gradle.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="GradleMigrationSettings" migrationVersion="1" />
-  <component name="GradleSettings">
-    <option name="linkedExternalProjectsSettings">
-      <GradleProjectSettings>
-        <option name="testRunner" value="GRADLE" />
-        <option name="distributionType" value="DEFAULT_WRAPPED" />
-        <option name="externalProjectPath" value="$PROJECT_DIR$" />
-        <option name="modules">
-          <set>
-            <option value="$PROJECT_DIR$" />
-            <option value="$PROJECT_DIR$/app" />
-          </set>
-        </option>
-        <option name="resolveModulePerSourceSet" value="false" />
-      </GradleProjectSettings>
-    </option>
-  </component>
-</project>
\ No newline at end of file
diff --git a/testapps/TestSliceApp/.idea/misc.xml b/testapps/TestSliceApp/.idea/misc.xml
deleted file mode 100644
index a329266..0000000
--- a/testapps/TestSliceApp/.idea/misc.xml
+++ /dev/null
@@ -1,76 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="DesignSurface">
-    <option name="filePathToZoomLevelMap">
-      <map>
-        <entry key="app/src/main/res/drawable/ic_launcher_background.xml" value="0.38177083333333334" />
-        <entry key="app/src/main/res/layout/_copy.xml" value="0.365625" />
-        <entry key="app/src/main/res/layout/activity_main.xml" value="0.4891304347826087" />
-        <entry key="app/src/main/res/layout/copy.xml" value="0.37135416666666665" />
-        <entry key="app/src/main/res/layout/fragment_c_b_s.xml" value="0.473731884057971" />
-        <entry key="app/src/main/res/layout/fragment_c_b_s_copy.xml" value="0.365625" />
-        <entry key="app/src/main/res/layout/fragment_main.xml" value="0.46693840579710144" />
-        <entry key="app/src/main/res/layout/fragment_prioritize_bandwidth.xml" value="0.473731884057971" />
-        <entry key="app/src/main/res/layout/fragment_prioritize_bandwidth2.xml" value="0.365625" />
-        <entry key="app/src/main/res/layout/fragment_prioritize_latency.xml" value="0.473731884057971" />
-        <entry key="app/src/main/res/layout/fragment_prioritize_latency2.xml" value="0.365625" />
-      </map>
-    </option>
-  </component>
-  <component name="NullableNotNullManager">
-    <option name="myDefaultNullable" value="androidx.annotation.Nullable" />
-    <option name="myDefaultNotNull" value="androidx.annotation.NonNull" />
-    <option name="myNullables">
-      <value>
-        <list size="17">
-          <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
-          <item index="1" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
-          <item index="2" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
-          <item index="3" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
-          <item index="4" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
-          <item index="5" class="java.lang.String" itemvalue="com.android.annotations.Nullable" />
-          <item index="6" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
-          <item index="7" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
-          <item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
-          <item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
-          <item index="10" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
-          <item index="11" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.Nullable" />
-          <item index="12" class="java.lang.String" itemvalue="io.reactivex.annotations.Nullable" />
-          <item index="13" class="java.lang.String" itemvalue="io.reactivex.rxjava3.annotations.Nullable" />
-          <item index="14" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
-          <item index="15" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
-          <item index="16" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
-        </list>
-      </value>
-    </option>
-    <option name="myNotNulls">
-      <value>
-        <list size="17">
-          <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
-          <item index="1" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
-          <item index="2" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
-          <item index="3" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
-          <item index="4" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
-          <item index="5" class="java.lang.String" itemvalue="com.android.annotations.NonNull" />
-          <item index="6" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
-          <item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
-          <item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
-          <item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
-          <item index="10" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.NonNull" />
-          <item index="11" class="java.lang.String" itemvalue="io.reactivex.annotations.NonNull" />
-          <item index="12" class="java.lang.String" itemvalue="io.reactivex.rxjava3.annotations.NonNull" />
-          <item index="13" class="java.lang.String" itemvalue="lombok.NonNull" />
-          <item index="14" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
-          <item index="15" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
-          <item index="16" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
-        </list>
-      </value>
-    </option>
-  </component>
-  <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="JDK" project-jdk-type="JavaSDK">
-    <output url="file://$PROJECT_DIR$/build/classes" />
-  </component>
-  <component name="ProjectType">
-    <option name="id" value="Android" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/testapps/TestSliceApp/.idea/vcs.xml b/testapps/TestSliceApp/.idea/vcs.xml
deleted file mode 100644
index 498ba99..0000000
--- a/testapps/TestSliceApp/.idea/vcs.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="IssueNavigationConfiguration">
-    <option name="links">
-      <list>
-        <IssueNavigationLink>
-          <option name="issueRegexp" value="\bb/(\d+)(#\w+)?\b" />
-          <option name="linkRegexp" value="https://buganizer.corp.google.com/issues/$1$2" />
-        </IssueNavigationLink>
-        <IssueNavigationLink>
-          <option name="issueRegexp" value="\b(?:BUG=|FIXED=)(\d+)\b" />
-          <option name="linkRegexp" value="https://buganizer.corp.google.com/issues/$1" />
-        </IssueNavigationLink>
-        <IssueNavigationLink>
-          <option name="issueRegexp" value="\b(?:cl/|cr/|OCL=|DIFFBASE=|ROLLBACK_OF=)(\d+)\b" />
-          <option name="linkRegexp" value="https://critique.corp.google.com/$1" />
-        </IssueNavigationLink>
-        <IssueNavigationLink>
-          <option name="issueRegexp" value="\bomg/(\d+)\b" />
-          <option name="linkRegexp" value="https://omg.corp.google.com/$1" />
-        </IssueNavigationLink>
-        <IssueNavigationLink>
-          <option name="issueRegexp" value="\b(?:go/|goto/)([^,.&lt;&gt;()&quot;\s]+(?:[.,][^,.&lt;&gt;()&quot;\s]+)*)" />
-          <option name="linkRegexp" value="https://goto.google.com/$1" />
-        </IssueNavigationLink>
-        <IssueNavigationLink>
-          <option name="issueRegexp" value="\bcs/([^\s]+[\w$])" />
-          <option name="linkRegexp" value="https://cs.corp.google.com/search/?q=$1" />
-        </IssueNavigationLink>
-        <IssueNavigationLink>
-          <option name="issueRegexp" value="(LINT\.IfChange)|(LINT\.ThenChange)" />
-          <option name="linkRegexp" value="https://goto.google.com/ifthisthenthatlint" />
-        </IssueNavigationLink>
-      </list>
-    </option>
-  </component>
-  <component name="VcsDirectoryMappings">
-    <mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/testapps/TestSliceApp/app/src/main/AndroidManifest.xml b/testapps/TestSliceApp/app/src/main/AndroidManifest.xml
index d28bbb0..a34c254 100644
--- a/testapps/TestSliceApp/app/src/main/AndroidManifest.xml
+++ b/testapps/TestSliceApp/app/src/main/AndroidManifest.xml
@@ -3,6 +3,8 @@
     package="com.google.android.sample.testsliceapp">
 
   <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+  <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+  <uses-permission android:name="android.permission.INTERNET" />
   <application
       android:allowBackup="true"
       android:icon="@mipmap/ic_launcher"
@@ -10,7 +12,8 @@
       android:roundIcon="@mipmap/ic_launcher_round"
       android:supportsRtl="true"
       android:theme="@style/Theme.AppCompat"
-      android:versionCode="34">
+      android:versionCode="34"
+      android:usesCleartextTraffic="true">
     <activity
         android:name=".MainActivity"
         android:exported="true">
@@ -29,4 +32,4 @@
           android:value="true" />
     </service>
   </application>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/CBS.java b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/CBS.java
index a555ce6..c85f830 100644
--- a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/CBS.java
+++ b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/CBS.java
@@ -20,7 +20,10 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
+import android.net.TelephonyNetworkSpecifier;
 import android.os.Bundle;
+import android.telephony.SubscriptionManager;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -62,6 +65,7 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        mConnectivityManager = getContext().getSystemService(ConnectivityManager.class);
     }
 
     @Override
@@ -80,23 +84,33 @@
         mRelease.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View view) {
-                mConnectivityManager.unregisterNetworkCallback(
+                try {
+                    mConnectivityManager.unregisterNetworkCallback(
                         mProfileCheckNetworkCallback);
+                } catch (Exception e) {
+                    Log.d("SliceTest", "Exception: " + e);
+                }
             }
         });
         mRequest = view.findViewById(R.id.requestcbs);
         mRequest.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View view) {
-                NetworkCallback mProfileCheckNetworkCallback = new NetworkCallback() {
+                mProfileCheckNetworkCallback = new NetworkCallback() {
                     @Override
                     public void onAvailable(final Network network) {
                         mNetwork = network;
+                        Log.d("CBS", "onAvailable + " + network);
                     }
                 };
                 NetworkRequest.Builder builder = new NetworkRequest.Builder();
                 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS);
+                builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+                int subId = SubscriptionManager.getDefaultDataSubscriptionId();
+                builder.setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+                        .setSubscriptionId(subId).build());
                 mConnectivityManager.requestNetwork(builder.build(), mProfileCheckNetworkCallback);
+                Log.d("CBS", "onClick + " + builder.build());
             }
         });
         mPing = view.findViewById(R.id.pingcbs);
@@ -106,8 +120,9 @@
                 if (mNetwork != null) {
                     //mNetwork.
                     try {
-                        new RequestTask().ping(mNetwork);
+                        new RequestTask().execute(mNetwork);
                     } catch (Exception e) {
+                        Log.d("SliceTest", "Exception: " + e);
                     }
                 }
             }
diff --git a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeBandwidth.java b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeBandwidth.java
index d997178..6812ddc 100644
--- a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeBandwidth.java
+++ b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeBandwidth.java
@@ -21,6 +21,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -73,6 +74,7 @@
                 new NetworkCallback() {
             @Override
             public void onAvailable(final Network network) {
+                Log.d("SliceTest", "onAvailable: " + network);
                 mNetwork = network;
             }
         };
@@ -80,23 +82,30 @@
         mRelease.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View view) {
-                mConnectivityManager.unregisterNetworkCallback(mProfileCheckNetworkCallback);
+                try {
+                    mConnectivityManager.unregisterNetworkCallback(
+                            mProfileCheckNetworkCallback);
+                } catch (Exception e) {
+                    Log.d("SliceTest", "Exception: " + e);
+                }
             }
         });
         mRequest = view.findViewById(R.id.requestbw);
         mRequest.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View view) {
-                NetworkCallback mProfileCheckNetworkCallback =
+                mProfileCheckNetworkCallback =
                         new NetworkCallback() {
                     @Override
                     public void onAvailable(final Network network) {
+                        Log.d("PrioritizeBandwidth", "onAvailable + " + network);
                         mNetwork = network;
                     }
                 };
                 NetworkRequest.Builder builder = new NetworkRequest.Builder();
                 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH);
                 mConnectivityManager.requestNetwork(builder.build(), mProfileCheckNetworkCallback);
+                Log.d("PrioritizeBandwidth", "onClick + " + builder.build());
             }
         });
         mPing = view.findViewById(R.id.pingbw);
@@ -104,10 +113,10 @@
             @Override
             public void onClick(View view) {
                 if (mNetwork != null) {
-                    //mNetwork.
                     try {
-                        new RequestTask().ping(mNetwork);
+                        new RequestTask().execute(mNetwork);
                     } catch (Exception e) {
+                        Log.d("SliceTest", "Exception: " + e);
                     }
                 }
             }
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 b45362c..45ea666 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
@@ -21,6 +21,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -61,6 +62,7 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        mConnectivityManager = getContext().getSystemService(ConnectivityManager.class);
     }
 
     @Override
@@ -79,22 +81,29 @@
         mRelease.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View view) {
-                mConnectivityManager.unregisterNetworkCallback(mProfileCheckNetworkCallback);
+                try {
+                    mConnectivityManager.unregisterNetworkCallback(
+                            mProfileCheckNetworkCallback);
+                } catch (Exception e) {
+                    Log.d("SliceTest", "Exception: " + e);
+                }
             }
         });
         mRequest = view.findViewById(R.id.requestlatency);
         mRequest.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View view) {
-                NetworkCallback mProfileCheckNetworkCallback = new NetworkCallback() {
+                mProfileCheckNetworkCallback = new NetworkCallback() {
                     @Override
                     public void onAvailable(final Network network) {
+                        Log.d("PrioritizeLatency", "onAvailable + " + network);
                         mNetwork = network;
                     }
                 };
                 NetworkRequest.Builder builder = new NetworkRequest.Builder();
                 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY);
                 mConnectivityManager.requestNetwork(builder.build(), mProfileCheckNetworkCallback);
+                Log.d("PrioritizeLatency", "onClick + " + builder.build());
             }
         });
         mPing = view.findViewById(R.id.pinglatency);
@@ -106,6 +115,7 @@
                     try {
                         new RequestTask().ping(mNetwork);
                     } catch (Exception e) {
+                        Log.d("SliceTest", "Exception: " + e);
                     }
                 }
             }
diff --git a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/RequestTask.java b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/RequestTask.java
index b12939e..3849860 100644
--- a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/RequestTask.java
+++ b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/RequestTask.java
@@ -16,6 +16,8 @@
 package com.google.android.sample.testsliceapp;
 
 import android.net.Network;
+import android.os.AsyncTask;
+import android.util.Log;
 
 import java.io.BufferedInputStream;
 import java.io.IOException;
@@ -23,7 +25,11 @@
 import java.net.HttpURLConnection;
 import java.net.URL;
 
-class RequestTask{
+class RequestTask extends AsyncTask<Network, Integer, Integer> {
+    protected Integer doInBackground(Network... network) {
+        ping(network[0]);
+        return 0;
+    }
     String ping(Network network) {
         URL url = null;
         try {
@@ -32,8 +38,12 @@
         }
         if (url != null) {
             try {
-                return httpGet(network, url);
+                Log.d("SliceTest", "ping " + url);
+                String result = httpGet(network, url);
+                Log.d("SliceTest", "result " + result);
+                return result;
             } catch (Exception e) {
+                Log.d("SliceTest", "exception: " + e);
             }
         }
         return "";
@@ -47,6 +57,7 @@
         HttpURLConnection connection = (HttpURLConnection) network.openConnection(httpUrl);
         try {
             InputStream inputStream = connection.getInputStream();
+            Log.d("httpGet", "httpUrl + " + httpUrl);
             return new BufferedInputStream(inputStream).toString();
         } finally {
             connection.disconnect();
diff --git a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/TestCarrierService.java b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/TestCarrierService.java
index b1d019e..daa1d17 100644
--- a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/TestCarrierService.java
+++ b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/TestCarrierService.java
@@ -21,6 +21,7 @@
 import android.service.carrier.CarrierService;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
+import android.util.Log;
 
 /**
  * Carrier Service that sets the carrier config upon being bound by the system. Requires UICC
@@ -32,11 +33,13 @@
         CarrierConfigManager cfgMgr =
                 (CarrierConfigManager) getSystemService(Context.CARRIER_CONFIG_SERVICE);
         cfgMgr.notifyConfigChangedForSubId(SubscriptionManager.getDefaultSubscriptionId());
+        Log.d("TestCarrierService", "onCreate + ");
     }
 
     @Override
     public PersistableBundle onLoadConfig(CarrierIdentifier carrierIdentifier) {
         PersistableBundle config = new PersistableBundle();
+        Log.d("TestCarrierService", "onLoadConfig + ");
         return config;
     }
 }
diff --git a/testapps/TestSliceApp/app/src/main/res/layout/fragment_c_b_s.xml b/testapps/TestSliceApp/app/src/main/res/layout/fragment_c_b_s.xml
index ac2ef9d..5305b53 100644
--- a/testapps/TestSliceApp/app/src/main/res/layout/fragment_c_b_s.xml
+++ b/testapps/TestSliceApp/app/src/main/res/layout/fragment_c_b_s.xml
@@ -8,9 +8,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:id="@+id/frameLayoutCBS">
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
+<androidx.constraintlayout.widget.ConstraintLayout
     android:id="@+id/frameLayout3"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
@@ -26,23 +24,26 @@
       android:id="@+id/requestcbs"
       android:layout_width="186dp"
       android:layout_height="57dp"
+      android:layout_marginTop="164dp"
       android:text="Request Network"
-      tools:layout_editor_absoluteX="120dp"
-      tools:layout_editor_absoluteY="154dp" />
+      app:layout_constraintTop_toTopOf="parent"
+      tools:layout_editor_absoluteX="112dp" />
   <Button
       android:id="@+id/releasecbs"
       android:layout_width="187dp"
       android:layout_height="61dp"
+      android:layout_marginTop="124dp"
       android:text="Release Network"
-      tools:layout_editor_absoluteX="119dp"
-      tools:layout_editor_absoluteY="273dp" />
+      app:layout_constraintTop_toBottomOf="@+id/requestcbs"
+      tools:layout_editor_absoluteX="119dp" />
   <Button
       android:id="@+id/pingcbs"
       android:layout_width="186dp"
       android:layout_height="55dp"
       android:text="Ping"
-      tools:layout_editor_absoluteX="120dp"
-      tools:layout_editor_absoluteY="379dp" />
+      app:layout_constraintBottom_toBottomOf="parent"
+      app:layout_constraintTop_toBottomOf="@+id/releasecbs"
+      tools:layout_editor_absoluteX="120dp" />
 </androidx.constraintlayout.widget.ConstraintLayout>
 </FrameLayout>
 </RelativeLayout>
\ No newline at end of file
diff --git a/testapps/TestSliceApp/app/src/main/res/layout/fragment_prioritize_latency.xml b/testapps/TestSliceApp/app/src/main/res/layout/fragment_prioritize_latency.xml
index 9527d69..b040995 100644
--- a/testapps/TestSliceApp/app/src/main/res/layout/fragment_prioritize_latency.xml
+++ b/testapps/TestSliceApp/app/src/main/res/layout/fragment_prioritize_latency.xml
@@ -8,51 +8,52 @@
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:id="@+id/frameLayoutLatency">
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/frameLayout"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    tools:context=".PrioritizeLatency" >
-  <Button
-      android:id="@+id/requestlatency"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:text="RequestNetwork"
-      app:layout_constraintBottom_toTopOf="@+id/button6"
-      app:layout_constraintEnd_toEndOf="parent"
-      app:layout_constraintHorizontal_bias="0.461"
-      app:layout_constraintStart_toStartOf="parent"
-      app:layout_constraintTop_toTopOf="parent"
-      app:layout_constraintVertical_bias="0.717" />
-  <Button
-      android:id="@+id/releaselatency"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_marginBottom="76dp"
-      android:text="Release Network"
-      app:layout_constraintBottom_toTopOf="@+id/button7"
-      app:layout_constraintEnd_toEndOf="parent"
-      app:layout_constraintHorizontal_bias="0.478"
-      app:layout_constraintStart_toStartOf="parent" />
-  <Button
-      android:id="@+id/pinglatency"
-      android:layout_width="182dp"
-      android:layout_height="42dp"
-      android:layout_marginBottom="308dp"
-      android:text="Ping"
-      app:layout_constraintBottom_toBottomOf="parent"
-      app:layout_constraintEnd_toEndOf="parent"
-      app:layout_constraintHorizontal_bias="0.471"
-      app:layout_constraintStart_toStartOf="parent" />
-  <TextView
-      android:id="@+id/textView"
-      android:layout_width="371dp"
-      android:layout_height="52dp"
-      android:text="Prioritize Latency"
-      tools:layout_editor_absoluteX="21dp"
-      tools:layout_editor_absoluteY="1dp" />
-</androidx.constraintlayout.widget.ConstraintLayout>
-    </FrameLayout>
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/frameLayout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        tools:context=".PrioritizeLatency">
+      <Button
+          android:id="@+id/requestlatency"
+          android:layout_width="183dp"
+          android:layout_height="50dp"
+          android:layout_marginTop="176dp"
+          android:text="RequestNetwork"
+          app:layout_constraintBottom_toTopOf="@+id/button6"
+          app:layout_constraintEnd_toEndOf="parent"
+          app:layout_constraintHorizontal_bias="0.495"
+          app:layout_constraintStart_toStartOf="parent"
+          app:layout_constraintTop_toTopOf="parent"
+          app:layout_constraintVertical_bias="0.717" />
+      <Button
+          android:id="@+id/releaselatency"
+          android:layout_width="183dp"
+          android:layout_height="50dp"
+          android:layout_marginTop="84dp"
+          android:text="ReleaseNetwork"
+          app:layout_constraintBottom_toTopOf="@+id/button6"
+          app:layout_constraintEnd_toEndOf="parent"
+          app:layout_constraintStart_toStartOf="parent"
+          app:layout_constraintTop_toBottomOf="@+id/requestlatency"
+          app:layout_constraintVertical_bias="0.717" />
+      <Button
+          android:id="@+id/pinglatency"
+          android:layout_width="182dp"
+          android:layout_height="42dp"
+          android:layout_marginBottom="92dp"
+          android:text="Ping"
+          app:layout_constraintBottom_toBottomOf="parent"
+          app:layout_constraintEnd_toEndOf="parent"
+          app:layout_constraintHorizontal_bias="0.493"
+          app:layout_constraintStart_toStartOf="parent"
+          app:layout_constraintTop_toBottomOf="@+id/releaselatency" />
+      <TextView
+          android:id="@+id/textView"
+          android:layout_width="371dp"
+          android:layout_height="52dp"
+          android:text="Prioritize Latency"
+          tools:layout_editor_absoluteX="16dp"
+          tools:layout_editor_absoluteY="16dp" />
+    </androidx.constraintlayout.widget.ConstraintLayout>
+  </FrameLayout>
     </RelativeLayout>
\ No newline at end of file
diff --git a/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java b/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java
index 7f9efdc..28a7b02 100644
--- a/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java
+++ b/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java
@@ -17,19 +17,104 @@
 package com.android.services.telephony;
 
 import static android.media.ToneGenerator.TONE_PROP_PROMPT;
+import static android.media.ToneGenerator.TONE_SUP_BUSY;
 
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.TestCase.assertEquals;
 
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
 
+import androidx.test.InstrumentationRegistry;
 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 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 {
+public class DisconnectCauseUtilTest extends TelephonyTestBase {
+
+    // constants
+    public static final int PHONE_ID = 123;
+    public static final String EMPTY_STRING = "";
+
+    // 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();
+        // objects that call static getInstance()
+        mMockPhone = Mockito.mock(GsmCdmaPhone.class);
+        mContext = InstrumentationRegistry.getTargetContext();
+        // set mocks
+        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.
@@ -43,4 +128,109 @@
         assertNotNull(tcCause.getDescription());
         assertNotNull(tcCause.getReason());
     }
+
+    /**
+     *  ensure the default behavior was not changed when a disconnect cause comes in as
+     *  DisconnectCause.ERROR_UNSPECIFIED
+     */
+    @Test
+    public void testDefaultDisconnectCauseBehaviorForCauseNotInCarrierBusyToneArray() {
+        android.telecom.DisconnectCause tcCause = DisconnectCauseUtil.toTelecomDisconnectCause(
+                DisconnectCause.ERROR_UNSPECIFIED, EMPTY_STRING, PHONE_ID);
+        // CODE
+        assertEquals(android.telecom.DisconnectCause.ERROR, tcCause.getCode());
+        // LABEL
+        safeAssertLabel(null, tcCause);
+        // TONE
+        assertEquals(TONE_PROP_PROMPT, tcCause.getTone());
+    }
+
+    /**
+     *  Simulate a Carrier classifying the DisconnectCause.ERROR_UNSPECIFIED as a
+     *  DisconnectCause.BUSY.  The code, label, and tone should match DisconnectCause.BUSY.
+     */
+    @Test
+    public void testCarrierSetDisconnectCauseInBusyToneArray() {
+        int[] carrierBusyArr = {DisconnectCause.BUSY, DisconnectCause.ERROR_UNSPECIFIED};
+        PersistableBundle config = new PersistableBundle();
+
+        config.putIntArray(
+                CarrierConfigManager.KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY,
+                carrierBusyArr);
+
+        android.telecom.DisconnectCause tcCause =
+                DisconnectCauseUtil.toTelecomDisconnectCause(
+                        DisconnectCause.ERROR_UNSPECIFIED, -1,
+                        EMPTY_STRING, PHONE_ID, null, config);
+
+        // CODE
+        assertEquals(android.telecom.DisconnectCause.BUSY, tcCause.getCode());
+        // LABEL
+        safeAssertLabel(R.string.callFailed_userBusy, tcCause);
+        // TONE
+        assertEquals(TONE_SUP_BUSY, tcCause.getTone());
+    }
+
+    private void setSinglePhone() throws Exception {
+        Phone[] mPhones = new Phone[]{mMockPhone};
+        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();
+        config.setLocale(locale);
+        Context localeContext = context.createConfigurationContext(config);
+        return localeContext.getResources();
+    }
+
+    private void safeAssertLabel(Integer resourceId,
+            android.telecom.DisconnectCause disconnectCause) {
+        Resources r = getResourcesForLocale(mContext, Locale.US);
+        if (resourceId == null || r == null) {
+            return;
+        }
+        String label = r.getString(resourceId);
+        assertEquals(label, disconnectCause.getLabel());
+    }
+
+    /**
+     * Verifies that an ICC_ERROR disconnect cause generates a message which mentions there is no
+     * SIM.
+     */
+    @Test
+    public void testIccError() {
+        android.telecom.DisconnectCause tcCause = DisconnectCauseUtil.toTelecomDisconnectCause(
+                DisconnectCause.ICC_ERROR);
+        assertEquals(android.telecom.DisconnectCause.ERROR, tcCause.getCode());
+        assertNotNull(tcCause.getLabel());
+        assertNotNull(tcCause.getDescription());
+    }
 }
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index efa906e..c4d22ab 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -49,6 +49,7 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.RadioAccessFamily;
 import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.emergency.EmergencyNumber;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -396,9 +397,6 @@
         // Slot 1 has more capabilities
         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
         setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
-        // Slot 1 has SIM inserted.
-        setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
-        setSlotHasIccCard(SLOT_1_PHONE_ID, true /*isInserted*/);
 
         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
 
@@ -511,9 +509,6 @@
         // Make Capability the same
         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
         setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
-        // Two SIMs inserted
-        setSlotHasIccCard(SLOT_0_PHONE_ID, true /*isInserted*/);
-        setSlotHasIccCard(SLOT_1_PHONE_ID, true /*isInserted*/);
 
         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
 
@@ -542,9 +537,6 @@
         // Make Capability the same
         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
         setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
-        // Slot 0 has SIM inserted.
-        setSlotHasIccCard(SLOT_0_PHONE_ID, true /*isInserted*/);
-        setSlotHasIccCard(SLOT_1_PHONE_ID, false /*isInserted*/);
 
         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
 
@@ -573,9 +565,35 @@
         // Make Capability the same
         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
         setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
-        // Slot 1 has SIM inserted.
-        setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
-        setSlotHasIccCard(SLOT_1_PHONE_ID, true /*isInserted*/);
+
+        Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+        assertEquals(slot1Phone, resultPhone);
+    }
+
+    /**
+     * Prerequisites:
+     * - MSIM Device with one ESIM, only slot 1 inserted has PSIM inserted
+     * - Both phones have the same capability
+     *
+     * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone because it is the only one
+     * with a SIM inserted
+     */
+    @Test
+    @SmallTest
+    public void testEqualCapabilitySim1Inserted_WithOneEsim() {
+        Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+            false /*isEmergencyOnly*/);
+        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+            false /*isEmergencyOnly*/);
+        setDefaultPhone(slot0Phone);
+        setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+        when(slot0Phone.getSubId()).thenReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+        setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+        // Make Capability the same
+        setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
+        setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
 
         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
 
@@ -604,9 +622,6 @@
         // Make Capability the same
         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
         setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
-        // No SIMs inserted
-        setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
-        setSlotHasIccCard(SLOT_1_PHONE_ID, false /*isInserted*/);
 
         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
 
@@ -634,9 +649,63 @@
         // Make Capability the same
         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_UNKNOWN);
         setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_UNKNOWN);
-        // No SIMs inserted
-        setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
-        setSlotHasIccCard(SLOT_1_PHONE_ID, false /*isInserted*/);
+
+        Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+        assertEquals(slot0Phone, resultPhone);
+    }
+
+    /**
+     * Prerequisites:
+     * - MSIM Device, no SIMs inserted (one ESIM)
+     * - Both SIMs have the same capability (Unknown)
+     *
+     * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone, since it is the first slot.
+     */
+    @Test
+    @SmallTest
+    public void testEqualCapabilityNoSimsInserted_WithOneESim() {
+        Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+            false /*isEmergencyOnly*/);
+        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+            false /*isEmergencyOnly*/);
+        setDefaultPhone(slot0Phone);
+        setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+        setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
+        when(slot1Phone.getSubId()).thenReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+        // Make Capability the samesvim
+        setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_UNKNOWN);
+        setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_UNKNOWN);
+
+        Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+        assertEquals(slot0Phone, resultPhone);
+    }
+
+    /**
+     * Prerequisites:
+     * - MSIM Device, both ESIMS (no profile activated)
+     * - Both phones have the same capability (Unknown)
+     *
+     * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone, since it is the first slot.
+     */
+    @Test
+    @SmallTest
+    public void testEqualCapabilityNoSimsInserted_WithTwoESims() {
+        Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+            false /*isEmergencyOnly*/);
+        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+            false /*isEmergencyOnly*/);
+        setDefaultPhone(slot0Phone);
+        setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+        when(slot0Phone.getSubId()).thenReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+        when(slot1Phone.getSubId()).thenReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+        // Make Capability the sames
+        setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_UNKNOWN);
+        setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_UNKNOWN);
 
         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
 
@@ -1497,10 +1566,6 @@
         when(mSubscriptionManagerProxy.getSimStateForSlotIdx(slotId)).thenReturn(slotState);
     }
 
-    private void setSlotHasIccCard(int slotId, boolean isInserted) {
-        when(mTelephonyManagerProxy.hasIccCard(slotId)).thenReturn(isInserted);
-    }
-
     private void setDefaultPhone(Phone phone) {
         when(mPhoneFactoryProxy.getDefaultPhone()).thenReturn(phone);
     }
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionTest.java
index 388fd29..c996e5f 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionTest.java
@@ -14,6 +14,7 @@
 import static org.mockito.Mockito.when;
 
 import android.os.Bundle;
+import android.os.PersistableBundle;
 import android.telecom.Connection;
 import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
@@ -25,6 +26,7 @@
 import com.android.internal.telephony.d2d.DtmfTransport;
 import com.android.internal.telephony.d2d.RtpTransport;
 import com.android.internal.telephony.imsphone.ImsPhoneConnection;
+import com.android.phone.PhoneGlobals;
 import com.android.phone.R;
 
 import org.junit.Before;
@@ -212,4 +214,47 @@
             fail("refreshConferenceSupported threw ClassCastException");
         }
     }
+
+    /**
+     * Tests TelephonyConnection#getCarrierConfig never returns a null given all cases that can
+     * cause a potential null.
+     */
+    @Test
+    public void testGetCarrierConfigBehaviorWithNull() throws Exception {
+        TestTelephonyConnectionSimple c = new TestTelephonyConnectionSimple();
+
+        // case: return a valid carrier config (good case)
+        when(c.mPhoneGlobals.getCarrierConfigForSubId(c.getPhone().getSubId())).
+                thenReturn(CarrierConfigManager.getDefaultConfig());
+        assertNotNull(c.getCarrierConfig());
+
+        // case: PhoneGlobals.getInstance().getCarrierConfigForSubId(int) returns null
+        when(c.mPhoneGlobals.getCarrierConfigForSubId(c.getPhone().getSubId()))
+                .thenReturn(null);
+        assertNotNull(c.getCarrierConfig());
+
+        // case: phone is null
+        c.setMockPhone(null);
+        assertNull(c.getPhone());
+        assertNotNull(c.getCarrierConfig());
+    }
+
+    /**
+     * Tests the behavior of TelephonyConnection#isRttMergeSupported(@NonNull PersistableBundle).
+     * Note, the function should be able to handle an empty PersistableBundle and should NEVER
+     * receive a null object as denoted in by @NonNull annotation.
+     */
+    @Test
+    public void testIsRttMergeSupportedBehavior() {
+        TestTelephonyConnection c = new TestTelephonyConnection();
+        //  ensure isRttMergeSupported(PersistableBundle) does not throw NPE when given an Empty PB
+        assertFalse(c.isRttMergeSupported(new PersistableBundle()));
+
+        // simulate the passing situation
+        c.getCarrierConfigBundle().putBoolean(
+                CarrierConfigManager.KEY_ALLOW_MERGING_RTT_CALLS_BOOL,
+                true);
+        assertTrue(c.isRttMergeSupported(c.getCarrierConfig()));
+    }
+
 }
diff --git a/tests/src/com/android/services/telephony/TelephonyManagerTest.java b/tests/src/com/android/services/telephony/TelephonyManagerTest.java
index cf1ae8f..89b558c 100644
--- a/tests/src/com/android/services/telephony/TelephonyManagerTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyManagerTest.java
@@ -15,11 +15,14 @@
  */
 
 package com.android.services.telephony;
-
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -28,6 +31,8 @@
 import android.app.PropertyInvalidatedCache;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.RemoteException;
 import android.telecom.PhoneAccountHandle;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -37,6 +42,8 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.telephony.ITelephony;
+import com.android.internal.telephony.IPhoneSubInfo;
+import com.android.internal.telephony.PhoneConstants;
 
 import org.junit.After;
 import org.junit.Before;
@@ -61,8 +68,10 @@
     private static final int TEST_SUBID_2 = 2;
 
     private ITelephony mMockITelephony;
+    private IPhoneSubInfo mMockIPhoneSubInfo;
     private SubscriptionManager mMockSubscriptionManager;
     private Context mMockContext;
+    private final PackageManager mPackageManager = mock(PackageManager.class);
 
     private TelephonyManager mTelephonyManager;
 
@@ -89,18 +98,23 @@
                     }
                     return null;
                 }
+                @Override
+                public PackageManager getPackageManager() {
+                    return mPackageManager;
+                }
             };
 
     @Before
     public void setUp() throws Exception {
         mMockITelephony = mock(ITelephony.class);
+        mMockIPhoneSubInfo = mock(IPhoneSubInfo.class);
         mMockSubscriptionManager = mock(SubscriptionManager.class);
         mMockContext = mock(Context.class);
         when(mMockContext.getSystemService(eq(Context.TELEPHONY_SUBSCRIPTION_SERVICE)))
                 .thenReturn(mMockSubscriptionManager);
-
         mTelephonyManager = new TelephonyManager(mContext);
         TelephonyManager.setupITelephonyForTest(mMockITelephony);
+        TelephonyManager.setupIPhoneSubInfoForTest(mMockIPhoneSubInfo);
         TelephonyManager.enableServiceHandleCaching();
     }
 
@@ -218,4 +232,32 @@
         verify(mMockITelephony, times(1)).getSubIdForPhoneAccountHandle(eq(TEST_HANDLE2),
                 anyString(), anyString());
     }
+
+    @Test
+    public void testGetSimServiceTable_USIM() throws RemoteException {
+        assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION, true));
+        when(mMockIPhoneSubInfo.getSimServiceTable(anyInt(), anyInt())).thenReturn("12345");
+        assertEquals("12345", mTelephonyManager.getSimServiceTable(PhoneConstants.APPTYPE_USIM));
+        verify(mMockIPhoneSubInfo, times(1)).getSimServiceTable(anyInt(), anyInt());
+    }
+
+    @Test
+    public void testGetSimServiceTable_ISIM() throws RemoteException {
+        when(mMockIPhoneSubInfo.getIsimIst(anyInt())).thenReturn("12345");
+        assertEquals("12345", mTelephonyManager.getSimServiceTable(PhoneConstants.APPTYPE_ISIM));
+        verify(mMockIPhoneSubInfo, times(1)).getIsimIst(anyInt());
+    }
+
+    @Test
+    public void testGetSimServiceTable_RUSIM() throws RemoteException {
+        assumeFalse(hasFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION, false));
+        assertEquals(null, mTelephonyManager.getSimServiceTable(PhoneConstants.APPTYPE_RUIM));
+    }
+
+    private boolean hasFeature(String feature, boolean status) {
+        doReturn(status)
+                .when(mPackageManager).hasSystemFeature(
+                        PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION);
+        return mContext.getPackageManager().hasSystemFeature(feature);
+    }
 }
diff --git a/tests/src/com/android/services/telephony/TestTelephonyConnectionSimple.java b/tests/src/com/android/services/telephony/TestTelephonyConnectionSimple.java
new file mode 100644
index 0000000..9dc2551
--- /dev/null
+++ b/tests/src/com/android/services/telephony/TestTelephonyConnectionSimple.java
@@ -0,0 +1,72 @@
+/*
+ * 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.services.telephony;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.AttributionSource;
+import android.content.Context;
+import android.os.Process;
+import android.telephony.TelephonyManager;
+
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.phone.PhoneGlobals;
+
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+public class TestTelephonyConnectionSimple extends TelephonyConnection{
+
+    @Mock
+    Context mMockContext;
+
+    @Mock
+    PhoneGlobals mPhoneGlobals;
+
+    private Phone mMockPhone;
+
+    public TelephonyConnection cloneConnection() {
+        return this;
+    }
+
+    public TestTelephonyConnectionSimple(){
+        super(null, null, android.telecom.Call.Details.DIRECTION_INCOMING);
+        MockitoAnnotations.initMocks(this);
+
+        AttributionSource attributionSource = new AttributionSource.Builder(
+                Process.myUid()).build();
+
+        mMockPhone    = mock(Phone.class);
+        mMockContext  = mock(Context.class);
+        mPhoneGlobals = mock(PhoneGlobals.class);
+
+        when(mMockPhone.getSubId()).thenReturn(1);
+    }
+
+    public void setMockPhone(Phone newPhone) {
+        mMockPhone = newPhone;
+    }
+
+    @Override
+    public Phone getPhone() {
+        return mMockPhone;
+    }
+
+}