prevent overlays on the phone settings am: e827d8f13c am: 8b6e49c268 am: 81a2fc9662 am: 247b2acf94 am: 3993e20efc am: ab7d024fa9 am: 3abfa6b5e5 am: 7b4b8687b7 am: dd83f29a3b

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

Change-Id: I9824101c4bd59014a376895e533b8eb4d2f696de
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 6781a2a..5d19229 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -34,7 +34,7 @@
     <string name="enter_input" msgid="6193628663039958990">"የUSSD መልዕክት በ<xliff:g id="MIN_LEN">%1$d</xliff:g> እና <xliff:g id="MAX_LEN">%2$d</xliff:g> ቁምፊዎች መካከል መሆን አለበት። እባክዎ እንደገና ይሞክሩ።"</string>
     <string name="manageConferenceLabel" msgid="8415044818156353233">"የስብሰባስልክ ጥሪ አደራጅ"</string>
     <string name="ok" msgid="7818974223666140165">"እሺ"</string>
-    <string name="audio_mode_speaker" msgid="243689733219312360">"ድምጽ ማጉያ"</string>
+    <string name="audio_mode_speaker" msgid="243689733219312360">"ድምፅ ማጉያ"</string>
     <string name="audio_mode_earpiece" msgid="2823700267171134282">"የስልክ እጀታ ጆሮማዳመጫ"</string>
     <string name="audio_mode_wired_headset" msgid="5028010823105817443">"ባለ ገመድ የጆሮ ማዳመጫ"</string>
     <string name="audio_mode_bluetooth" msgid="25732183428018809">"ብሉቱዝ"</string>
@@ -623,7 +623,7 @@
     <string name="ota_title_activate_success" msgid="1272135024761004889">"ስልክ አግብረሃል!"</string>
     <string name="ota_title_problem_with_activation" msgid="7019745985413368726">"ከአግብር ጋር ያለ ችግር"</string>
     <string name="ota_listen" msgid="2772252405488894280">"አግብር መጠናቀቁን እስኪሰሙ የተነገሩትን መመሪያዎች ይከተሉ።"</string>
-    <string name="ota_speaker" msgid="1086766980329820528">"ድምጽ ማጉያ"</string>
+    <string name="ota_speaker" msgid="1086766980329820528">"ድምፅ ማጉያ"</string>
     <string name="ota_progress" msgid="8837259285255700132">"ስልክዎን ፕሮግራም በማድረግ ላይ…"</string>
     <string name="ota_failure" msgid="5674217489921481576">"ስልክዎን ፕሮግራም ማድረግ አልተቻለም"</string>
     <string name="ota_successful" msgid="1106825981548107774">"አሁን ስልክዎ አግብሯል።አገልግሎቱ ለመጀመር እስከ 15 ደቂቃዎች ሊፈጅ ይችላል።"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 2a7f7e3..583de99 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -144,7 +144,7 @@
     <string name="stk_cc_ss_to_ussd_error" msgid="8330749347425752192">"SS অনুৰোধ USSD অনুৰোধলৈ সলনি কৰা হ’ল"</string>
     <string name="stk_cc_ss_to_ss_error" msgid="8297155544652134278">"নতুন SS অনুৰোধলৈ সলনি কৰা হ’ল"</string>
     <string name="stk_cc_ss_to_dial_video_error" msgid="4255261231466032505">"SS অনুৰোধ ভিডিঅ\' কললৈ সলনি কৰা হ’ল"</string>
-    <string name="fdn_check_failure" msgid="1833769746374185247">"আপোনাৰ ফ\'ন এপটোৰ ফিক্সড্ ডায়েলিং নম্বৰ ছেটিঙটো অন কৰি থোৱা আছে। ফলস্বৰূপে, কল সম্পৰ্কীয় কিছুমান সুবিধাই কাম কৰা নাই।"</string>
+    <string name="fdn_check_failure" msgid="1833769746374185247">"আপোনাৰ ফ\'ন এপ্‌টোৰ ফিক্সড্ ডায়েলিং নম্বৰ ছেটিঙটো অন কৰি থোৱা আছে। ফলস্বৰূপে, কল সম্পৰ্কীয় কিছুমান সুবিধাই কাম কৰা নাই।"</string>
     <string name="radio_off_error" msgid="8321564164914232181">"এই ছেটিংসমূহ চোৱাৰ আগতে ৰেডিঅ\' অন কৰক।"</string>
     <string name="close_dialog" msgid="1074977476136119408">"ঠিক"</string>
     <string name="enable" msgid="2636552299455477603">"অন কৰক"</string>
