Catch SIP exceptions which can crash Phone process on answer. am: 232a03b341  -s ours am: 5b52037b55 am: d6f335dff5 am: a0ba18f893 am: 216f7000ef am: 9cab826be9 am: 9b220dbac9 am: 16244eb4ee
am: eb5a259c5f

Change-Id: I5216def0a90112416df4a5ea141572edbae4329a
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 36a5c07..b5fd399 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -49,6 +49,7 @@
     <protected-broadcast android:name="android.intent.action.DATA_SMS_RECEIVED" />
     <protected-broadcast android:name="android.provider.Telephony.SMS_RECEIVED" />
     <protected-broadcast android:name="android.provider.Telephony.SMS_DELIVER" />
+    <protected-broadcast android:name="android.provider.Telephony.SMS_REJECTED" />
     <protected-broadcast android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
     <protected-broadcast android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
     <protected-broadcast android:name="android.provider.Telephony.SMS_CB_RECEIVED" />
@@ -70,6 +71,8 @@
     <protected-broadcast android:name= "com.android.imsconnection.DISCONNECTED" />
     <protected-broadcast android:name= "com.android.intent.action.IMS_FEATURE_CHANGED" />
     <protected-broadcast android:name= "com.android.intent.action.IMS_CONFIG_CHANGED" />
+    <protected-broadcast android:name= "com.android.ims.REGISTRATION_ERROR" />
+    <protected-broadcast android:name= "com.android.phone.vvm.omtp.sms.REQUEST_SENT" />
 
     <uses-permission android:name="android.permission.BROADCAST_STICKY" />
     <uses-permission android:name="android.permission.CALL_PHONE" />
@@ -366,22 +369,6 @@
             </intent-filter>
         </activity>
 
-        <activity android:name="GsmUmtsOptions"
-                android:label="@string/gsm_umts_options"
-                android:theme="@style/DialerSettingsLight">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name="CdmaOptions"
-                android:label="@string/cdma_options"
-                android:theme="@style/DialerSettingsLight">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
         <activity android:name="GsmUmtsCallOptions"
                 android:label="@string/gsm_umts_options"
                 android:theme="@style/DialerSettingsLight">
@@ -416,14 +403,6 @@
             </intent-filter>
         </activity>
 
-        <activity android:name="CellBroadcastSms"
-            android:label="@string/cell_broadcast_sms"
-            android:theme="@android:style/Theme.Holo.DialogWhenLarge">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
         <!-- fdn setting -->
         <activity android:name="com.android.phone.settings.fdn.FdnSetting"
                 android:label="@string/fdn"
@@ -468,23 +447,6 @@
                 android:label="@string/delete_fdn_contact">
         </activity>
 
-        <activity android:name="DataRoamingReenable"
-                android:label="@string/dialog_alert_title"
-                android:theme="@android:style/Theme.Holo.Dialog">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <!-- data roaming setting -->
-        <activity android:name="RoamingSetting"
-                android:label="@string/roaming"
-                android:theme="@android:style/Theme.Holo.DialogWhenLarge">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
         <!-- "Call settings" UI, used only on voice-capable phone devices. -->
         <activity android:name="CallFeaturesSetting"
                 android:label="@string/call_settings"
diff --git a/res/layout/voicemail_change_pin.xml b/res/layout/voicemail_change_pin.xml
index ba0d823..b0db64b 100644
--- a/res/layout/voicemail_change_pin.xml
+++ b/res/layout/voicemail_change_pin.xml
@@ -28,7 +28,9 @@
     android:layout_height="0dp"
     android:layout_weight="1"
     android:orientation="vertical"
-    android:padding="48dp">
+    android:paddingTop="48dp"
+    android:paddingStart="48dp"
+    android:paddingEnd="48dp">
     <TextView
       android:id="@+id/headerText"
       android:layout_width="match_parent"
diff --git a/res/layout/voicemail_dialog_change_pin.xml b/res/layout/voicemail_dialog_change_pin.xml
deleted file mode 100644
index a5cfa80..0000000
--- a/res/layout/voicemail_dialog_change_pin.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-  android:layout_width="match_parent"
-  android:layout_height="match_parent"
-  android:orientation="vertical"
-  android:padding="?android:attr/dialogPreferredPadding">
-
-    <TextView
-      android:id="@+id/vm_old_pin_label"
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:text="@string/vm_change_pin_old_pin"
-      android:labelFor="@+id/vm_old_pin"/>
-
-    <EditText android:id="@id/vm_old_pin"
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:textColor="?android:attr/textColorSecondary"
-      android:inputType="numberPassword"/>
-
-    <TextView
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:text="@string/vm_change_pin_new_pin"
-      android:labelFor="@+id/vm_new_pin"/>
-
-    <EditText android:id="@id/vm_new_pin"
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:textColor="?android:attr/textColorSecondary"
-      android:inputType="numberPassword"/>
-
-</LinearLayout>
\ No newline at end of file
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 62b56f3..00472ea 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -569,7 +569,7 @@
     <string name="sim_description_emergency_calls" msgid="7535215397212301562">"Samo za hitne pozive"</string>
     <string name="sim_description_default" msgid="4778679519938775515">"SIM kartica, otvor: <xliff:g id="SLOT_ID">%s</xliff:g>"</string>
     <string name="accessibility_settings_activity_title" msgid="8562004288733103868">"Pristupačnost"</string>
-    <string name="status_hint_label_incoming_wifi_call" msgid="8772915926382037499">"Dolazni Wi-Fi poziv"</string>
+    <string name="status_hint_label_incoming_wifi_call" msgid="5932176406432044638">"Wi-Fi poziv od"</string>
     <string name="status_hint_label_wifi_call" msgid="8900805254974653903">"Wi-Fi poziv"</string>
     <string name="emergency_action_launch_hint" msgid="4906759256275562674">"Dodirnite ponovo da biste otvorili"</string>
     <string name="message_decode_error" msgid="3456481534066924855">"Došlo je do greške pri dekodiranju poruke."</string>
diff --git a/res/values-be-rBY/strings.xml b/res/values-be-rBY/strings.xml
index e33db92..2a3bc77 100644
--- a/res/values-be-rBY/strings.xml
+++ b/res/values-be-rBY/strings.xml
@@ -572,7 +572,7 @@
     <string name="sim_description_emergency_calls" msgid="7535215397212301562">"Толькі экстранныя выклікі"</string>
     <string name="sim_description_default" msgid="4778679519938775515">"SIM-карта, гняздо: <xliff:g id="SLOT_ID">%s</xliff:g>"</string>
     <string name="accessibility_settings_activity_title" msgid="8562004288733103868">"Спецыяльныя магчымасці"</string>
-    <string name="status_hint_label_incoming_wifi_call" msgid="8772915926382037499">"Уваход. выклік праз Wi-Fi"</string>
+    <string name="status_hint_label_incoming_wifi_call" msgid="5932176406432044638">"Выклік праз Wi-Fi ад"</string>
     <string name="status_hint_label_wifi_call" msgid="8900805254974653903">"Выклік праз Wi-Fi"</string>
     <string name="emergency_action_launch_hint" msgid="4906759256275562674">"Дакраніцеся яшчэ раз, каб адкрыць"</string>
     <string name="message_decode_error" msgid="3456481534066924855">"Памылка расшыфравання паведамлення."</string>
diff --git a/res/values-bs-rBA/strings.xml b/res/values-bs-rBA/strings.xml
index c711127..3e8eb07 100644
--- a/res/values-bs-rBA/strings.xml
+++ b/res/values-bs-rBA/strings.xml
@@ -569,7 +569,7 @@
     <string name="sim_description_emergency_calls" msgid="7535215397212301562">"Samo hitni pozivi"</string>
     <string name="sim_description_default" msgid="4778679519938775515">"SIM kartica, utor: <xliff:g id="SLOT_ID">%s</xliff:g>"</string>
     <string name="accessibility_settings_activity_title" msgid="8562004288733103868">"Pristupačnost"</string>
-    <string name="status_hint_label_incoming_wifi_call" msgid="8772915926382037499">"Dolazni Wi-Fi poziv"</string>
+    <string name="status_hint_label_incoming_wifi_call" msgid="5932176406432044638">"Wi-Fi poziv od"</string>
     <string name="status_hint_label_wifi_call" msgid="8900805254974653903">"Wi-Fi poziv"</string>
     <string name="emergency_action_launch_hint" msgid="4906759256275562674">"Dodirnite ponovo da otvorite"</string>
     <string name="message_decode_error" msgid="3456481534066924855">"Došlo je do greške prilikom dekodiranja poruke."</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index fe87ee6..e095c18 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -364,7 +364,7 @@
     <string name="tty_mode_option_summary" msgid="1073835131534808732">"‏تنظیم حالت TTY"</string>
     <string name="auto_retry_mode_title" msgid="4073265511427813322">"سعی مجدد خودکار"</string>
     <string name="auto_retry_mode_summary" msgid="4973886004067532288">"فعال کردن حالت سعی مجدد خودکار"</string>
-    <string name="tty_mode_not_allowed_video_call" msgid="3795846787901909176">"‏تغییر حالت TTY در طول تماس ویدئویی مجاز نیست"</string>
+    <string name="tty_mode_not_allowed_video_call" msgid="3795846787901909176">"‏تغییر حالت TTY در طول تماس ویدیویی مجاز نیست"</string>
     <string name="menu_add" msgid="1882023737425114762">"افزودن مخاطب"</string>
     <string name="menu_edit" msgid="7143003705504672374">"ویرایش مخاطب"</string>
     <string name="menu_delete" msgid="3977150783449642851">"حذف مخاطب"</string>
@@ -476,7 +476,7 @@
     <string name="onscreenManageCallsText" msgid="5473231160123254154">"مدیریت تماس‌ها"</string>
     <string name="onscreenManageConferenceText" msgid="6485935856534311346">"مدیریت کنفرانس"</string>
     <string name="onscreenAudioText" msgid="1710087112800041743">"صوتی"</string>
-    <string name="onscreenVideoCallText" msgid="4800924186056115442">"تماس ویدئویی"</string>
+    <string name="onscreenVideoCallText" msgid="4800924186056115442">"تماس ویدیویی"</string>
     <string name="importSimEntry" msgid="6614358325359736031">"وارد کردن"</string>
     <string name="importAllSimEntries" msgid="1503181169636198673">"وارد کردن همه"</string>
     <string name="importingSimContacts" msgid="7374056215462575769">"وارد کردن مخاطبین سیم"</string>
@@ -558,8 +558,8 @@
     <string name="voicemail_notification_ringtone_title" msgid="2609519527849101590">"صدا"</string>
     <string name="preference_category_ringtone" msgid="5197960752529332721">"آهنگ‌ زنگ و لرزش"</string>
     <string name="pstn_connection_service_label" msgid="1743245930577325900">"سیم‌کارت‌های داخلی"</string>
-    <string name="enable_video_calling_title" msgid="7237253660669000899">"روشن کردن تماس ویدئویی"</string>
-    <string name="enable_video_calling_dialog_msg" msgid="8948186136957417948">"‏برای روشن کردن تماس ویدئویی، باید حالت پیشرفته 4G LTE را در تنظیمات شبکه فعال کنید."</string>
+    <string name="enable_video_calling_title" msgid="7237253660669000899">"روشن کردن تماس ویدیویی"</string>
+    <string name="enable_video_calling_dialog_msg" msgid="8948186136957417948">"‏برای روشن کردن تماس ویدیویی، باید حالت پیشرفته 4G LTE را در تنظیمات شبکه فعال کنید."</string>
     <string name="enable_video_calling_dialog_settings" msgid="576528473599603249">"تنظیمات شبکه"</string>
     <string name="enable_video_calling_dialog_close" msgid="7411471282167927991">"بستن"</string>
     <string name="sim_label_emergency_calls" msgid="4847699229529306397">"تماس‌های اضطراری"</string>
diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml
index dccc579..774ecab 100644
--- a/res/values-kn-rIN/strings.xml
+++ b/res/values-kn-rIN/strings.xml
@@ -21,7 +21,7 @@
     <string name="emergencyDialerIconLabel" msgid="7812140032168171053">"ತುರ್ತು ಡಯಲರ್"</string>
     <string name="phoneIconLabel" msgid="2331230813161304895">"ಫೋನ್"</string>
     <string name="fdnListLabel" msgid="8630418672279521003">"FDN ಪಟ್ಟಿ"</string>
-    <string name="unknown" msgid="6878797917991465859">"ಅಪರಿಚಿತ"</string>
+    <string name="unknown" msgid="6878797917991465859">"ಅಜ್ಞಾತ"</string>
     <string name="private_num" msgid="6713286113000232309">"ಖಾಸಗಿ ಸಂಖ್ಯೆ"</string>
     <string name="payphone" msgid="4793877574636445118">"ಪೇಫೋನ್"</string>
     <string name="onHold" msgid="9035493194749959955">"ತಡೆಹಿಡಿಯಲಾಗಿದೆ"</string>
diff --git a/res/xml/vvm_config.xml b/res/xml/vvm_config.xml
index 8807ca9..19c667e 100644
--- a/res/xml/vvm_config.xml
+++ b/res/xml/vvm_config.xml
@@ -23,6 +23,26 @@
   </pbundle_as_map>
 
   <pbundle_as_map>
