Merge "Also set call direction during single party call emulation" into rvc-dev
diff --git a/res/layout/sim_ndp.xml b/res/layout/sim_ndp.xml
index 5e3c472..5f03d7b 100644
--- a/res/layout/sim_ndp.xml
+++ b/res/layout/sim_ndp.xml
@@ -29,6 +29,7 @@
             android:layout_centerInParent="true">
 
         <TextView
+                android:id="@+id/perso_subtype_text"
                 android:textAppearance="?android:attr/textAppearanceMedium"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index ccef876..e2c5779 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -294,7 +294,7 @@
     <string name="carrier_settings_euicc_summary" msgid="2027941166597330117">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> — <xliff:g id="PHONE_NUMBER">%2$s</xliff:g>"</string>
     <string name="mobile_data_settings_title" msgid="7228249980933944101">"بيانات الجوّال"</string>
     <string name="mobile_data_settings_summary" msgid="5012570152029118471">"الوصول إلى البيانات باستخدام شبكة الجوّال"</string>
-    <string name="data_usage_disable_mobile" msgid="5669109209055988308">"هل تريد إيقاف تفعيل بيانات الجوّال؟"</string>
+    <string name="data_usage_disable_mobile" msgid="5669109209055988308">"هل تريد إيقاف بيانات الجوّال؟"</string>
     <string name="sim_selection_required_pref" msgid="6985901872978341314">"يلزم التحديد"</string>
     <string name="sim_change_data_title" msgid="9142726786345906606">"‏هل تريد تغيير شريحة SIM للبيانات؟"</string>
     <string name="sim_change_data_message" msgid="3567358694255933280">"هل تريد استخدام <xliff:g id="NEW_SIM">%1$s</xliff:g> بدلاً من <xliff:g id="OLD_SIM">%2$s</xliff:g> لبيانات الجوّال؟"</string>
@@ -704,7 +704,7 @@
     <string name="change_pin_confirm_pins_dont_match" msgid="305164501222587215">"أرقام التعريف الشخصي غير متطابقة"</string>
     <string name="change_pin_succeeded" msgid="2504705600693014403">"تمّ تحديث رقم التعريف الشخصي للبريد الصوتي"</string>
     <string name="change_pin_system_error" msgid="7772788809875146873">"يتعذر تعيين رقم التعريف الشخصي"</string>
-    <string name="mobile_data_status_roaming_turned_off_subtext" msgid="6840673347416227054">"تم إيقاف تفعيل تجوال البيانات"</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>
     <string name="mobile_data_status_roaming_without_plan_subtext" msgid="6536671968072284677">"التجوال قيد التشغيل حاليًا، يتطلب خطة بيانات"</string>
     <string name="mobile_data_status_roaming_with_plan_subtext" msgid="2576177169108123095">"التجوال قيد التشغيل حاليًا، خطة البيانات نشطة"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index e83c315..948c7cc 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -49,12 +49,12 @@
     <string name="add_vm_number_str" msgid="7368168964435881637">"Nummer hinzufügen"</string>
     <string name="voice_number_setting_primary_user_only" msgid="3394706575741912843">"Mailboxeinstellungen können nur vom primären Nutzer geändert werden."</string>
     <string name="puk_unlocked" msgid="4627340655215746511">"Deine SIM-Karte wurde entsperrt. Dein Telefon wird nun entsperrt..."</string>
-    <string name="label_ndp" msgid="7617392683877410341">"PIN zur Entsperrung des SIM-Netzwerks"</string>
+    <string name="label_ndp" msgid="7617392683877410341">"Entsperr-PIN für netzgebundenes Gerät"</string>
     <string name="sim_ndp_unlock_text" msgid="7737338355451978338">"Entsperren"</string>
     <string name="sim_ndp_dismiss_text" msgid="89667342248929777">"Verwerfen"</string>
-    <string name="requesting_unlock" msgid="930512210309437741">"Netzwerkentsperrung wird angefordert..."</string>
-    <string name="unlock_failed" msgid="7103543844840661366">"Anfrage für Entsperrung des Netzwerks war nicht erfolgreich."</string>
-    <string name="unlock_success" msgid="32681089371067565">"Entsperrung des Netzwerks nicht erfolgreich."</string>
+    <string name="requesting_unlock" msgid="930512210309437741">"Entsperrung des netzgebundenen Geräts wird angefordert..."</string>
+    <string name="unlock_failed" msgid="7103543844840661366">"Entsperranforderung für netzgebundenes Gerät war nicht erfolgreich."</string>
+    <string name="unlock_success" msgid="32681089371067565">"Entsperrung des netzgebundenen Geräts war nicht erfolgreich."</string>
     <string name="mobile_network_settings_not_available" msgid="8678168497517090039">"Mobile Netzwerkeinstellungen sind für diesen Nutzer nicht verfügbar."</string>
     <string name="labelGSMMore" msgid="7354182269461281543">"GSM-Anrufeinstellungen"</string>
     <string name="labelGsmMore_with_label" msgid="3206015314393246224">"GSM-Anrufeinstellungen (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index bde92dc..7e32dd2 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -867,7 +867,7 @@
     <string name="radio_info_dds" msgid="1122593144425697126">"Sous-identifiant de la carte SIM par défaut :"</string>
     <string name="radio_info_dl_kbps" msgid="2382922659525318726">"Bande passante de téléchargement (kb/s) :"</string>
     <string name="radio_info_ul_kbps" msgid="2102225400904799036">"Bande passante de téléversement (kb/s) :"</string>
-    <string name="radio_info_signal_location_label" msgid="6188435197086550049">"Données de la position de la cellule (discontinuées) :"</string>
+    <string name="radio_info_signal_location_label" msgid="6188435197086550049">"Données de la position de la cellule (obsolètes) :"</string>
     <string name="radio_info_phy_chan_config" msgid="1277949603275436081">"Configuration du canal physique LTE :"</string>
     <string name="radio_info_cell_info_refresh_rate" msgid="670511448975997340">"Taux d\'actualisation des données de la cellule :"</string>
     <string name="radio_info_cellinfo_label" msgid="8199062974670377659">"Données des mesures de toutes les cellules :"</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index e8a0bed..8218a84 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -259,7 +259,7 @@
         <item name="android:statusBarColor">@android:color/transparent</item>
         <item name="android:navigationBarColor">@android:color/transparent</item>
         <item name="android:homeAsUpIndicator">@drawable/ic_back_arrow</item>
-        <item name="emergencyButtonBackgroundColor">#3cffffff</item>
+        <item name="emergencyButtonBackgroundColor">#10ffffff</item>
         <item name="dialpadTheme">@style/Dialpad_DarkTransparent.Emergency</item>
     </style>
 
diff --git a/sip/res/values-in/strings.xml b/sip/res/values-in/strings.xml
index 535e5ac..709205c 100644
--- a/sip/res/values-in/strings.xml
+++ b/sip/res/values-in/strings.xml
@@ -40,7 +40,7 @@
     <string name="registration_status_registering" msgid="7986331597809521791">"Mendaftarkan..."</string>
     <string name="registration_status_still_trying" msgid="7178623685868766282">"Masih mencoba..."</string>
     <string name="registration_status_not_receiving" msgid="3873074208531938401">"Tidak menerima panggilan."</string>
