Merge "Clean up some voicemail methods to be more clear." into lmp-mr1-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c086376..7875afb 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -95,7 +95,8 @@
     <uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS" />
     <uses-permission android:name="android.permission.READ_SEARCH_INDEXABLES" />
     <uses-permission android:name="android.permission.DUMP" />
-    <uses-permission android:name="android.permission.REGISTER_PROVIDER_OR_SUBSCRIPTION" />
+    <uses-permission android:name="android.permission.REGISTER_CALL_PROVIDER" />
+    <uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" />
 
     <!-- This tells the activity manager to not delay any of our activity
          start requests, even if they happen immediately after the user
@@ -542,6 +543,11 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="com.android.phone.settings.VoicemailSettingsActivity"
+            android:label="@string/voicemail"
+            android:theme="@style/DialerSettingsLight">
+        </activity>
+
         <!-- BroadcastReceiver for receiving Intents from Notification mechanism. -->
         <receiver android:name="PhoneGlobals$NotificationBroadcastReceiver" android:exported="false">
             <intent-filter>
diff --git a/res/values-mcc204-mnc04/strings.xml b/res/values-mcc204-mnc04/strings.xml
new file mode 100644
index 0000000..fec694f
--- /dev/null
+++ b/res/values-mcc204-mnc04/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string translatable="false" name="config_world_mode">true;BAE0000000000000</string>
+</resources>
diff --git a/res/values-mcc310-mnc004/config.xml b/res/values-mcc310-mnc004/config.xml
new file mode 100755
index 0000000..bbe9e7b
--- /dev/null
+++ b/res/values-mcc310-mnc004/config.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<!-- Phone app resources that may need to be customized
+     for different hardware or product builds. -->
+<resources>
+    <!-- Flag indicating if dtmf tone type is enabled -->
+    <bool name="support_swap_after_merge" translatable="false">false</bool>
+</resources>
diff --git a/res/values-mcc310-mnc004/strings.xml b/res/values-mcc310-mnc004/strings.xml
new file mode 100644
index 0000000..55cbcd6
--- /dev/null
+++ b/res/values-mcc310-mnc004/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string translatable="false" name="config_world_mode">true</string>
+</resources>
diff --git a/res/values-mcc311-mnc480/config.xml b/res/values-mcc311-mnc480/config.xml
old mode 100644
new mode 100755
index 7c269e0..df95aa4
--- a/res/values-mcc311-mnc480/config.xml
+++ b/res/values-mcc311-mnc480/config.xml
@@ -19,4 +19,5 @@
 <resources>
     <!-- Flag indicating if dtmf tone type is enabled -->
     <bool name="dtmf_type_enabled">true</bool>
+    <bool name="support_swap_after_merge" translatable="false">false</bool>
 </resources>
diff --git a/res/values-mcc311-mnc480/strings.xml b/res/values-mcc311-mnc480/strings.xml
new file mode 100644
index 0000000..55cbcd6
--- /dev/null
+++ b/res/values-mcc311-mnc480/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string translatable="false" name="config_world_mode">true</string>
+</resources>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
new file mode 100644
index 0000000..8187ff3
--- /dev/null
+++ b/res/values/arrays.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 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.
+-->
+<resources>
+
+    <!--String arrays for World preferred netwrok modes -->
+    <string-array name="preferred_network_mode_choices_world_mode">
+        <item>Global</item>
+        <item>LTE / CDMA</item>
+        <item>LTE / GSM / UMTS</item>
+    </string-array>
+
+    <string-array name="preferred_network_mode_values_world_mode">
+        <item>"10"</item>
+        <item>"8"</item>
+        <item>"9"</item>
+    </string-array>
+
+</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
old mode 100644
new mode 100755
index cd82234..881762d
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -149,4 +149,7 @@
 
     <!-- Allows the telephony HFA logic to run even if we're not in setup wizard. -->
     <bool name="config_allow_hfa_outside_of_setup_wizard">true</bool>
+
+    <!-- After a CDMA conference call is merged, the swap button should be displayed. -->
+    <bool name="support_swap_after_merge" translatable="false">true</bool>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5d9f835..4c7f558 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -382,7 +382,10 @@
     <string name="preferred_network_mode_global_summary">Preferred network mode: Global</string>
     <!-- Mobile network settings, summary for preferred network mode LTE / WCDMA[CHAR LIMIT=100] -->
     <string name="preferred_network_mode_lte_wcdma_summary">Preferred network mode: LTE / WCDMA</string>
-
+     <!-- Mobile network settings, summary for preferred network mode LTE / GSM / UMTS [CHAR LIMIT=100] -->
+     <string name="preferred_network_mode_lte_gsm_umts_summary">Preferred network mode: LTE / GSM / UMTS</string>
+     <!-- Mobile network settings, summary for preferred network mode LTE / CDMA [CHAR LIMIT=100] -->
+     <string name="preferred_network_mode_lte_cdma_summary">Preferred network mode: LTE / CDMA</string>
 
     <string-array name="preferred_network_mode_choices">
         <item>LTE / WCDMA</item>