+    <!-- Orange France -->
+    <string-array name="mccmnc">
+      <item value="20801"/>
+      <item value="20802"/>
+    </string-array>
+
+    <int name="vvm_port_number_int" value="20481"/>
+    <string name="vvm_destination_number_string">21101</string>
+    <string-array name="carrier_vvm_package_name_string_array">
+      <item value="com.orange.vvm"/>
+    </string-array>
+    <string name="vvm_type_string">vvm_type_omtp</string>
+    <boolean name="vvm_cellular_data_required_bool" value="true"/>
+    <string-array name="vvm_disabled_capabilities_string_array">
+      <!-- b/32365569 -->
+      <item value="STARTTLS"/>
+    </string-array>
+  </pbundle_as_map>
+
+  <pbundle_as_map>
     <!-- T-Mobile USA-->
     <string-array name="mccmnc">
       <item value="310160"/>
diff --git a/src/com/android/phone/CellBroadcastSms.java b/src/com/android/phone/CellBroadcastSms.java
deleted file mode 100644
index 7428321..0000000
--- a/src/com/android/phone/CellBroadcastSms.java
+++ /dev/null
@@ -1,669 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package com.android.phone;
-
-import android.os.Bundle;
-import android.preference.CheckBoxPreference;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.PreferenceScreen;
-import android.preference.PreferenceActivity;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.RILConstants;
-
-import android.os.AsyncResult;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-
-
-/**
- * List of Phone-specific settings screens.
- */
-public class CellBroadcastSms extends PreferenceActivity
-        implements Preference.OnPreferenceChangeListener{
-    // debug data
-    private static final String LOG_TAG = "CellBroadcastSms";
-    private static final boolean DBG = false;
-
-    //String keys for preference lookup
-    private static final String BUTTON_ENABLE_DISABLE_BC_SMS_KEY =
-        "button_enable_disable_cell_bc_sms";
-    private static final String LIST_LANGUAGE_KEY =
-        "list_language";
-    private static final String BUTTON_EMERGENCY_BROADCAST_KEY =
-        "button_emergency_broadcast";
-    private static final String BUTTON_ADMINISTRATIVE_KEY =
-        "button_administrative";
-    private static final String BUTTON_MAINTENANCE_KEY =
-        "button_maintenance";
-    private static final String BUTTON_LOCAL_WEATHER_KEY =
-        "button_local_weather";
-    private static final String BUTTON_ATR_KEY =
-        "button_atr";
-    private static final String BUTTON_LAFS_KEY =
-        "button_lafs";
-    private static final String BUTTON_RESTAURANTS_KEY =
-        "button_restaurants";
-    private static final String BUTTON_LODGINGS_KEY =
-        "button_lodgings";
-    private static final String BUTTON_RETAIL_DIRECTORY_KEY =
-        "button_retail_directory";
-    private static final String BUTTON_ADVERTISEMENTS_KEY =
-        "button_advertisements";
-    private static final String BUTTON_STOCK_QUOTES_KEY =
-        "button_stock_quotes";
-    private static final String BUTTON_EO_KEY =
-        "button_eo";
-    private static final String BUTTON_MHH_KEY =
-        "button_mhh";
-    private static final String BUTTON_TECHNOLOGY_NEWS_KEY =
-        "button_technology_news";
-    private static final String BUTTON_MULTI_CATEGORY_KEY =
-        "button_multi_category";
-
-    private static final String BUTTON_LOCAL_GENERAL_NEWS_KEY =
-        "button_local_general_news";
-    private static final String BUTTON_REGIONAL_GENERAL_NEWS_KEY =
-        "button_regional_general_news";
-    private static final String BUTTON_NATIONAL_GENERAL_NEWS_KEY =
-        "button_national_general_news";
-    private static final String BUTTON_INTERNATIONAL_GENERAL_NEWS_KEY =
-        "button_international_general_news";
-
-    private static final String BUTTON_LOCAL_BF_NEWS_KEY =
-        "button_local_bf_news";
-    private static final String BUTTON_REGIONAL_BF_NEWS_KEY =
-        "button_regional_bf_news";
-    private static final String BUTTON_NATIONAL_BF_NEWS_KEY =
-        "button_national_bf_news";
-    private static final String BUTTON_INTERNATIONAL_BF_NEWS_KEY =
-        "button_international_bf_news";
-
-    private static final String BUTTON_LOCAL_SPORTS_NEWS_KEY =
-        "button_local_sports_news";
-    private static final String BUTTON_REGIONAL_SPORTS_NEWS_KEY =
-        "button_regional_sports_news";
-    private static final String BUTTON_NATIONAL_SPORTS_NEWS_KEY =
-        "button_national_sports_news";
-    private static final String BUTTON_INTERNATIONAL_SPORTS_NEWS_KEY =
-        "button_international_sports_news";
-
-    private static final String BUTTON_LOCAL_ENTERTAINMENT_NEWS_KEY =
-        "button_local_entertainment_news";
-    private static final String BUTTON_REGIONAL_ENTERTAINMENT_NEWS_KEY =
-        "button_regional_entertainment_news";
-    private static final String BUTTON_NATIONAL_ENTERTAINMENT_NEWS_KEY =
-        "button_national_entertainment_news";
-    private static final String BUTTON_INTERNATIONAL_ENTERTAINMENT_NEWS_KEY =
-        "button_international_entertainment_news";
-
-    //Class constants
-    //These values are related to the C structs. See the comments in  method
-    //setCbSmsConfig for more information.
-    private static final int NO_OF_SERVICE_CATEGORIES = 31;
-    private static final int NO_OF_INTS_STRUCT_1 = 3;
-    private static final int MAX_LENGTH_RESULT = NO_OF_SERVICE_CATEGORIES * NO_OF_INTS_STRUCT_1 + 1;
-    //Handler keys
-    private static final int MESSAGE_ACTIVATE_CB_SMS = 1;
-    private static final int MESSAGE_GET_CB_SMS_CONFIG = 2;
-    private static final int MESSAGE_SET_CB_SMS_CONFIG = 3;
-
-    //UI objects
-    private CheckBoxPreference mButtonBcSms;
-
-    private ListPreference mListLanguage;
-
-    private CheckBoxPreference mButtonEmergencyBroadcast;
-    private CheckBoxPreference mButtonAdministrative;
-    private CheckBoxPreference mButtonMaintenance;
-    private CheckBoxPreference mButtonLocalWeather;
-    private CheckBoxPreference mButtonAtr;
-    private CheckBoxPreference mButtonLafs;
-    private CheckBoxPreference mButtonRestaurants;
-    private CheckBoxPreference mButtonLodgings;
-    private CheckBoxPreference mButtonRetailDirectory;
-    private CheckBoxPreference mButtonAdvertisements;
-    private CheckBoxPreference mButtonStockQuotes;
-    private CheckBoxPreference mButtonEo;
-    private CheckBoxPreference mButtonMhh;
-    private CheckBoxPreference mButtonTechnologyNews;
-    private CheckBoxPreference mButtonMultiCategory;
-
-    private CheckBoxPreference mButtonLocal1;
-    private CheckBoxPreference mButtonRegional1;
-    private CheckBoxPreference mButtonNational1;
-    private CheckBoxPreference mButtonInternational1;
-
-    private CheckBoxPreference mButtonLocal2;
-    private CheckBoxPreference mButtonRegional2;
-    private CheckBoxPreference mButtonNational2;
-    private CheckBoxPreference mButtonInternational2;
-
-    private CheckBoxPreference mButtonLocal3;
-    private CheckBoxPreference mButtonRegional3;
-    private CheckBoxPreference mButtonNational3;
-    private CheckBoxPreference mButtonInternational3;
-
-    private CheckBoxPreference mButtonLocal4;
-    private CheckBoxPreference mButtonRegional4;
-    private CheckBoxPreference mButtonNational4;
-    private CheckBoxPreference mButtonInternational4;
-
-
-    //Member variables
-    private Phone mPhone;
-    private MyHandler mHandler;
-
-    /**
-     * Invoked on each preference click in this hierarchy, overrides
-     * PreferenceActivity's implementation.  Used to make sure we track the
-     * preference click events.
-     */
-    @Override
-    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
-            Preference preference) {
-        if (preference == mButtonBcSms) {
-            if (DBG) Log.d(LOG_TAG, "onPreferenceTreeClick: preference == mButtonBcSms.");
-            if(mButtonBcSms.isChecked()) {
-                mPhone.activateCellBroadcastSms(RILConstants.CDMA_CELL_BROADCAST_SMS_ENABLED,
-                        Message.obtain(mHandler, MESSAGE_ACTIVATE_CB_SMS));
-                android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
-                        android.provider.Settings.Global.CDMA_CELL_BROADCAST_SMS,
-                        RILConstants.CDMA_CELL_BROADCAST_SMS_ENABLED);
-                enableDisableAllCbConfigButtons(true);
-            } else {
-                mPhone.activateCellBroadcastSms(RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED,
-                        Message.obtain(mHandler, MESSAGE_ACTIVATE_CB_SMS));
-                android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
-                        android.provider.Settings.Global.CDMA_CELL_BROADCAST_SMS,
-                        RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED);
-                enableDisableAllCbConfigButtons(false);
-            }
-        } else if (preference == mListLanguage) {
-            //Do nothing here, because this click will be handled in onPreferenceChange
-        } else if (preference == mButtonEmergencyBroadcast) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonEmergencyBroadcast.isChecked(), 1);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(
-                    mButtonEmergencyBroadcast.isChecked(), 1);
-        } else if (preference == mButtonAdministrative) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonAdministrative.isChecked(), 2);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonAdministrative.isChecked(), 2);
-        } else if (preference == mButtonMaintenance) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonMaintenance.isChecked(), 3);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonMaintenance.isChecked(), 3);
-        } else if (preference == mButtonLocalWeather) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonLocalWeather.isChecked(), 20);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonLocalWeather.isChecked(), 20);
-        } else if (preference == mButtonAtr) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(mButtonAtr.isChecked(), 21);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonAtr.isChecked(), 21);
-        } else if (preference == mButtonLafs) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(mButtonLafs.isChecked(), 22);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonLafs.isChecked(), 22);
-        } else if (preference == mButtonRestaurants) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonRestaurants.isChecked(), 23);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonRestaurants.isChecked(), 23);
-        } else if (preference == mButtonLodgings) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(mButtonLodgings.isChecked(), 24);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonLodgings.isChecked(), 24);
-        } else if (preference == mButtonRetailDirectory) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonRetailDirectory.isChecked(), 25);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonRetailDirectory.isChecked(), 25);
-        } else if (preference == mButtonAdvertisements) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonAdvertisements.isChecked(), 26);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonAdvertisements.isChecked(), 26);
-        } else if (preference == mButtonStockQuotes) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonStockQuotes.isChecked(), 27);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonStockQuotes.isChecked(), 27);
-        } else if (preference == mButtonEo) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(mButtonEo.isChecked(), 28);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonEo.isChecked(), 28);
-        } else if (preference == mButtonMhh) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(mButtonMhh.isChecked(), 29);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonMhh.isChecked(), 29);
-        } else if (preference == mButtonTechnologyNews) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonTechnologyNews.isChecked(), 30);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonTechnologyNews.isChecked(), 30);
-        } else if (preference == mButtonMultiCategory) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonMultiCategory.isChecked(), 31);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonMultiCategory.isChecked(), 31);
-        } else if (preference == mButtonLocal1) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(mButtonLocal1.isChecked(), 4);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonLocal1.isChecked(), 4);
-        } else if (preference == mButtonRegional1) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonRegional1.isChecked(), 5);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonRegional1.isChecked(), 5);
-        } else if (preference == mButtonNational1) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonNational1.isChecked(), 6);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonNational1.isChecked(), 6);
-        } else if (preference == mButtonInternational1) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonInternational1.isChecked(), 7);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonInternational1.isChecked(), 7);
-        } else if (preference == mButtonLocal2) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(mButtonLocal2.isChecked(), 8);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonLocal2.isChecked(), 8);
-        } else if (preference == mButtonRegional2) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonRegional2.isChecked(), 9);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonRegional2.isChecked(), 9);
-        } else if (preference == mButtonNational2) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonNational2.isChecked(), 10);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonNational2.isChecked(), 10);
-        } else if (preference == mButtonInternational2) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonInternational2.isChecked(), 11);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonInternational2.isChecked(), 11);
-        } else if (preference == mButtonLocal3) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(mButtonLocal3.isChecked(), 12);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonLocal3.isChecked(), 12);
-        } else if (preference == mButtonRegional3) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonRegional3.isChecked(), 13);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonRegional3.isChecked(), 13);
-        } else if (preference == mButtonNational3) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonNational3.isChecked(), 14);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonNational3.isChecked(), 14);
-        } else if (preference == mButtonInternational3) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonInternational3.isChecked(), 15);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonInternational3.isChecked(), 15);
-        } else if (preference == mButtonLocal4) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(mButtonLocal4.isChecked(), 16);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonLocal4.isChecked(), 16);
-        } else if (preference == mButtonRegional4) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonRegional4.isChecked(), 17);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonRegional4.isChecked(), 17);
-        } else if (preference == mButtonNational4) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonNational4.isChecked(), 18);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonNational4.isChecked(), 18);
-        } else if (preference == mButtonInternational4) {
-            CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
-                    mButtonInternational4.isChecked(), 19);
-            CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonInternational4.isChecked(), 19);
-        } else {
-            preferenceScreen.setEnabled(false);
-            return false;
-        }
-
-        return true;
-    }
-
-    public boolean onPreferenceChange(Preference preference, Object objValue) {
-        if (preference == mListLanguage) {
-            // set the new language to the array which will be transmitted later
-            CellBroadcastSmsConfig.setConfigDataCompleteLanguage(
-                    mListLanguage.findIndexOfValue((String) objValue) + 1);
-        }
-
-        // always let the preference setting proceed.
-        return true;
-    }
-
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        addPreferencesFromResource(R.xml.cell_broadcast_sms);
-
-        mPhone = PhoneGlobals.getPhone();
-        mHandler = new MyHandler();
-
-        PreferenceScreen prefSet = getPreferenceScreen();
-
-        mButtonBcSms = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_ENABLE_DISABLE_BC_SMS_KEY);
-        mListLanguage = (ListPreference) prefSet.findPreference(
-                LIST_LANGUAGE_KEY);
-        // set the listener for the language list preference
-        mListLanguage.setOnPreferenceChangeListener(this);
-        mButtonEmergencyBroadcast = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_EMERGENCY_BROADCAST_KEY);
-        mButtonAdministrative = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_ADMINISTRATIVE_KEY);
-        mButtonMaintenance = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_MAINTENANCE_KEY);
-        mButtonLocalWeather = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_LOCAL_WEATHER_KEY);
-        mButtonAtr = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_ATR_KEY);
-        mButtonLafs = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_LAFS_KEY);
-        mButtonRestaurants = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_RESTAURANTS_KEY);
-        mButtonLodgings = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_LODGINGS_KEY);
-        mButtonRetailDirectory = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_RETAIL_DIRECTORY_KEY);
-        mButtonAdvertisements = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_ADVERTISEMENTS_KEY);
-        mButtonStockQuotes = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_STOCK_QUOTES_KEY);
-        mButtonEo = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_EO_KEY);
-        mButtonMhh = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_MHH_KEY);
-        mButtonTechnologyNews = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_TECHNOLOGY_NEWS_KEY);
-        mButtonMultiCategory = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_MULTI_CATEGORY_KEY);
-
-        mButtonLocal1 = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_LOCAL_GENERAL_NEWS_KEY);
-        mButtonRegional1 = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_REGIONAL_GENERAL_NEWS_KEY);
-        mButtonNational1 = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_NATIONAL_GENERAL_NEWS_KEY);
-        mButtonInternational1 = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_INTERNATIONAL_GENERAL_NEWS_KEY);
-
-        mButtonLocal2 = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_LOCAL_BF_NEWS_KEY);
-        mButtonRegional2 = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_REGIONAL_BF_NEWS_KEY);
-        mButtonNational2 = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_NATIONAL_BF_NEWS_KEY);
-        mButtonInternational2 = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_INTERNATIONAL_BF_NEWS_KEY);
-
-        mButtonLocal3 = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_LOCAL_SPORTS_NEWS_KEY);
-        mButtonRegional3 = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_REGIONAL_SPORTS_NEWS_KEY);
-        mButtonNational3 = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_NATIONAL_SPORTS_NEWS_KEY);
-        mButtonInternational3 = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_INTERNATIONAL_SPORTS_NEWS_KEY);
-
-        mButtonLocal4 = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_LOCAL_ENTERTAINMENT_NEWS_KEY);
-        mButtonRegional4 = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_REGIONAL_ENTERTAINMENT_NEWS_KEY);
-        mButtonNational4 = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_NATIONAL_ENTERTAINMENT_NEWS_KEY);
-        mButtonInternational4 = (CheckBoxPreference) prefSet.findPreference(
-                BUTTON_INTERNATIONAL_ENTERTAINMENT_NEWS_KEY);
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-
-        getPreferenceScreen().setEnabled(true);
-
-        int settingCbSms = android.provider.Settings.Global.getInt(
-                mPhone.getContext().getContentResolver(),
-                android.provider.Settings.Global.CDMA_CELL_BROADCAST_SMS,
-                RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED);
-        mButtonBcSms.setChecked(settingCbSms == RILConstants.CDMA_CELL_BROADCAST_SMS_ENABLED);
-
-        if(mButtonBcSms.isChecked()) {
-            enableDisableAllCbConfigButtons(true);
-        } else {
-            enableDisableAllCbConfigButtons(false);
-        }
-
-        mPhone.getCellBroadcastSmsConfig(Message.obtain(mHandler, MESSAGE_GET_CB_SMS_CONFIG));
-    }
-
-    @Override
-    protected void onPause() {
-        super.onPause();
-
-            CellBroadcastSmsConfig.setCbSmsNoOfStructs(NO_OF_SERVICE_CATEGORIES);
-
-            mPhone.setCellBroadcastSmsConfig(CellBroadcastSmsConfig.getCbSmsAllValues(),
-                    Message.obtain(mHandler, MESSAGE_SET_CB_SMS_CONFIG));
-        }
-
-    private void enableDisableAllCbConfigButtons(boolean enable) {
-        mButtonEmergencyBroadcast.setEnabled(enable);
-        mListLanguage.setEnabled(enable);
-        mButtonAdministrative.setEnabled(enable);
-        mButtonMaintenance.setEnabled(enable);
-        mButtonLocalWeather.setEnabled(enable);
-        mButtonAtr.setEnabled(enable);
-        mButtonLafs.setEnabled(enable);
-        mButtonRestaurants.setEnabled(enable);
-        mButtonLodgings.setEnabled(enable);
-        mButtonRetailDirectory.setEnabled(enable);
-        mButtonAdvertisements.setEnabled(enable);
-        mButtonStockQuotes.setEnabled(enable);
-        mButtonEo.setEnabled(enable);
-        mButtonMhh.setEnabled(enable);
-        mButtonTechnologyNews.setEnabled(enable);
-        mButtonMultiCategory.setEnabled(enable);
-
-        mButtonLocal1.setEnabled(enable);
-        mButtonRegional1.setEnabled(enable);
-        mButtonNational1.setEnabled(enable);
-        mButtonInternational1.setEnabled(enable);
-
-        mButtonLocal2.setEnabled(enable);
-        mButtonRegional2.setEnabled(enable);
-        mButtonNational2.setEnabled(enable);
-        mButtonInternational2.setEnabled(enable);
-
-        mButtonLocal3.setEnabled(enable);
-        mButtonRegional3.setEnabled(enable);
-        mButtonNational3.setEnabled(enable);
-        mButtonInternational3.setEnabled(enable);
-
-        mButtonLocal4.setEnabled(enable);
-        mButtonRegional4.setEnabled(enable);
-        mButtonNational4.setEnabled(enable);
-        mButtonInternational4.setEnabled(enable);
-    }
-
-    private void setAllCbConfigButtons(int[] configArray) {
-        //These buttons are in a well defined sequence. If you want to change it,
-        //be sure to map the buttons to their corresponding slot in the configArray !
-        mButtonEmergencyBroadcast.setChecked(configArray[1] != 0);
-        //subtract 1, because the values are handled in an array which starts with 0 and not with 1
-        mListLanguage.setValueIndex(CellBroadcastSmsConfig.getConfigDataLanguage() - 1);
-        mButtonAdministrative.setChecked(configArray[2] != 0);
-        mButtonMaintenance.setChecked(configArray[3] != 0);
-        mButtonLocalWeather.setChecked(configArray[20] != 0);
-        mButtonAtr.setChecked(configArray[21] != 0);
-        mButtonLafs.setChecked(configArray[22] != 0);
-        mButtonRestaurants.setChecked(configArray[23] != 0);
-        mButtonLodgings.setChecked(configArray[24] != 0);
-        mButtonRetailDirectory.setChecked(configArray[25] != 0);
-        mButtonAdvertisements.setChecked(configArray[26] != 0);
-        mButtonStockQuotes.setChecked(configArray[27] != 0);
-        mButtonEo.setChecked(configArray[28] != 0);
-        mButtonMhh.setChecked(configArray[29] != 0);
-        mButtonTechnologyNews.setChecked(configArray[30] != 0);
-        mButtonMultiCategory.setChecked(configArray[31] != 0);
-
-        mButtonLocal1.setChecked(configArray[4] != 0);
-        mButtonRegional1.setChecked(configArray[5] != 0);
-        mButtonNational1.setChecked(configArray[6] != 0);
-        mButtonInternational1.setChecked(configArray[7] != 0);
-
-        mButtonLocal2.setChecked(configArray[8] != 0);
-        mButtonRegional2.setChecked(configArray[9] != 0);
-        mButtonNational2.setChecked(configArray[10] != 0);
-        mButtonInternational2.setChecked(configArray[11] != 0);
-
-        mButtonLocal3.setChecked(configArray[12] != 0);
-        mButtonRegional3.setChecked(configArray[13] != 0);
-        mButtonNational3.setChecked(configArray[14] != 0);
-        mButtonInternational3.setChecked(configArray[15] != 0);
-
-        mButtonLocal4.setChecked(configArray[16] != 0);
-        mButtonRegional4.setChecked(configArray[17] != 0);
-        mButtonNational4.setChecked(configArray[18] != 0);
-        mButtonInternational4.setChecked(configArray[19] != 0);
-    }
-
-    private class MyHandler extends Handler {
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-            case MESSAGE_ACTIVATE_CB_SMS:
-                //Only a log message here, because the received response is always null
-                if (DBG) Log.d(LOG_TAG, "Cell Broadcast SMS enabled/disabled.");
-                break;
-            case MESSAGE_GET_CB_SMS_CONFIG:
-                int result[] = (int[])((AsyncResult)msg.obj).result;
-
-                // check if the actual service categoties table size on the NV is '0'
-                if (result[0] == 0) {
-                    result[0] = NO_OF_SERVICE_CATEGORIES;
-
-                    mButtonBcSms.setChecked(false);
-                    mPhone.activateCellBroadcastSms(RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED,
-                            Message.obtain(mHandler, MESSAGE_ACTIVATE_CB_SMS));
-                    android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
-                            android.provider.Settings.Global.CDMA_CELL_BROADCAST_SMS,
-                            RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED);
-                    enableDisableAllCbConfigButtons(false);
-                }
-
-                CellBroadcastSmsConfig.setCbSmsConfig(result);
-                setAllCbConfigButtons(CellBroadcastSmsConfig.getCbSmsBselectedValues());
-
-                break;
-            case MESSAGE_SET_CB_SMS_CONFIG:
-                //Only a log message here, because the received response is always null
-                if (DBG) Log.d(LOG_TAG, "Set Cell Broadcast SMS values.");
-                break;
-            default:
-                Log.e(LOG_TAG, "Error! Unhandled message in CellBroadcastSms.java. Message: "
-                        + msg.what);
-            break;
-            }
-        }
-    }
-
-    private static final class CellBroadcastSmsConfig {
-
-        //The values in this array are stored in a particular order. This order
-        //is calculated in the setCbSmsConfig method of this class.
-        //For more information see comments below...
-        //NO_OF_SERVICE_CATEGORIES +1 is used, because we will leave the first array entry 0
-        private static int mBSelected[] = new int[NO_OF_SERVICE_CATEGORIES + 1];
-        private static int mConfigDataComplete[] = new int[MAX_LENGTH_RESULT];
-
-        private static void setCbSmsConfig(int[] configData) {
-            if(configData == null) {
-                Log.e(LOG_TAG, "Error! No cell broadcast service categories returned.");
-                return;
-            }
-
-            if(configData[0] > MAX_LENGTH_RESULT) {
-                Log.e(LOG_TAG, "Error! Wrong number of service categories returned from RIL");
-                return;
-            }
-
-            //The required config values for broadcast SMS are stored in a C struct:
-            //
-            //  typedef struct {
-            //      int size;
-            //      RIL_CDMA_BcServiceInfo *entries;
-            //  } RIL_CDMA_BcSMSConfig;
-            //
-            //  typedef struct {
-            //      int uServiceCategory;
-            //      int uLanguage;
-            //      unsigned char bSelected;
-            //  } RIL_CDMA_BcServiceInfo;
-            //
-            // This means, that we have to ignore the first value and check every
-            // 3rd value starting with the 2nd of all. This value indicates, where we
-            // will store the appropriate bSelected value, which is 2 values behind it.
-            for(int i = 1; i < configData.length; i += NO_OF_INTS_STRUCT_1) {
-                mBSelected[configData[i]] = configData[i +2];
-            }
-
-            //Store all values in an extra array
-            mConfigDataComplete = configData;
-        }
-
-        private static void setCbSmsBSelectedValue(boolean value, int pos) {
-            if(pos < mBSelected.length) {
-                mBSelected[pos] = (value == true ? 1 : 0);
-            } else {
-                Log.e(LOG_TAG,"Error! Invalid value position.");
-            }
-        }
-
-        private static int[] getCbSmsBselectedValues() {
-            return(mBSelected);
-        }
-
-        // TODO: Change the return value to a RIL_BroadcastSMSConfig
-        private static int[] getCbSmsAllValues() {
-            return(mConfigDataComplete);
-        }
-
-        private static void setCbSmsNoOfStructs(int value) {
-            //Sets the size parameter, which contains the number of structs
-            //that will be transmitted
-            mConfigDataComplete[0] = value;
-        }
-
-        private static void setConfigDataCompleteBSelected(boolean value, int serviceCategory) {
-            //Sets the bSelected value for a specific serviceCategory
-            for(int i = 1; i < mConfigDataComplete.length; i += NO_OF_INTS_STRUCT_1) {
-                if(mConfigDataComplete[i] == serviceCategory) {
-                    mConfigDataComplete[i + 2] = value == true ? 1 : 0;
-                    break;
-                }
-            }
-        }
-
-        private static void setConfigDataCompleteLanguage(int language) {
-            //It is only possible to set the same language for all entries
-            for(int i = 2; i < mConfigDataComplete.length; i += NO_OF_INTS_STRUCT_1) {
-                mConfigDataComplete[i] = language;
-            }
-        }
-
-        private static int getConfigDataLanguage() {
-            int language = mConfigDataComplete[2];
-            //2 is the language value of the first entry
-            //It is only possible to set the same language for all entries
-            if (language < 1 || language > 7) {
-                Log.e(LOG_TAG, "Error! Wrong language returned from RIL...defaulting to 1, english");
-                return 1;
-            }
-            else {
-                return language;
-            }
-        }
-    }
-}
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 227e112..1d34788 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -515,6 +515,11 @@
      */
     private void placeCall() {
         mLastNumber = mDigits.getText().toString();
+        // Convert into emergency number if necessary
+        // This is required in some regions (e.g. Taiwan).
+        if (PhoneNumberUtils.isConvertToEmergencyNumberEnabled()) {
+            mLastNumber = PhoneNumberUtils.convertToEmergencyNumber(mLastNumber);
+        }
         if (PhoneNumberUtils.isLocalEmergencyNumber(this, mLastNumber)) {
             if (DBG) Log.d(LOG_TAG, "placing call to " + mLastNumber);
 
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index 9504f34..d40b08e 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -47,11 +47,13 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.widget.Toast;
+
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.TelephonyCapabilities;
 import com.android.phone.settings.VoicemailNotificationSettingsUtil;
 import com.android.phone.settings.VoicemailSettingsActivity;
 import com.android.phone.vvm.omtp.sync.VoicemailStatusQueryHelper;
+
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
@@ -72,6 +74,9 @@
     // Do not check in with VDBG = true, since that may write PII to the system log.
     private static final boolean VDBG = false;
 
+    private static final String MWI_SHOULD_CHECK_VVM_CONFIGURATION_KEY_PREFIX =
+            "mwi_should_check_vvm_configuration_state_";
+
     // notification types
     static final int MMI_NOTIFICATION = 1;
     static final int NETWORK_SELECTION_NOTIFICATION = 2;
@@ -201,6 +206,27 @@
         }
     }
 
