[automerger skipped] Import translations. DO NOT MERGE ANYWHERE am: b5f3e8194a -s ours am: 2f2dae4c13 -s ours am: b5225e5fb2 -s ours

am skip reason: subject contains skip directive

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

Change-Id: I2915b77e4391d3f18179a2f0c7ead36b257468a3
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 2e2bf46..edc71b3 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -47,7 +47,7 @@
     <string name="no_vm_number" msgid="6623853880546176930">"వాయిస్ మెయిల్ నంబర్ లేదు"</string>
     <string name="no_vm_number_msg" msgid="5165161462411372504">"సిమ్ కార్డులో వాయిస్ మెయిల్ నంబర్ ఏదీ నిల్వ చేయబడలేదు."</string>
     <string name="add_vm_number_str" msgid="7368168964435881637">"నంబర్‌ను జోడించు"</string>
-    <string name="voice_number_setting_primary_user_only" msgid="3394706575741912843">"వాయిస్ మెయిల్ సెట్టింగ్‌లను ప్రాథమిక వినియోగదారు మాత్రమే ఎడిట్ చేయగలరు."</string>
+    <string name="voice_number_setting_primary_user_only" msgid="3394706575741912843">"వాయిస్ మెయిల్ సెట్టింగ్‌లను ప్రాథమిక వినియోగదారు మాత్రమే సవరించగలరు."</string>
     <string name="puk_unlocked" msgid="4627340655215746511">"మీ SIM కార్డు అన్‌బ్లాక్ చేయబడింది. మీ ఫోన్ అన్‌లాక్ చేయబడుతోంది…"</string>
     <string name="label_ndp" msgid="7617392683877410341">"SIM నెట్‌వర్క్ అన్‌లాక్ పిన్‌"</string>
     <string name="label_phoneid" msgid="8775611434123577808">"ఈ ఆపరేటర్‌కు సంబంధించి SIM లాక్ చేయబడింది"</string>
@@ -145,7 +145,7 @@
     <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="radio_off_error" msgid="8321564164914232181">"ఈ సెట్టింగ్‌లను చూడటానికి ముందు రేడియోను ప్రారంభించండి."</string>
+    <string name="radio_off_error" msgid="8321564164914232181">"ఈ సెట్టింగ్‌లను వీక్షించడానికి ముందు రేడియోను ప్రారంభించండి."</string>
     <string name="close_dialog" msgid="1074977476136119408">"సరే"</string>
     <string name="enable" msgid="2636552299455477603">"ఆన్ చేయి"</string>
     <string name="disable" msgid="1122698860799462116">"ఆఫ్ చేయి"</string>
@@ -471,13 +471,13 @@
     <string name="fdn_contact_added" msgid="2840016151693394596">"ఫిక్స్‌డ్ డయలింగ్ నంబర్ జోడించబడింది."</string>
     <string name="edit_fdn_contact" msgid="6030829994819587408">"ఫిక్స్‌డ్ డయలింగ్ నంబర్‌ను ఎడిట్ చేయండి"</string>
     <string name="updating_fdn_contact" msgid="6989341376868227150">"ఫిక్స్‌డ్ డయలింగ్ నంబర్‌ను అప్‌డేట్ చేస్తోంది..."</string>
-    <string name="fdn_contact_updated" msgid="6876330243323118937">"ఫిక్స్‌డ్ డయలింగ్ నంబర్ అప్‌డేట్ చేయబడింది."</string>
+    <string name="fdn_contact_updated" msgid="6876330243323118937">"ఫిక్స్‌డ్ డయలింగ్ నంబర్ నవీకరించబడింది."</string>
     <string name="delete_fdn_contact" msgid="7027405651994507077">"ఫిక్స్‌డ్ డయలింగ్ నంబర్‌ను తొలగించండి"</string>
     <string name="deleting_fdn_contact" msgid="6872320570844460428">"ఫిక్స్‌డ్ డయలింగ్ నంబర్‌ను తొలగిస్తోంది..."</string>
     <string name="fdn_contact_deleted" msgid="1680714996763848838">"ఫిక్స్‌డ్ డయలింగ్ నంబర్ తొలగించబడింది."</string>
-    <string name="pin2_invalid" msgid="2313954262684494442">"మీరు చెల్లని PINను టైప్ చేసినందున FDN అప్‌డేట్ చేయబడలేదు."</string>
+    <string name="pin2_invalid" msgid="2313954262684494442">"మీరు చెల్లని PINను టైప్ చేసినందున FDN నవీకరించబడలేదు."</string>
     <string name="fdn_invalid_number" msgid="9067189814657840439">"నంబర్ <xliff:g id="FDN_NUMBER_LIMIT_LENGTH">%d</xliff:g> అంకెలను మించినందున FDN అప్‌డేట్ చేయబడలేదు."</string>
-    <string name="pin2_or_fdn_invalid" msgid="7542639487955868181">"FDN అప్‌డేట్ చేయబడలేదు. PIN2 చెల్లదు లేదా ఫోన్ నంబర్ తిరస్కరించబడింది."</string>
+    <string name="pin2_or_fdn_invalid" msgid="7542639487955868181">"FDN నవీకరించబడలేదు. PIN2 చెల్లదు లేదా ఫోన్ నంబర్ తిరస్కరించబడింది."</string>
     <string name="fdn_failed" msgid="216592346853420250">"FDN చర్య విఫలమైంది."</string>
     <string name="simContacts_emptyLoading" msgid="4989040293858675483">"SIM కార్డు నుండి చదువుతోంది…"</string>
     <string name="simContacts_empty" msgid="1135632055473689521">"మీ SIM కార్డులో కాంటాక్ట్‌లు ఏవీ లేవు."</string>