@@ -1245,4 +1248,6 @@
     <string name="sim_label_emergency_calls">Emergency calls</string>
     <string name="sim_description_emergency_calls">Emergency calling only</string>
     <string name="sim_description_default">SIM card, slot: <xliff:g id="slot_id">%s</xliff:g></string>
+    <!-- Configuration setting for world mode Format is <true;GID if any to be checked>-->
+    <string translatable="false" name="config_world_mode"/>
 </resources>
diff --git a/res/xml/voicemail_settings.xml b/res/xml/voicemail_settings.xml
new file mode 100644
index 0000000..f4679e5
--- /dev/null
+++ b/res/xml/voicemail_settings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+    android:title="@string/voicemail">
+
+    <!-- Temporary placeholder until prefs are migrated from Call Settings. -->
+    <Preference android:title="@string/voicemail" />
+
+</PreferenceScreen>
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index eb211f1..796e3e5 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -48,7 +48,6 @@
 import android.provider.Settings;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
-import android.telephony.PhoneNumberUtils;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
@@ -64,6 +63,7 @@
 import com.android.phone.common.util.SettingsUtil;
 import com.android.phone.settings.AccountSelectionPreference;
 import com.android.phone.settings.VoicemailProviderSettings;
+import com.android.phone.settings.VoicemailProviderSettingsUtil;
 import com.android.services.telephony.sip.SipUtil;
 
 import java.lang.String;
@@ -131,20 +131,6 @@
     // choose another VM provider
     public static final String SIGNOUT_EXTRA = "com.android.phone.Signout";
 
-    // Suffix appended to provider key for storing vm number
-    public static final String VM_NUMBER_TAG = "#VMNumber";
-    // Suffix appended to provider key for storing forwarding settings
-    public static final String FWD_SETTINGS_TAG = "#FWDSettings";
-    // Suffix appended to forward settings key for storing length of settings array
-    public static final String FWD_SETTINGS_LENGTH_TAG = "#Length";
-    // Suffix appended to forward settings key for storing an individual setting
-    public static final String FWD_SETTING_TAG = "#Setting";
-    // Suffixes appended to forward setting key for storing an individual setting properties
-    public static final String FWD_SETTING_STATUS = "#Status";
-    public static final String FWD_SETTING_REASON = "#Reason";
-    public static final String FWD_SETTING_NUMBER = "#Number";
-    public static final String FWD_SETTING_TIME = "#Time";
-
     // Key identifying the default vocie mail provider
     public static final String DEFAULT_VM_PROVIDER_KEY = "";
 
@@ -183,8 +169,6 @@
     private static final String BUTTON_GSM_UMTS_OPTIONS = "button_gsm_more_expand_key";
     private static final String BUTTON_CDMA_OPTIONS = "button_cdma_more_expand_key";
 
-    private static final String VM_NUMBERS_SHARED_PREFERENCES_NAME = "vm_numbers";
-
     private static final String DEFAULT_OUTGOING_ACCOUNT_KEY = "default_outgoing_account";
     private static final String PHONE_ACCOUNT_SETTINGS_KEY =
             "phone_account_settings_preference_screen";
@@ -207,8 +191,8 @@
     private static final int VOICEMAIL_PROVIDER_CFG_ID = 2;
 
     private Phone mPhone;
-
     private AudioManager mAudioManager;
+    private VoicemailProviderSettingsUtil mVmProviderSettingsUtil;
 
     private static final int VM_NOCHANGE_ERROR = 400;
     private static final int VM_RESPONSE_ERROR = 500;
@@ -264,8 +248,6 @@
         public Intent intent;
     }
 
-    private SharedPreferences mPerProviderSavedVMNumbers;
-
     /**
      * Results of reading forwarding settings
      */
@@ -471,14 +453,11 @@
             updateVMPreferenceWidgets(newProviderKey);
 
             final VoicemailProviderSettings newProviderSettings =
-                    loadSettingsForVoiceMailProvider(newProviderKey);
+                    mVmProviderSettingsUtil.load(newProviderKey);
 