+    public void setShouldCheckVisualVoicemailConfigurationForMwi(int subId, boolean enabled) {
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            Log.e(LOG_TAG, "setShouldCheckVisualVoicemailConfigurationForMwi: invalid subId"
+                    + subId);
+            return;
+        }
+
+        PreferenceManager.getDefaultSharedPreferences(mContext).edit()
+                .putBoolean(MWI_SHOULD_CHECK_VVM_CONFIGURATION_KEY_PREFIX + subId, enabled)
+                .apply();
+    }
+
+    private boolean shouldCheckVisualVoicemailConfigurationForMwi(int subId) {
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            Log.e(LOG_TAG, "shouldCheckVisualVoicemailConfigurationForMwi: invalid subId" + subId);
+            return true;
+        }
+        return PreferenceManager
+                .getDefaultSharedPreferences(mContext)
+                .getBoolean(MWI_SHOULD_CHECK_VVM_CONFIGURATION_KEY_PREFIX + subId, true);
+    }
     /**
      * Updates the message waiting indicator (voicemail) notification.
      *
@@ -226,7 +252,7 @@
         }
 
         Phone phone = PhoneGlobals.getPhone(subId);
-        if (visible && phone != null) {
+        if (visible && phone != null && shouldCheckVisualVoicemailConfigurationForMwi(subId)) {
             VoicemailStatusQueryHelper queryHelper = new VoicemailStatusQueryHelper(mContext);
             PhoneAccountHandle phoneAccount = PhoneUtils.makePstnPhoneAccountHandle(phone);
             if (queryHelper.isVoicemailSourceConfigured(phoneAccount)) {
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 2d87e78..14a451f 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -45,6 +45,7 @@
 import android.telephony.SubscriptionManager;
 import android.util.Log;
 import android.widget.Toast;
+
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallManager;
 import com.android.internal.telephony.IccCardConstants;
@@ -856,4 +857,23 @@
             phone.setVoiceMessageCount(0);
         }
     }
+
+    /**
+     * Enables or disables the visual voicemail check for message waiting indicator. Default value
+     * is true. MWI is the traditional voicemail notification which should be suppressed if visual
+     * voicemail is active. {@link NotificationMgr#updateMwi(int, boolean, boolean)} currently
+     * checks the {@link android.provider.VoicemailContract.Status#CONFIGURATION_STATE} to suppress
+     * the MWI, but there are several issues. b/31229016 is a bug that when the device boots the
+     * configuration state will be cleared and the MWI for voicemail that arrives when the device
+     * is offline will be cleared, even if the account cannot be activated. A full solution will be
+     * adding a setMwiEnabled() method and stop checking the configuration state, but that is too
+     * risky at this moment. This is a temporary workaround to shut down the configuration state
+     * check if visual voicemail cannot be activated.
+     * <p>TODO(twyen): implement the setMwiEnabled() mentioned above.
+     *
+     * @param subId the account to set the enabled state
+     */
+    public void setShouldCheckVisualVoicemailConfigurationForMwi(int subId, boolean enabled) {
+        notificationMgr.setShouldCheckVisualVoicemailConfigurationForMwi(subId, enabled);
+    }
 }
