Merge "Fix ADD_VOICEMAIL intent." into mnc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 7ad2a4e..a0dd9c9 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -604,12 +604,6 @@
         <service android:name="HfaService" android:exported="false"/>
 
         <!-- Telecom integration -->
-        <service android:name="com.android.services.telephony.TelephonyCallServiceProvider"
-                android:singleUser="true">
-            <intent-filter>
-                <action android:name="android.telecom.CallServiceProvider" />
-            </intent-filter>
-        </service>
         <service
                 android:singleUser="true"
                 android:name="com.android.services.telephony.TelephonyConnectionService"
@@ -638,7 +632,7 @@
             </intent-filter>
         </receiver>
         <service
-            android:name="com.android.phone.vvm.omtp.OmtpVvmSyncService"
+            android:name="com.android.phone.vvm.omtp.sync.OmtpVvmSyncService"
             android:exported="true"
             android:process=":sync">
             <intent-filter>
@@ -664,7 +658,7 @@
             </intent-filter>
        </receiver>
        <receiver
-           android:name="com.android.phone.vvm.omtp.sync.FetchVoicemailReceiver"
+           android:name="com.android.phone.vvm.omtp.fetch.FetchVoicemailReceiver"
            android:exported="true">
            <intent-filter>
               <action android:name="android.intent.action.FETCH_VOICEMAIL" />
diff --git a/res/values-ur-rPK/strings.xml b/res/values-ur-rPK/strings.xml
index 3a0a1b2..cb46060 100644
--- a/res/values-ur-rPK/strings.xml
+++ b/res/values-ur-rPK/strings.xml
@@ -339,7 +339,7 @@
     <string name="fdn_list_with_label" msgid="7437232552210469217">"‏FDN فہرست (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
     <string name="fdn_activation" msgid="2156479741307463576">"‏FDN کو فعال کرنا"</string>
     <string name="fdn_enabled" msgid="5238109009915521240">"فکسڈ ڈائلنگ نمبرز فعال ہیں"</string>
-    <string name="fdn_disabled" msgid="4700049736675368279">"فکسڈ ڈائلنگ نمبرز غیر فعال ہوگئے ہیں"</string>
+    <string name="fdn_disabled" msgid="4700049736675368279">"فکسڈ ڈائلنگ نمبرز غیر فعال ہیں"</string>
     <string name="enable_fdn" msgid="3740191529180493851">"‏FDN فعال کریں"</string>
     <string name="disable_fdn" msgid="7944020890722540616">"‏FDN غیر فعال کریں"</string>
     <string name="change_pin2" msgid="2153563695382176676">"‏PIN2 تبدیل کریں"</string>
@@ -479,8 +479,8 @@
     <string name="hac_mode_title" msgid="8740268574688743289">"سماعتی آلات"</string>
     <string name="hac_mode_summary" msgid="6833851160514929341">"سماعتی آلہ کی ہم آہنگی آن کریں"</string>
   <string-array name="tty_mode_entries">
-    <item msgid="512950011423868021">"‏TTY آف ہے"</item>
-    <item msgid="3971695875449640648">"‏TTY پورا ہے"</item>
+    <item msgid="512950011423868021">"‏TTY آف"</item>
+    <item msgid="3971695875449640648">"‏TTY مکمل"</item>
     <item msgid="1937509904407445684">"TTY HCO"</item>
     <item msgid="5644925873488772224">"TTY VCO"</item>
   </string-array>
diff --git a/res/values-uz-rUZ/strings.xml b/res/values-uz-rUZ/strings.xml
index 024f4e4..2c46b98 100644
--- a/res/values-uz-rUZ/strings.xml
+++ b/res/values-uz-rUZ/strings.xml
@@ -42,8 +42,8 @@
     <string name="pause_prompt_yes" msgid="3564467212025151797">"Ha"</string>
     <string name="pause_prompt_no" msgid="6686238803236884877">"Yo‘q"</string>
     <string name="wild_prompt_str" msgid="5543521676355533577">"Belgilarni quyidagilar bilan almashtiring:"</string>
-    <string name="no_vm_number" msgid="4164780423805688336">"Javobsiz ovozli xabar raqami"</string>
-    <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM kartada birorta ham ovozli xabar saqlanmagan."</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"Ovozli pochta raqami ko‘rsatilmagan"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM kartada birorta ham ovozli pochta raqami yo‘q."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Raqam qo‘shish"</string>
     <string name="puk_unlocked" msgid="2284912838477558454">"To‘sib qo‘yilgan SIM kartangiz ochildi. Telefoningiz qulfdan chiqarilmoqda…"</string>
     <string name="label_ndp" msgid="780479633159517250">"SIM kartani tarmoqdagi qulfidan chiqarish PIN kodi"</string>
@@ -59,7 +59,7 @@
     <string name="labelCdmaMore_with_label" msgid="6333588719319970399">"CDMA qo‘ng‘iroq sozlamalari (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
     <string name="apn_settings" msgid="9043423184895642077">"Ulanish nuqtasi nomlari"</string>
     <string name="settings_label" msgid="3876743539816984008">"Tarmoq sozlamalari"</string>
-    <string name="phone_accounts" msgid="6376603393888116364">"Qo‘ng‘iroq uchun hisoblar"</string>
+    <string name="phone_accounts" msgid="6376603393888116364">"Qo‘ng‘iroq hisoblari"</string>
     <string name="phone_accounts_make_calls_with" msgid="1969188078933152231">"Qo‘ng‘iroqlar uchun hisob"</string>
     <string name="phone_accounts_make_sip_calls_with" msgid="4677789312053828493">"SIP qo‘ng‘iroqlari uchun hisob"</string>
     <string name="phone_accounts_ask_every_time" msgid="4346499067149985702">"Avval so‘ralsin"</string>
@@ -71,7 +71,7 @@
     <string name="wifi_calling" msgid="739018212480165598">"Wi-Fi qo‘ng‘iroq"</string>
     <string name="wifi_calling_do_not_use" msgid="7491443219113013323">"Wi-Fi qo‘ng‘iroqlardan foydalanilmasin"</string>
     <string name="wifi_calling_do_not_use_call_assistant" msgid="5420257095556091770">"Qo‘ng‘iroq yordamchisidan foydalanilmasin"</string>
-    <string name="wifi_calling_call_assistant_none" msgid="6283702349285593683">"Hech biri"</string>
+    <string name="wifi_calling_call_assistant_none" msgid="6283702349285593683">"Ishlatilmasin"</string>
     <string name="wifi_calling_call_assistant" msgid="229102032881680320">"Qo‘ng‘iroq yordamchisi"</string>
     <string name="wifi_calling_use_call_assistant" msgid="8460024827012666199">"Qo‘ng‘iroq yordamchisidan foydalanish"</string>
     <string name="wifi_calling_select_call_assistant" msgid="9296558058772293">"Qo‘ng‘iroq yordamchisini tanlang"</string>