@@ -179,7 +179,7 @@
     <string name="network_query_error" msgid="3862515805115145124">"নেটৱৰ্ক বিচাৰি পোৱা নগ\'ল। আকৌ চেষ্টা কৰক।"</string>
     <string name="register_on_network" msgid="4194770527833960423">"<xliff:g id="NETWORK">%s</xliff:g>ৰ লগত পঞ্জীয়ন কৰি থকা হৈছে…"</string>
     <string name="not_allowed" msgid="8541221928746104798">"আপোনাৰ ছিম কাৰ্ডখনে এই নেটৱৰ্কটোৰ সৈতে সংযোগ কৰিবলৈ অনুমতি নিদিয়ে।"</string>
-    <string name="connect_later" msgid="1950138106010005425">"এই মুহূৰ্তত এই নেটৱৰ্কটোৰ সৈতে সংযোগ কৰিব নোৱাৰি। পিছত আকৌ চেষ্টা কৰক।"</string>
+    <string name="connect_later" msgid="1950138106010005425">"এই মুহূৰ্তত এই নেটৱৰ্কটোৰ সৈতে সংযোগ কৰিব নোৱাৰি। পাছত আকৌ চেষ্টা কৰক।"</string>
     <string name="registration_done" msgid="5337407023566953292">"নেটৱৰ্কৰ লগত পঞ্জীয়ন কৰা হ’ল।"</string>
     <string name="already_auto" msgid="8607068290733079336">"স্বয়ংক্ৰিয় বাছনিত ইতিমধ্যে আছে।"</string>
     <string name="select_automatically" msgid="779750291257872651">"স্বয়ংক্ৰিয়ভাৱে নেটৱৰ্ক বাছনি কৰক"</string>
@@ -613,7 +613,7 @@
     <string name="network_info_message" msgid="7599413947016532355">"নেটৱৰ্ক বাৰ্তা"</string>
     <string name="network_error_message" msgid="4271579424089326618">"আসোঁৱাহ বাৰ্তা"</string>
     <string name="ota_title_activate" msgid="4049645324841263423">"আপোনাৰ ফ\'নটো সক্ৰিয় কৰক"</string>
-    <string name="ota_touch_activate" msgid="838764494319694754">"আপোনাৰ ফ\'নৰ সেৱা সক্ৰিয় কৰিবলৈ এটা বিশেষ কল কৰা প্ৰয়োজন। \n\nআপোনাৰ ফ\'নটো সক্ৰিয় কৰিবলৈ \"সক্ৰিয় কৰক\"ত টিপাৰ পিছত নিৰ্দেশনাসমূহ শুনক।"</string>
+    <string name="ota_touch_activate" msgid="838764494319694754">"আপোনাৰ ফ\'নৰ সেৱা সক্ৰিয় কৰিবলৈ এটা বিশেষ কল কৰা প্ৰয়োজন। \n\nআপোনাৰ ফ\'নটো সক্ৰিয় কৰিবলৈ \"সক্ৰিয় কৰক\"ত টিপাৰ পাছত নিৰ্দেশনাসমূহ শুনক।"</string>
     <string name="ota_hfa_activation_title" msgid="3300556778212729671">"সক্ৰিয় কৰি থকা হৈছে..."</string>
     <string name="ota_hfa_activation_dialog_message" msgid="7921718445773342996">"ফ\'নটোৱে আপোনাৰ ম’বাইল ডেটা সেৱা সক্ৰিয় কৰি আছে।\n\nএই কামটো সম্পূৰ্ণ হ\'বলৈ ৫ মিনিট পৰ্যন্ত সময় লাগিব পাৰে।"</string>
     <string name="ota_skip_activation_dialog_title" msgid="7666611236789203797">"সক্ৰিয়কৰণ এৰি যায় নেকি?"</string>
@@ -794,7 +794,7 @@
     <string name="call_barring_confirm_pwd" msgid="7552526161616461858">"পাছৱৰ্ড নিশ্চিত কৰক"</string>
     <string name="messageCallBarring" msgid="5537730400652466912">"পাছৱৰ্ড দিয়ক"</string>
     <string name="call_barring_settings" msgid="4616607285790258919">"কল প্ৰতিবন্ধক ছেটিংসমূহ"</string>