-    <string name="registration_status_no_data" msgid="2987064560116584121">"Pendaftaran akun terhenti karena tidak ada sambungan internet."</string>
+    <string name="registration_status_no_data" msgid="2987064560116584121">"Pendaftaran akun terhenti karena tidak ada koneksi internet."</string>
     <string name="registration_status_no_wifi_data" msgid="685470618241482948">"Pendaftaran akun terhenti karena tidak ada sambungan Wi-Fi."</string>
     <string name="registration_status_not_running" msgid="6236403137652262659">"Pendaftaran akun gagal."</string>
     <string name="registration_status_done" msgid="6787397199273357721">"Menerima panggilan."</string>
@@ -71,7 +71,7 @@
     <string name="all_empty_alert" msgid="6085603517610199098">"Masukkan detail akun SIP baru."</string>
     <string name="empty_alert" msgid="3693655518612836718">"<xliff:g id="INPUT_FIELD_NAME">%s</xliff:g> diwajibkan dan tidak boleh kosong."</string>
     <string name="not_a_valid_port" msgid="3664668836663491376">"Nomor port harus dalam rentang 1000 dan 65534."</string>
-    <string name="no_internet_available" msgid="161720645084325479">"Untuk melakukan panggilan SIP, periksa sambungan internet terlebih dahulu."</string>
+    <string name="no_internet_available" msgid="161720645084325479">"Untuk melakukan panggilan SIP, periksa koneksi internet terlebih dahulu."</string>
     <string name="no_wifi_available" msgid="1179092018692306312">"Anda harus tersambung ke jaringan Wi-Fi untuk melakukan panggilan SIP (gunakan setelan Nirkabel &amp; Jaringan)."</string>
     <string name="no_voip" msgid="3366395789297981738">"Panggilan SIP tidak didukung"</string>
     <string name="sip_system_decide" msgid="197230378376326430">"Otomatis"</string>
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 9699e1b..e3a7de6 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -103,8 +103,10 @@
     private CarrierServiceConnection[] mServiceConnection;
     // Whether we are bound to a service for each phone
     private boolean[] mServiceBound;
-    // Whether we have sent config change bcast for each phone id.
+    // Whether we have sent config change broadcast for each phone id.
     private boolean[] mHasSentConfigChange;
+    // Whether the broadcast was sent from EVENT_SYSTEM_UNLOCKED, to track rebroadcasts
+    private boolean[] mFromSystemUnlocked;
     // SubscriptionInfoUpdater
     private final SubscriptionInfoUpdater mSubscriptionInfoUpdater;
 
@@ -200,11 +202,13 @@
                 case EVENT_SYSTEM_UNLOCKED: {
                     for (int i = 0; i < TelephonyManager.from(mContext).getActiveModemCount();
                             ++i) {
-                        // When user unlock device, we should only try to send broadcast again if we
-                        // have sent it before unlock. This will avoid we try to load carrier config
-                        // when SIM is still loading when unlock happens.
+                        // When the user unlocks the device, send the broadcast again (with a
+                        // rebroadcast extra) if we have sent it before unlock. This will avoid
+                        // trying to load the carrier config when the SIM is still loading when the
+                        // unlock happens.
                         if (mHasSentConfigChange[i]) {
                             logdWithLocalLog("System unlocked");
+                            mFromSystemUnlocked[i] = true;
                             updateConfigForPhoneId(i);
                         }
                     }
@@ -538,6 +542,7 @@
         mServiceConnection = new CarrierServiceConnection[numPhones];
         mServiceBound = new boolean[numPhones];
         mHasSentConfigChange = new boolean[numPhones];
+        mFromSystemUnlocked = new boolean[numPhones];
         // Make this service available through ServiceManager.
         TelephonyFrameworkInitializer
                 .getTelephonyServiceManager().getCarrierConfigServiceRegisterer().register(this);
@@ -636,6 +641,8 @@
             }
         }
         intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, phoneId);
+        intent.putExtra(CarrierConfigManager.EXTRA_REBROADCAST_ON_UNLOCK,
+                mFromSystemUnlocked[phoneId]);
         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
         int[] subIds = SubscriptionManager.getSubId(phoneId);
         if (subIds != null && subIds.length > 0) {
@@ -643,8 +650,8 @@
         } else {
             logd("Broadcast CARRIER_CONFIG_CHANGED for phone " + phoneId);
         }
-
         mHasSentConfigChange[phoneId] = true;
+        mFromSystemUnlocked[phoneId] = false;
     }
 
     /** Binds to the default or carrier config app. */
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index c6bac02..5d630af 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -20,6 +20,7 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.annotation.ColorInt;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -44,7 +45,6 @@
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
-import com.android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -72,6 +72,7 @@
 import com.android.phone.common.dialpad.DialpadKeyButton;
 import com.android.phone.common.util.ViewUtil;
 import com.android.phone.common.widget.ResizingTextEditText;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -151,6 +152,11 @@
     /** Size limit of emergency shortcut buttons container. **/
     private static final int SHORTCUT_SIZE_LIMIT = 3;
 
+    private static final float COLOR_DELTA = 1.0f / 16.0f;
+
+    /** Dial button color, from packages/apps/PhoneCommon/res/drawable-mdpi/fab_green.png **/
+    @ColorInt private static final int DIALER_GREEN = 0xff00c853;
+
     ResizingTextEditText mDigits;
     private View mDialButton;
     private View mDelete;
@@ -719,8 +725,12 @@
             isEmergencyNumber = true;
             phoneToMakeCall = mShortcutViewConfig.getPhoneInfo();
         } else {
-            isEmergencyNumber = getSystemService(TelephonyManager.class)
-                    .isEmergencyNumber(mLastNumber);
+            try {
+                isEmergencyNumber = getSystemService(TelephonyManager.class)
+                        .isEmergencyNumber(mLastNumber);
+            } catch (IllegalStateException ise) {
+                isEmergencyNumber = false;
+            }
         }
 
         if (isEmergencyNumber) {
@@ -1196,11 +1206,52 @@
 
     private static int getPrimaryColor(WallpaperColors colors) {
         if (colors != null) {
-            return colors.getPrimaryColor().toArgb();
+            // Android accessibility scanner
+            // (https://support.google.com/accessibility/android/answer/7158390)
+            // suggest small text and graphics have a contrast ratio greater than
+            // 4.5 with background color. The color generated from wallpaper may not
+            // follow this rule. Calculate a proper color here.
+            Color primary = colors.getPrimaryColor();
+            Color text = Color.valueOf(Color.WHITE);
+            Color dial = Color.valueOf(DIALER_GREEN);
+            // If current primary color can't follow the contrast ratio rule, make it
+            // deeper and try again.
+            while (!checkContrastRatio(primary, text)) {
+                primary = getDeeper(primary);
+            }
+            while (!checkContrastRatio(primary, dial)) {
+                primary = getDeeper(primary);
+            }
+            return primary.toArgb();
         }
         // It's possible that wallpaper colors are null (e.g. when colors are being
         // processed or a live wallpaper is used). In this case, fallback to same
         // behavior as when shortcut view is enabled.
         return Color.BLACK;
     }
+
+    private static Color getDeeper(Color color) {
+        float r = color.red() - COLOR_DELTA;
+        float g = color.green() - COLOR_DELTA;
+        float b = color.blue() - COLOR_DELTA;
+        if (r < 0f) r = 0f;
+        if (g < 0f) g = 0f;
+        if (b < 0f) b = 0f;
+        return Color.valueOf(r, g, b);
+    }
+
+    private static boolean checkContrastRatio(Color color1, Color color2) {
+        float lum1 = color1.luminance();
+        float lum2 = color2.luminance();
+        double cr;
+        if (lum1 >= lum2) {
+            cr = (lum1 + 0.05) / (lum2 + 0.05);
+        } else {
+            cr = (lum2 + 0.05) / (lum1 + 0.05);
+        }
+
+        // Make cr greater than 5.0 instead of 4.5 to guarantee that transparent white
+        // text and graphics can have contrast ratio greather than 4.5 with background.
+        return cr > 5.0;
+    }
 }