-            // If the user switches to a voice mail provider and we have a
-            // numbers stored for it we will automatically change the
-            // phone's
-            // voice mail and forwarding number to the stored ones.
-            // Otherwise we will bring up provider's configuration UI.
-
+            // If the user switches to a voice mail provider and we have numbers stored for it we
+            // will automatically change the phone's voice mail and forwarding number to the stored
+            // ones. Otherwise we will bring up provider's configuration UI.
             if (newProviderSettings == null) {
                 // Force the user into a configuration of the chosen provider
                 Log.w(LOG_TAG, "Saved preferences not found - invoking config");
@@ -573,7 +552,7 @@
 
                 showDialogIfForeground(VOICEMAIL_REVERTING_DIALOG);
                 final VoicemailProviderSettings prevSettings =
-                        loadSettingsForVoiceMailProvider(mPreviousVMProviderKey);
+                        mVmProviderSettingsUtil.load(mPreviousVMProviderKey);
                 if (prevSettings == null) {
                     // prevSettings never becomes null since it should be already loaded!
                     Log.e(LOG_TAG, "VoicemailProviderSettings for the key \""
@@ -803,7 +782,7 @@
             return;
         }
 
-        maybeSaveSettingsForVoicemailProvider(key, newSettings);
+        mVmProviderSettingsUtil.save(key, newSettings);
         mVMChangeCompletedSuccessfully = false;
         mFwdChangesRequireRollback = false;
         mVMOrFwdSetError = 0;
@@ -905,9 +884,8 @@
             if (DBG) Log.d(LOG_TAG, "Done receiving fwd info");
             dismissDialogSafely(VOICEMAIL_FWD_READING_DIALOG);
             if (mReadingSettingsForDefaultProvider) {
-                maybeSaveSettingsForVoicemailProvider(DEFAULT_VM_PROVIDER_KEY,
-                        new VoicemailProviderSettings(this.mOldVmNumber,
-                                mForwardingReadResults));
+                mVmProviderSettingsUtil.save(DEFAULT_VM_PROVIDER_KEY,
+                        new VoicemailProviderSettings(this.mOldVmNumber, mForwardingReadResults));
                 mReadingSettingsForDefaultProvider = false;
             }
             saveVoiceMailAndForwardingNumberStage2();
@@ -1368,6 +1346,7 @@
         if (DBG) log("onCreate(). Intent: " + getIntent());
         mPhone = PhoneGlobals.getPhone();
         mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        mVmProviderSettingsUtil = new VoicemailProviderSettingsUtil(getApplicationContext());
 
         // Show the voicemail preference in onResume if the calling intent specifies the
         // ACTION_ADD_VOICEMAIL action.
@@ -1654,9 +1633,6 @@
      */
     private void initVoiceMailProviders() {
         if (DBG) log("initVoiceMailProviders()");
-        mPerProviderSavedVMNumbers =
-                this.getApplicationContext().getSharedPreferences(
-                        VM_NUMBERS_SHARED_PREFERENCES_NAME, MODE_PRIVATE);
 
         String providerToIgnore = null;
         if (getIntent().getAction().equals(ACTION_ADD_VOICEMAIL)) {
@@ -1666,7 +1642,7 @@
             if (DBG) log("Found ACTION_ADD_VOICEMAIL. providerToIgnore=" + providerToIgnore);
             if (providerToIgnore != null) {
                 // IGNORE_PROVIDER_EXTRA implies we want to remove the choice from the list.
-                deleteSettingsForVoicemailProvider(providerToIgnore);
+                mVmProviderSettingsUtil.delete(providerToIgnore);
             }
         }
 
@@ -1764,98 +1740,6 @@
         }
     }
 
-    /**
-     * Saves new VM provider settings associating them with the currently selected
-     * provider if settings are different than the ones already stored for this
-     * provider.
-     * Later on these will be used when the user switches a provider.
-     */
-    private void maybeSaveSettingsForVoicemailProvider(String key,
-            VoicemailProviderSettings newSettings) {
-        final VoicemailProviderSettings curSettings = loadSettingsForVoiceMailProvider(key);
-        if (newSettings.equals(curSettings)) {
-            if (DBG) {
-                log("maybeSaveSettingsForVoicemailProvider:"
-                        + " Not saving setting for " + key + " since they have not changed");
-            }
-            return;
-        }
-        if (DBG) log("Saving settings for " + key + ": " + newSettings.toString());
-        Editor editor = mPerProviderSavedVMNumbers.edit();
-        editor.putString(key + VM_NUMBER_TAG, newSettings.getVoicemailNumber());
-        String fwdKey = key + FWD_SETTINGS_TAG;
-        CallForwardInfo[] s = newSettings.getForwardingSettings();
-        if (s != VoicemailProviderSettings.NO_FORWARDING) {
-            editor.putInt(fwdKey + FWD_SETTINGS_LENGTH_TAG, s.length);
-            for (int i = 0; i < s.length; i++) {
-                final String settingKey = fwdKey + FWD_SETTING_TAG + String.valueOf(i);
-                final CallForwardInfo fi = s[i];
-                editor.putInt(settingKey + FWD_SETTING_STATUS, fi.status);
-                editor.putInt(settingKey + FWD_SETTING_REASON, fi.reason);
-                editor.putString(settingKey + FWD_SETTING_NUMBER, fi.number);
-                editor.putInt(settingKey + FWD_SETTING_TIME, fi.timeSeconds);
-            }
-        } else {
-            editor.putInt(fwdKey + FWD_SETTINGS_LENGTH_TAG, 0);
-        }
-        editor.apply();
-    }
-
-    /**
-     * Returns settings previously stored for the currently selected
-     * voice mail provider. If none is stored returns null.
-     * If the user switches to a voice mail provider and we have settings
-     * stored for it we will automatically change the phone's voice mail number
-     * and forwarding number to the stored one. Otherwise we will bring up provider's configuration
-     * UI.
-     */
-    private VoicemailProviderSettings loadSettingsForVoiceMailProvider(String key) {
-        final String vmNumberSetting = mPerProviderSavedVMNumbers.getString(key + VM_NUMBER_TAG,
-                null);
-        if (vmNumberSetting == null) {
-            Log.w(LOG_TAG, "VoiceMailProvider settings for the key \"" + key + "\""
-                    + " was not found. Returning null.");
-            return null;
-        }
-
-        CallForwardInfo[] cfi = VoicemailProviderSettings.NO_FORWARDING;
-        String fwdKey = key + FWD_SETTINGS_TAG;
-        final int fwdLen = mPerProviderSavedVMNumbers.getInt(fwdKey + FWD_SETTINGS_LENGTH_TAG, 0);
-        if (fwdLen > 0) {
-            cfi = new CallForwardInfo[fwdLen];
-            for (int i = 0; i < cfi.length; i++) {
-                final String settingKey = fwdKey + FWD_SETTING_TAG + String.valueOf(i);
-                cfi[i] = new CallForwardInfo();
-                cfi[i].status = mPerProviderSavedVMNumbers.getInt(
-                        settingKey + FWD_SETTING_STATUS, 0);
-                cfi[i].reason = mPerProviderSavedVMNumbers.getInt(
-                        settingKey + FWD_SETTING_REASON,
-                        CommandsInterface.CF_REASON_ALL_CONDITIONAL);
-                cfi[i].serviceClass = CommandsInterface.SERVICE_CLASS_VOICE;
-                cfi[i].toa = PhoneNumberUtils.TOA_International;
-                cfi[i].number = mPerProviderSavedVMNumbers.getString(
-                        settingKey + FWD_SETTING_NUMBER, "");
-                cfi[i].timeSeconds = mPerProviderSavedVMNumbers.getInt(
-                        settingKey + FWD_SETTING_TIME, 20);
-            }
-        }
-
-        VoicemailProviderSettings settings =  new VoicemailProviderSettings(vmNumberSetting, cfi);
-        if (DBG) log("Loaded settings for " + key + ": " + settings.toString());
-        return settings;
-    }
-
-    /**
-     * Deletes settings for the specified provider.
-     */
-    private void deleteSettingsForVoicemailProvider(String key) {
-        if (DBG) log("Deleting settings for" + key);
-        mPerProviderSavedVMNumbers.edit()
-            .putString(key + VM_NUMBER_TAG, null)
-            .putInt(key + FWD_SETTINGS_TAG + FWD_SETTINGS_LENGTH_TAG, 0)
-            .commit();
-    }
-
     private String getCurrentVoicemailProviderKey() {
         final String key = mVoicemailProviders.getValue();
         return (key != null) ? key : DEFAULT_VM_PROVIDER_KEY;
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index 2c57b47..d618b5c 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -312,6 +312,12 @@
             } else {
                 throw new IllegalStateException("Unexpected phone type: " + phoneType);
             }
+            if (isWorldMode()) {
+                mButtonEnabledNetworks.setEntries(
+                        R.array.preferred_network_mode_choices_world_mode);
+                mButtonEnabledNetworks.setEntryValues(
+                        R.array.preferred_network_mode_values_world_mode);
+            }
             mButtonEnabledNetworks.setOnPreferenceChangeListener(this);
             int settingsNetworkMode = android.provider.Settings.Global.getInt(
                     mPhone.getContext().getContentResolver(),
@@ -731,6 +737,11 @@
                 }
                 break;
             case Phone.NT_MODE_LTE_GSM_WCDMA:
+                if(isWorldMode()) {
+                    mButtonEnabledNetworks.setSummary(
+                            R.string.preferred_network_mode_lte_gsm_umts_summary);
+                    break;
+                }
             case Phone.NT_MODE_LTE_ONLY:
             case Phone.NT_MODE_LTE_WCDMA:
                 if (!mIsGlobalCdma) {
@@ -745,9 +756,14 @@
                 }
                 break;
             case Phone.NT_MODE_LTE_CDMA_AND_EVDO:
-                mButtonEnabledNetworks.setValue(
-                        Integer.toString(Phone.NT_MODE_LTE_CDMA_AND_EVDO));
-                mButtonEnabledNetworks.setSummary(R.string.network_lte);
+                if(isWorldMode()) {
+                    mButtonEnabledNetworks.setSummary(
+                            R.string.preferred_network_mode_lte_cdma_summary);
+                } else {
+                    mButtonEnabledNetworks.setValue(
+                            Integer.toString(Phone.NT_MODE_LTE_CDMA_AND_EVDO));
+                    mButtonEnabledNetworks.setSummary(R.string.network_lte);
+                }
                 break;
             case Phone.NT_MODE_CDMA:
             case Phone.NT_MODE_EVDO_NO_CDMA:
@@ -820,4 +836,28 @@
         }
         return super.onOptionsItemSelected(item);
     }