diff --git a/src/com/android/phone/VoicemailStatus.java b/src/com/android/phone/VoicemailStatus.java
index 4d7d388..00130f1 100644
--- a/src/com/android/phone/VoicemailStatus.java
+++ b/src/com/android/phone/VoicemailStatus.java
@@ -83,17 +83,29 @@
             return this;
         }
 
-        public void apply() {
+        /**
+         * Apply the changes to the {@link VoicemailStatus} {@link #Editor}.
+         *
+         * @return {@code true} if the changes were successfully applied, {@code false} otherwise.
+         */
+        public boolean apply() {
             if (mPhoneAccountHandle == null) {
-                return;
+                return false;
             }
             mValues.put(Status.PHONE_ACCOUNT_COMPONENT_NAME,
                     mPhoneAccountHandle.getComponentName().flattenToString());
             mValues.put(Status.PHONE_ACCOUNT_ID, mPhoneAccountHandle.getId());
             ContentResolver contentResolver = mContext.getContentResolver();
             Uri statusUri = VoicemailContract.Status.buildSourceUri(mContext.getPackageName());
-            contentResolver.insert(statusUri, mValues);
+            try {
+                contentResolver.insert(statusUri, mValues);
+            } catch (IllegalArgumentException iae) {
+                VvmLog.e(TAG, "apply :: failed to insert content resolver ", iae);
+                mValues.clear();
+                return false;
+            }
             mValues.clear();
+            return true;
         }
 
         public ContentValues getValues() {
@@ -114,8 +126,9 @@
         }
 
         @Override
-        public void apply() {
+        public boolean apply() {
             // Do nothing
+            return true;
         }
 
         public void deferredApply() {
diff --git a/src/com/android/phone/common/mail/store/imap/DigestMd5Utils.java b/src/com/android/phone/common/mail/store/imap/DigestMd5Utils.java
index f78dbdf..436d03c 100644
--- a/src/com/android/phone/common/mail/store/imap/DigestMd5Utils.java
+++ b/src/com/android/phone/common/mail/store/imap/DigestMd5Utils.java
@@ -54,7 +54,7 @@
      */
     public static class Data {
 
-        private static final String CHARSET = "utf-8'";
+        private static final String CHARSET = "utf-8";
 
         public String username;
         public String password;
diff --git a/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java b/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
index b556aa1..22fb70e 100644
--- a/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
+++ b/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
@@ -17,8 +17,6 @@
 
 import android.content.Context;
 import android.telecom.PhoneAccountHandle;
-import com.android.internal.telephony.Phone;
-import com.android.phone.PhoneUtils;
 import com.android.phone.R;
 import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
 import com.android.phone.vvm.omtp.VisualVoicemailPreferences;
@@ -67,11 +65,6 @@
                 PhoneAccountHandleConverter.toSubId(phoneAccount)).isEnabledByDefault();
     }
 
-    public static boolean isEnabled(Phone phone) {
-        return isEnabled(phone.getContext(),
-                PhoneUtils.makePstnPhoneAccountHandle(phone));
-    }
-
     /**
      * Whether the client enabled status is explicitly set by user or by default(Whether carrier VVM
      * app is installed). This is used to determine whether to disable the client when the carrier
diff --git a/src/com/android/phone/settings/VoicemailChangePinActivity.java b/src/com/android/phone/settings/VoicemailChangePinActivity.java
index 8027dc1..33da27a 100644
--- a/src/com/android/phone/settings/VoicemailChangePinActivity.java
+++ b/src/com/android/phone/settings/VoicemailChangePinActivity.java
@@ -35,6 +35,7 @@
 import android.text.InputFilter.LengthFilter;
 import android.text.TextWatcher;
 import android.view.KeyEvent;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.WindowManager;
@@ -436,7 +437,19 @@
         }
     }
 
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == android.R.id.home) {
+            onBackPressed();
+            return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
     public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+      if (!mNextButton.isEnabled()) {
+        return true;
+      }
         // Check if this was the result of hitting the enter or "done" key
         if (actionId == EditorInfo.IME_NULL
                 || actionId == EditorInfo.IME_ACTION_DONE
diff --git a/src/com/android/phone/settings/VoicemailSettingsActivity.java b/src/com/android/phone/settings/VoicemailSettingsActivity.java
index 92e1b5f..35d9a1c 100644
--- a/src/com/android/phone/settings/VoicemailSettingsActivity.java
+++ b/src/com/android/phone/settings/VoicemailSettingsActivity.java
@@ -45,7 +45,9 @@
 import com.android.phone.PhoneUtils;
 import com.android.phone.R;
 import com.android.phone.SubscriptionInfoHelper;
+import com.android.phone.vvm.omtp.OmtpConstants;
 import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.VisualVoicemailPreferences;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -193,6 +195,7 @@
 
     private boolean mForeground;
     private Phone mPhone;
+    private PhoneAccountHandle mPhoneAccountHandle;
     private SubscriptionInfoHelper mSubscriptionInfoHelper;
     private OmtpVvmCarrierConfigHelper mOmtpVvmCarrierConfigHelper;
 
@@ -221,6 +224,7 @@
         mSubscriptionInfoHelper.setActionBarTitle(
                 getActionBar(), getResources(), R.string.voicemail_settings_with_label);
         mPhone = mSubscriptionInfoHelper.getPhone();
+        mPhoneAccountHandle = PhoneUtils.makePstnPhoneAccountHandle(mPhone);
         mOmtpVvmCarrierConfigHelper = new OmtpVvmCarrierConfigHelper(
                 mPhone.getContext(), mPhone.getSubId());
     }
@@ -265,13 +269,12 @@
 
         mVoicemailChangePinPreference = findPreference(
                 getResources().getString(R.string.voicemail_change_pin_key));
-        PhoneAccountHandle phoneAccountHandle = PhoneUtils.makePstnPhoneAccountHandle(mPhone);
         Intent changePinIntent = new Intent(new Intent(this, VoicemailChangePinActivity.class));
         changePinIntent.putExtra(VoicemailChangePinActivity.EXTRA_PHONE_ACCOUNT_HANDLE,
-                phoneAccountHandle);
+                mPhoneAccountHandle);
 
         mVoicemailChangePinPreference.setIntent(changePinIntent);
-        if (VoicemailChangePinActivity.isDefaultOldPinSet(this, phoneAccountHandle)) {
+        if (VoicemailChangePinActivity.isDefaultOldPinSet(this, mPhoneAccountHandle)) {
             mVoicemailChangePinPreference.setTitle(R.string.voicemail_set_pin_dialog_title);
         } else {
             mVoicemailChangePinPreference.setTitle(R.string.voicemail_change_pin_dialog_title);
@@ -280,7 +283,10 @@
         if (mOmtpVvmCarrierConfigHelper.isValid()) {
             mVoicemailVisualVoicemail.setOnPreferenceChangeListener(this);
             mVoicemailVisualVoicemail.setChecked(
-                    VisualVoicemailSettingsUtil.isEnabled(mPhone));
+                    VisualVoicemailSettingsUtil.isEnabled(this, mPhoneAccountHandle));
+            if (!isVisualVoicemailActivated()) {
+                prefSet.removePreference(mVoicemailChangePinPreference);
+            }
         } else {
             prefSet.removePreference(mVoicemailVisualVoicemail);
             prefSet.removePreference(mVoicemailChangePinPreference);
@@ -406,11 +412,10 @@
                     mPhone, Boolean.TRUE.equals(objValue));
         } else if (preference.getKey().equals(mVoicemailVisualVoicemail.getKey())) {
             boolean isEnabled = (boolean) objValue;
-            PhoneAccountHandle handle = PhoneUtils.makePstnPhoneAccountHandle(mPhone);
             VisualVoicemailSettingsUtil
-                    .setEnabled(mPhone.getContext(), handle, isEnabled);
+                    .setEnabled(mPhone.getContext(), mPhoneAccountHandle, isEnabled);
             PreferenceScreen prefSet = getPreferenceScreen();
-            if (isEnabled) {
+            if (isVisualVoicemailActivated()) {
                 prefSet.addPreference(mVoicemailChangePinPreference);
             } else {
                 prefSet.removePreference(mVoicemailChangePinPreference);
@@ -1150,6 +1155,16 @@
         return true;
     }
 
+    private boolean isVisualVoicemailActivated() {
+        if (!VisualVoicemailSettingsUtil.isEnabled(this, mPhoneAccountHandle)) {
+            return false;
+        }
+        VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(this,
+                mPhoneAccountHandle);
+        return preferences.getString(OmtpConstants.SERVER_ADDRESS, null) != null;
+
+    }
+
     private static void log(String msg) {
         Log.d(LOG_TAG, msg);
     }
diff --git a/src/com/android/phone/vvm/omtp/ActivationTask.java b/src/com/android/phone/vvm/omtp/ActivationTask.java
index 9c58b95..72f1f54 100644
--- a/src/com/android/phone/vvm/omtp/ActivationTask.java
+++ b/src/com/android/phone/vvm/omtp/ActivationTask.java
@@ -24,10 +24,10 @@
 import android.os.Bundle;
 import android.provider.Settings;
 import android.provider.Settings.Global;
-import android.provider.VoicemailContract.Status;
 import android.telecom.PhoneAccountHandle;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
+
 import com.android.phone.Assert;
 import com.android.phone.PhoneGlobals;
 import com.android.phone.VoicemailStatus;
@@ -40,9 +40,11 @@
 import com.android.phone.vvm.omtp.sync.OmtpVvmSyncService;
 import com.android.phone.vvm.omtp.sync.SyncTask;
 import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
+
 import java.io.IOException;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.concurrent.CancellationException;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
 
@@ -67,7 +69,7 @@
 
     private final RetryPolicy mRetryPolicy;
 
-    private Bundle mData;
+    private Bundle mMessageData;
 
     public ActivationTask() {
         super(TASK_ACTIVATION);
@@ -83,7 +85,12 @@
             context.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) == 1;
     }
 
-    public static void start(Context context, int subId, @Nullable Bundle data) {
+    /**
+     * @param messageData The optional bundle from {@link android.provider.VoicemailContract#
+     * EXTRA_VOICEMAIL_SMS_FIELDS}, if the task is initiated by a status SMS. If null the task will
+     * request a status SMS itself.
+     */
+    public static void start(Context context, int subId, @Nullable Bundle messageData) {
         if (!isDeviceProvisioned(context)) {
             VvmLog.i(TAG, "Activation requested while device is not provisioned, postponing");
             // Activation might need information such as system language to be set, so wait until
@@ -93,31 +100,22 @@
             return;
         }
 
-        // Check for signal before activating. The event often happen while boot and the
-        // network is not connected yet. Launching activation will likely to cause the SMS
-        // sending to fail and waste unnecessary time waiting for time out.
-        if (context.getSystemService(TelephonyManager.class)
-            .getServiceStateForSubscriber(subId).getState()
-            != ServiceState.STATE_IN_SERVICE) {
-            VvmLog.i(TAG, "Activation requested while not in service, rejecting");
-        }
-
         Intent intent = BaseTask.createIntent(context, ActivationTask.class, subId);
-        if (data != null) {
-            intent.putExtra(EXTRA_MESSAGE_DATA_BUNDLE, data);
+        if (messageData != null) {
+            intent.putExtra(EXTRA_MESSAGE_DATA_BUNDLE, messageData);
         }
         context.startService(intent);
     }
 
     public void onCreate(Context context, Intent intent, int flags, int startId) {
         super.onCreate(context, intent, flags, startId);
-        mData = intent.getParcelableExtra(EXTRA_MESSAGE_DATA_BUNDLE);
+        mMessageData = intent.getParcelableExtra(EXTRA_MESSAGE_DATA_BUNDLE);
     }
 
     @Override
     public Intent createRestartIntent() {
         Intent intent = super.createRestartIntent();
-        // mData is discarded, request a fresh STATUS SMS for retries.
+        // mMessageData is discarded, request a fresh STATUS SMS for retries.
         return intent;
     }
 
@@ -140,8 +138,22 @@
             VoicemailStatus.disable(getContext(), phoneAccountHandle);
             return;
         }
+
+        // OmtpVvmCarrierConfigHelper can start the activation process; it will pass in a vvm
+        // content provider URI which we will use.  On some occasions, setting that URI will
+        // fail, so we will perform a few attempts to ensure that the vvm content provider has
+        // a good chance of being started up.
+        if (!VoicemailStatus.edit(getContext(), phoneAccountHandle)
+            .setType(helper.getVvmType())
+            .apply()) {
+            VvmLog.e(TAG, "Failed to configure content provider - " + helper.getVvmType());
+            fail();
+        }
+        VvmLog.i(TAG, "VVM content provider configured - " + helper.getVvmType());
+
         if (!OmtpVvmSourceManager.getInstance(getContext())
                 .isVvmSourceRegistered(phoneAccountHandle)) {
+            // This account has not been activated before during the lifetime of this boot.
             VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(getContext(),
                     phoneAccountHandle);
             if (preferences.getString(OmtpConstants.SERVER_ADDRESS, null) == null) {
@@ -153,12 +165,20 @@
             } else {
                 // The account has been activated on this device before. Pretend it is already
                 // activated. If there are any activation error it will overwrite this status.
-                VoicemailStatus.edit(getContext(), phoneAccountHandle)
-                        .setConfigurationState(Status.CONFIGURATION_STATE_OK)
-                        .apply();
+                helper.handleEvent(VoicemailStatus.edit(getContext(), phoneAccountHandle),
+                        OmtpEvents.CONFIG_ACTIVATING_SUBSEQUENT);
             }
 
         }
+        if (!hasSignal(getContext(), subId)) {
+            VvmLog.i(TAG, "Service lost during activation, aborting");
+            // Restore the "NO SIGNAL" state since it will be overwritten by the CONFIG_ACTIVATING
+            // event.
+            helper.handleEvent(VoicemailStatus.edit(getContext(), phoneAccountHandle),
+                    OmtpEvents.NOTIFICATION_SERVICE_LOST);
+            // Don't retry, a new activation will be started after the signal returned.
+            return;
+        }
 
         helper.activateSmsFilter();
         VoicemailStatus.Editor status = mRetryPolicy.getVoicemailStatusEditor();
@@ -166,13 +186,13 @@
         VisualVoicemailProtocol protocol = helper.getProtocol();
 
         Bundle data;
-        if (mData != null) {
+        if (mMessageData != null) {
             // The content of STATUS SMS is provided to launch this task, no need to request it
             // again.
-            data = mData;
+            data = mMessageData;
         } else {
             try (StatusSmsFetcher fetcher = new StatusSmsFetcher(getContext(), subId)) {
-                protocol.startActivation(helper);
+                protocol.startActivation(helper, fetcher.getSentIntent());
                 // Both the fetcher and OmtpMessageReceiver will be triggered, but
                 // OmtpMessageReceiver will just route the SMS back to ActivationTask, which will be
                 // rejected because the task is still running.
@@ -183,6 +203,10 @@
                 helper.handleEvent(status, OmtpEvents.CONFIG_STATUS_SMS_TIME_OUT);
                 fail();
                 return;
+            } catch (CancellationException e) {
+                VvmLog.e(TAG, "Unable to send status request SMS");
+                fail();
+                return;
             } catch (InterruptedException | ExecutionException | IOException e) {
                 VvmLog.e(TAG, "can't get future STATUS SMS", e);
                 fail();
@@ -210,6 +234,7 @@
             } else {
                 VvmLog.i(TAG, "Subscriber not ready but provisioning is not supported");
                 helper.handleEvent(status, OmtpEvents.CONFIG_SERVICE_NOT_AVAILABLE);
+                PhoneGlobals.getInstance().setShouldCheckVisualVoicemailConfigurationForMwi(subId, false);
             }
         }
     }
@@ -231,14 +256,21 @@
             vvmSourceManager.addSource(phone);
 
             SyncTask.start(context, phone, OmtpVvmSyncService.SYNC_FULL_SYNC);
-            // Remove the message waiting indicator, which is a stick notification fo traditional
+            // Remove the message waiting indicator, which is a sticky notification for traditional
             // voicemails.
+            PhoneGlobals.getInstance()
+                    .setShouldCheckVisualVoicemailConfigurationForMwi(subId, true);
             PhoneGlobals.getInstance().clearMwiIndicator(subId);
         } else {
             VvmLog.e(TAG, "Visual voicemail not available for subscriber.");
         }
     }
 