@@ -143,8 +143,8 @@
     <item msgid="7876195870037833661">"Raqamni yashirish"</item>
     <item msgid="1108394741608734023">"Raqamni ko‘rsatish"</item>
   </string-array>
-    <string name="vm_changed" msgid="380744030726254139">"Ovozli xabar raqami o‘zgartirildi."</string>
-    <string name="vm_change_failed" msgid="3352934863246208918">"Ovozli xabar raqami o‘zgartirimaldi.\nUshbu muammoni hal qila olmasangiz, operatoringiz bilan bog‘laning."</string>
+    <string name="vm_changed" msgid="380744030726254139">"Ovozli pochta raqami o‘zgardi."</string>
+    <string name="vm_change_failed" msgid="3352934863246208918">"Ovozli pochta raqami o‘zgarmadi.\nUshbu muammoni hal qila olmasangiz, operatoringiz bilan bog‘laning."</string>
     <string name="fw_change_failed" msgid="5298103228470214665">"Yo‘naltirish raqamini o‘zgartirib bo‘lmadi.\nAgar ushbu muammoni hal qilib bo‘lmasa, operator bilan bog‘laning."</string>
     <string name="fw_get_in_vm_failed" msgid="8862896836093833973">"Joriy raqamlarni yo‘naltirish sozlamalarini olib va saqlab bo‘lmadi.\nYangi operatorga o‘tilaverilsinmi?"</string>
     <string name="no_change" msgid="3186040086622435212">"O‘zgarishlar qilinmadi."</string>
@@ -377,7 +377,7 @@
     <string name="fdn_failed" msgid="540018079008319747">"FDN jarayoni amalga oshmadi."</string>
     <string name="simContacts_emptyLoading" msgid="2203331234764498011">"SIM kartadan o‘qilmoqda…"</string>
     <string name="simContacts_empty" msgid="5270660846489561932">"SIM kartangizda kontaktlar yo‘q."</string>
-    <string name="simContacts_title" msgid="1861472842524839921">"Import qilish uchun kontaktlarni tanlang"</string>
+    <string name="simContacts_title" msgid="1861472842524839921">"Import u-n kontaktlarni tanlang"</string>
     <string name="simContacts_airplaneMode" msgid="5254946758982621072">"SIM kartadan kontaktlarni import qilish uchun parvoz rejimini o‘chiring"</string>
     <string name="enable_pin" msgid="5422767284133234860">"SIM karta PIN kodini yoqish/o‘chirish"</string>
     <string name="change_pin" msgid="9174186126330785343">"SIM karta PIN kodini o‘zgartirish"</string>
@@ -413,7 +413,7 @@
     <string name="pin2_attempts" msgid="720736232885011507">\n"Sizda <xliff:g id="NUMBER">%d</xliff:g> ta urinish qoldi."</string>
     <string name="pin2_unblocked" msgid="7791600368153469078">"PIN2 kodi blokdan chiqarildi"</string>
     <string name="doneButton" msgid="2859593360997984240">"Tayyor"</string>
-    <string name="voicemail_settings_number_label" msgid="8524164258691887790">"Ovozli xabar raqami"</string>
+    <string name="voicemail_settings_number_label" msgid="8524164258691887790">"Ovozli pochta raqami"</string>
     <string name="card_title_dialing" msgid="5769417478498348054">"Raqam terilmoqda"</string>
     <string name="card_title_redialing" msgid="8253487008234167266">"Qayta terilmoqda"</string>
     <string name="card_title_conf_call" msgid="1162980346189744501">"Konferensiya qo‘ng‘irog‘i"</string>
@@ -423,22 +423,22 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Go‘shak qo‘yilmoqda"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Qo‘ng‘iroqda"</string>
     <string name="notification_dialing" msgid="2107666444937350731">"Terilmoqda"</string>
-    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Javob berilmagan qo‘ng‘iroq"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Javobsiz qo‘ng‘iroq"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Javobsiz qo‘ng‘iroqlar"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> ta javobsiz qo‘ng‘iroq"</string>
-    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g>dan javobsiz qo‘ng‘iroq"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> qo‘ng‘irog‘i javobsiz qoldirildi"</string>
     <string name="notification_ongoing_call" msgid="7068688957273482989">"Joriy qo‘ng‘iroq"</string>
     <string name="notification_on_hold" msgid="3480694969511790465">"Kutmoqda"</string>
     <string name="notification_incoming_call" msgid="2820429205043529642">"Kiruvchi qo‘ng‘iroq"</string>
     <string name="notification_voicemail_title" msgid="8933468752045550523">"Yangi ovozli xabar"</string>
     <string name="notification_voicemail_title_count" msgid="4366360747660929916">"Yangi ovozli xabar (<xliff:g id="COUNT">%d</xliff:g>)"</string>
     <string name="notification_voicemail_text_format" msgid="4447323569453981685">"<xliff:g id="VOICEMAIL_NUMBER">%s</xliff:g>ni terish"</string>
-    <string name="notification_voicemail_no_vm_number" msgid="760963466895609716">"Ovozli qo‘ng‘iroq raqami noma’lum"</string>
+    <string name="notification_voicemail_no_vm_number" msgid="760963466895609716">"Ovozli pochta raqami noma’lum"</string>
     <string name="notification_network_selection_title" msgid="4224455487793492772">"Xizmat mavjud emas"</string>
     <string name="notification_network_selection_text" msgid="2607085729661923269">"Tanlangan tarmoq (<xliff:g id="OPERATOR_NAME">%s</xliff:g>) mavjud emas"</string>
     <string name="notification_action_end_call" msgid="6069460915123531620">"Go‘shakni qo‘yish"</string>
-    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Teskari qo‘ng‘iroq"</string>
-    <string name="notification_missedCall_message" msgid="3049928912736917988">"Xabar"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Qo‘ng‘iroq"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"SMS"</string>
     <string name="incall_error_power_off" msgid="2947938060513306698">"Qo‘ng‘iroq qilish uchun parvoz rejimini o‘chiring"</string>
     <string name="incall_error_power_off_wfc" msgid="8711428920632416575">"Qo‘ng‘iroq qilish uchun parvoz rejimini o‘chiring yoki simsiz tarmoqqa ulaning."</string>
     <string name="incall_error_emergency_only" msgid="4678640422710818317">"Tarmoqda ro‘yxatdan o‘tmagan."</string>
@@ -535,7 +535,7 @@
     <string name="alert_dialog_dismiss" msgid="2491494287075907171">"Rad qilish"</string>
     <string name="voicemail_provider" msgid="5135942703327136909">"Xizmat"</string>
     <string name="voicemail_settings" msgid="72448049107749316">"Moslash"</string>