+
+    private boolean isWorldMode() {
+        boolean worldModeOn = false;
+        final TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
+        final String configString = getResources().getString(R.string.config_world_mode);
+
+        if (!TextUtils.isEmpty(configString)) {
+            String[] configArray = configString.split(";");
+            // Check if we have World mode configuration set to True only or config is set to True
+            // and SIM GID value is also set and matches to the current SIM GID.
+            if (configArray != null &&
+                   ((configArray.length == 1 && configArray[0].equalsIgnoreCase("true")) ||
+                       (configArray.length == 2 && !TextUtils.isEmpty(configArray[1]) &&
+                           tm != null && configArray[1].equalsIgnoreCase(tm.getGroupIdLevel1())))) {
+                               worldModeOn = true;
+            }
+        }
+
+        if (DBG) {
+            log("World mode is set to" + worldModeOn);
+        }
+
+        return worldModeOn;
+    }
 }
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 31337ee..55449d7 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -86,7 +86,7 @@
      *
      * ***** DO NOT SUBMIT WITH DBG_LEVEL > 0 *************
      */
-    /* package */ static final int DBG_LEVEL = 0;
+    public static final int DBG_LEVEL = 0;
 
     private static final boolean DBG =
             (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
diff --git a/src/com/android/phone/settings/PhoneAccountSettingsActivity.java b/src/com/android/phone/settings/PhoneAccountSettingsActivity.java
index 14add68..71ae8cf 100644
--- a/src/com/android/phone/settings/PhoneAccountSettingsActivity.java
+++ b/src/com/android/phone/settings/PhoneAccountSettingsActivity.java
@@ -1,4 +1,4 @@
-/*
+/**
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,12 +20,8 @@
 import android.preference.PreferenceActivity;
 import android.view.MenuItem;
 
-import com.android.internal.telephony.PhoneConstants;
-import com.android.phone.PhoneGlobals;
 import com.android.phone.R;
 
-// TODO: Convert FeatureCallSettings into a preference fragment based activity, and load the
-// PhoneAccountSettings fragment directly instead of starting this PreferenceActivity.
 public class PhoneAccountSettingsActivity extends PreferenceActivity {
 
     @Override
@@ -39,8 +35,7 @@
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-        final int itemId = item.getItemId();
-        if (itemId == android.R.id.home) {
+        if (item.getItemId() == android.R.id.home) {
             onBackPressed();
             return true;
         }
diff --git a/src/com/android/phone/settings/PhoneAccountSettingsFragment.java b/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
index 20fc108..5f5a32e 100644
--- a/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
+++ b/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
@@ -82,7 +82,7 @@
             getPreferenceScreen().removeAll();
         }
 
-        addPreferencesFromResource(com.android.phone.R.xml.phone_account_settings);
+        addPreferencesFromResource(R.xml.phone_account_settings);
 
         TelephonyManager telephonyManager =
                 (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
diff --git a/src/com/android/phone/settings/VoicemailProviderSettingsUtil.java b/src/com/android/phone/settings/VoicemailProviderSettingsUtil.java
new file mode 100644
index 0000000..20fd05a
--- /dev/null
+++ b/src/com/android/phone/settings/VoicemailProviderSettingsUtil.java
@@ -0,0 +1,145 @@
+/**
+ * Copyright (C) 2014 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.settings;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.telephony.PhoneNumberUtils;
+import android.util.Log;
+
+import com.android.internal.telephony.CallForwardInfo;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.phone.PhoneGlobals;
+
+public class VoicemailProviderSettingsUtil {
+    private static final String LOG_TAG = VoicemailProviderSettingsUtil.class.getSimpleName();
+    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
+
+    private static final String VM_NUMBERS_SHARED_PREFERENCES_NAME = "vm_numbers";
+
+    // Suffix appended to provider key for storing vm number
+    private static final String VM_NUMBER_TAG = "#VMNumber";
+    // Suffix appended to forward settings key for storing an individual setting
+    private static final String FWD_SETTING_TAG = "#Setting";
+    // Suffix appended to provider key for storing forwarding settings
+    private static final String FWD_SETTINGS_TAG = "#FWDSettings";
+    // Suffix appended to forward settings key for storing length of settings array
+    private static final String FWD_SETTINGS_LENGTH_TAG = "#Length";
+
+    // Suffixes appended to forward setting key for storing an individual setting properties
+    private static final String FWD_SETTING_STATUS = "#Status";
+    private static final String FWD_SETTING_REASON = "#Reason";
+    private static final String FWD_SETTING_NUMBER = "#Number";
+    private static final String FWD_SETTING_TIME = "#Time";
+
+    private SharedPreferences mVmProviderPrefs;
+
+    public VoicemailProviderSettingsUtil(Context context) {
+        mVmProviderPrefs = context.getSharedPreferences(
+                VM_NUMBERS_SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
+    }
+
+    /**
+     * Returns settings previously stored for the currently selected voice mail provider. If no
+     * setting is stored for the voice mail provider, return null.
+     */
+    public VoicemailProviderSettings load(String key) {
+        String vmNumberSetting = mVmProviderPrefs.getString(key + VM_NUMBER_TAG, null);
+        if (vmNumberSetting == null) {
+            Log.w(LOG_TAG, "VoiceMailProvider settings for the key \"" + key + "\""
+                    + " were not found. Returning null.");
+            return null;
+        }
+
+        CallForwardInfo[] cfi = VoicemailProviderSettings.NO_FORWARDING;
+        String fwdKey = key + FWD_SETTINGS_TAG;
+        int fwdLen = mVmProviderPrefs.getInt(fwdKey + FWD_SETTINGS_LENGTH_TAG, 0);
+        if (fwdLen > 0) {
+            cfi = new CallForwardInfo[fwdLen];
+            for (int i = 0; i < cfi.length; i++) {
+                String settingKey = fwdKey + FWD_SETTING_TAG + String.valueOf(i);
+                cfi[i] = new CallForwardInfo();
+                cfi[i].status = mVmProviderPrefs.getInt(settingKey + FWD_SETTING_STATUS, 0);
+                cfi[i].reason = mVmProviderPrefs.getInt(
+                        settingKey + FWD_SETTING_REASON,
+                        CommandsInterface.CF_REASON_ALL_CONDITIONAL);
+                cfi[i].serviceClass = CommandsInterface.SERVICE_CLASS_VOICE;
+                cfi[i].toa = PhoneNumberUtils.TOA_International;
+                cfi[i].number = mVmProviderPrefs.getString(settingKey + FWD_SETTING_NUMBER, "");
+                cfi[i].timeSeconds = mVmProviderPrefs.getInt(settingKey + FWD_SETTING_TIME, 20);
+            }
+        }
+
+        VoicemailProviderSettings settings = new VoicemailProviderSettings(vmNumberSetting, cfi);
+        if (DBG) log("Loaded settings for " + key + ": " + settings.toString());
+        return settings;
+    }
+
+    /**
+     * Saves new VM provider settings and associates them with the currently selected provider if
+     * the settings are different than the ones already stored for this provider.
+     *
+     * These will be used later when the user switches a provider.
+     */
+    public void save(String key, VoicemailProviderSettings newSettings) {
+        VoicemailProviderSettings curSettings = load(key);
+        if (newSettings.equals(curSettings)) {
+            if (DBG) log("save: Not saving setting for " + key + " since they have not changed");
+            return;
+        }
+
+        if (DBG) log("Saving settings for " + key + ": " + newSettings.toString());
+
+        Editor editor = mVmProviderPrefs.edit();
+        editor.putString(key + VM_NUMBER_TAG, newSettings.getVoicemailNumber());
+        String fwdKey = key + FWD_SETTINGS_TAG;
+
+        CallForwardInfo[] s = newSettings.getForwardingSettings();
+        if (s != VoicemailProviderSettings.NO_FORWARDING) {
+            editor.putInt(fwdKey + FWD_SETTINGS_LENGTH_TAG, s.length);
+            for (int i = 0; i < s.length; i++) {
+                String settingKey = fwdKey + FWD_SETTING_TAG + String.valueOf(i);
+                CallForwardInfo fi = s[i];
+                editor.putInt(settingKey + FWD_SETTING_STATUS, fi.status);
+                editor.putInt(settingKey + FWD_SETTING_REASON, fi.reason);
+                editor.putString(settingKey + FWD_SETTING_NUMBER, fi.number);
+                editor.putInt(settingKey + FWD_SETTING_TIME, fi.timeSeconds);
+            }
+        } else {
+            editor.putInt(fwdKey + FWD_SETTINGS_LENGTH_TAG, 0);
+        }
+
+        editor.apply();
+    }
+
+    /**
+     * Deletes settings for the provider identified by this key.
+     */
+    public void delete(String key) {
+        if (DBG) log("Deleting settings for" + key);
+
+        mVmProviderPrefs.edit()
+                .putString(key + VM_NUMBER_TAG, null)
+                .putInt(key + FWD_SETTINGS_TAG + FWD_SETTINGS_LENGTH_TAG, 0)
+                .commit();
+    }
+
+    private void log(String msg) {
+        Log.d(LOG_TAG, msg);
+    }
+}
diff --git a/src/com/android/phone/settings/VoicemailSettingsActivity.java b/src/com/android/phone/settings/VoicemailSettingsActivity.java
new file mode 100644
index 0000000..a94c27a
--- /dev/null
+++ b/src/com/android/phone/settings/VoicemailSettingsActivity.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (C) 2014 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.settings;
+
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+import android.view.MenuItem;
+
+import com.android.phone.R;
+
+public class VoicemailSettingsActivity extends PreferenceActivity {
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        getActionBar().setTitle(R.string.voicemail);
+        getFragmentManager().beginTransaction().replace(
+                android.R.id.content, new VoicemailSettingsFragment()).commit();
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == android.R.id.home) {
+            onBackPressed();
+            return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+}
diff --git a/src/com/android/phone/settings/VoicemailSettingsFragment.java b/src/com/android/phone/settings/VoicemailSettingsFragment.java
new file mode 100644
index 0000000..fef3e8c
--- /dev/null
+++ b/src/com/android/phone/settings/VoicemailSettingsFragment.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2014 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.settings;
+
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+
+import com.android.phone.R;
+
+public class VoicemailSettingsFragment extends PreferenceFragment {
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        addPreferencesFromResource(R.xml.voicemail_settings);
+    }
+}
diff --git a/src/com/android/services/telephony/CdmaConference.java b/src/com/android/services/telephony/CdmaConference.java
old mode 100644
new mode 100755
index c77557f..5372548
--- a/src/com/android/services/telephony/CdmaConference.java
+++ b/src/com/android/services/telephony/CdmaConference.java
@@ -16,6 +16,8 @@
 
 package com.android.services.telephony;
 