+    private static boolean hasSignal(Context context, int subId) {
+        return context.getSystemService(TelephonyManager.class)
+                .getServiceStateForSubscriber(subId).getState() == ServiceState.STATE_IN_SERVICE;
+    }
+
     private static void queueActivationAfterProvisioned(Context context, int subId) {
         if (sDeviceProvisionedObserver == null) {
             sDeviceProvisionedObserver = new DeviceProvisionedObserver(context);
diff --git a/src/com/android/phone/vvm/omtp/DefaultOmtpEventHandler.java b/src/com/android/phone/vvm/omtp/DefaultOmtpEventHandler.java
index 88943c9..0c19a6a 100644
--- a/src/com/android/phone/vvm/omtp/DefaultOmtpEventHandler.java
+++ b/src/com/android/phone/vvm/omtp/DefaultOmtpEventHandler.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.provider.VoicemailContract;
 import android.provider.VoicemailContract.Status;
+
 import com.android.phone.VoicemailStatus;
 import com.android.phone.vvm.omtp.OmtpEvents.Type;
 
@@ -49,6 +50,7 @@
     private static void handleConfigurationEvent(Context context, VoicemailStatus.Editor status,
             OmtpEvents event) {
         switch (event) {
+            case CONFIG_DEFAULT_PIN_REPLACED:
             case CONFIG_REQUEST_STATUS_SUCCESS:
             case CONFIG_PIN_SET:
                 status
@@ -61,8 +63,14 @@
                 // for this activation.
                 status
                         .setConfigurationState(Status.CONFIGURATION_STATE_CONFIGURING)
-                        .setDataChannelState(Status.DATA_CHANNEL_STATE_OK)
-                        .setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_OK).apply();
+                        .setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_OK)
+                        .setDataChannelState(Status.DATA_CHANNEL_STATE_OK).apply();
+                break;
+            case CONFIG_ACTIVATING_SUBSEQUENT:
+                status
+                        .setConfigurationState(Status.CONFIGURATION_STATE_OK)
+                        .setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_OK)
+                        .setDataChannelState(Status.DATA_CHANNEL_STATE_OK).apply();
                 break;
             case CONFIG_SERVICE_NOT_AVAILABLE:
                 status
@@ -116,6 +124,7 @@
             case DATA_SSL_INVALID_HOST_NAME:
             case DATA_CANNOT_ESTABLISH_SSL_SESSION:
             case DATA_IOE_ON_OPEN:
+            case DATA_GENERIC_IMAP_IOE:
                 status
                         .setDataChannelState(
                                 VoicemailContract.Status.DATA_CHANNEL_STATE_COMMUNICATION_ERROR)
@@ -137,6 +146,7 @@
 
             case DATA_REJECTED_SERVER_RESPONSE:
             case DATA_INVALID_INITIAL_SERVER_RESPONSE:
+            case DATA_MAILBOX_OPEN_FAILED:
             case DATA_SSL_EXCEPTION:
             case DATA_ALL_SOCKET_CONNECTION_FAILED:
                 status
diff --git a/src/com/android/phone/vvm/omtp/OmtpEvents.java b/src/com/android/phone/vvm/omtp/OmtpEvents.java
index 648e0d0..7a89418 100644
--- a/src/com/android/phone/vvm/omtp/OmtpEvents.java
+++ b/src/com/android/phone/vvm/omtp/OmtpEvents.java
@@ -17,6 +17,7 @@
 package com.android.phone.vvm.omtp;
 
 import android.annotation.IntDef;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -34,6 +35,8 @@
     // The voicemail PIN is replaced with a generated PIN, user should change it.
     CONFIG_DEFAULT_PIN_REPLACED(Type.CONFIGURATION, true),
     CONFIG_ACTIVATING(Type.CONFIGURATION, true),
+    // There are already activation records, this is only a book-keeping activation.
+    CONFIG_ACTIVATING_SUBSEQUENT(Type.CONFIGURATION, true),
     CONFIG_STATUS_SMS_TIME_OUT(Type.CONFIGURATION),
     CONFIG_SERVICE_NOT_AVAILABLE(Type.CONFIGURATION),
 
diff --git a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
index b4fbb3f..0b321b5 100644
--- a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
+++ b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
@@ -16,6 +16,7 @@
 package com.android.phone.vvm.omtp;
 
 import android.annotation.Nullable;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Bundle;
@@ -315,9 +316,15 @@
             // Error logged in getPhoneAccountHandle().
             return;
         }
-        VoicemailStatus.edit(mContext, phoneAccountHandle)
-                .setType(getVvmType())
-                .apply();
+
+        if (mVvmType == null || mVvmType.isEmpty()) {
+            // The VVM type is invalid; we should never have gotten here in the first place since
+            // this is loaded initially in the constructor, and callers should check isValid()
+            // before trying to start activation anyways.
+            VvmLog.e(TAG, "startActivation : vvmType is null or empty for account " +
+                    phoneAccountHandle);
+            return;
+        }
 
         activateSmsFilter();
 