diff --git a/src/com/android/phone/IccNetworkDepersonalizationPanel.java b/src/com/android/phone/IccNetworkDepersonalizationPanel.java
index 8bd10a2..7d854cd 100644
--- a/src/com/android/phone/IccNetworkDepersonalizationPanel.java
+++ b/src/com/android/phone/IccNetworkDepersonalizationPanel.java
@@ -22,7 +22,10 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.PersistableBundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.telephony.CarrierConfigManager;
+import android.telephony.TelephonyManager;
 import android.text.Editable;
 import android.text.Spannable;
 import android.text.TextUtils;
@@ -37,6 +40,8 @@
 import android.widget.TextView;
 
 import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.uicc.IccCardApplicationStatus;
+import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState;
 
 /**
  * "SIM network unlock" PIN entry screen.
@@ -52,7 +57,8 @@
      * Tracks whether there is an instance of the network depersonalization dialog showing or not.
      * Ensures only a single instance of the dialog is visible.
      */
-    private static boolean sShowingDialog = false;
+    private static boolean [] sShowingDialog =
+            new boolean[TelephonyManager.getDefault().getSimCount()];
 
     //debug constants
     private static final boolean DBG = false;
@@ -61,29 +67,48 @@
     private static final int EVENT_ICC_NTWRK_DEPERSONALIZATION_RESULT = 100;
 
     private Phone mPhone;
+    private int mPersoSubtype;
+    private static IccNetworkDepersonalizationPanel [] sNdpPanel =
+            new IccNetworkDepersonalizationPanel[TelephonyManager.getDefault().getSimCount()];
 
     //UI elements
     private EditText     mPinEntry;
     private LinearLayout mEntryPanel;
     private LinearLayout mStatusPanel;
+    private TextView     mPersoSubtypeText;
+    private PersoSubState mPersoSubState;
     private TextView     mStatusText;
 
     private Button       mUnlockButton;
     private Button       mDismissButton;
 
+    enum statusType {
+        ENTRY,
+        IN_PROGRESS,
+        ERROR,
+        SUCCESS
+    }
+
     /**
      * Shows the network depersonalization dialog, but only if it is not already visible.
      */
-    public static void showDialog(Phone phone) {
-        if (sShowingDialog) {
+    public static void showDialog(Phone phone, int subType) {
+        int phoneId = phone == null ? 0: phone.getPhoneId();
+        if (sShowingDialog[phoneId]) {
             Log.i(TAG, "[IccNetworkDepersonalizationPanel] - showDialog; skipped already shown.");
             return;
         }
         Log.i(TAG, "[IccNetworkDepersonalizationPanel] - showDialog; showing dialog.");
-        sShowingDialog = true;
-        IccNetworkDepersonalizationPanel ndpPanel =
-                new IccNetworkDepersonalizationPanel(PhoneGlobals.getInstance(), phone);
-        ndpPanel.show();
+        sShowingDialog[phoneId] = true;
+        sNdpPanel[phoneId] = new IccNetworkDepersonalizationPanel(PhoneGlobals.getInstance(),
+                phone, subType);
+        sNdpPanel[phoneId].show();
+    }
+
+    public static void dialogDismiss(int phoneId) {
+        if (sNdpPanel[phoneId] != null && sShowingDialog[phoneId]) {
+            sNdpPanel[phoneId].dismiss();
+        }
     }
 
     //private textwatcher to control text entry.
@@ -109,37 +134,41 @@
                 AsyncResult res = (AsyncResult) msg.obj;
                 if (res.exception != null) {
                     if (DBG) log("network depersonalization request failure.");
-                    indicateError();
+                    displayStatus(statusType.ERROR.name());
                     postDelayed(new Runnable() {
-                                    public void run() {
-                                        hideAlert();
-                                        mPinEntry.getText().clear();
-                                        mPinEntry.requestFocus();
-                                    }
-                                }, 3000);
+                        public void run() {
+                            hideAlert();
+                            mPinEntry.getText().clear();
+                            mPinEntry.requestFocus();
+                        }
+                    }, 3000);
                 } else {
                     if (DBG) log("network depersonalization success.");
-                    indicateSuccess();
+                    displayStatus(statusType.SUCCESS.name());
                     postDelayed(new Runnable() {
-                                    public void run() {
-                                        dismiss();
-                                    }
-                                }, 3000);
+                        public void run() {
+                            dismiss();
+                        }
+                    }, 3000);
                 }
             }
         }
     };
 
+
     //constructor
     public IccNetworkDepersonalizationPanel(Context context) {
         super(context);
         mPhone = PhoneGlobals.getPhone();
+        mPersoSubtype = PersoSubState.PERSOSUBSTATE_SIM_NETWORK.ordinal();
     }
 
     //constructor
-    public IccNetworkDepersonalizationPanel(Context context, Phone phone) {
+    public IccNetworkDepersonalizationPanel(Context context, Phone phone,
+            int subtype) {
         super(context);
         mPhone = phone == null ? PhoneGlobals.getPhone() : phone;
+        mPersoSubtype = subtype;
     }
 
     @Override
@@ -158,6 +187,8 @@
         span.setSpan(mPinEntryWatcher, 0, text.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
 
         mEntryPanel = (LinearLayout) findViewById(R.id.entry_panel);
+        mPersoSubtypeText = (TextView) findViewById(R.id.perso_subtype_text);
+        displayStatus(statusType.ENTRY.name());
 
         mUnlockButton = (Button) findViewById(R.id.ndp_unlock);
         mUnlockButton.setOnClickListener(mUnlockListener);
@@ -190,7 +221,8 @@
     public void onStop() {
         super.onStop();
         Log.i(TAG, "[IccNetworkDepersonalizationPanel] - showDialog; hiding dialog.");
-        sShowingDialog = false;
+        int phoneId = mPhone == null ? 0 : mPhone.getPhoneId();
+        sShowingDialog[phoneId] = false;
     }
 
     //Mirrors IccPinUnlockPanel.onKeyDown().
@@ -210,29 +242,45 @@
                 return;
             }
 
-            if (DBG) log("requesting network depersonalization with code " + pin);
-            mPhone.getIccCard().supplyNetworkDepersonalization(pin,
-                    Message.obtain(mHandler, EVENT_ICC_NTWRK_DEPERSONALIZATION_RESULT));
-            indicateBusy();
+            log("Requesting De-Personalization for subtype " + mPersoSubtype);
+
+            try {
+                mPhone.getIccCard().supplySimDepersonalization(mPersoSubState,pin,
+                        Message.obtain(mHandler, EVENT_ICC_NTWRK_DEPERSONALIZATION_RESULT));
+            } catch (NullPointerException ex) {
+                log("NullPointerException @supplySimDepersonalization" + ex);
+            }
+            displayStatus(statusType.IN_PROGRESS.name());
         }
     };
 