+import android.content.Context;
+import android.content.res.Resources;
 import android.telecom.Conference;
 import android.telecom.Connection;
 import android.telecom.PhoneAccountHandle;
@@ -23,6 +25,8 @@
 
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallStateException;
+import com.android.phone.PhoneGlobals;
+import com.android.phone.common.R;
 
 import java.util.List;
 
@@ -82,7 +86,9 @@
         // Can only merge once
         mCapabilities &= ~PhoneCapabilities.MERGE_CONFERENCE;
         // Once merged, swap is enabled.
-        mCapabilities |= PhoneCapabilities.SWAP_CONFERENCE;
+        if (isSwapSupportedAfterMerge()){
+            mCapabilities |= PhoneCapabilities.SWAP_CONFERENCE;
+        }
         updateCapabilities();
         sendFlash();
     }
@@ -149,6 +155,27 @@
         return null;
     }
 
+    /**
+     * Return whether network support swap after merge conference call.
+     *
+     * @return true to support, false not support.
+     */
+    private final boolean isSwapSupportedAfterMerge()
+    {
+        boolean supportSwapAfterMerge = true;
+        Context context = PhoneGlobals.getInstance();
+
+        if (context != null) {
+            Resources r = context.getResources();
+            if (r != null) {
+                supportSwapAfterMerge = r.getBoolean(R.bool.support_swap_after_merge);
+                Log.d(this, "Current network support swap after call merged capability is "
+                        + supportSwapAfterMerge);
+            }
+        }
+        return supportSwapAfterMerge;
+    }
+
     private com.android.internal.telephony.Connection getOriginalConnection(Connection connection) {
         if (connection instanceof CdmaConnection) {
             return ((CdmaConnection) connection).getOriginalConnection();
diff --git a/src/com/android/services/telephony/ConferenceParticipantConnection.java b/src/com/android/services/telephony/ConferenceParticipantConnection.java
index a1ed6a3..7874404 100644
--- a/src/com/android/services/telephony/ConferenceParticipantConnection.java
+++ b/src/com/android/services/telephony/ConferenceParticipantConnection.java
@@ -50,7 +50,7 @@
         mParentConnection = parentConnection;
         setAddress(participant.getHandle(), PhoneConstants.PRESENTATION_ALLOWED);
         setCallerDisplayName(participant.getDisplayName(), PhoneConstants.PRESENTATION_ALLOWED);
-        updateState(participant.getState());
+
         mEndpoint = participant.getEndpoint();
         setCapabilities();
     }
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index f50db0c..ef63068 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -60,6 +60,16 @@
             R.drawable.ic_multi_sim4
     };
 