@@ -358,9 +365,9 @@
         }
     }
 
-    public void requestStatus() {
+    public void requestStatus(@Nullable PendingIntent sentIntent) {
         if (mProtocol != null) {
-            mProtocol.requestStatus(this);
+            mProtocol.requestStatus(this, sentIntent);
         }
     }
 
diff --git a/src/com/android/phone/vvm/omtp/VvmPhoneStateListener.java b/src/com/android/phone/vvm/omtp/VvmPhoneStateListener.java
index 94e616c..7e2472b 100644
--- a/src/com/android/phone/vvm/omtp/VvmPhoneStateListener.java
+++ b/src/com/android/phone/vvm/omtp/VvmPhoneStateListener.java
@@ -20,7 +20,7 @@
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
-import com.android.phone.PhoneGlobals;
+
 import com.android.phone.PhoneUtils;
 import com.android.phone.VoicemailStatus;
 import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
@@ -75,7 +75,6 @@
                             .v(TAG, "Notifications channel is active for " + subId);
                     helper.handleEvent(VoicemailStatus.edit(mContext, mPhoneAccount),
                         OmtpEvents.NOTIFICATION_IN_SERVICE);
-                    PhoneGlobals.getInstance().clearMwiIndicator(subId);
                 }
             }
 
diff --git a/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java b/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java
index e0b6359..6e6d6ef 100644
--- a/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java
+++ b/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java
@@ -17,6 +17,7 @@
 package com.android.phone.vvm.omtp.protocol;
 
 import android.annotation.Nullable;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.os.Bundle;
 import android.telecom.PhoneAccountHandle;
@@ -34,10 +35,10 @@
     /**
      * Activation should cause the carrier to respond with a STATUS SMS.
      */
-    public void startActivation(OmtpVvmCarrierConfigHelper config) {
+    public void startActivation(OmtpVvmCarrierConfigHelper config, PendingIntent sentIntent) {
         OmtpMessageSender messageSender = ProtocolHelper.getMessageSender(this, config);
         if (messageSender != null) {
-            messageSender.requestVvmActivation(null);
+            messageSender.requestVvmActivation(sentIntent);
         }
     }
 
@@ -58,10 +59,11 @@
         // Do nothing
     }
 
-    public void requestStatus(OmtpVvmCarrierConfigHelper config) {
+    public void requestStatus(OmtpVvmCarrierConfigHelper config,
+            @Nullable PendingIntent sentIntent) {
         OmtpMessageSender messageSender = ProtocolHelper.getMessageSender(this, config);
         if (messageSender != null) {
-            messageSender.requestVvmStatus(null);
+            messageSender.requestVvmStatus(sentIntent);
         }
     }
 
diff --git a/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java b/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
index 39d2b34..93e8fb9 100644
--- a/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
+++ b/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
@@ -17,12 +17,15 @@
 package com.android.phone.vvm.omtp.protocol;
 
 import android.annotation.Nullable;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.net.Network;
 import android.os.Bundle;
 import android.telecom.PhoneAccountHandle;
 import android.telephony.SmsManager;
 import android.text.TextUtils;
+
+import com.android.phone.PhoneGlobals;
 import com.android.phone.VoicemailStatus;
 import com.android.phone.common.mail.MessagingException;
 import com.android.phone.settings.VisualVoicemailSettingsUtil;
@@ -41,6 +44,7 @@
 import com.android.phone.vvm.omtp.sync.VvmNetworkRequest;
 import com.android.phone.vvm.omtp.sync.VvmNetworkRequest.NetworkWrapper;
 import com.android.phone.vvm.omtp.sync.VvmNetworkRequest.RequestFailedException;
+
 import java.io.IOException;
 import java.security.SecureRandom;
 import java.util.Locale;
@@ -82,12 +86,13 @@
     private static final int DEFAULT_PIN_LENGTH = 6;
 
     @Override
-    public void startActivation(OmtpVvmCarrierConfigHelper config) {
+    public void startActivation(OmtpVvmCarrierConfigHelper config,
+            @Nullable PendingIntent sentIntent) {
         // VVM3 does not support activation SMS.
         // Send a status request which will start the provisioning process if the user is not
         // provisioned.
         VvmLog.i(TAG, "Activating");
-        config.requestStatus();
+        config.requestStatus(sentIntent);
     }
 
     @Override
@@ -114,6 +119,8 @@
                 new Vvm3Subscriber(task, phoneAccountHandle, config, status, data).subscribe();
             } else {
                 config.handleEvent(status, OmtpEvents.VVM3_SUBSCRIBER_UNKNOWN);
+                PhoneGlobals.getInstance().setShouldCheckVisualVoicemailConfigurationForMwi(task.getSubId(),
+                        false);
             }
         } else if (OmtpConstants.SUBSCRIBER_NEW.equals(message.getProvisioningStatus())) {
             VvmLog.i(TAG, "setting up new user");
@@ -127,9 +134,13 @@
             VvmLog.i(TAG, "User provisioned but not activated, disabling VVM");
             VisualVoicemailSettingsUtil
                     .setEnabled(config.getContext(), phoneAccountHandle, false);
+            PhoneGlobals.getInstance().setShouldCheckVisualVoicemailConfigurationForMwi(task.getSubId(),
+                    false);
         } else if (OmtpConstants.SUBSCRIBER_BLOCKED.equals(message.getProvisioningStatus())) {
             VvmLog.i(TAG, "User blocked");
             config.handleEvent(status, OmtpEvents.VVM3_SUBSCRIBER_BLOCKED);
+            PhoneGlobals.getInstance().setShouldCheckVisualVoicemailConfigurationForMwi(task.getSubId(),
+                    false);
         }
     }
 
@@ -215,7 +226,7 @@
                     helper.closeNewUserTutorial();
                     VvmLog.i(TAG, "new user: NUT closed");
 