-    private void indicateBusy() {
-        mStatusText.setText(R.string.requesting_unlock);
-        mEntryPanel.setVisibility(View.GONE);
-        mStatusPanel.setVisibility(View.VISIBLE);
-    }
+    private void displayStatus(String type) {
+        int label = 0;
 
-    private void indicateError() {
-        mStatusText.setText(R.string.unlock_failed);
-        mEntryPanel.setVisibility(View.GONE);
-        mStatusPanel.setVisibility(View.VISIBLE);
-    }
+        mPersoSubState = PersoSubState.values()[mPersoSubtype];
+        log("displayStatus mPersoSubState: " +mPersoSubState.name() +"type: " +type);
 
-    private void indicateSuccess() {
-        mStatusText.setText(R.string.unlock_success);
-        mEntryPanel.setVisibility(View.GONE);
-        mStatusPanel.setVisibility(View.VISIBLE);
+        label = getContext().getResources().getIdentifier(mPersoSubState.name()
+                + "_" + type, "string", "android");
+
+        if (label == 0) {
+            log ("Unable to get the PersoSubType string");
+            return;
+        }
+
+        if(!PersoSubState.isPersoLocked(mPersoSubState)) {
+            log ("Unsupported Perso Subtype :" + mPersoSubState.name());
+            return;
+        }
+
+        if (type == statusType.ENTRY.name()) {
+            String displayText = getContext().getString(label);
+            mPersoSubtypeText.setText(displayText);
+        } else {
+            mStatusText.setText(label);
+            mEntryPanel.setVisibility(View.GONE);
+            mStatusPanel.setVisibility(View.VISIBLE);
+        }
     }
 
     private void hideAlert() {
@@ -241,13 +289,13 @@
     }
 
     View.OnClickListener mDismissListener = new View.OnClickListener() {
-            public void onClick(View v) {
-                if (DBG) log("mDismissListener: skipping depersonalization...");
-                dismiss();
-            }
-        };
+        public void onClick(View v) {
+            if (DBG) log("mDismissListener: skipping depersonalization...");
+            dismiss();
+        }
+    };
 
     private void log(String msg) {
-        Log.v(TAG, "[IccNetworkDepersonalizationPanel] " + msg);
+        Log.d(TAG, "[IccNetworkDepersonalizationPanel] " + msg);
     }
 }
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 810ccdf..5e3c224 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -205,6 +205,16 @@
 
     private final SettingsObserver mSettingsObserver;
 
+    private static class EventSimStateChangedBag {
+        final int mPhoneId;
+        final String mIccStatus;
+
+        EventSimStateChangedBag(int phoneId, String iccStatus) {
+            mPhoneId = phoneId;
+            mIccStatus = iccStatus;
+        }
+    }
+
     Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -225,7 +235,8 @@
                         // they enter a valid SIM network PIN.
                         Log.i(LOG_TAG, "show sim depersonal panel");
                         Phone phone = (Phone) ((AsyncResult) msg.obj).userObj;
-                        IccNetworkDepersonalizationPanel.showDialog(phone);
+                        int subType = (Integer)((AsyncResult)msg.obj).result;
+                        IccNetworkDepersonalizationPanel.showDialog(phone, subType);
                     }
                     break;
 
@@ -253,8 +264,9 @@
                     // Marks the event where the SIM goes into ready state.
                     // Right now, this is only used for the PUK-unlocking
                     // process.
-                    if (msg.obj.equals(IccCardConstants.INTENT_VALUE_ICC_READY)
-                            || msg.obj.equals(IccCardConstants.INTENT_VALUE_ICC_LOADED)) {
+                    EventSimStateChangedBag bag = (EventSimStateChangedBag)msg.obj;
+                    if (bag.mIccStatus == IccCardConstants.INTENT_VALUE_ICC_READY
+                            || bag.mIccStatus == IccCardConstants.INTENT_VALUE_ICC_LOADED) {
                         // when the right event is triggered and there
                         // are UI objects in the foreground, we close
                         // them to display the lock panel.
@@ -266,6 +278,8 @@
                             mPUKEntryProgressDialog.dismiss();
                             mPUKEntryProgressDialog = null;
                         }
+                        Log.i(LOG_TAG, "Dismissing depersonal panel");
+                        IccNetworkDepersonalizationPanel.dialogDismiss(bag.mPhoneId);
                     }
                     break;
 
@@ -650,14 +664,9 @@
                     PhoneUtils.unregisterIccStatus(mHandler, phoneId);
                     PhoneUtils.registerIccStatus(mHandler, EVENT_SIM_NETWORK_LOCKED, phoneId);
                 }