+    private final static int[] colors = {
+        0xff00796b,
+        0xff3367d6,
+        0xff303f9f,
+        0xff7b1fa2,
+        0xffc2185b,
+        0xffc53929
+    };
+
+
     // This icon is the one that is used when the Slot ID that we have for a particular SIM
     // is not supported, i.e. SubscriptionManager.INVALID_SLOT_ID or the 5th SIM in a phone.
     private final static int defaultPhoneAccountIcon =  R.drawable.ic_multi_sim;
@@ -124,9 +134,8 @@
                     subDisplayName = record.displayName;
                     slotId = record.slotId;
 
-                    // Assign a "fake" color while the underlying Telephony stuff is refactored
-                    // Assign PhoneAccount.NO_COLOR to first slot so single-SIM phones are unchanged
-                    color = slotId == 0? PhoneAccount.NO_COLOR : makeFakeColor(subId);
+                    // Assign a "fake" color while the underlying Telephony stuff is refactored.
+                    color = makeFakeColor(subId);
                 }
 
                 String slotIdString;
@@ -180,11 +189,6 @@
     }
 
     private int makeFakeColor(long subId) {
-        int[] colors = new int[] {
-                0xff0000,
-                0x00ff00,
-                0x0000ff,
-        };
         return colors[((int) subId) % colors.length];
     }
 