-                    config.requestStatus();
+                    config.requestStatus(null);
                 }
             } catch (InitializingException | MessagingException | IOException e) {
                 config.handleEvent(status, OmtpEvents.VVM3_NEW_USER_SETUP_FAILED);
diff --git a/src/com/android/phone/vvm/omtp/scheduling/TaskSchedulerService.java b/src/com/android/phone/vvm/omtp/scheduling/TaskSchedulerService.java
index 1e099e8..3d6fcdb 100644
--- a/src/com/android/phone/vvm/omtp/scheduling/TaskSchedulerService.java
+++ b/src/com/android/phone/vvm/omtp/scheduling/TaskSchedulerService.java
@@ -19,6 +19,8 @@
 import android.annotation.MainThread;
 import android.annotation.Nullable;
 import android.annotation.WorkerThread;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
@@ -30,6 +32,7 @@
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
+import android.os.SystemClock;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.phone.Assert;
 import com.android.phone.NeededForTesting;
@@ -45,9 +48,25 @@
  */
 public class TaskSchedulerService extends Service {
 
-    private static final String TAG = "TaskSchedulerService";
+    private static final String TAG = "VvmTaskScheduler";
+
+    private static final String ACTION_WAKEUP = "action_wakeup";
 
     private static final int READY_TOLERANCE_MILLISECONDS = 100;
+
+    /**
+     * Threshold to determine whether to do a short or long sleep when a task is scheduled in the
+     * future.
+     *
+     * <p>A short sleep will continue to held the wake lock and use {@link
+     * Handler#postDelayed(Runnable, long)} to wait for the next task.
+     *
+     * <p>A long sleep will release the wake lock and set a {@link AlarmManager} alarm. The alarm is
+     * exact and will wake up the device. Note: as this service is run in the telephony process it
+     * does not seem to be restricted by doze or sleep, it will fire exactly at the moment. The
+     * unbundled version should take doze into account.
+     */
+    private static final int SHORT_SLEEP_THRESHOLD_MILLISECONDS = 60_000;
     /**
      * When there are no more tasks to be run the service should be stopped. But when all tasks has
      * finished there might still be more tasks in the message queue waiting to be processed,
@@ -141,7 +160,7 @@
         super.onCreate();
         mWakeLock = getSystemService(PowerManager.class)
                 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG);
-        mWakeLock.acquire();
+        mWakeLock.setReferenceCounted(false);
         HandlerThread thread = new HandlerThread("VvmTaskSchedulerService");
         thread.start();
 
@@ -159,12 +178,20 @@
     @MainThread
     public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
         Assert.isMainThread();
-        Task task = createTask(intent, flags, startId);
-        if (task == null) {
-            VvmLog.e(TAG, "cannot create task form intent");
+        // maybeRunNextTask() will release the wakelock either by entering a long sleep or stopping
+        // the service.
+        mWakeLock.acquire();
+        if (ACTION_WAKEUP.equals(intent.getAction())) {
+            VvmLog.d(TAG, "woke up by AlarmManager");
         } else {
-            addTask(task);
+            Task task = createTask(intent, flags, startId);
+            if (task == null) {
+                VvmLog.e(TAG, "cannot create task form intent");
+            } else {
+                addTask(task);
+            }
         }
+        maybeRunNextTask();
         // STICKY means the service will be automatically restarted will the last intent if it is
         // killed.
         return START_NOT_STICKY;
@@ -187,7 +214,6 @@
         mMainThreadHandler.removeCallbacks(mStopServiceWithDelay);
         getTasks().add(task);
         maybeRunNextTask();
-
     }
 
     @MainThread
@@ -258,6 +284,8 @@
     @MainThread
     void runNextTask() {
         Assert.isMainThread();
+        // The current alarm is no longer valid, a new one will be set up if required.
+        getSystemService(AlarmManager.class).cancel(getWakeupIntent());
         if (getTasks().isEmpty()) {
             prepareStop();
             return;
@@ -280,15 +308,37 @@
         }
         VvmLog.d(TAG, "minimal wait time:" + minimalWaitTime);
         if (!mTaskAutoRunDisabledForTesting && minimalWaitTime != null) {
-            // No tests are currently ready. Sleep until the next one should be.
+            // No tasks are currently ready. Sleep until the next one should be.
             // If a new task is added during the sleep the service will wake immediately.
+            sleep(minimalWaitTime);
+        }
+    }
+
+    private void sleep(long timeMillis) {
+        if (timeMillis < SHORT_SLEEP_THRESHOLD_MILLISECONDS) {
             mMainThreadHandler.postDelayed(new Runnable() {
                 @Override
                 public void run() {
                     maybeRunNextTask();
                 }
-            }, minimalWaitTime);
+            }, timeMillis);
+            return;
         }
+
+        // Tasks does not have a strict timing requirement, use AlarmManager.set() so the OS could
+        // optimize the battery usage. As this service currently run in the telephony process the
+        // OS give it privileges to behave the same as setExact(), but set() is the targeted
+        // behavior once this is unbundled.
+        getSystemService(AlarmManager.class).set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                SystemClock.elapsedRealtime() + timeMillis,
+                getWakeupIntent());
+        mWakeLock.release();
+        VvmLog.d(TAG, "Long sleep for " + timeMillis + " millis");
+    }
+
+    private PendingIntent getWakeupIntent() {
+        Intent intent = new Intent(ACTION_WAKEUP, null, this, getClass());
+        return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
     }
 
     private void prepareStop() {
diff --git a/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java b/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java
index 2c37dd9..69e4f5f 100644
--- a/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java
+++ b/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java
@@ -17,20 +17,27 @@
 package com.android.phone.vvm.omtp.sms;
 
 import android.annotation.MainThread;
+import android.annotation.Nullable;
 import android.annotation.WorkerThread;
+import android.app.Activity;
+import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Bundle;
 import android.provider.VoicemailContract;
+import android.telephony.SmsManager;
+
 import com.android.phone.Assert;
 import com.android.phone.vvm.omtp.OmtpConstants;
 import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
 import com.android.phone.vvm.omtp.VvmLog;
 import com.android.phone.vvm.omtp.protocol.VisualVoicemailProtocol;
+
 import java.io.Closeable;
 import java.io.IOException;
+import java.util.concurrent.CancellationException;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
@@ -44,6 +51,9 @@
     private static final String TAG = "VvmStatusSmsFetcher";
 
     private static final long STATUS_SMS_TIMEOUT_MILLIS = 60_000;
+    private static final String ACTION_REQUEST_SENT_INTENT
+            = "com.android.phone.vvm.omtp.sms.REQUEST_SENT";
+    private static final int ACTION_REQUEST_SENT_REQUEST_CODE = 0;
 
     private CompletableFuture<Bundle> mFuture = new CompletableFuture<>();
 
@@ -54,6 +64,7 @@
         mContext = context;
         mSubId = subId;
         IntentFilter filter = new IntentFilter(VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED);
+        filter.addAction(ACTION_REQUEST_SENT_INTENT);
         context.registerReceiver(this, filter);
     }
 
@@ -63,16 +74,39 @@
     }
 
     @WorkerThread
-    public Bundle get()
-            throws InterruptedException, ExecutionException, TimeoutException {
+    @Nullable
+    public Bundle get() throws InterruptedException, ExecutionException, TimeoutException,
+            CancellationException {
         Assert.isNotMainThread();
         return mFuture.get(STATUS_SMS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
     }
 
+    public PendingIntent getSentIntent() {
+        Intent intent = new Intent(ACTION_REQUEST_SENT_INTENT);
+        intent.setPackage(mContext.getPackageName());
+        // Because the receiver is registered dynamically, implicit intent must be used.
+        // There should only be a single status SMS request at a time.
+        return PendingIntent.getBroadcast(mContext, ACTION_REQUEST_SENT_REQUEST_CODE, intent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+    }
+
     @Override
     @MainThread
     public void onReceive(Context context, Intent intent) {
         Assert.isMainThread();
+        if (ACTION_REQUEST_SENT_INTENT.equals(intent.getAction())) {
+            int resultCode = getResultCode();
+
+            if (resultCode == Activity.RESULT_OK) {
+                VvmLog.d(TAG, "Request SMS successfully sent");
+                return;
+            }
+
+            VvmLog.e(TAG, "Request SMS send failed: " + sentSmsResultToString(resultCode));
+            mFuture.cancel(true);
+            return;
+        }
+
         int subId = intent.getExtras().getInt(VoicemailContract.EXTRA_VOICEMAIL_SMS_SUBID);
 
         if (mSubId != subId) {
@@ -105,4 +139,21 @@
             mFuture.complete(translatedBundle);
         }
     }
+
+    private static String sentSmsResultToString(int resultCode) {
+        switch (resultCode) {
+            case Activity.RESULT_OK:
+                return "OK";
+            case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
+                return "RESULT_ERROR_GENERIC_FAILURE";
+            case SmsManager.RESULT_ERROR_NO_SERVICE:
+                return "RESULT_ERROR_GENERIC_FAILURE";
+            case SmsManager.RESULT_ERROR_NULL_PDU:
+                return "RESULT_ERROR_GENERIC_FAILURE";
+            case SmsManager.RESULT_ERROR_RADIO_OFF:
+                return "RESULT_ERROR_GENERIC_FAILURE";
+            default:
+                return "UNKNOWN CODE: " + resultCode;
+        }
+    }
 }
diff --git a/src/com/android/services/telephony/CdmaConnection.java b/src/com/android/services/telephony/CdmaConnection.java
index 8020996..29ccc6c 100644
--- a/src/com/android/services/telephony/CdmaConnection.java
+++ b/src/com/android/services/telephony/CdmaConnection.java
@@ -184,7 +184,7 @@
     }
 
     @Override
-    public void performConference(TelephonyConnection otherConnection) {
+    public void performConference(android.telecom.Connection otherConnection) {
         if (isImsConnection()) {
             super.performConference(otherConnection);
         } else {
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index bcc22fd..6eb4a4e 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -128,6 +128,7 @@
             case android.telephony.DisconnectCause.MAXIMUM_NUMBER_OF_CALLS_REACHED:
             case android.telephony.DisconnectCause.DATA_DISABLED:
             case android.telephony.DisconnectCause.DATA_LIMIT_REACHED:
+            case android.telephony.DisconnectCause.DIALED_ON_WRONG_SLOT:
                 return DisconnectCause.ERROR;
 
             case android.telephony.DisconnectCause.DIALED_MMI:
@@ -377,7 +378,7 @@
                 break;
 
             case android.telephony.DisconnectCause.DATA_LIMIT_REACHED:
-                resourceId = R.string.callFailed_data_limit_reached;
+                resourceId = R.string.callFailed_data_limit_reached_description;
                 break;
 
             default:
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index 3f49c6f..4acb6f8 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -20,6 +20,7 @@
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.PersistableBundle;
 import android.telecom.Conference;
 import android.telecom.ConferenceParticipant;
 import android.telecom.Connection.VideoProvider;
@@ -29,6 +30,7 @@
 import android.telecom.PhoneAccountHandle;
 import android.telecom.StatusHints;
 import android.telecom.VideoProfile;
+import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
 import android.util.Pair;
 
@@ -36,6 +38,7 @@
 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;
 
@@ -279,8 +282,11 @@
         mTelephonyConnectionService = telephonyConnectionService;
         setConferenceHost(conferenceHost);
 
-        int capabilities = Connection.CAPABILITY_SUPPORT_HOLD | Connection.CAPABILITY_HOLD |
-                Connection.CAPABILITY_MUTE | Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN;
+        int capabilities = Connection.CAPABILITY_MUTE |
+                Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN;
+        if (canHoldImsCalls()) {
+            capabilities |= Connection.CAPABILITY_SUPPORT_HOLD | Connection.CAPABILITY_HOLD;
+        }
         capabilities = applyHostCapabilities(capabilities,
                 mConferenceHost.getConnectionCapabilities(),
                 mConferenceHost.isCarrierVideoConferencingSupported());
@@ -433,7 +439,7 @@
     @Override
     public void onMerge(android.telecom.Connection connection) {
         try {
-            Phone phone = ((TelephonyConnection) connection).getPhone();
+            Phone phone = mConferenceHost.getPhone();
             if (phone != null) {
                 phone.conference();
             }
@@ -976,4 +982,22 @@
         sb.append("]");
         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());
+    }
 }
diff --git a/src/com/android/services/telephony/ImsConferenceController.java b/src/com/android/services/telephony/ImsConferenceController.java
index 6669482..f7d587d 100644
--- a/src/com/android/services/telephony/ImsConferenceController.java
+++ b/src/com/android/services/telephony/ImsConferenceController.java
@@ -187,6 +187,7 @@
         Log.v(this, "recalculateConferenceable : %d", mTelephonyConnections.size());
         HashSet<Conferenceable> conferenceableSet = new HashSet<>(mTelephonyConnections.size() +
                 mImsConferences.size());
+        HashSet<Conferenceable> conferenceParticipantsSet = new HashSet<>();
 
         // Loop through and collect all calls which are active or holding
         for (TelephonyConnection connection : mTelephonyConnections) {
@@ -240,6 +241,7 @@
                 case Connection.STATE_ACTIVE:
                     //fall through
                 case Connection.STATE_HOLDING:
+                    conferenceParticipantsSet.addAll(conference.getConnections());
                     conferenceableSet.add(conference);
                     continue;
                 default:
@@ -256,6 +258,16 @@
                         .stream()
                         .filter(conferenceable -> c != conferenceable)
                         .collect(Collectors.toList());
+                // TODO: Remove this once RemoteConnection#setConferenceableConnections is fixed.
+                // Add all conference participant connections as conferenceable with a standalone
+                // Connection.  We need to do this to ensure that RemoteConnections work properly.
+                // At the current time, a RemoteConnection will not be conferenceable with a
+                // Conference, so we need to add its children to ensure the user can merge the call
+                // into the conference.
+                // We should add support for RemoteConnection#setConferenceables, which accepts a
+                // list of remote conferences and connections in the future.
+                conferenceables.addAll(conferenceParticipantsSet);
+
                 ((Connection) c).setConferenceables(conferenceables);
             } else if (c instanceof Conference) {
                 // Remove all conferences from the set, since we can not conference a conference
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 3810699..c4f9c9a 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -33,6 +33,7 @@
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
 import android.telephony.CarrierConfigManager;
+import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.TelephonyManager;
 import android.util.Pair;
@@ -254,6 +255,7 @@
      */
     public abstract static class TelephonyConnectionListener {
         public void onOriginalConnectionConfigured(TelephonyConnection c) {}
+        public void onOriginalConnectionRetry(TelephonyConnection c) {}
     }
 
     private final PostDialListener mPostDialListener = new PostDialListener() {
@@ -681,7 +683,7 @@
         }
     }
 
-    public void performConference(TelephonyConnection otherConnection) {
+    public void performConference(Connection otherConnection) {
         Log.d(this, "performConference - %s", this);
         if (getPhone() != null) {
             try {
@@ -738,7 +740,7 @@
         // shown.
         Phone phone = getPhone();
         if (phone != null && phone.isInEcm()) {
-            connectionProperties |= PROPERTY_SHOW_CALLBACK_NUMBER;
+            connectionProperties |= PROPERTY_EMERGENCY_CALLBACK_MODE;
         }
 
         return connectionProperties;
@@ -973,7 +975,8 @@
     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);
+        return !doesDeviceRespectHoldCarrierConfig() || b == null ||
+                b.getBoolean(CarrierConfigManager.KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL);
     }
 
     private PersistableBundle getCarrierConfig() {
@@ -985,6 +988,23 @@
     }
 
     /**
+     * Determines if the device will respect the value of the
+     * {@link CarrierConfigManager#KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL} configuration option.
+     *
+     * @return {@code false} if the device always supports holding IMS calls, {@code true} if it
+     *      will use {@link CarrierConfigManager#KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL} to determine if
+     *      hold is supported.
+     */
+    private boolean doesDeviceRespectHoldCarrierConfig() {
+        Phone phone = getPhone();
+        if (phone == null) {
+            return true;
+        }
+        return phone.getContext().getResources().getBoolean(
+                com.android.internal.R.bool.config_device_respects_hold_carrier_config);
+    }
+
+    /**
      * Whether the connection should be treated as an emergency.
      * @return {@code true} if the connection should be treated as an emergency call based
      * on the number dialed, {@code false} otherwise.
@@ -1248,10 +1268,19 @@
                     setRinging();
                     break;
                 case DISCONNECTED:
-                    setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
-                            mOriginalConnection.getDisconnectCause(),
-                            mOriginalConnection.getVendorDisconnectCause()));
-                    close();
+                    // We can get into a situation where the radio wants us to redial the same
+                    // emergency call on the other available slot. This will not set the state to
+                    // disconnected and will instead tell the TelephonyConnectionService to create
+                    // a new originalConnection using the new Slot.
+                    if (mOriginalConnection.getDisconnectCause() ==
+                            DisconnectCause.DIALED_ON_WRONG_SLOT) {
+                        fireOnOriginalConnectionRetryDial();
+                    } else {
+                        setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
+                                mOriginalConnection.getDisconnectCause(),
+                                mOriginalConnection.getVendorDisconnectCause()));
+                        close();
+                    }
                     break;
                 case DISCONNECTING:
                     break;
@@ -1629,6 +1658,12 @@
         }
     }
 
+    private final void fireOnOriginalConnectionRetryDial() {
+        for (TelephonyConnectionListener l : mTelephonyListeners) {
+            l.onOriginalConnectionRetry(this);
+        }
+    }
+
     /**
      * Handles exiting ECM mode.
      */
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 54cbda7..5afdd72 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -33,10 +33,12 @@
 import android.telecom.VideoProfile;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.RadioAccessFamily;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.Pair;
 
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallStateException;
@@ -52,8 +54,11 @@
 import com.android.phone.PhoneUtils;
 import com.android.phone.R;
 
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.regex.Pattern;
 
@@ -77,6 +82,13 @@
     private EmergencyCallHelper mEmergencyCallHelper;
     private EmergencyTonePlayer mEmergencyTonePlayer;
 
+    // Contains one TelephonyConnection that has placed a call and a memory of which Phones it has
+    // already tried to connect with. There should be only one TelephonyConnection trying to place a
+    // call at one time. We also only access this cache from a TelephonyConnection that wishes to
+    // redial, so we use a WeakReference that will become stale once the TelephonyConnection is
+    // destroyed.
+    private Pair<WeakReference<TelephonyConnection>, List<Phone>> mEmergencyRetryCache;
+
     /**
      * A listener to actionable events specific to the TelephonyConnection.
      */
@@ -86,6 +98,11 @@
         public void onOriginalConnectionConfigured(TelephonyConnection c) {
             addConnectionToConferenceController(c);
         }
+
+        @Override
+        public void onOriginalConnectionRetry(TelephonyConnection c) {
+            retryOutgoingOriginalConnection(c);
+        }
     };
 
     @Override
@@ -112,7 +129,7 @@
         }
 
         String scheme = handle.getScheme();
-        final String number;
+        String number;
         if (PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
             // TODO: We don't check for SecurityException here (requires
             // CALL_PRIVILEGED permission).
@@ -176,14 +193,36 @@
             }
         }
 