-                if (mPUKEntryActivity != null) {
-                    // if an attempt to un-PUK-lock the device was made, while we're
-                    // receiving this state change notification, notify the handler.
-                    // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has
-                    // been attempted.
-                    mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED,
-                            intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)));
-                }
+                String iccStatus = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
+                mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED,
+                        new EventSimStateChangedBag(phoneId, iccStatus)));
             } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) {
                 String newPhone = intent.getStringExtra(PhoneConstants.PHONE_NAME_KEY);
                 Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " is active.");
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index fee5ecc..98af8e6 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -5509,7 +5509,6 @@
 
     /**
      * Set the preferred network type.
-     * Used for device configuration by some CDMA operators.
      *
      * @param networkType the preferred network type, defined in RILConstants.java.
      * @return true on success; false on any failure.
@@ -5523,7 +5522,11 @@
         try {
             Settings.Global.putInt(mApp.getContentResolver(),
                     Settings.Global.PREFERRED_NETWORK_MODE + subId, networkType);
-            return setPreferredNetworkTypesInternal(subId);
+
+            Boolean success = (Boolean) sendRequest(
+                    CMD_SET_PREFERRED_NETWORK_TYPE, networkType, subId);
+            if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
+            return success;
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -5561,38 +5564,15 @@
     public boolean setAllowedNetworkTypes(int subId, long allowedNetworkTypes) {
         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
                 mApp, subId, "setAllowedNetworkTypes");
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            SubscriptionManager.setSubscriptionProperty(subId,
-                    SubscriptionManager.ALLOWED_NETWORK_TYPES,
-                    String.valueOf(allowedNetworkTypes));
-            return setPreferredNetworkTypesInternal(subId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
 
-    private boolean setPreferredNetworkTypesInternal(int subId) {
-        long networkTypeBitMask = RadioAccessFamily.getRafFromNetworkType(
-                Settings.Global.getInt(mApp.getContentResolver(),
-                        Settings.Global.PREFERRED_NETWORK_MODE + subId,
-                        RILConstants.PREFERRED_NETWORK_MODE));
-        long allowedNetworkTypes = SubscriptionManager.getLongSubscriptionProperty(
-                subId, SubscriptionManager.ALLOWED_NETWORK_TYPES, -1, mApp);
-        int networkMode = RadioAccessFamily.getNetworkTypeFromRaf(
-                (int) (networkTypeBitMask & allowedNetworkTypes));
+        SubscriptionManager.setSubscriptionProperty(subId,
+                SubscriptionManager.ALLOWED_NETWORK_TYPES,
+                String.valueOf(allowedNetworkTypes));
 
-        if (DBG) {
-            log("setPreferredNetworkTypesInternal: subId " + subId
-                    + " networkTypes " + networkTypeBitMask
-                    + " allowedNetworkTypes " + allowedNetworkTypes
-                    + " networkMode " + networkMode);
-        }
-
-        Boolean success = (Boolean) sendRequest(
-                CMD_SET_PREFERRED_NETWORK_TYPE, networkMode, subId);
-        if (DBG) log("setPreferredNetworkTypesInternal: " + (success ? "ok" : "fail"));
-        return success;
+        int preferredNetworkMode = Settings.Global.getInt(mApp.getContentResolver(),
+                Settings.Global.PREFERRED_NETWORK_MODE + subId,
+                RILConstants.PREFERRED_NETWORK_MODE);
+        return setPreferredNetworkType(subId, preferredNetworkMode);
     }
 
     /**
@@ -5755,14 +5735,13 @@
         }
     }
 
-    private int getCarrierPrivilegeStatusFromCarrierConfigRules(int privilegeFromSim,
+    private int getCarrierPrivilegeStatusFromCarrierConfigRules(int privilegeFromSim, int uid,
             Phone phone) {
         //load access rules from carrier configs, and check those as well: b/139133814
         SubscriptionController subController = SubscriptionController.getInstance();
         if (privilegeFromSim == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
                 || subController == null) return privilegeFromSim;
 
-        int uid = Binder.getCallingUid();
         PackageManager pkgMgr = phone.getContext().getPackageManager();
         String[] packages = pkgMgr.getPackagesForUid(uid);
 
@@ -5816,7 +5795,7 @@
 
         return getCarrierPrivilegeStatusFromCarrierConfigRules(
             card.getCarrierPrivilegeStatusForCurrentTransaction(
-                phone.getContext().getPackageManager()), phone);
+                phone.getContext().getPackageManager()), Binder.getCallingUid(), phone);
     }
 
     @Override
@@ -5835,7 +5814,7 @@
         }
         return getCarrierPrivilegeStatusFromCarrierConfigRules(
                 profile.getCarrierPrivilegeStatusForUid(
-                        phone.getContext().getPackageManager(), uid), phone);
+                        phone.getContext().getPackageManager(), uid), uid, phone);
     }
 
     @Override
diff --git a/src/com/android/services/telephony/CdmaConnection.java b/src/com/android/services/telephony/CdmaConnection.java
index bd015e3..36618c5 100644
--- a/src/com/android/services/telephony/CdmaConnection.java
+++ b/src/com/android/services/telephony/CdmaConnection.java
@@ -288,9 +288,8 @@
 
     private boolean isEmergency() {
         Phone phone = getPhone();
-        return phone != null &&
-                PhoneNumberUtils.isLocalEmergencyNumber(
-                    phone.getContext(), getAddress().getSchemeSpecificPart());
+        return phone != null && getAddress() != null && PhoneNumberUtils.isLocalEmergencyNumber(
+                phone.getContext(), getAddress().getSchemeSpecificPart());
     }
 
     /**
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index 1a8aa07..f243462 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -348,6 +348,9 @@
             case android.telephony.DisconnectCause.DATA_LIMIT_REACHED:
                 resourceId = R.string.callFailed_data_limit_reached;
                 break;
+            case android.telephony.DisconnectCause.WIFI_LOST:
+                resourceId = R.string.callFailed_wifi_lost;
+                break;
             case android.telephony.DisconnectCause.ALREADY_DIALING:
                 resourceId = R.string.callFailed_already_dialing;
                 break;
@@ -867,6 +870,7 @@
             case android.telephony.DisconnectCause.NORMAL:
             case android.telephony.DisconnectCause.NORMAL_UNSPECIFIED:
             case android.telephony.DisconnectCause.VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED:
+            case android.telephony.DisconnectCause.WIFI_LOST:
             default:
                 return ToneGenerator.TONE_PROP_PROMPT;
         }
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index fccdb72..f739603 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -20,7 +20,6 @@
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.PersistableBundle;
 import android.telecom.Connection;
 import android.telecom.Connection.VideoProvider;
 import android.telecom.DisconnectCause;
@@ -28,7 +27,6 @@
 import android.telecom.StatusHints;
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
-import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
 import android.util.Pair;
 
@@ -38,7 +36,6 @@
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
-import com.android.phone.PhoneGlobals;
 import com.android.phone.PhoneUtils;
 import com.android.phone.R;
 import com.android.telephony.Rlog;
@@ -79,6 +76,126 @@
     }
 
     /**
+     * Abstracts out carrier configuration items specific to the conference.
+     */
+    public static class CarrierConfiguration {
+        /**
+         * Builds and instance of {@link CarrierConfiguration}.
+         */
+        public static class Builder {
+            private boolean mIsMaximumConferenceSizeEnforced = false;
+            private int mMaximumConferenceSize = 5;
+            private boolean mShouldLocalDisconnectEmptyConference = false;
+            private boolean mIsHoldAllowed = false;
+
+            /**
+             * Sets whether the maximum size of the conference is enforced.
+             * @param isMaximumConferenceSizeEnforced {@code true} if conference size enforced.
+             * @return builder instance.
+             */
+            public Builder setIsMaximumConferenceSizeEnforced(
+                    boolean isMaximumConferenceSizeEnforced) {
+                mIsMaximumConferenceSizeEnforced = isMaximumConferenceSizeEnforced;
+                return this;
+            }
+
+            /**
+             * Sets the maximum size of an IMS conference.
+             * @param maximumConferenceSize Max conference size.
+             * @return builder instance.
+             */
+            public Builder setMaximumConferenceSize(int maximumConferenceSize) {
+                mMaximumConferenceSize = maximumConferenceSize;
+                return this;
+            }
+
+            /**
+             * Sets whether an empty conference should be locally disconnected.
+             * @param shouldLocalDisconnectEmptyConference {@code true} if conference should be
+             * locally disconnected if empty.
+             * @return builder instance.
+             */
+            public Builder setShouldLocalDisconnectEmptyConference(
+                    boolean shouldLocalDisconnectEmptyConference) {
+                mShouldLocalDisconnectEmptyConference = shouldLocalDisconnectEmptyConference;
+                return this;
+            }
+
+            /**
+             * Sets whether holding the conference is allowed.
+             * @param isHoldAllowed {@code true} if holding is allowed.
+             * @return builder instance.
+             */
+            public Builder setIsHoldAllowed(boolean isHoldAllowed) {
+                mIsHoldAllowed = isHoldAllowed;
+                return this;
+            }
+
+            /**
+             * Build instance of {@link CarrierConfiguration}.
+             * @return carrier config instance.
+             */
+            public ImsConference.CarrierConfiguration build() {
+                return new ImsConference.CarrierConfiguration(mIsMaximumConferenceSizeEnforced,
+                        mMaximumConferenceSize, mShouldLocalDisconnectEmptyConference,
+                        mIsHoldAllowed);
+            }
+        }
+
+        private CarrierConfiguration(boolean isMaximumConferenceSizeEnforced,
+                int maximumConferenceSize, boolean shouldLocalDisconnectEmptyConference,
+                boolean isHoldAllowed) {
+            mIsMaximumConferenceSizeEnforced = isMaximumConferenceSizeEnforced;
+            mMaximumConferenceSize = maximumConferenceSize;
+            mShouldLocalDisconnectEmptyConference = shouldLocalDisconnectEmptyConference;
+            mIsHoldAllowed = isHoldAllowed;
+        }
+
+        private boolean mIsMaximumConferenceSizeEnforced;
+
+        private int mMaximumConferenceSize;
+
+        private boolean mShouldLocalDisconnectEmptyConference;
+
+        private boolean mIsHoldAllowed;
+
+        /**
+         * Determines whether the {@link ImsConference} should enforce a size limit based on
+         * {@link #getMaximumConferenceSize()}.
+         * {@code true} if maximum size limit should be enforced, {@code false} otherwise.
+         */
+        public boolean isMaximumConferenceSizeEnforced() {
+            return mIsMaximumConferenceSizeEnforced;
+        }
+
+        /**
+         * Determines the maximum number of participants (not including the host) in a conference
+         * which is enforced when {@link #isMaximumConferenceSizeEnforced()} is {@code true}.
+         */
+        public int getMaximumConferenceSize() {
+            return mMaximumConferenceSize;
+        }
+
+        /**
+         * Determines whether this {@link ImsConference} should locally disconnect itself when the
+         * number of participants in the conference drops to zero.
+         * {@code true} if empty conference should be locally disconnected, {@code false}
+         * otherwise.
+         */
+        public boolean shouldLocalDisconnectEmptyConference() {
+            return mShouldLocalDisconnectEmptyConference;
+        }
+
+        /**
+         * Determines whether holding the conference is permitted or not.
+         * {@code true} if hold is permitted, {@code false} otherwise.
+         */
+        public boolean isHoldAllowed() {
+            return mIsHoldAllowed;
+        }
+    }
+
+    /**
      * Listener used to respond to changes to the underlying radio connection for the conference
      * host connection.  Used to respond to SRVCC changes.
      */