@@ -498,7 +498,7 @@
     <string name="enable_pin_ok" msgid="2877428038280804256">"PIN సెట్ చేయబడింది"</string>
     <string name="disable_pin_ok" msgid="888505244389647754">"PIN తీసివేయబడింది"</string>
     <string name="pin_failed" msgid="4527347792881939652">"PIN చెల్లదు"</string>
-    <string name="pin_changed" msgid="7291153750090452808">"PIN అప్‌డేట్ చేయబడింది"</string>
+    <string name="pin_changed" msgid="7291153750090452808">"PIN నవీకరించబడింది"</string>
     <string name="puk_requested" msgid="2061337960609806851">"పాస్‌వర్డ్ చెల్లదు. PIN ఇప్పుడు బ్లాక్ చేయబడింది. PUK రిక్వెస్ట్ చేయబడింది."</string>
     <string name="enter_pin2_text" msgid="7266379426804295979">"PIN2"</string>
     <string name="oldPin2Label" msgid="4648543187859997203">"పాత PIN2"</string>
@@ -509,7 +509,7 @@
     <string name="mismatchPin2" msgid="4952718725266700631">"PIN2లు సరిపోలలేదు. మళ్లీ ప్రయత్నించండి."</string>
     <string name="invalidPin2" msgid="6467957903056379343">"4 నుండి 8 సంఖ్యలు ఉండే PIN2ని నమోదు చేయండి."</string>
     <string name="invalidPuk2" msgid="713729511903849544">"8 సంఖ్యలు ఉండే PUK2ను నమోదు చేయండి."</string>
-    <string name="pin2_changed" msgid="5710551850481287821">"PIN2 అప్‌డేట్ చేయబడింది"</string>
+    <string name="pin2_changed" msgid="5710551850481287821">"PIN2 నవీకరించబడింది"</string>
     <string name="label_puk2_code" msgid="2852217004288085562">"PUK2 కోడ్‌ను నమోదు చేయండి"</string>
     <string name="fdn_enable_puk2_requested" msgid="5793652792131588041">"పాస్‌వర్డ్ చెల్లదు. PIN2 ఇప్పుడు బ్లాక్ చేయబడింది. మళ్లీ ప్రయత్నించడానికి, PIN 2ను మార్చండి."</string>
     <string name="puk2_requested" msgid="6992374450720307514">"పాస్‌వర్డ్ చెల్లదు. SIM ఇప్పుడు లాక్ చేయబడింది. PUK2ని నమోదు చేయండి."</string>
@@ -675,7 +675,7 @@
     <string name="status_hint_label_incoming_wifi_call" msgid="2606052595898044071">"వీరి నుండి Wi-Fi కాల్"</string>
     <string name="status_hint_label_wifi_call" msgid="942993035689809853">"Wi-Fi కాల్"</string>
     <string name="message_decode_error" msgid="1061856591500290887">"మెసేజ్‌ను డీకోడ్ చేస్తున్నప్పుడు ఎర్రర్ ఏర్పడింది."</string>
-    <string name="callFailed_cdma_activation" msgid="5392057031552253550">"SIM కార్డ్ మీ సేవను సక్రియం చేసింది మరియు మీ ఫోన్ రోమింగ్ సామర్థ్యాలను అప్‌డేట్ చేసింది."</string>
+    <string name="callFailed_cdma_activation" msgid="5392057031552253550">"SIM కార్డ్ మీ సేవను సక్రియం చేసింది మరియు మీ ఫోన్ రోమింగ్ సామర్థ్యాలను నవీకరించింది."</string>
     <string name="callFailed_cdma_call_limit" msgid="1074219746093031412">"చాలా ఎక్కువ కాల్స్‌ యాక్టివ్‌గా ఉన్నాయి. దయచేసి మరొక కొత్త కాల్ చేసే ముందు ఇప్పటికే ఉన్న కాల్స్‌ను ముగించండి లేదా విలీనం చేయండి."</string>
     <string name="callFailed_imei_not_accepted" msgid="7257903653685147251">"కనెక్ట్ చేయడం సాధ్యపడలేదు, దయచేసి చెల్లుబాటు అయ్యే SIM కార్డ్‌ను చొప్పించండి."</string>
     <string name="callFailed_wifi_lost" msgid="1788036730589163141">"Wi-Fi కనెక్షన్ పోయింది. కాల్ ముగిసింది."</string>
@@ -693,7 +693,7 @@
     <string name="change_pin_enter_new_pin_hint" msgid="2326038476516364210">"PIN తప్పనిసరిగా <xliff:g id="MIN">%1$d</xliff:g>-<xliff:g id="MAX">%2$d</xliff:g> అంకెల మధ్య ఉండాలి."</string>
     <string name="change_pin_confirm_pin_header" msgid="2606303906320705726">"మీ PINని నిర్ధారించండి"</string>
     <string name="change_pin_confirm_pins_dont_match" msgid="305164501222587215">"PINలు సరిపోలలేదు"</string>
-    <string name="change_pin_succeeded" msgid="2504705600693014403">"వాయిస్ మెయిల్ PIN అప్‌డేట్ చేయబడింది"</string>
+    <string name="change_pin_succeeded" msgid="2504705600693014403">"వాయిస్ మెయిల్ PIN నవీకరించబడింది"</string>
     <string name="change_pin_system_error" msgid="7772788809875146873">"PINని సెట్ చేయడం సాధ్యపడలేదు"</string>
     <string name="mobile_data_status_roaming_turned_off_subtext" msgid="6840673347416227054">"డేటా రోమింగ్ ఆఫ్ చేయబడింది"</string>
     <string name="mobile_data_status_roaming_turned_on_subtext" msgid="5615757897768777865">"డేటా రోమింగ్ ఆన్ చేయబడింది"</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/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/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/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/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());
+    }
 }