diff --git a/src/com/android/services/telephony/TelephonyConference.java b/src/com/android/services/telephony/TelephonyConference.java
index fdb7261..54529bb 100644
--- a/src/com/android/services/telephony/TelephonyConference.java
+++ b/src/com/android/services/telephony/TelephonyConference.java
@@ -71,7 +71,7 @@
     @Override
     public void onSeparate(Connection connection) {
         com.android.internal.telephony.Connection radioConnection =
-                getOriginalConnection(connection, "onSeparate");
+                getOriginalConnection(connection);
         try {
             radioConnection.separate();
         } catch (CallStateException e) {
@@ -129,9 +129,28 @@
         }
     }
 
+    @Override
+    public Connection getPrimaryConnection() {
+        // Default to the first connection.
+        Connection primaryConnection = getConnections().get(0);
+
+        // Otherwise look for a connection where the radio connection states it is multiparty.
+        for (Connection connection : getConnections()) {
+            com.android.internal.telephony.Connection radioConnection =
+                    getOriginalConnection(connection);
+
+            if (radioConnection != null && radioConnection.isMultiparty()) {
+                primaryConnection = connection;
+                break;
+            }
+        }
+
+        return primaryConnection;
+    }
+
     private Call getMultipartyCallForConnection(Connection connection, String tag) {
         com.android.internal.telephony.Connection radioConnection =
-                getOriginalConnection(connection, tag);
+                getOriginalConnection(connection);
         if (radioConnection != null) {
             Call call = radioConnection.getCall();
             if (call != null && call.isMultiparty()) {
@@ -142,12 +161,11 @@
     }
 
     private com.android.internal.telephony.Connection getOriginalConnection(
-            Connection connection, String tag) {
+            Connection connection) {
 
         if (connection instanceof TelephonyConnection) {
             return ((TelephonyConnection) connection).getOriginalConnection();
         } else {
-            Log.e(this, null, "Non TelephonyConnection found in a TelephonyConference (%s)", tag);
             return null;
         }
     }
diff --git a/src/com/android/services/telephony/TelephonyConferenceController.java b/src/com/android/services/telephony/TelephonyConferenceController.java
index b64464d..892f3f9 100644
--- a/src/com/android/services/telephony/TelephonyConferenceController.java
+++ b/src/com/android/services/telephony/TelephonyConferenceController.java
@@ -28,6 +28,7 @@
 import android.telecom.ConferenceParticipant;
 import android.telecom.Connection;
 import android.telecom.DisconnectCause;
+import android.telecom.PhoneAccountHandle;
 
 import com.android.internal.telephony.Call;
 
@@ -65,10 +66,16 @@
          * @param participant The participant information.
          */
         @Override
-        public void onConferenceParticipantChanged(Connection c, ConferenceParticipant participant)
-        {
+        public void onConferenceParticipantChanged(Connection c,
+                ConferenceParticipant participant) {
+
+            if (c == null) {
+                return;
+            }
+            TelephonyConnection telephonyConnection = (TelephonyConnection) c;
+
             Log.v(this, "onConferenceParticipantChanged: %s", participant);
-            handleConferenceParticipantUpdate(c, participant);
+            handleConferenceParticipantUpdate(telephonyConnection, participant);
         }
     };
 
@@ -176,7 +183,7 @@
     }
 
     private void recalculateConference() {
-        Set<TelephonyConnection> conferencedConnections = new HashSet<>();
+        Set<Connection> conferencedConnections = new HashSet<>();
 
         for (TelephonyConnection connection : mTelephonyConnections) {
             com.android.internal.telephony.Connection radioConnection =
@@ -192,6 +199,12 @@
             }
         }
 
+        // Include conference participants in the list of conferenced connections.
+        for (ConferenceParticipantConnection participant :
+                mConferenceParticipantConnections.values()) {
+            conferencedConnections.add(participant);
+        }
+
         Log.d(this, "Recalculate conference calls %s %s.",
                 mTelephonyConference, conferencedConnections);
 
@@ -230,7 +243,7 @@
             }
 
             // Set the conference state to the same state as its child connections.