-        final boolean isEmergencyNumber = PhoneNumberUtils.isLocalEmergencyNumber(this, number);
+        // Convert into emergency number if necessary
+        // This is required in some regions (e.g. Taiwan).
+        if (!PhoneNumberUtils.isLocalEmergencyNumber(this, number) &&
+                PhoneNumberUtils.isConvertToEmergencyNumberEnabled()) {
+            final Phone phone = getPhoneForAccount(request.getAccountHandle(), false);
+            // We only do the conversion if the phone is not in service. The un-converted
+            // emergency numbers will go to the correct destination when the phone is in-service,
+            // so they will only need the special emergency call setup when the phone is out of
+            // service.
+            if (phone == null || phone.getServiceState().getState()
+                    != ServiceState.STATE_IN_SERVICE) {
+                String convertedNumber = PhoneNumberUtils.convertToEmergencyNumber(number);
+                if (!TextUtils.equals(convertedNumber, number)) {
+                    Log.i(this, "onCreateOutgoingConnection, converted to emergency number");
+                    number = convertedNumber;
+                    handle = Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null);
+                }
+            }
+        }
+        final String numberToDial = number;
+
+        final boolean isEmergencyNumber =
+                PhoneNumberUtils.isLocalEmergencyNumber(this, numberToDial);
 
         if (isEmergencyNumber && !isRadioOn()) {
             final Uri emergencyHandle = handle;
             // By default, Connection based on the default Phone, since we need to return to Telecom
             // now.
             final int defaultPhoneType = PhoneFactory.getDefaultPhone().getPhoneType();
-            final Connection emergencyConnection = getTelephonyConnection(request, number,
+            final Connection emergencyConnection = getTelephonyConnection(request, numberToDial,
                     isEmergencyNumber, emergencyHandle, PhoneFactory.getDefaultPhone());
             if (mEmergencyCallHelper == null) {
                 mEmergencyCallHelper = new EmergencyCallHelper(this);
@@ -206,7 +245,7 @@
                         // Phone, then we need create a new Connection using that PhoneType and
                         // replace it in Telecom.
                         if (phone.getPhoneType() != defaultPhoneType) {
-                            Connection repConnection = getTelephonyConnection(request, number,
+                            Connection repConnection = getTelephonyConnection(request, numberToDial,
                                     isEmergencyNumber, emergencyHandle, phone);
                             // If there was a failure, the resulting connection will not be a
                             // TelephonyConnection, so don't place the call, just return!
@@ -256,8 +295,8 @@
 
             // Get the right phone object from the account data passed in.
             final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber);
-            Connection resultConnection = getTelephonyConnection(request, number, isEmergencyNumber,
-                    handle, phone);
+            Connection resultConnection = getTelephonyConnection(request, numberToDial,
+                    isEmergencyNumber, handle, phone);
             // If there was a failure, the resulting connection will not be a TelephonyConnection,
             // so don't place the call!
             if(resultConnection instanceof TelephonyConnection) {
@@ -577,14 +616,35 @@
         }
     }
 
+    /**
+     * Conferences two connections.
+     *
+     * Note: The {@link android.telecom.RemoteConnection#setConferenceableConnections(List)} API has
+     * a limitation in that it can only specify conferenceables which are instances of
+     * {@link android.telecom.RemoteConnection}.  In the case of an {@link ImsConference}, the
+     * regular {@link Connection#setConferenceables(List)} API properly handles being able to merge
+     * a {@link Conference} and a {@link Connection}.  As a result when, merging a
+     * {@link android.telecom.RemoteConnection} into a {@link android.telecom.RemoteConference}
+     * require merging a {@link ConferenceParticipantConnection} which is a child of the
+     * {@link Conference} with a {@link TelephonyConnection}.  The
+     * {@link ConferenceParticipantConnection} class does not have the capability to initiate a
+     * conference merge, so we need to call
+     * {@link TelephonyConnection#performConference(Connection)} on either {@code connection1} or
+     * {@code connection2}, one of which is an instance of {@link TelephonyConnection}.
+     *
+     * @param connection1 A connection to merge into a conference call.
+     * @param connection2 A connection to merge into a conference call.
+     */
     @Override
     public void onConference(Connection connection1, Connection connection2) {
-        if (connection1 instanceof TelephonyConnection &&
-                connection2 instanceof TelephonyConnection) {
-            ((TelephonyConnection) connection1).performConference(
-                (TelephonyConnection) connection2);
+        if (connection1 instanceof TelephonyConnection) {
+            ((TelephonyConnection) connection1).performConference(connection2);
+        } else if (connection2 instanceof TelephonyConnection) {
+            ((TelephonyConnection) connection2).performConference(connection1);
+        } else {
+            Log.w(this, "onConference - cannot merge connections " +
+                    "Connection1: %s, Connection2: %2", connection1, connection2);
         }
-
     }
 
     private boolean isRadioOn() {
@@ -595,14 +655,78 @@
         return result;
     }
 
+    private Pair<WeakReference<TelephonyConnection>, List<Phone>> makeCachedConnectionPhonePair(
+            TelephonyConnection c) {
+        List<Phone> phones = new ArrayList<>(Arrays.asList(PhoneFactory.getPhones()));
+        return new Pair<>(new WeakReference<>(c), phones);
+    }
+
+    // Check the mEmergencyRetryCache to see if it contains the TelephonyConnection. If it doesn't,
+    // then it is stale. Create a new one!
+    private void updateCachedConnectionPhonePair(TelephonyConnection c) {
+        if (mEmergencyRetryCache == null) {
+            Log.i(this, "updateCachedConnectionPhonePair, cache is null. Generating new cache");
+            mEmergencyRetryCache = makeCachedConnectionPhonePair(c);
+        } else {
+            // Check to see if old cache is stale. If it is, replace it
+            WeakReference<TelephonyConnection> cachedConnection = mEmergencyRetryCache.first;
+            if (cachedConnection.get() != c) {
+                Log.i(this, "updateCachedConnectionPhonePair, cache is stale. Regenerating.");
+                mEmergencyRetryCache = makeCachedConnectionPhonePair(c);
+            }
+        }
+    }
+
+    /**
+     * Returns the first Phone that has not been used yet to place the call. Any Phones that have
+     * been used to place a call will have already been removed from mEmergencyRetryCache.second.
+     * The phone that it excluded will be removed from mEmergencyRetryCache.second in this method.
+     * @param phoneToExclude The Phone object that will be removed from our cache of available
+     * phones.
+     * @return the first Phone that is available to be used to retry the call.
+     */
+    private Phone getPhoneForRedial(Phone phoneToExclude) {
+        List<Phone> cachedPhones = mEmergencyRetryCache.second;
+        if (cachedPhones.contains(phoneToExclude)) {
+            Log.i(this, "getPhoneForRedial, removing Phone[" + phoneToExclude.getPhoneId() +
+                    "] from the available Phone cache.");
+            cachedPhones.remove(phoneToExclude);
+        }
+        return cachedPhones.isEmpty() ? null : cachedPhones.get(0);
+    }
+
+    private void retryOutgoingOriginalConnection(TelephonyConnection c) {
+        updateCachedConnectionPhonePair(c);
+        Phone newPhoneToUse = getPhoneForRedial(c.getPhone());
+        if (newPhoneToUse != null) {
+            int videoState = c.getVideoState();
+            Bundle connExtras = c.getExtras();
+            Log.i(this, "retryOutgoingOriginalConnection, redialing on Phone Id: " + newPhoneToUse);
+            c.clearOriginalConnection();
+            placeOutgoingConnection(c, newPhoneToUse, videoState, connExtras);
+        } else {
+            // We have run out of Phones to use. Disconnect the call and destroy the connection.
+            Log.i(this, "retryOutgoingOriginalConnection, no more Phones to use. Disconnecting.");
+            c.setDisconnected(new DisconnectCause(DisconnectCause.ERROR));
+            c.clearOriginalConnection();
+            c.destroy();
+        }
+    }
+
     private void placeOutgoingConnection(
             TelephonyConnection connection, Phone phone, ConnectionRequest request) {
+        placeOutgoingConnection(connection, phone, request.getVideoState(), request.getExtras());
+    }
+
+    private void placeOutgoingConnection(
+            TelephonyConnection connection, Phone phone, int videoState, Bundle extras) {
         String number = connection.getAddress().getSchemeSpecificPart();
 
-        com.android.internal.telephony.Connection originalConnection;
+        com.android.internal.telephony.Connection originalConnection = null;
         try {
-            originalConnection =
-                    phone.dial(number, null, request.getVideoState(), request.getExtras());
+            if (phone != null) {
+                originalConnection = phone.dial(number, null, videoState, extras);
+            }
         } catch (CallStateException e) {
             Log.e(this, e, "placeOutgoingConnection, phone.dial exception: " + e);
             int cause = android.telephony.DisconnectCause.OUTGOING_FAILURE;
@@ -699,12 +823,11 @@
      *  list (for multi-SIM devices):
      *  1) The User's SIM preference for Voice calling
      *  2) The First Phone that is currently IN_SERVICE or is available for emergency calling
-     *  3) The First Phone that has a SIM card in it (Starting from Slot 0...N)
-     *  4) The Default Phone (Currently set as Slot 0)
+     *  3) The Phone with more Capabilities.
+     *  4) The First Phone that has a SIM card in it (Starting from Slot 0...N)
+     *  5) The Default Phone (Currently set as Slot 0)
      */
     private Phone getFirstPhoneForEmergencyCall() {
-        Phone firstPhoneWithSim = null;
-
         // 1)
         int phoneId = SubscriptionManager.getDefaultVoicePhoneId();
         if (phoneId != SubscriptionManager.INVALID_PHONE_INDEX) {
@@ -714,32 +837,77 @@
             }
         }
 
-        for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
+        Phone firstPhoneWithSim = null;
+        int phoneCount = TelephonyManager.getDefault().getPhoneCount();
+        List<Pair<Integer, Integer>> phoneNetworkType = new ArrayList<>(phoneCount);
+        for (int i = 0; i < phoneCount; i++) {
             Phone phone = PhoneFactory.getPhone(i);
             if (phone == null)
                 continue;
             // 2)
             if (isAvailableForEmergencyCalls(phone)) {
                 // the slot has the radio on & state is in service.
-                Log.d(this, "getFirstPhoneForEmergencyCall, radio on & in service, Phone Id:" + i);
+                Log.i(this, "getFirstPhoneForEmergencyCall, radio on & in service, Phone Id:" + i);
                 return phone;
             }
             // 3)
+            // Store the RAF Capabilities for sorting later only if there are capabilities to sort.
+            int radioAccessFamily = phone.getRadioAccessFamily();
+            if(RadioAccessFamily.getHighestRafCapability(radioAccessFamily) != 0) {
+                phoneNetworkType.add(new Pair<>(i, radioAccessFamily));
+                Log.i(this, "getFirstPhoneForEmergencyCall, RAF:" +
+                        Integer.toHexString(radioAccessFamily) + " saved for Phone Id:" + i);
+            }
+            // 4)
             if (firstPhoneWithSim == null && TelephonyManager.getDefault().hasIccCard(i)) {
                 // The slot has a SIM card inserted, but is not in service, so keep track of this
                 // Phone. Do not return because we want to make sure that none of the other Phones
                 // are in service (because that is always faster).
-                Log.d(this, "getFirstPhoneForEmergencyCall, SIM card inserted, Phone Id:" + i);
+                Log.i(this, "getFirstPhoneForEmergencyCall, SIM card inserted, Phone Id:" + i);
                 firstPhoneWithSim = phone;
             }
         }
-        // 4)
-        if (firstPhoneWithSim == null) {
+        // 5)
+        if (firstPhoneWithSim == null && phoneNetworkType.isEmpty()) {
             // No SIMs inserted, get the default.
-            Log.d(this, "getFirstPhoneForEmergencyCall, return default phone");
+            Log.i(this, "getFirstPhoneForEmergencyCall, return default phone");
             return PhoneFactory.getDefaultPhone();
         } else {
-            return firstPhoneWithSim;
+            // 3)
+            final Phone firstOccupiedSlot = firstPhoneWithSim;
+            if (!phoneNetworkType.isEmpty()) {
+                // Only sort if there are enough elements to do so.
+                if(phoneNetworkType.size() > 1) {
+                    Collections.sort(phoneNetworkType, (o1, o2) -> {
+                        // First start by sorting by number of RadioAccessFamily Capabilities.
+                        int compare = Integer.bitCount(o1.second) - Integer.bitCount(o2.second);
+                        if (compare == 0) {
+                            // Sort by highest RAF Capability if the number is the same.
+                            compare = RadioAccessFamily.getHighestRafCapability(o1.second) -
+                                    RadioAccessFamily.getHighestRafCapability(o2.second);
+                            if (compare == 0 && firstOccupiedSlot != null) {
+                                // If the RAF capability is the same, choose based on whether or not
+                                // any of the slots are occupied with a SIM card (if both are,
+                                // always choose the first).
+                                if (o1.first == firstOccupiedSlot.getPhoneId()) {
+                                    return 1;
+                                } else if (o2.first == firstOccupiedSlot.getPhoneId()) {
+                                    return -1;
+                                }
+                                // Compare is still 0, return equal.
+                            }
+                        }
+                        return compare;
+                    });
+                }
+                int mostCapablePhoneId = phoneNetworkType.get(phoneNetworkType.size()-1).first;
+                Log.i(this, "getFirstPhoneForEmergencyCall, Using Phone Id: " + mostCapablePhoneId +
+                        "with highest capability");
+                return PhoneFactory.getPhone(mostCapablePhoneId);
+            } else {
+                // 4)
+                return firstPhoneWithSim;
+            }
         }
     }
 
diff --git a/tests/src/com/android/phone/common/mail/store/imap/DigestMd5UtilsTest.java b/tests/src/com/android/phone/common/mail/store/imap/DigestMd5UtilsTest.java
index 5534632..81717a1 100644
--- a/tests/src/com/android/phone/common/mail/store/imap/DigestMd5UtilsTest.java
+++ b/tests/src/com/android/phone/common/mail/store/imap/DigestMd5UtilsTest.java
@@ -50,4 +50,24 @@
         assertEquals("ea40f60335c427b5527b84dbabcdfffd", response);
     }
 
+    public void testData_createResponse() {
+        DigestMd5Utils.Data data = new DigestMd5Utils.Data();
+        data.username = "chris";
+        data.password = "secret";
+        data.realm = "elwood.innosoft.com";
+        data.nonce = "OA6MG9tEQGm2hh";
+        data.cnonce = "OA6MHXh6VqTrRk";
+        data.nc = "00000001";
+        data.qop = "auth";
+        data.digestUri = "imap/elwood.innosoft.com";
+        assertEquals(data.createResponse(), "CHARSET=utf-8,"
+                + "username=\"chris\","
+                + "realm=\"elwood.innosoft.com\","
+                + "nonce=\"OA6MG9tEQGm2hh\","
+                + "nc=00000001,"
+                + "cnonce=\"OA6MHXh6VqTrRk\","
+                + "digest-uri=\"imap/elwood.innosoft.com\","
+                + "response=d388dad90d4bbd760a152321f2143af7,"
+                + "qop=auth");
+    }
 }