@@ -260,6 +377,7 @@
     private boolean mIsHoldable;
     private boolean mCouldManageConference;
     private FeatureFlagProxy mFeatureFlagProxy;
+    private final CarrierConfiguration mCarrierConfig;
     private boolean mIsEmulatingSinglePartyCall = false;
     private boolean mIsUsingSimCallManager = false;
 
@@ -301,12 +419,13 @@
     public ImsConference(TelecomAccountRegistry telecomAccountRegistry,
             TelephonyConnectionServiceProxy telephonyConnectionService,
             TelephonyConnection conferenceHost, PhoneAccountHandle phoneAccountHandle,
-            FeatureFlagProxy featureFlagProxy) {
+            FeatureFlagProxy featureFlagProxy, CarrierConfiguration carrierConfig) {
 
         super(phoneAccountHandle);
 
         mTelecomAccountRegistry = telecomAccountRegistry;
         mFeatureFlagProxy = featureFlagProxy;
+        mCarrierConfig = carrierConfig;
 
         // Specify the connection time of the conference to be the connection time of the original
         // connection.
@@ -323,7 +442,7 @@
 
         int capabilities = Connection.CAPABILITY_MUTE |
                 Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN;
-        if (canHoldImsCalls()) {
+        if (mCarrierConfig.isHoldAllowed()) {
             capabilities |= Connection.CAPABILITY_SUPPORT_HOLD | Connection.CAPABILITY_HOLD;
             mIsHoldable = true;
         }
@@ -491,6 +610,8 @@
             } catch (CallStateException e) {
                 Log.e(this, e, "Exception thrown trying to hangup conference");
             }
+        } else {
+            Log.w(this, "onDisconnect - null call");
         }
     }
 
@@ -935,6 +1056,14 @@
             if (newParticipantsAdded || oldParticipantsRemoved) {
                 updateManageConference();
             }
+
+            // If the conference is empty and we're supposed to do a local disconnect, do so now.
+            if (mCarrierConfig.shouldLocalDisconnectEmptyConference()
+                    && oldParticipantCount > 0 && newParticipantCount == 0) {
+                Log.i(this, "handleConferenceParticipantsUpdate: empty conference; "
+                        + "local disconnect.");
+                onDisconnect();
+            }
         }
     }
 
@@ -1347,51 +1476,6 @@
         return sb.toString();
     }
 
-    private boolean canHoldImsCalls() {
-        PersistableBundle b = getCarrierConfig();
-        // Return true if the CarrierConfig is unavailable
-        return b == null || b.getBoolean(CarrierConfigManager.KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL);
-    }
-
-    private PersistableBundle getCarrierConfig() {
-        if (mConferenceHost == null) {
-            return null;
-        }
-
-        Phone phone = mConferenceHost.getPhone();
-        if (phone == null) {
-            return null;
-        }
-        return PhoneGlobals.getInstance().getCarrierConfigForSubId(phone.getSubId());
-    }
-
-    /**
-     * @return {@code true} if the carrier associated with the conference requires that the maximum
-     *      size of the conference is enforced, {@code false} otherwise.
-     */
-    public boolean isMaximumConferenceSizeEnforced() {
-        PersistableBundle b = getCarrierConfig();
-        // Return false if the CarrierConfig is unavailable
-        return b != null && b.getBoolean(
-                CarrierConfigManager.KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL);
-    }
-
-    /**
-     * @return The maximum size of a conference call where
-     * {@link #isMaximumConferenceSizeEnforced()} is true.
-     */
-    public int getMaximumConferenceSize() {
-        PersistableBundle b = getCarrierConfig();
-
-        // If there is no carrier config its really a problem, but we'll still define a sane limit
-        // of 5 so that we can still make a conference.
-        if (b == null) {
-            Log.w(this, "getMaximumConferenceSize - failed to get conference size");
-            return 5;
-        }
-        return b.getInt(CarrierConfigManager.KEY_IMS_CONFERENCE_SIZE_LIMIT_INT);
-    }
-
     /**
      * @return The number of participants in the conference.
      */