-    <string name="voicemail_number_not_set" msgid="6724904736891087856">"&lt;O‘rnatilmagan&gt;"</string>
+    <string name="voicemail_number_not_set" msgid="6724904736891087856">"&lt;Ko‘rsatilmagan&gt;"</string>
     <string name="other_settings" msgid="3672912580359716394">"Boshqa qo‘ng‘iroq sozlamalari"</string>
     <string name="calling_via_template" msgid="4839419581866928142">"<xliff:g id="PROVIDER_NAME">%s</xliff:g> orqali qo‘ng‘rioq qilinmoqda"</string>
     <string name="contactPhoto" msgid="4713193418046639466">"kontakt surati"</string>
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index 82b6e00..a75bd3a 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -35,6 +35,7 @@
 import android.provider.Settings;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.telephony.CarrierConfigManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
@@ -210,7 +211,9 @@
 
         mEnableVideoCalling = (CheckBoxPreference) findPreference(ENABLE_VIDEO_CALLING_KEY);
 
-        if (getResources().getBoolean(R.bool.auto_retry_enabled)) {
+        Bundle carrierConfig = PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
+
+        if (carrierConfig.getBoolean(CarrierConfigManager.BOOL_AUTO_RETRY_ENABLED)) {
             mButtonAutoRetry.setOnPreferenceChangeListener(this);
             int autoretry = Settings.Global.getInt(
                     getContentResolver(), Settings.Global.CALL_AUTO_RETRY, 0);
@@ -222,7 +225,7 @@
 
         Preference cdmaOptions = prefSet.findPreference(BUTTON_CDMA_OPTIONS);
         Preference gsmOptions = prefSet.findPreference(BUTTON_GSM_UMTS_OPTIONS);
-        if (getResources().getBoolean(R.bool.world_phone)) {
+        if (carrierConfig.getBoolean(CarrierConfigManager.BOOL_WORLD_PHONE)) {
             cdmaOptions.setIntent(mSubscriptionInfoHelper.getIntent(CdmaCallOptions.class));
             gsmOptions.setIntent(mSubscriptionInfoHelper.getIntent(GsmUmtsCallOptions.class));
         } else {
@@ -239,13 +242,13 @@
                 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
                     prefSet.removePreference(fdnButton);
 
-                    if (!getResources().getBoolean(R.bool.config_voice_privacy_disable)) {
+                    if (!carrierConfig.getBoolean(CarrierConfigManager.BOOL_VOICE_PRIVACY_DISABLE)) {
                         addPreferencesFromResource(R.xml.cdma_call_privacy);
                     }
                 } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
                     fdnButton.setIntent(mSubscriptionInfoHelper.getIntent(FdnSetting.class));
 
-                    if (getResources().getBoolean(R.bool.config_additional_call_setting)) {
+                    if (carrierConfig.getBoolean(CarrierConfigManager.BOOL_ADDITIONAL_CALL_SETTING)) {
                         addPreferencesFromResource(R.xml.gsm_umts_call_options);
                         GsmUmtsCallOptions.init(prefSet, mSubscriptionInfoHelper);
                     }
diff --git a/src/com/android/phone/CdmaCallOptions.java b/src/com/android/phone/CdmaCallOptions.java
index 8f7b1b1..9247173 100644
--- a/src/com/android/phone/CdmaCallOptions.java
+++ b/src/com/android/phone/CdmaCallOptions.java
@@ -28,6 +28,7 @@
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceScreen;
+import android.telephony.CarrierConfigManager;
 import android.util.Log;
 import android.view.MenuItem;
 
@@ -49,9 +50,16 @@
                 getActionBar(), getResources(), R.string.labelCdmaMore_with_label);
 
         mButtonVoicePrivacy = (CheckBoxPreference) findPreference(BUTTON_VP_KEY);
+        Bundle carrierConfig;
+        if (subInfoHelper.hasSubId()) {
+            carrierConfig = PhoneGlobals.getInstance().getCarrierConfigForSubId(
+                    subInfoHelper.getSubId());
+        } else {
+            carrierConfig = PhoneGlobals.getInstance().getCarrierConfig();
+        }
         if (subInfoHelper.getPhone().getPhoneType() != PhoneConstants.PHONE_TYPE_CDMA
-                || getResources().getBoolean(R.bool.config_voice_privacy_disable)) {
-            //disable the entire screen
+                || carrierConfig.getBoolean(CarrierConfigManager.BOOL_VOICE_PRIVACY_DISABLE)) {
+            // disable the entire screen
             getPreferenceScreen().setEnabled(false);
         }
     }
diff --git a/src/com/android/phone/CdmaOptions.java b/src/com/android/phone/CdmaOptions.java
index a04427e..fa3db13 100644
--- a/src/com/android/phone/CdmaOptions.java
+++ b/src/com/android/phone/CdmaOptions.java
@@ -20,11 +20,13 @@
 import android.content.Intent;
 import android.content.res.Resources;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.SystemProperties;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceScreen;
 import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 
@@ -64,9 +66,9 @@
 
         mButtonAPNExpand = (PreferenceScreen) mPrefScreen.findPreference(BUTTON_APN_EXPAND_KEY);
         boolean removedAPNExpand = false;
-        Resources res = mPrefActivity.getResources();
-        // Some CDMA carriers want the APN settings
-        if (!res.getBoolean(R.bool.config_show_apn_setting_cdma) && mButtonAPNExpand != null) {
+        Bundle carrierConfig = PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
+        // Some CDMA carriers want the APN settings.
+        if (!carrierConfig.getBoolean(CarrierConfigManager.BOOL_SHOW_APN_SETTING_CDMA) && mButtonAPNExpand != null) {
             mPrefScreen.removePreference(mButtonAPNExpand);
             removedAPNExpand = true;
         }
@@ -115,8 +117,8 @@
         }
 
         // Read platform settings for carrier settings
-        final boolean isCarrierSettingsEnabled = mPrefActivity.getResources().getBoolean(
-                R.bool.config_carrier_settings_enable);
+        final boolean isCarrierSettingsEnabled = carrierConfig.getBoolean(
+                CarrierConfigManager.BOOL_CARRIER_SETTINGS_ENABLE);
         if (!isCarrierSettingsEnabled) {
             Preference pref = mPrefScreen.findPreference(BUTTON_CARRIER_SETTINGS_KEY);
             if (pref != null) {
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index c7dd1e9..e25d91f 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -31,6 +31,7 @@
 import android.os.Bundle;
 import android.provider.Settings;
 import android.telecom.PhoneAccount;
+import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
 import android.text.Editable;
 import android.text.TextUtils;
@@ -198,8 +199,8 @@
         mDialButton = findViewById(R.id.floating_action_button);
 
         // Check whether we should show the onscreen "Dial" button and co.
-        Resources res = getResources();
-        if (res.getBoolean(R.bool.config_show_onscreen_dial_button)) {
+        Bundle carrierConfig = PhoneGlobals.getInstance().getCarrierConfig();
+        if (carrierConfig.getBoolean(CarrierConfigManager.BOOL_SHOW_ONSCREEN_DIAL_BUTTON)) {
             mDialButton.setOnClickListener(this);
         } else {
             mDialButton.setVisibility(View.GONE);
@@ -238,7 +239,7 @@
         registerReceiver(mBroadcastReceiver, intentFilter);
 
         try {
-            mHaptic.init(this, res.getBoolean(R.bool.config_enable_dialer_key_vibration));
+            mHaptic.init(this, carrierConfig.getBoolean(CarrierConfigManager.BOOL_ENABLE_DIALER_KEY_VIBRATION));
         } catch (Resources.NotFoundException nfe) {
              Log.e(LOG_TAG, "Vibrate control bool missing.", nfe);
         }
diff --git a/src/com/android/phone/GsmUmtsOptions.java b/src/com/android/phone/GsmUmtsOptions.java
index ee6a738..b8597f7 100644
--- a/src/com/android/phone/GsmUmtsOptions.java
+++ b/src/com/android/phone/GsmUmtsOptions.java
@@ -16,13 +16,16 @@
 
 package com.android.phone;
 
+import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
+import android.os.Bundle;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceScreen;
-import android.content.res.Resources;
-
 import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
+
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneFactory;
 
@@ -63,16 +66,18 @@
         } else {
             log("Not a CDMA phone");
             Resources res = mPrefActivity.getResources();
+            Bundle carrierConfig = PhoneGlobals.getInstance().getCarrierConfigForSubId(mSubId);
 
-            // Determine which options to display, for GSM these are defaulted
-            // are defaulted to true in Phone/res/values/config.xml. But for
-            // some operators like verizon they maybe overriden in operator
-            // specific resources or device specific overlays.
-            if (!res.getBoolean(R.bool.config_apn_expand) && mButtonAPNExpand != null) {
+            // Determine which options to display. For GSM these are defaulted to true in
+            // CarrierConfigManager, but they maybe overriden by DefaultCarrierConfigService or a
+            // carrier app.
+            // Note: these settings used to be controlled with overlays in
+            // Telephony/res/values/config.xml
+            if (!carrierConfig.getBoolean(CarrierConfigManager.BOOL_APN_EXPAND) && mButtonAPNExpand != null) {
                 mPrefScreen.removePreference(mButtonAPNExpand);
                 removedAPNExpand = true;
             }
-            if (!res.getBoolean(R.bool.config_operator_selection_expand)) {
+            if (!carrierConfig.getBoolean(CarrierConfigManager.BOOL_OPERATOR_SELECTION_EXPAND)) {
                 mPrefScreen.removePreference(mPrefScreen
                         .findPreference(BUTTON_OPERATOR_SELECTION_EXPAND_KEY));
             }
@@ -89,8 +94,8 @@
             }
 
             // Read platform settings for carrier settings
-            final boolean isCarrierSettingsEnabled = mPrefActivity.getResources().getBoolean(
-                    R.bool.config_carrier_settings_enable);
+            final boolean isCarrierSettingsEnabled = carrierConfig.getBoolean(
+                CarrierConfigManager.BOOL_CARRIER_SETTINGS_ENABLE);
             if (!isCarrierSettingsEnabled) {
                 Preference pref = mPrefScreen.findPreference(BUTTON_CARRIER_SETTINGS_KEY);
                 if (pref != null) {
diff --git a/src/com/android/phone/IccNetworkDepersonalizationPanel.java b/src/com/android/phone/IccNetworkDepersonalizationPanel.java
index aa582a1..5f448a3 100644
--- a/src/com/android/phone/IccNetworkDepersonalizationPanel.java
+++ b/src/com/android/phone/IccNetworkDepersonalizationPanel.java
@@ -21,6 +21,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.telephony.CarrierConfigManager;
 import android.text.Editable;
 import android.text.Spannable;
 import android.text.TextUtils;
@@ -135,7 +136,8 @@
         // The "Dismiss" button is present in some (but not all) products,
         // based on the "sim_network_unlock_allow_dismiss" resource.
         mDismissButton = (Button) findViewById(R.id.ndp_dismiss);
-        if (getContext().getResources().getBoolean(R.bool.sim_network_unlock_allow_dismiss)) {
+        Bundle carrierConfig = PhoneGlobals.getInstance().getCarrierConfig();
+        if (carrierConfig.getBoolean(CarrierConfigManager.BOOL_SIM_NETWORK_UNLOCK_ALLOW_DISMISS)) {
             if (DBG) log("Enabling 'Dismiss' button...");
             mDismissButton.setVisibility(View.VISIBLE);
             mDismissButton.setOnClickListener(mDismissListener);
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index 571f32f..8d45002 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -48,6 +48,7 @@
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceScreen;
 import android.preference.SwitchPreference;
+import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneStateListener;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -535,15 +536,17 @@
                 android.provider.Settings.Global.PREFERRED_NETWORK_MODE + phoneSubId,
                 preferredNetworkMode);
 
-        mIsGlobalCdma = isLteOnCdma && getResources().getBoolean(R.bool.config_show_cdma);
+        Bundle carrierConfig = PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
+        mIsGlobalCdma = isLteOnCdma
+                && carrierConfig.getBoolean(CarrierConfigManager.BOOL_SHOW_CDMA);
         int shouldHideCarrierSettings = android.provider.Settings.Global.getInt(
                 mPhone.getContext().getContentResolver(),
                 android.provider.Settings.Global.HIDE_CARRIER_NETWORK_SETTINGS, 0);
-        if (shouldHideCarrierSettings == 1 ) {
+        if (shouldHideCarrierSettings == 1) {
             prefSet.removePreference(mButtonPreferredNetworkMode);
             prefSet.removePreference(mButtonEnabledNetworks);
             prefSet.removePreference(mLteDataServicePref);
-        } else if (getResources().getBoolean(R.bool.world_phone) == true) {
+        } else if (carrierConfig.getBoolean(CarrierConfigManager.BOOL_WORLD_PHONE) == true) {
             prefSet.removePreference(mButtonEnabledNetworks);
             // set the listener for the mButtonPreferredNetworkMode list preference so we can issue
             // change Preferred Network Mode.
@@ -601,16 +604,16 @@
                     mGsmUmtsOptions = null;
                 }
             } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
-                if (!getResources().getBoolean(R.bool.config_prefer_2g)
+                if (!carrierConfig.getBoolean(CarrierConfigManager.BOOL_PREFER_2G)
                         && !getResources().getBoolean(R.bool.config_enabled_lte)) {
                     mButtonEnabledNetworks.setEntries(
                             R.array.enabled_networks_except_gsm_lte_choices);
                     mButtonEnabledNetworks.setEntryValues(
                             R.array.enabled_networks_except_gsm_lte_values);
-                } else if (!getResources().getBoolean(R.bool.config_prefer_2g)) {
+                } else if (!carrierConfig.getBoolean(CarrierConfigManager.BOOL_PREFER_2G)) {
                     int select = (mShow4GForLTE == true) ?
-                        R.array.enabled_networks_except_gsm_4g_choices
-                        : R.array.enabled_networks_except_gsm_choices;
+                            R.array.enabled_networks_except_gsm_4g_choices
+                            : R.array.enabled_networks_except_gsm_choices;
                     mButtonEnabledNetworks.setEntries(select);
                     mButtonEnabledNetworks.setEntryValues(
                             R.array.enabled_networks_except_gsm_values);
@@ -626,7 +629,7 @@
                             R.array.enabled_networks_cdma_values);
                 } else {
                     int select = (mShow4GForLTE == true) ? R.array.enabled_networks_4g_choices
-                        : R.array.enabled_networks_choices;
+                            : R.array.enabled_networks_choices;
                     mButtonEnabledNetworks.setEntries(select);
                     mButtonEnabledNetworks.setEntryValues(
                             R.array.enabled_networks_values);
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index 1460d63..a6ccca9 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -27,6 +27,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -36,6 +37,7 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
@@ -372,7 +374,7 @@
                 }
                 intent = new Intent(
                         Intent.ACTION_CALL, Uri.fromParts(PhoneAccount.SCHEME_VOICEMAIL, "",
-                        null));
+                                null));
                 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
             }
 
@@ -385,6 +387,8 @@
             }
 
             Resources res = mContext.getResources();
+            Bundle carrierConfig = PhoneGlobals.getInstance().getCarrierConfigForSubId(
+                    mPhone.getSubId());
             Notification.Builder builder = new Notification.Builder(mContext);
             builder.setSmallIcon(resId)
                     .setWhen(System.currentTimeMillis())
@@ -394,7 +398,8 @@
                     .setContentIntent(pendingIntent)
                     .setSound(ringtoneUri)
                     .setColor(res.getColor(R.color.dialer_theme_color))
-                    .setOngoing(res.getBoolean(R.bool.voicemail_notification_persistent));
+                    .setOngoing(carrierConfig.getBoolean(
+                            CarrierConfigManager.BOOL_VOICEMAIL_NOTIFICATION_PERSISTENT));
 
             if (VoicemailNotificationSettingsUtil.isVibrationEnabled(phone)) {
                 builder.setDefaults(Notification.DEFAULT_VIBRATE);
@@ -407,7 +412,7 @@
                 final UserHandle userHandle = user.getUserHandle();
                 if (!mUserManager.hasUserRestriction(
                         UserManager.DISALLOW_OUTGOING_CALLS, userHandle)
-                            && !user.isManagedProfile()) {
+                        && !user.isManagedProfile()) {
                     mNotificationManager.notifyAsUser(
                             Integer.toString(subId) /* tag */,
                             VOICEMAIL_NOTIFICATION,
diff --git a/src/com/android/phone/vvm/omtp/OmtpVvmSyncService.java b/src/com/android/phone/vvm/omtp/OmtpVvmSyncService.java
deleted file mode 100644
index fc444ba..0000000
--- a/src/com/android/phone/vvm/omtp/OmtpVvmSyncService.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2015 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
- */
-
-/**
- * A {@link Service} which runs the internal implementation of {@link AbstractThreadedSyncAdapter},
- * syncing voicemails to and from a visual voicemail server.
- */
-
-package com.android.phone.vvm.omtp;
-
-import android.accounts.Account;
-import android.app.Service;
-import android.content.AbstractThreadedSyncAdapter;
-import android.content.ContentProviderClient;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SyncResult;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.provider.VoicemailContract;
-import android.provider.VoicemailContract.Voicemails;
-import android.telecom.Voicemail;
-
-import com.android.phone.vvm.omtp.imap.ImapHelper;
-import com.android.phone.vvm.omtp.sync.DirtyVoicemailQuery;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A service to run the VvmSyncAdapter.
- */
-public class OmtpVvmSyncService extends Service {
-    // Storage for an instance of the sync adapter
-    private static OmtpVvmSyncAdapter sSyncAdapter = null;
-    // Object to use as a thread-safe lock
-    private static final Object sSyncAdapterLock = new Object();
-
-    @Override
-    public void onCreate() {
-        synchronized (sSyncAdapterLock) {
-            if (sSyncAdapter == null) {
-                sSyncAdapter = new OmtpVvmSyncAdapter(getApplicationContext(), true);
-            }
-        }
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return sSyncAdapter.getSyncAdapterBinder();
-    }
-
-    public class OmtpVvmSyncAdapter extends AbstractThreadedSyncAdapter {
-        /**
-         * Sync triggers should pass this extra to clear the database and freshly populate from the
-         * server.
-         */
-        public static final String SYNC_EXTRAS_CLEAR_AND_RELOAD = "extra_clear_and_reload";
-
-        private Context mContext;
-        private ContentResolver mContentResolver;
-
-        public OmtpVvmSyncAdapter(Context context, boolean autoInitialize) {
-            super(context, autoInitialize);
-            mContext = context;
-            mContentResolver = context.getContentResolver();
-        }
-
-        @Override
-        public void onPerformSync(Account account, Bundle extras, String authority,
-                ContentProviderClient provider, SyncResult syncResult) {
-            ImapHelper imapHelper = new ImapHelper(mContext, account);
-
-            if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false)) {
-                List<Voicemail> readVoicemails = new ArrayList<Voicemail>();
-                List<Voicemail> deletedVoicemails = new ArrayList<Voicemail>();
-
-                Cursor cursor = DirtyVoicemailQuery.getDirtyVoicemails(mContext);
-                if (cursor == null) {
-                    return;
-                }
-                try {
-                    while (cursor.moveToNext()) {
-                        final long id = cursor.getLong(DirtyVoicemailQuery._ID);
-                        final String sourceData = cursor.getString(DirtyVoicemailQuery.SOURCE_DATA);
-                        final boolean isRead = cursor.getInt(DirtyVoicemailQuery.IS_READ) == 1;
-                        final boolean deleted = cursor.getInt(DirtyVoicemailQuery.DELETED) == 1;
-                        Voicemail voicemail = Voicemail.createForUpdate(id, sourceData).build();
-                        if (deleted) {
-                            // Check deleted first because if the voicemail is deleted, there's no
-                            // need to mark as read.
-                            deletedVoicemails.add(voicemail);
-                        } else if (isRead) {
-                            readVoicemails.add(voicemail);
-                        }
-                    }
-                } finally {
-                    cursor.close();
-                }
-                if (imapHelper.markMessagesAsDeleted(deletedVoicemails)) {
-                    // We want to delete selectively instead of all the voicemails for this provider
-                    // in case the state changed since the IMAP query was completed.
-                    deleteFromDatabase(deletedVoicemails);
-                }
-
-                if (imapHelper.markMessagesAsRead(readVoicemails)) {
-                    markReadInDatabase(readVoicemails);
-                }
-            }
-
-            if (extras.getBoolean(SYNC_EXTRAS_CLEAR_AND_RELOAD, false)) {
-                // Fetch voicemails first before deleting local copy, the fetching may take awhile.
-                List<Voicemail> voicemails = imapHelper.fetchAllVoicemails();
-
-                // Deleting current local messages ensure that we start with a fresh copy
-                // and also don't need to deal with comparing between local and server.
-                VoicemailContract.Voicemails.deleteAll(mContext);
-
-                if (voicemails != null) {
-                    VoicemailContract.Voicemails.insert(mContext, voicemails);
-                }
-            }
-        }
-
-        /**
-         * Deletes a list of voicemails from the voicemail content provider.
-         *
-         * @param voicemails The list of voicemails to delete
-         * @return The number of voicemails deleted
-         */
-        public int deleteFromDatabase(List<Voicemail> voicemails) {
-            int count = voicemails.size();
-            for (int i = 0; i < count; i++) {
-                mContentResolver.delete(Voicemails.CONTENT_URI, Voicemails._ID + "=?",
-                        new String[] { Long.toString(voicemails.get(i).getId()) });
-            }
-            return count;
-        }
-
-        /**
-         * Sends an update command to the voicemail content provider for a list of voicemails.
-         * From the view of the provider, since the updater is the owner of the entry, a blank
-         * "update" means that the voicemail source is indicating that the server has up-to-date
-         * information on the voicemail. This flips the "dirty" bit to "0".
-         *
-         * @param voicemails The list of voicemails to update
-         * @return The number of voicemails updated
-         */
-        public int markReadInDatabase(List<Voicemail> voicemails) {
-            int count = voicemails.size();
-            for (int i = 0; i < count; i++) {
-                Uri uri = ContentUris.withAppendedId(
-                        VoicemailContract.Voicemails.buildSourceUri(mContext.getPackageName()),
-                        voicemails.get(i).getId());
-                mContentResolver.update(uri, new ContentValues(), null, null);
-            }
-            return count;
-        }
-    }
-}
diff --git a/src/com/android/phone/vvm/omtp/SimChangeReceiver.java b/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
index ec8e45e..df30ff0 100644
--- a/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
+++ b/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
@@ -29,6 +29,7 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.phone.vvm.omtp.sms.OmtpMessageSender;
+import com.android.phone.vvm.omtp.sync.OmtpVvmSyncAccountManager;
 
 /**
  * This class listens to the {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} and
diff --git a/src/com/android/phone/vvm/omtp/sync/FetchVoicemailReceiver.java b/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
similarity index 97%
rename from src/com/android/phone/vvm/omtp/sync/FetchVoicemailReceiver.java
rename to src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
index 88d6983..ae32c27 100644
--- a/src/com/android/phone/vvm/omtp/sync/FetchVoicemailReceiver.java
+++ b/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License
  */
-package com.android.phone.vvm.omtp.sync;
+package com.android.phone.vvm.omtp.fetch;
 
 import android.accounts.Account;
 import android.content.BroadcastReceiver;
@@ -28,8 +28,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import com.android.phone.vvm.omtp.OmtpVvmSyncAccountManager;
 import com.android.phone.vvm.omtp.imap.ImapHelper;
+import com.android.phone.vvm.omtp.sync.OmtpVvmSyncAccountManager;
 
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
diff --git a/src/com/android/phone/vvm/omtp/sync/VoicemailFetchedCallback.java b/src/com/android/phone/vvm/omtp/fetch/VoicemailFetchedCallback.java
similarity index 98%
rename from src/com/android/phone/vvm/omtp/sync/VoicemailFetchedCallback.java
rename to src/com/android/phone/vvm/omtp/fetch/VoicemailFetchedCallback.java
index 006e83f..bf5befd 100644
--- a/src/com/android/phone/vvm/omtp/sync/VoicemailFetchedCallback.java
+++ b/src/com/android/phone/vvm/omtp/fetch/VoicemailFetchedCallback.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License
  */
-package com.android.phone.vvm.omtp.sync;
+package com.android.phone.vvm.omtp.fetch;
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
diff --git a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
index eae6cac..1d6c559 100644
--- a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
+++ b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
@@ -37,7 +37,7 @@
 import com.android.phone.common.mail.store.imap.ImapConstants;
 import com.android.phone.common.mail.utils.LogUtils;
 import com.android.phone.vvm.omtp.OmtpConstants;
-import com.android.phone.vvm.omtp.sync.VoicemailFetchedCallback;
+import com.android.phone.vvm.omtp.fetch.VoicemailFetchedCallback;
 
 import libcore.io.IoUtils;
 
diff --git a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
index 57979ff..7e6d645 100644
--- a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
+++ b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
@@ -31,10 +31,8 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.phone.PhoneUtils;
 import com.android.phone.vvm.omtp.OmtpConstants;
-import com.android.phone.vvm.omtp.OmtpVvmSyncAccountManager;
-import com.android.phone.vvm.omtp.OmtpVvmSyncService.OmtpVvmSyncAdapter;
-
-import java.io.UnsupportedEncodingException;
+import com.android.phone.vvm.omtp.sync.OmtpVvmSyncAccountManager;
+import com.android.phone.vvm.omtp.sync.OmtpVvmSyncService.OmtpVvmSyncAdapter;
 
 /**
  * Receive SMS messages and send for processing by the OMTP visual voicemail source.
@@ -55,7 +53,9 @@
         StringBuilder messageBody = new StringBuilder();
 
         for (int i = 0; i < messages.length; i++) {
-            messageBody.append(messages[i].getMessageBody());
+            if (messages[i].mWrappedSmsMessage != null) {
+                messageBody.append(messages[i].getMessageBody());
+            }
         }
 
         WrappedMessageData messageData = OmtpSmsParser.parse(messageBody.toString());
@@ -96,7 +96,7 @@
             case OmtpConstants.MAILBOX_UPDATE:
                 // Needs a total resync
                 Bundle bundle = new Bundle();
-                bundle.putBoolean(OmtpVvmSyncAdapter.SYNC_EXTRAS_CLEAR_AND_RELOAD, true);
+                bundle.putBoolean(OmtpVvmSyncAdapter.SYNC_EXTRAS_DOWNLOAD, true);
                 ContentResolver.requestSync(
                         new Account(mPhoneAccount.getId(), OmtpVvmSyncAccountManager.ACCOUNT_TYPE),
                         VoicemailContract.AUTHORITY, bundle);
@@ -105,7 +105,7 @@
                 // Not implemented in V1
                 break;
            default:
-               Log.e(TAG, "Unrecognized sync trigger event: "+message.getSyncTriggerEvent());
+               Log.e(TAG, "Unrecognized sync trigger event: " + message.getSyncTriggerEvent());
                break;
         }
     }
@@ -126,7 +126,7 @@
                     VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_OK);
 
             Bundle bundle = new Bundle();
-            bundle.putBoolean(OmtpVvmSyncAdapter.SYNC_EXTRAS_CLEAR_AND_RELOAD, true);
+            bundle.putBoolean(OmtpVvmSyncAdapter.SYNC_EXTRAS_DOWNLOAD, true);
             bundle.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
             ContentResolver.requestSync(account, VoicemailContract.AUTHORITY, bundle);
         }
diff --git a/src/com/android/phone/vvm/omtp/sms/WrappedMessageData.java b/src/com/android/phone/vvm/omtp/sms/WrappedMessageData.java
index 109dfb2..b4c86d4 100644
--- a/src/com/android/phone/vvm/omtp/sms/WrappedMessageData.java
+++ b/src/com/android/phone/vvm/omtp/sms/WrappedMessageData.java
@@ -66,6 +66,10 @@
      */
     String extractString(final String field) {
         String value = mFields.get(field);
+        if (value == null) {
+            return null;
+        }
+
         String[] possibleValues = OmtpConstants.possibleValuesMap.get(field);
         if (possibleValues == null) {
             return value;
diff --git a/src/com/android/phone/vvm/omtp/sync/DirtyVoicemailQuery.java b/src/com/android/phone/vvm/omtp/sync/DirtyVoicemailQuery.java
deleted file mode 100644
index 8c70372..0000000
--- a/src/com/android/phone/vvm/omtp/sync/DirtyVoicemailQuery.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp.sync;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.VoicemailContract;
-import android.provider.VoicemailContract.Voicemails;
-
-/**
- * Construct a query to get dirty voicemails.
- */
-public class DirtyVoicemailQuery {
-    final static String[] PROJECTION = new String[] {
-            Voicemails._ID,              // 0
-            Voicemails.SOURCE_DATA,      // 1
-            Voicemails.IS_READ,          // 2
-            Voicemails.DELETED,          // 3
-    };
-
-    public static final int _ID = 0;
-    public static final int SOURCE_DATA = 1;
-    public static final int IS_READ = 2;
-    public static final int DELETED = 3;
-
-    final static String SELECTION = Voicemails.DIRTY + "=1";
-
-    /**
-     * Get all the locally modified voicemails that have not been synced to the server.
-     *
-     * @param context The context from the package calling the method. This will be the source.
-     * @return A list of all locally modified voicemails.
-     */
-    public static Cursor getDirtyVoicemails(Context context) {
-        ContentResolver contentResolver = context.getContentResolver();
-        Uri sourceUri = VoicemailContract.Voicemails.buildSourceUri(context.getPackageName());
-        return contentResolver.query(sourceUri, PROJECTION, SELECTION, null, null);
-    }
-}
diff --git a/src/com/android/phone/vvm/omtp/OmtpVvmSyncAccountManager.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncAccountManager.java
similarity index 98%
rename from src/com/android/phone/vvm/omtp/OmtpVvmSyncAccountManager.java
rename to src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncAccountManager.java
index b891c70..4ac21b4 100644
--- a/src/com/android/phone/vvm/omtp/OmtpVvmSyncAccountManager.java
+++ b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncAccountManager.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License
  */
-package com.android.phone.vvm.omtp;
+package com.android.phone.vvm.omtp.sync;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
@@ -25,6 +25,7 @@
 import android.util.Log;
 
 import com.android.phone.PhoneUtils;
+import com.android.phone.vvm.omtp.OmtpConstants;
 import com.android.phone.vvm.omtp.sms.StatusMessage;
 
 /**
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
new file mode 100644
index 0000000..2fbeaab
--- /dev/null
+++ b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2015 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
+ */
+
+/**
+ * A {@link Service} which runs the internal implementation of {@link AbstractThreadedSyncAdapter},
+ * syncing voicemails to and from a visual voicemail server.
+ */
+
+package com.android.phone.vvm.omtp.sync;
+
+import android.accounts.Account;
+import android.app.Service;
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SyncResult;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.provider.VoicemailContract;
+import android.telecom.Voicemail;
+
+import com.android.phone.vvm.omtp.imap.ImapHelper;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A service to run the VvmSyncAdapter.
+ */
+public class OmtpVvmSyncService extends Service {
+    // Storage for an instance of the sync adapter
+    private static OmtpVvmSyncAdapter sSyncAdapter = null;
+    // Object to use as a thread-safe lock
+    private static final Object sSyncAdapterLock = new Object();
+
+    @Override
+    public void onCreate() {
+        synchronized (sSyncAdapterLock) {
+            if (sSyncAdapter == null) {
+                sSyncAdapter = new OmtpVvmSyncAdapter(getApplicationContext(), true);
+            }
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return sSyncAdapter.getSyncAdapterBinder();
+    }
+
+    public class OmtpVvmSyncAdapter extends AbstractThreadedSyncAdapter {
+        /**
+         * Sync triggers should pass this extra to clear the database and freshly populate from the
+         * server.
+         */
+        public static final String SYNC_EXTRAS_DOWNLOAD = "extra_download";
+
+        private Context mContext;
+
+        public OmtpVvmSyncAdapter(Context context, boolean autoInitialize) {
+            super(context, autoInitialize);
+            mContext = context;
+        }
+
+        @Override
+        public void onPerformSync(Account account, Bundle extras, String authority,
+                ContentProviderClient provider, SyncResult syncResult) {
+            ImapHelper imapHelper = new ImapHelper(mContext, account);
+            VoicemailsQueryHelper queryHelper = new VoicemailsQueryHelper(mContext);
+
+            if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false)) {
+                List<Voicemail> readVoicemails = queryHelper.getReadVoicemails();
+                List<Voicemail> deletedVoicemails = queryHelper.getDeletedVoicemails();
+
+                if (deletedVoicemails != null &&
+                        imapHelper.markMessagesAsDeleted(deletedVoicemails)) {
+                    // We want to delete selectively instead of all the voicemails for this provider
+                    // in case the state changed since the IMAP query was completed.
+                    queryHelper.deleteFromDatabase(deletedVoicemails);
+                }
+
+                if (readVoicemails != null && imapHelper.markMessagesAsRead(readVoicemails)) {
+                    queryHelper.markReadInDatabase(readVoicemails);
+                }
+            }
+
+            if (extras.getBoolean(SYNC_EXTRAS_DOWNLOAD, false)) {
+                List<Voicemail> serverVoicemails = imapHelper.fetchAllVoicemails();
+                List<Voicemail> localVoicemails = queryHelper.getAllVoicemails();
+
+                if (localVoicemails == null || serverVoicemails == null) {
+                    // Null value means the query failed.
+                    return;
+                }
+
+                Map<String, Voicemail> remoteMap = buildMap(serverVoicemails);
+
+                // Go through all the local voicemails and check if they are on the server.
+                // They may be read or deleted on the server but not locally. Perform the
+                // appropriate local operation if the status differs from the server. Remove
+                // the messages that exist both locally and on the server to know which server
+                // messages to insert locally.
+                for (int i = 0; i < localVoicemails.size(); i++) {
+                    Voicemail localVoicemail = localVoicemails.get(i);
+                    Voicemail remoteVoicemail = remoteMap.remove(localVoicemail.getSourceData());
+                    if (remoteVoicemail == null) {
+                        queryHelper.deleteFromDatabase(localVoicemail);
+                    } else {
+                        if (remoteVoicemail.isRead() != localVoicemail.isRead()) {
+                            queryHelper.markReadInDatabase(localVoicemail);
+                        }
+                    }
+                }
+
+                // The leftover messages are messages that exist on the server but not locally.
+                for (Voicemail remoteVoicemail : remoteMap.values()) {
+                    VoicemailContract.Voicemails.insert(mContext, remoteVoicemail);
+                }
+            }
+        }
+
+        /**
+         * Builds a map from provider data to message for the given collection of voicemails.
+         */
+        private Map<String, Voicemail> buildMap(List<Voicemail> messages) {
+            Map<String, Voicemail> map = new HashMap<String, Voicemail>();
+            for (Voicemail message : messages) {
+                map.put(message.getSourceData(), message);
+            }
+            return map;
+        }
+    }
+}
diff --git a/src/com/android/phone/vvm/omtp/sync/VoicemailsQueryHelper.java b/src/com/android/phone/vvm/omtp/sync/VoicemailsQueryHelper.java
new file mode 100644
index 0000000..151afed
--- /dev/null
+++ b/src/com/android/phone/vvm/omtp/sync/VoicemailsQueryHelper.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2015 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.vvm.omtp.sync;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.VoicemailContract;
+import android.provider.VoicemailContract.Voicemails;
+import android.telecom.Voicemail;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Construct a queries to interact with the voicemails table.
+ */
+public class VoicemailsQueryHelper {
+    final static String[] PROJECTION = new String[] {
+            Voicemails._ID,              // 0
+            Voicemails.SOURCE_DATA,      // 1
+            Voicemails.IS_READ,          // 2
+            Voicemails.DELETED,          // 3
+    };
+
+    public static final int _ID = 0;
+    public static final int SOURCE_DATA = 1;
+    public static final int IS_READ = 2;
+    public static final int DELETED = 3;
+
+    final static String READ_SELECTION = Voicemails.DIRTY + "=1 AND " + Voicemails.DELETED + "!=1";
+    final static String DELETED_SELECTION = Voicemails.DELETED + "=1";
+
+    private Context mContext;
+    private ContentResolver mContentResolver;
+    private Uri mSourceUri;
+
+    public VoicemailsQueryHelper(Context context) {
+        mContext = context;
+        mContentResolver = context.getContentResolver();
+        mSourceUri = VoicemailContract.Voicemails.buildSourceUri(mContext.getPackageName());
+    }
+
+    /**
+     * Get all the local read voicemails that have not been synced to the server.
+     *
+     * @return A list of read voicemails.
+     */
+    public List<Voicemail> getReadVoicemails() {
+        return getLocalVoicemails(READ_SELECTION);
+    }
+
+    /**
+     * Get all the locally deleted voicemails that have not been synced to the server.
+     *
+     * @return A list of deleted voicemails.
+     */
+    public List<Voicemail> getDeletedVoicemails() {
+        return getLocalVoicemails(DELETED_SELECTION);
+    }
+
+    /**
+     * Get all voicemails locally stored.
+     *
+     * @return A list of all locally stored voicemails.
+     */
+    public List<Voicemail> getAllVoicemails() {
+        return getLocalVoicemails(null);
+    }
+
+    /**
+     * Utility method to make queries to the voicemail database.
+     *
+     * @param selection A filter declaring which rows to return. {@code null} returns all rows.
+     * @return A list of voicemails according to the selection statement.
+     */
+    private List<Voicemail> getLocalVoicemails(String selection) {
+        Cursor cursor = mContentResolver.query(mSourceUri, PROJECTION, selection, null, null);
+        if (cursor == null) {
+            return null;
+        }
+        try {
+            List<Voicemail> voicemails = new ArrayList<Voicemail>();
+            while (cursor.moveToNext()) {
+                final long id = cursor.getLong(VoicemailsQueryHelper._ID);
+                final String sourceData = cursor.getString(VoicemailsQueryHelper.SOURCE_DATA);
+                Voicemail voicemail = Voicemail.createForUpdate(id, sourceData).build();
+                voicemails.add(voicemail);
+            }
+            return voicemails;
+        } finally {
+            cursor.close();
+        }
+    }
+
+    /**
+     * Deletes a list of voicemails from the voicemail content provider.
+     *
+     * @param voicemails The list of voicemails to delete
+     * @return The number of voicemails deleted
+     */
+    public int deleteFromDatabase(List<Voicemail> voicemails) {
+        int count = voicemails.size();
+        if (count == 0) {
+            return 0;
+        }
+
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < count; i++) {
+            if (i > 0) {
+                sb.append(",");
+            }
+            sb.append(voicemails.get(i).getId());
+        }
+
+        String selectionStatement = String.format(Voicemails._ID + " IN (%s)", sb.toString());
+        return mContentResolver.delete(Voicemails.CONTENT_URI, selectionStatement, null);
+    }
+
+    /**
+     * Utility method to delete a single voicemail.
+     */
+    public void deleteFromDatabase(Voicemail voicemail) {
+        mContentResolver.delete(Voicemails.CONTENT_URI, Voicemails._ID + "=?",
+                new String[] { Long.toString(voicemail.getId()) });
+    }
+
+    /**
+     * Sends an update command to the voicemail content provider for a list of voicemails.
+     * From the view of the provider, since the updater is the owner of the entry, a blank
+     * "update" means that the voicemail source is indicating that the server has up-to-date
+     * information on the voicemail. This flips the "dirty" bit to "0".
+     *
+     * @param voicemails The list of voicemails to update
+     * @return The number of voicemails updated
+     */
+    public int markReadInDatabase(List<Voicemail> voicemails) {
+        int count = voicemails.size();
+        for (int i = 0; i < count; i++) {
+            markReadInDatabase(voicemails.get(i));
+        }
+        return count;
+    }
+
+    /**
+     * Utility method to mark single message as read.
+     */
+    public void markReadInDatabase(Voicemail voicemail) {
+        Uri uri = ContentUris.withAppendedId(mSourceUri, voicemail.getId());
+        ContentValues contentValues = new ContentValues();
+        contentValues.put(Voicemails.IS_READ, "1");
+        mContentResolver.update(uri, contentValues, null, null);
+    }
+}
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index e7a02ec..8fb101d 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -580,7 +580,6 @@
         }
 
         participant.removeConnectionListener(mParticipantListener);
-        participant.getEndpoint();
         mConferenceParticipantConnections.remove(participant.getEndpoint());
     }
 
@@ -593,8 +592,7 @@
         for (ConferenceParticipantConnection connection :
                 mConferenceParticipantConnections.values()) {
 
-            removeConferenceParticipant(connection);
-
+            connection.removeConnectionListener(mParticipantListener);
             // Mark disconnect cause as cancelled to ensure that the call is not logged in the
             // call log.
             connection.setDisconnected(new DisconnectCause(DisconnectCause.CANCELED));