-            Connection conferencedConnection = mTelephonyConference.getConnections().get(0);
+            Connection conferencedConnection = mTelephonyConference.getPrimaryConnection();
             switch (conferencedConnection.getState()) {
                 case Connection.STATE_ACTIVE:
                     mTelephonyConference.setActive();
@@ -249,7 +262,7 @@
      * @param participant The conference participant.
      */
     private void handleConferenceParticipantUpdate(
-            Connection parent, ConferenceParticipant participant) {
+            TelephonyConnection parent, ConferenceParticipant participant) {
 
         Uri endpoint = participant.getEndpoint();
         if (!mConferenceParticipantConnections.containsKey(endpoint)) {
@@ -272,13 +285,20 @@
      * @param participant The conference participant information.
      */
     private void createConferenceParticipantConnection(
-            Connection parent, ConferenceParticipant participant) {
+            TelephonyConnection parent, ConferenceParticipant participant) {
 
+        // Create and add the new connection in holding state so that it does not become the
+        // active call.
         ConferenceParticipantConnection connection = new ConferenceParticipantConnection(
                 parent, participant);
         connection.addConnectionListener(mConnectionListener);
+        connection.updateState(Connection.STATE_HOLDING);
         mConferenceParticipantConnections.put(participant.getEndpoint(), connection);
+        PhoneAccountHandle phoneAccountHandle =
+                TelecomAccountRegistry.makePstnPhoneAccountHandle(parent.getPhone());
+        mConnectionService.addExistingConnection(phoneAccountHandle, connection);
 
-        // TODO: Inform telecom of the new participant.
+        // Recalculate to add to the conference and set its state appropriately.
+        recalculateConference();
     }
 }