-    <string name="callFailed_NetworkBusy" msgid="5437103975842913681">"নেটৱৰ্ক ব্যস্ত। অনুগ্ৰহ কৰি কিছুসময় পিছত আকৌ কল কৰাৰ চেষ্টা কৰক।"</string>
+    <string name="callFailed_NetworkBusy" msgid="5437103975842913681">"নেটৱৰ্ক ব্যস্ত। অনুগ্ৰহ কৰি কিছুসময় পাছত আকৌ কল কৰাৰ চেষ্টা কৰক।"</string>
     <string name="callFailed_NetworkCongested" msgid="6801283142342775380">"নেটৱর্ক ব্যস্ত আছে। সহায়তাৰ বাবে আপোনাৰ ম\'বাইল অ\'পাৰেটৰৰ সৈতে যোগাযোগ কৰক।"</string>
     <string name="supp_service_notification_call_deflected" msgid="4980942818105909813">"কলটো বিচ্যুত কৰা হৈছে।"</string>
     <string name="supp_service_notification_call_forwarded" msgid="7102930311735433088">"কলটো ফৰৱাৰ্ড কৰা হ’ল।"</string>
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/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index f2641a1..226664d 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.READ_PHONE_STATE;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.BroadcastOptions;
 import android.app.Notification;
@@ -47,6 +48,7 @@
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.RadioAccessFamily;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -59,6 +61,7 @@
 
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.TelephonyCapabilities;
 import com.android.internal.telephony.util.NotificationChannelController;
 import com.android.phone.settings.VoicemailSettingsActivity;
@@ -895,15 +898,21 @@
         Log.i(LOG_TAG, msg);
     }
 