@@ -1404,8 +1488,8 @@
      *      participants in the conference has reached the limit, {@code false} otherwise.
      */
     public boolean isFullConference() {
-        return isMaximumConferenceSizeEnforced()
-                && getNumberOfParticipants() >= getMaximumConferenceSize();
+        return mCarrierConfig.isMaximumConferenceSizeEnforced()
+                && getNumberOfParticipants() >= mCarrierConfig.getMaximumConferenceSize();
     }
 
     /**
diff --git a/src/com/android/services/telephony/ImsConferenceController.java b/src/com/android/services/telephony/ImsConferenceController.java
index 8789ba8..1d1c5d8 100644
--- a/src/com/android/services/telephony/ImsConferenceController.java
+++ b/src/com/android/services/telephony/ImsConferenceController.java
@@ -16,12 +16,16 @@
 
 package com.android.services.telephony;
 
+import android.content.Context;
+import android.os.PersistableBundle;
 import android.telecom.Conference;
 import android.telecom.Conferenceable;
 import android.telecom.Connection;
 import android.telecom.ConnectionService;
 import android.telecom.DisconnectCause;
 import android.telecom.PhoneAccountHandle;
+import android.telephony.CarrierConfigManager;
+
 import com.android.telephony.Rlog;
 
 import com.android.internal.telephony.Phone;
@@ -403,6 +407,7 @@
         PhoneAccountHandle phoneAccountHandle = null;
 
         // Attempt to determine the phone account associated with the conference host connection.
+        ImsConference.CarrierConfiguration carrierConfig = null;
         if (connection.getPhone() != null &&
                 connection.getPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
             Phone imsPhone = connection.getPhone();
@@ -410,10 +415,11 @@
             // base GSM or CDMA phone, not on the ImsPhone itself).
             phoneAccountHandle =
                     PhoneUtils.makePstnPhoneAccountHandle(imsPhone.getDefaultPhone());
+            carrierConfig = getCarrierConfig(imsPhone);
         }
 
         ImsConference conference = new ImsConference(mTelecomAccountRegistry, mConnectionService,
-                conferenceHostConnection, phoneAccountHandle, mFeatureFlagProxy);
+                conferenceHostConnection, phoneAccountHandle, mFeatureFlagProxy, carrierConfig);
         conference.setState(conferenceHostConnection.getState());
         conference.addTelephonyConferenceListener(mConferenceListener);
         conference.updateConferenceParticipantsAfterCreation();
@@ -433,4 +439,33 @@
         // conferenceable connections for the conference to show merge calls option.
         recalculateConferenceable();
     }
+
+    public static ImsConference.CarrierConfiguration getCarrierConfig(Phone phone) {
+        ImsConference.CarrierConfiguration.Builder config =
+                new ImsConference.CarrierConfiguration.Builder();
+        if (phone == null) {
+            return config.build();
+        }
+
+        CarrierConfigManager cfgManager = (CarrierConfigManager)
+                phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        if (cfgManager != null) {
+            PersistableBundle bundle = cfgManager.getConfigForSubId(phone.getSubId());
+            boolean isMaximumConferenceSizeEnforced = bundle.getBoolean(
+                    CarrierConfigManager.KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL);
+            int maximumConferenceSize = bundle.getInt(
+                    CarrierConfigManager.KEY_IMS_CONFERENCE_SIZE_LIMIT_INT);
+            boolean isHoldAllowed = bundle.getBoolean(
+                    CarrierConfigManager.KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL);
+            boolean shouldLocalDisconnectOnEmptyConference = bundle.getBoolean(
+                    CarrierConfigManager.KEY_LOCAL_DISCONNECT_EMPTY_IMS_CONFERENCE_BOOL);
+
+            config.setIsMaximumConferenceSizeEnforced(isMaximumConferenceSizeEnforced)
+                    .setMaximumConferenceSize(maximumConferenceSize)
+                    .setIsHoldAllowed(isHoldAllowed)
+                    .setShouldLocalDisconnectEmptyConference(
+                            shouldLocalDisconnectOnEmptyConference);
+        }
+        return config.build();
+    }
 }
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 0b60e37..f1b44bf 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -71,6 +71,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -246,12 +247,20 @@
 
         @Override
         public boolean isCurrentEmergencyNumber(String number) {
-            return mTelephonyManager.isEmergencyNumber(number);
+            try {
+                return mTelephonyManager.isEmergencyNumber(number);
+            } catch (IllegalStateException ise) {
+                return false;
+            }
         }
 
         @Override
         public Map<Integer, List<EmergencyNumber>> getCurrentEmergencyNumberList() {
-            return mTelephonyManager.getEmergencyNumberList();
+            try {
+                return mTelephonyManager.getEmergencyNumberList();
+            } catch (IllegalStateException ise) {
+                return new HashMap<>();
+            }
         }
     }
 
@@ -571,9 +580,11 @@
         }
 
         TelephonyConnection connection = (TelephonyConnection)conn;
+
         ImsConference conference = new ImsConference(TelecomAccountRegistry.getInstance(this),
                 mTelephonyConnectionServiceProxy, connection,
-                phoneAccountHandle, () -> true);
+                phoneAccountHandle, () -> true,
+                ImsConferenceController.getCarrierConfig(connection.getPhone()));
         mImsConferenceController.addConference(conference);
         conference.setVideoState(connection,
                 connection.getVideoState());
@@ -1639,7 +1650,10 @@
 
     private void placeOutgoingConnection(
             TelephonyConnection connection, Phone phone, int videoState, Bundle extras) {
-        String number = connection.getAddress().getSchemeSpecificPart();
+
+        String number = (connection.getAddress() != null)
+                ? connection.getAddress().getSchemeSpecificPart()
+                : "";
 
         com.android.internal.telephony.Connection originalConnection = null;
         try {
diff --git a/tests/src/com/android/phone/LocationAccessPolicyTest.java b/tests/src/com/android/phone/LocationAccessPolicyTest.java
index 2061f38..b2489e7 100644
--- a/tests/src/com/android/phone/LocationAccessPolicyTest.java
+++ b/tests/src/com/android/phone/LocationAccessPolicyTest.java
@@ -147,6 +147,9 @@
         }
     }
 
+    private static final int TESTING_UID = 10001;
+    private static final int TESTING_PID = 8009;
+
     @Mock Context mContext;
     @Mock AppOpsManager mAppOpsManager;
     @Mock LocationManager mLocationManager;
@@ -195,15 +198,18 @@
                 anyInt(), anyString(), nullable(String.class), nullable(String.class)))
                 .thenReturn(s.coarseAppOp);
 
+        // set this permission to denied by default, and only allow for the proper pid/uid
+        // combination
+        when(mContext.checkPermission(eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL),
+                anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED);
         if (s.isDynamicLocationEnabled) {
             when(mLocationManager.isLocationEnabledForUser(any(UserHandle.class))).thenReturn(true);
             when(mContext.checkPermission(eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL),
-                    anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED);
+                    eq(TESTING_PID), eq(TESTING_UID)))
+                    .thenReturn(PackageManager.PERMISSION_GRANTED);
         } else {
             when(mLocationManager.isLocationEnabledForUser(any(UserHandle.class)))
                     .thenReturn(false);
-            when(mContext.checkPermission(eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL),
-                    anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED);
         }
 
         ApplicationInfo fakeAppInfo = new ApplicationInfo();
@@ -222,8 +228,8 @@
                 .setMethod("test")
                 .setCallingPackage("com.android.test")
                 .setCallingFeatureId(null)
-                .setCallingPid(10001)
-                .setCallingUid(10001);
+                .setCallingPid(TESTING_PID)
+                .setCallingUid(TESTING_UID);
     }
 
     @Parameterized.Parameters(name = "{0}")
diff --git a/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java b/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java
new file mode 100644
index 0000000..7f9efdc
--- /dev/null
+++ b/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 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 android.media.ToneGenerator.TONE_PROP_PROMPT;
+
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.TestCase.assertEquals;
+
+import android.telephony.DisconnectCause;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DisconnectCauseUtilTest {
+    /**
+     * 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.
+     */
+    @Test
+    public void testDropDueToWifiLoss() {
+        android.telecom.DisconnectCause tcCause = DisconnectCauseUtil.toTelecomDisconnectCause(
+                DisconnectCause.WIFI_LOST);
+        assertEquals(android.telecom.DisconnectCause.ERROR, tcCause.getCode());
+        assertEquals(TONE_PROP_PROMPT, tcCause.getTone());
+        assertNotNull(tcCause.getDescription());
+        assertNotNull(tcCause.getReason());
+    }
+}
diff --git a/tests/src/com/android/services/telephony/ImsConferenceTest.java b/tests/src/com/android/services/telephony/ImsConferenceTest.java
index a01a64f..b84aca1 100644
--- a/tests/src/com/android/services/telephony/ImsConferenceTest.java
+++ b/tests/src/com/android/services/telephony/ImsConferenceTest.java
@@ -43,6 +43,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.Arrays;
+import java.util.Collections;
 
 public class ImsConferenceTest {
     @Mock
@@ -73,7 +74,8 @@
 
         ImsConference imsConference = new ImsConference(mMockTelecomAccountRegistry,
                 mMockTelephonyConnectionServiceProxy, mConferenceHost,
-                null /* phoneAccountHandle */, () -> true /* featureFlagProxy */);
+                null /* phoneAccountHandle */, () -> true /* featureFlagProxy */,
+                new ImsConference.CarrierConfiguration.Builder().build());
 
         ConferenceParticipant participant1 = new ConferenceParticipant(
                 Uri.parse("tel:6505551212"),
@@ -122,7 +124,8 @@
 
         ImsConference imsConference = new ImsConference(mMockTelecomAccountRegistry,
                 mMockTelephonyConnectionServiceProxy, mConferenceHost,
-                null /* phoneAccountHandle */, () -> true /* featureFlagProxy */);
+                null /* phoneAccountHandle */, () -> true /* featureFlagProxy */,
+                new ImsConference.CarrierConfiguration.Builder().build());
 
         // Start off with 3 participants.
         ConferenceParticipant participant1 = new ConferenceParticipant(
@@ -185,7 +188,8 @@
 
         ImsConference imsConference = new ImsConference(mMockTelecomAccountRegistry,
                 mMockTelephonyConnectionServiceProxy, mConferenceHost,
-                null /* phoneAccountHandle */, () -> true /* featureFlagProxy */);
+                null /* phoneAccountHandle */, () -> true /* featureFlagProxy */,
+                new ImsConference.CarrierConfiguration.Builder().build());
 
         // Start off with 3 participants.
         ConferenceParticipant participant1 = new ConferenceParticipant(
@@ -242,7 +246,8 @@
 
         ImsConference imsConference = new ImsConference(mMockTelecomAccountRegistry,
                 mMockTelephonyConnectionServiceProxy, mConferenceHost,
-                null /* phoneAccountHandle */, () -> true /* featureFlagProxy */);
+                null /* phoneAccountHandle */, () -> true /* featureFlagProxy */,
+                new ImsConference.CarrierConfiguration.Builder().build());
 
         // Setup the initial conference state with 2 participants.
         ConferenceParticipant participant1 = new ConferenceParticipant(
@@ -300,7 +305,8 @@
 
         ImsConference imsConference = new ImsConference(mMockTelecomAccountRegistry,
                 mMockTelephonyConnectionServiceProxy, mConferenceHost,
-                null /* phoneAccountHandle */, () -> true /* featureFlagProxy */);
+                null /* phoneAccountHandle */, () -> true /* featureFlagProxy */,
+                new ImsConference.CarrierConfiguration.Builder().build());
 
         final boolean[] isConferenceState = new boolean[1];
         TelephonyConferenceBase.TelephonyConferenceListener conferenceListener =