-    /**
-     * In case network selection notification shows up repeatedly under
-     * unstable network condition. The logic is to check whether or not
-     * the service state keeps in no service condition for at least
-     * {@link #NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIME_IN_MS}.
-     * And checking {@link #NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIMES} times.
-     * To avoid the notification showing up for the momentary state.
-     */
     private void shouldShowNotification(int serviceState, int subId) {
+        // "Network selection unavailable" notification should only show when network selection is
+        // visible to the end user. Some CC items e.g. KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL
+        // can be overridden to hide the network selection to the end user. In this case, the
+        // notification is not shown to avoid confusion to the end user.
+        if (!shouldDisplayNetworkSelectOptions(subId)) {
+            logi("Skipping network selection unavailable notification due to carrier policy.");
+            return;
+        }
+
+        // In unstable network condition, the phone may go in and out of service. Add logic here to
+        // debounce the network selection notification. The notification only shows after phone is
+        // out of service, AND fulfills one of the two conditions below:
+        // - Out of service lasts {@link #NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIME_IN_MS}
+        // - Or has checked {@link #NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIMES} times
         if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
             if (mPreviousServiceState.get(subId, STATE_UNKNOWN_SERVICE)
                     != ServiceState.STATE_OUT_OF_SERVICE) {
@@ -955,4 +964,111 @@
     private static long getTimeStamp() {
         return SystemClock.elapsedRealtime();
     }
+
+    // TODO(b/243010310): merge methods below with Settings#MobileNetworkUtils and optimize them.
+    // The methods below are copied from com.android.settings.network.telephony.MobileNetworkUtils
+    // to make sure the network selection unavailable notification should not show when network
+    // selection menu is not visible to the end user in Settings app.
+    private boolean shouldDisplayNetworkSelectOptions(int subId) {
+        final TelephonyManager telephonyManager = mTelephonyManager.createForSubscriptionId(subId);
+        final CarrierConfigManager carrierConfigManager = mContext.getSystemService(
+                CarrierConfigManager.class);
+        final PersistableBundle carrierConfig = carrierConfigManager.getConfigForSubId(subId);
+
+        if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID
+                || carrierConfig == null
+                || !carrierConfig.getBoolean(
+                CarrierConfigManager.KEY_OPERATOR_SELECTION_EXPAND_BOOL)
+                || carrierConfig.getBoolean(
+                CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL)
+                || (carrierConfig.getBoolean(CarrierConfigManager.KEY_CSP_ENABLED_BOOL)
+                && !telephonyManager.isManualNetworkSelectionAllowed())) {
+            return false;
+        }
+
+        if (isWorldMode(carrierConfig)) {
+            final int networkMode = RadioAccessFamily.getNetworkTypeFromRaf(
+                    (int) telephonyManager.getAllowedNetworkTypesForReason(
+                            TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER));
+            if (networkMode == RILConstants.NETWORK_MODE_LTE_CDMA_EVDO) {
+                return false;
+            }
+            if (shouldSpeciallyUpdateGsmCdma(telephonyManager, carrierConfig)) {
+                return false;
+            }
+            if (networkMode == RILConstants.NETWORK_MODE_LTE_GSM_WCDMA) {
+                return true;
+            }
+        }
+
+        return isGsmBasicOptions(telephonyManager, carrierConfig);
+    }
+
+    private static boolean isWorldMode(@NonNull PersistableBundle carrierConfig) {
+        return carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_MODE_ENABLED_BOOL);
+    }
+
+    private static boolean shouldSpeciallyUpdateGsmCdma(@NonNull TelephonyManager telephonyManager,
+            @NonNull PersistableBundle carrierConfig) {
+        if (!isWorldMode(carrierConfig)) {
+            return false;
+        }
+
+        final int networkMode = RadioAccessFamily.getNetworkTypeFromRaf(
+                (int) telephonyManager.getAllowedNetworkTypesForReason(
+                        TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER));
+        if (networkMode == RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM
+                || networkMode == RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA
+                || networkMode == RILConstants.NETWORK_MODE_LTE_TDSCDMA
+                || networkMode == RILConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA
+                || networkMode
+                == RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA
+                || networkMode == RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA) {
+            if (!isTdscdmaSupported(telephonyManager, carrierConfig)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private static boolean isTdscdmaSupported(@NonNull TelephonyManager telephonyManager,
+            @NonNull PersistableBundle carrierConfig) {
+        if (carrierConfig.getBoolean(CarrierConfigManager.KEY_SUPPORT_TDSCDMA_BOOL)) {
+            return true;
+        }
+        final String[] numericArray = carrierConfig.getStringArray(
+                CarrierConfigManager.KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY);
+        if (numericArray == null) {
+            return false;
+        }
+        final ServiceState serviceState = telephonyManager.getServiceState();
+        final String operatorNumeric =
+                (serviceState != null) ? serviceState.getOperatorNumeric() : null;
+        if (operatorNumeric == null) {
+            return false;
+        }
+        for (String numeric : numericArray) {
+            if (operatorNumeric.equals(numeric)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean isGsmBasicOptions(@NonNull TelephonyManager telephonyManager,
+            @NonNull PersistableBundle carrierConfig) {
+        if (!carrierConfig.getBoolean(
+                CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL)
+                && carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) {
+            return true;
+        }
+
+        if (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) {
+            return true;
+        }
+
+        return false;
+    }
+    // END of TODO:(b/243010310): merge methods above with Settings#MobileNetworkUtils and optimize.
 }
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/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 99e73ff..f6ec75d 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -549,15 +549,15 @@
                     mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED, null);
 
             mTelephonyCallbacks = new PhoneAppCallback[tm.getSupportedModemCount()];
-
-            for (Phone phone : PhoneFactory.getPhones()) {
-                int subId = phone.getSubId();
-                PhoneAppCallback callback = new PhoneAppCallback(subId);
-                tm.createForSubscriptionId(subId).registerTelephonyCallback(
-                        TelephonyManager.INCLUDE_LOCATION_DATA_NONE, mHandler::post, callback);
-                mTelephonyCallbacks[phone.getPhoneId()] = callback;
+            if (tm.getSupportedModemCount() > 0) {
+                for (Phone phone : PhoneFactory.getPhones()) {
+                    int subId = phone.getSubId();
+                    PhoneAppCallback callback = new PhoneAppCallback(subId);
+                    tm.createForSubscriptionId(subId).registerTelephonyCallback(
+                            TelephonyManager.INCLUDE_LOCATION_DATA_NONE, mHandler::post, callback);
+                    mTelephonyCallbacks[phone.getPhoneId()] = callback;
+                }
             }
-
             mCarrierVvmPackageInstalledReceiver.register(this);
 
             //set the default values for the preferences in the phone.
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 66cef64..a47701c 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -50,6 +50,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.LocaleList;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
@@ -7703,7 +7704,7 @@
                 if (!localeFromDefaultSim.getCountry().isEmpty()) {
                     if (DBG) log("Using locale from subId: " + subId + " locale: "
                             + localeFromDefaultSim);
-                    return localeFromDefaultSim.toLanguageTag();
+                    return matchLocaleFromSupportedLocaleList(localeFromDefaultSim);
                 } else {
                     simLanguage = localeFromDefaultSim.getLanguage();
                 }
@@ -7716,7 +7717,7 @@
             final Locale mccLocale = LocaleUtils.getLocaleFromMcc(mApp, mcc, simLanguage);
             if (mccLocale != null) {
                 if (DBG) log("No locale from SIM, using mcc locale:" + mccLocale);
-                return mccLocale.toLanguageTag();
+                return matchLocaleFromSupportedLocaleList(mccLocale);
             }
 
             if (DBG) log("No locale found - returning null");
@@ -7726,6 +7727,21 @@
         }
     }
 
+    @VisibleForTesting
+    String matchLocaleFromSupportedLocaleList(@NonNull Locale inputLocale) {
+        String[] supportedLocale = com.android.internal.app.LocalePicker.getSupportedLocales(
+                getDefaultPhone().getContext());
+        for (String localeTag : supportedLocale) {
+            if (LocaleList.matchesLanguageAndScript(
+                    inputLocale, Locale.forLanguageTag(localeTag))
+                    && inputLocale.getCountry().equals(
+                    Locale.forLanguageTag(localeTag).getCountry())) {
+                return localeTag;
+            }
+        }
+        return inputLocale.toLanguageTag();
+    }
+
     private List<SubscriptionInfo> getAllSubscriptionInfoList() {
         return mSubscriptionController.getAllSubInfoList(mApp.getOpPackageName(),
                 mApp.getAttributionTag());
@@ -8095,8 +8111,7 @@
             }
             String vvmPackage = componentName.getPackageName();
             if (!callingPackage.equals(vvmPackage)) {
-                throw new SecurityException("Caller not current active visual voicemail package["
-                        + vvmPackage + "]");
+                throw new SecurityException("Caller not current active visual voicemail package");
             }
         } finally {
             Binder.restoreCallingIdentity(identity);
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/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/tests/src/com/android/TelephonyTestBase.java b/tests/src/com/android/TelephonyTestBase.java
index 09abb15..ffda81b 100644
--- a/tests/src/com/android/TelephonyTestBase.java
+++ b/tests/src/com/android/TelephonyTestBase.java
@@ -24,7 +24,9 @@
 
 import com.android.internal.telephony.PhoneConfigurationManager;
 
-import org.mockito.MockitoAnnotations;
+import org.junit.Rule;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
@@ -34,11 +36,11 @@
  * Helper class to load Mockito Resources into a test.
  */
 public class TelephonyTestBase {
+    @Rule public final MockitoRule mocks = MockitoJUnit.rule();
 
     protected TestContext mContext;
 
     public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
         mContext = spy(new TestContext());
         // Set up the looper if it does not exist on the test thread.
         if (Looper.myLooper() == null) {
diff --git a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
index fe5d013..ffc0177 100644
--- a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
+++ b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.phone;
 
+import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -35,6 +36,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Locale;
 
 /**
  * Unit Test for CarrierConfigLoader.
@@ -54,6 +58,7 @@
     @UiThreadTest
     public void setUp() throws Exception {
         super.setUp();
+        MockitoAnnotations.initMocks(this);
         doReturn(mPackageManager).when(mPhoneGlobals).getPackageManager();
         doReturn(false).when(mPackageManager).hasSystemFeature(
                 PackageManager.FEATURE_TELEPHONY_IMS);
@@ -83,4 +88,19 @@
         verify(mPhone, never()).setAllowedNetworkTypes(
                 TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER, defaultNetworkType, null);
     }
+
+    @Test
+    public void matchLocaleFromSupportedLocaleList_inputLocaleChangeToSupportedLocale() {
+        // Input zh-TW, then look up the matched supported locale, zh-Hant-TW, instead.
+        String result1 = mPhoneInterfaceManager.matchLocaleFromSupportedLocaleList(
+                Locale.forLanguageTag("zh-TW"));
+
+        assertEquals(result1, "zh-Hant-TW");
+
+        // Input ff-BF, then find the matched supported locale, ff-Latn-BF, instead.
+        String result2 = mPhoneInterfaceManager.matchLocaleFromSupportedLocaleList(
+                Locale.forLanguageTag("ff-BF"));
+
+        assertEquals(result2, "ff-Latn-BF");
+    }
 }
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());
+    }
 }