@@ -356,7 +362,8 @@
 
         ImsConference imsConference = new ImsConference(mMockTelecomAccountRegistry,
                 mMockTelephonyConnectionServiceProxy, mConferenceHost,
-                null /* phoneAccountHandle */, () -> true /* featureFlagProxy */);
+                null /* phoneAccountHandle */, () -> true /* featureFlagProxy */,
+                new ImsConference.CarrierConfiguration.Builder().build());
 
         ConferenceParticipant participant1 = new ConferenceParticipant(
                 Uri.parse("tel:6505551212"),
@@ -381,7 +388,8 @@
 
         ImsConference imsConference = new ImsConference(mMockTelecomAccountRegistry,
                 mMockTelephonyConnectionServiceProxy, mConferenceHost,
-                null /* phoneAccountHandle */, () -> true /* featureFlagProxy */);
+                null /* phoneAccountHandle */, () -> true /* featureFlagProxy */,
+                new ImsConference.CarrierConfiguration.Builder().build());
 
         ConferenceParticipant participant1 = new ConferenceParticipant(
                 Uri.parse("tel:6505551212"),
@@ -412,13 +420,14 @@
 
     @Test
     @SmallTest
-    public void testNormalConference() {
+    public void testNormalConference() throws Exception {
         when(mMockTelecomAccountRegistry.isUsingSimCallManager(any(PhoneAccountHandle.class)))
                 .thenReturn(false);
 
         ImsConference imsConference = new ImsConference(mMockTelecomAccountRegistry,
                 mMockTelephonyConnectionServiceProxy, mConferenceHost,
-                null /* phoneAccountHandle */, () -> false /* featureFlagProxy */);
+                null /* phoneAccountHandle */, () -> false /* featureFlagProxy */,
+                new ImsConference.CarrierConfiguration.Builder().build());
 
         ConferenceParticipant participant1 = new ConferenceParticipant(
                 Uri.parse("tel:6505551212"),
@@ -440,5 +449,45 @@
         imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
                 Arrays.asList(participant1));
         assertEquals(1, imsConference.getNumberOfParticipants());
+
+        // Drop to 0 participants; should not hangup the conf now
+        imsConference.handleConferenceParticipantsUpdate(mConferenceHost, Collections.emptyList());
+        assertEquals(0, imsConference.getNumberOfParticipants());
+        verify(mConferenceHost.mMockCall, never()).hangup();
+    }
+
+    @Test
+    @SmallTest
+    public void testLocalDisconnectOnEmptyConference() throws Exception {
+        when(mMockTelecomAccountRegistry.isUsingSimCallManager(any(PhoneAccountHandle.class)))
+                .thenReturn(false);
+
+        ImsConference imsConference = new ImsConference(mMockTelecomAccountRegistry,
+                mMockTelephonyConnectionServiceProxy, mConferenceHost,
+                null /* phoneAccountHandle */, () -> false /* featureFlagProxy */,
+                new ImsConference.CarrierConfiguration.Builder()
+                        .setShouldLocalDisconnectEmptyConference(true)
+                        .build());
+
+        ConferenceParticipant participant1 = new ConferenceParticipant(
+                Uri.parse("tel:6505551212"),
+                "A",
+                Uri.parse("sip:6505551212@testims.com"),
+                Connection.STATE_ACTIVE,
+                Call.Details.DIRECTION_INCOMING);
+        ConferenceParticipant participant2 = new ConferenceParticipant(
+                Uri.parse("tel:6505551213"),
+                "A",
+                Uri.parse("sip:6505551213@testims.com"),
+                Connection.STATE_ACTIVE,
+                Call.Details.DIRECTION_INCOMING);
+        imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
+                Arrays.asList(participant1, participant2));
+        assertEquals(2, imsConference.getNumberOfParticipants());
+
+        // Drop to 0 participants; should have a hangup request.
+        imsConference.handleConferenceParticipantsUpdate(mConferenceHost, Collections.emptyList());
+        assertEquals(0, imsConference.getNumberOfParticipants());
+        verify(mConferenceHost.mMockCall).hangup();
     }
 }
diff --git a/tests/src/com/android/services/telephony/TestTelephonyConnection.java b/tests/src/com/android/services/telephony/TestTelephonyConnection.java
index 5b31c0f..8b7a477 100644
--- a/tests/src/com/android/services/telephony/TestTelephonyConnection.java
+++ b/tests/src/com/android/services/telephony/TestTelephonyConnection.java
@@ -30,6 +30,7 @@
 import static org.mockito.Mockito.when;
 
 import com.android.internal.telephony.Call;
+import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.Connection;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
@@ -72,6 +73,11 @@
         return mMockRadioConnection;
     }
 
+    @Override
+    protected Call getCall() {
+        return mMockCall;
+    }
+
     public TestTelephonyConnection() {
         super(null, null, false);
         MockitoAnnotations.initMocks(this);
@@ -100,6 +106,11 @@
         when(mMockPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_IMS);
         when(mMockCall.getState()).thenReturn(Call.State.ACTIVE);
         when(mMockCall.getPhone()).thenReturn(mMockPhone);
+        try {
+            doNothing().when(mMockCall).hangup();
+        } catch (CallStateException e) {
+            e.printStackTrace();
+        }
     }
 
     @Override