Merge "Disable voicemail number setting according to carrier config"
diff --git a/res/drawable-hdpi/ic_sim_sub1.png b/res/drawable-hdpi/ic_sim_sub1.png
new file mode 100644
index 0000000..dc24b06
--- /dev/null
+++ b/res/drawable-hdpi/ic_sim_sub1.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_sim_sub2.png b/res/drawable-hdpi/ic_sim_sub2.png
new file mode 100644
index 0000000..297bc72
--- /dev/null
+++ b/res/drawable-hdpi/ic_sim_sub2.png
Binary files differ
diff --git a/res/drawable-hdpi/stat_sys_phone_call_forward.png b/res/drawable-hdpi/stat_sys_phone_call_forward.png
index 4b7c236..e8d3149 100644
--- a/res/drawable-hdpi/stat_sys_phone_call_forward.png
+++ b/res/drawable-hdpi/stat_sys_phone_call_forward.png
Binary files differ
diff --git a/res/drawable-ldrtl-hdpi/ic_sim_sub1.png b/res/drawable-ldrtl-hdpi/ic_sim_sub1.png
new file mode 100644
index 0000000..9ec62ca
--- /dev/null
+++ b/res/drawable-ldrtl-hdpi/ic_sim_sub1.png
Binary files differ
diff --git a/res/drawable-ldrtl-hdpi/ic_sim_sub2.png b/res/drawable-ldrtl-hdpi/ic_sim_sub2.png
new file mode 100644
index 0000000..23559bf
--- /dev/null
+++ b/res/drawable-ldrtl-hdpi/ic_sim_sub2.png
Binary files differ
diff --git a/res/drawable-ldrtl-hdpi/stat_sys_phone_call_forward.png b/res/drawable-ldrtl-hdpi/stat_sys_phone_call_forward.png
index 132b0e5..ff5451c 100644
--- a/res/drawable-ldrtl-hdpi/stat_sys_phone_call_forward.png
+++ b/res/drawable-ldrtl-hdpi/stat_sys_phone_call_forward.png
Binary files differ
diff --git a/res/drawable-ldrtl-mdpi/ic_sim_sub1.png b/res/drawable-ldrtl-mdpi/ic_sim_sub1.png
new file mode 100644
index 0000000..64ab4c6
--- /dev/null
+++ b/res/drawable-ldrtl-mdpi/ic_sim_sub1.png
Binary files differ
diff --git a/res/drawable-ldrtl-mdpi/ic_sim_sub2.png b/res/drawable-ldrtl-mdpi/ic_sim_sub2.png
new file mode 100644
index 0000000..c0aebdd
--- /dev/null
+++ b/res/drawable-ldrtl-mdpi/ic_sim_sub2.png
Binary files differ
diff --git a/res/drawable-ldrtl-mdpi/stat_sys_phone_call_forward.png b/res/drawable-ldrtl-mdpi/stat_sys_phone_call_forward.png
index d49745f..a42b5bb 100644
--- a/res/drawable-ldrtl-mdpi/stat_sys_phone_call_forward.png
+++ b/res/drawable-ldrtl-mdpi/stat_sys_phone_call_forward.png
Binary files differ
diff --git a/res/drawable-ldrtl-xhdpi/ic_sim_sub1.png b/res/drawable-ldrtl-xhdpi/ic_sim_sub1.png
new file mode 100644
index 0000000..2513c24
--- /dev/null
+++ b/res/drawable-ldrtl-xhdpi/ic_sim_sub1.png
Binary files differ
diff --git a/res/drawable-ldrtl-xhdpi/ic_sim_sub2.png b/res/drawable-ldrtl-xhdpi/ic_sim_sub2.png
new file mode 100644
index 0000000..1d50b29
--- /dev/null
+++ b/res/drawable-ldrtl-xhdpi/ic_sim_sub2.png
Binary files differ
diff --git a/res/drawable-ldrtl-xhdpi/stat_sys_phone_call_forward.png b/res/drawable-ldrtl-xhdpi/stat_sys_phone_call_forward.png
index 4cce562..81791a8 100644
--- a/res/drawable-ldrtl-xhdpi/stat_sys_phone_call_forward.png
+++ b/res/drawable-ldrtl-xhdpi/stat_sys_phone_call_forward.png
Binary files differ
diff --git a/res/drawable-ldrtl-xxhdpi/ic_sim_sub1.png b/res/drawable-ldrtl-xxhdpi/ic_sim_sub1.png
new file mode 100644
index 0000000..4355c12
--- /dev/null
+++ b/res/drawable-ldrtl-xxhdpi/ic_sim_sub1.png
Binary files differ
diff --git a/res/drawable-ldrtl-xxhdpi/ic_sim_sub2.png b/res/drawable-ldrtl-xxhdpi/ic_sim_sub2.png
new file mode 100644
index 0000000..2bbc1ef
--- /dev/null
+++ b/res/drawable-ldrtl-xxhdpi/ic_sim_sub2.png
Binary files differ
diff --git a/res/drawable-ldrtl-xxhdpi/stat_sys_phone_call_forward.png b/res/drawable-ldrtl-xxhdpi/stat_sys_phone_call_forward.png
new file mode 100644
index 0000000..8c68bf8
--- /dev/null
+++ b/res/drawable-ldrtl-xxhdpi/stat_sys_phone_call_forward.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_sim_sub1.png b/res/drawable-mdpi/ic_sim_sub1.png
new file mode 100644
index 0000000..8d04637
--- /dev/null
+++ b/res/drawable-mdpi/ic_sim_sub1.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_sim_sub2.png b/res/drawable-mdpi/ic_sim_sub2.png
new file mode 100644
index 0000000..f3201d6
--- /dev/null
+++ b/res/drawable-mdpi/ic_sim_sub2.png
Binary files differ
diff --git a/res/drawable-mdpi/stat_sys_phone_call_forward.png b/res/drawable-mdpi/stat_sys_phone_call_forward.png
index a21718c..5975172 100644
--- a/res/drawable-mdpi/stat_sys_phone_call_forward.png
+++ b/res/drawable-mdpi/stat_sys_phone_call_forward.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_sim_sub1.png b/res/drawable-xhdpi/ic_sim_sub1.png
new file mode 100644
index 0000000..2f512ee
--- /dev/null
+++ b/res/drawable-xhdpi/ic_sim_sub1.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_sim_sub2.png b/res/drawable-xhdpi/ic_sim_sub2.png
new file mode 100644
index 0000000..777a7a6
--- /dev/null
+++ b/res/drawable-xhdpi/ic_sim_sub2.png
Binary files differ
diff --git a/res/drawable-xhdpi/stat_sys_phone_call_forward.png b/res/drawable-xhdpi/stat_sys_phone_call_forward.png
index 578a42a..76ffc5c 100644
--- a/res/drawable-xhdpi/stat_sys_phone_call_forward.png
+++ b/res/drawable-xhdpi/stat_sys_phone_call_forward.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_sim_sub1.png b/res/drawable-xxhdpi/ic_sim_sub1.png
new file mode 100644
index 0000000..720c326
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_sim_sub1.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_sim_sub2.png b/res/drawable-xxhdpi/ic_sim_sub2.png
new file mode 100644
index 0000000..992aff6
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_sim_sub2.png
Binary files differ
diff --git a/res/drawable-xxhdpi/stat_sys_phone_call_forward.png b/res/drawable-xxhdpi/stat_sys_phone_call_forward.png
new file mode 100644
index 0000000..9bc3435
--- /dev/null
+++ b/res/drawable-xxhdpi/stat_sys_phone_call_forward.png
Binary files differ
diff --git a/res/drawable/stat_notify_voicemail_sub1.xml b/res/drawable/stat_notify_voicemail_sub1.xml
new file mode 100644
index 0000000..0884557
--- /dev/null
+++ b/res/drawable/stat_notify_voicemail_sub1.xml
@@ -0,0 +1,25 @@
+<!-- Copyright (C) 2017 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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:drawable="@android:drawable/stat_notify_voicemail"
+        android:gravity="center">
+    </item>
+    <item
+        android:drawable="@drawable/ic_sim_sub1"
+        android:gravity="center|top">
+    </item>
+</layer-list>
diff --git a/res/drawable/stat_notify_voicemail_sub2.xml b/res/drawable/stat_notify_voicemail_sub2.xml
new file mode 100644
index 0000000..3b63649
--- /dev/null
+++ b/res/drawable/stat_notify_voicemail_sub2.xml
@@ -0,0 +1,25 @@
+<!-- Copyright (C) 2017 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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:drawable="@android:drawable/stat_notify_voicemail"
+        android:gravity="center">
+    </item>
+    <item
+        android:drawable="@drawable/ic_sim_sub2"
+        android:gravity="center|top">
+    </item>
+</layer-list>
diff --git a/res/drawable/stat_sys_phone_call_forward_sub1.xml b/res/drawable/stat_sys_phone_call_forward_sub1.xml
new file mode 100644
index 0000000..93f4ff6
--- /dev/null
+++ b/res/drawable/stat_sys_phone_call_forward_sub1.xml
@@ -0,0 +1,26 @@
+<!-- Copyright (C) 2017 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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:drawable="@drawable/stat_sys_phone_call_forward"
+        android:gravity="center">
+    </item>
+    <item
+        android:drawable="@drawable/ic_sim_sub1"
+        android:autoMirrored="true"
+        android:gravity="start|bottom">
+    </item>
+</layer-list>
diff --git a/res/drawable/stat_sys_phone_call_forward_sub2.xml b/res/drawable/stat_sys_phone_call_forward_sub2.xml
new file mode 100644
index 0000000..fa91222
--- /dev/null
+++ b/res/drawable/stat_sys_phone_call_forward_sub2.xml
@@ -0,0 +1,26 @@
+<!-- Copyright (C) 2017 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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:drawable="@drawable/stat_sys_phone_call_forward"
+        android:gravity="center">
+    </item>
+    <item
+        android:drawable="@drawable/ic_sim_sub2"
+        android:autoMirrored="true"
+        android:gravity="start|bottom">
+    </item>
+</layer-list>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a765a6f..14cd952 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1079,7 +1079,7 @@
     <!-- In-call screen: call failure message displayed in an error dialog -->
     <string name="incall_error_call_failed">Call failed.</string>
     <!-- In-call screen: call failure message displayed in an error dialog -->
-    <string name="incall_error_cannot_add_call">Call cannot be added at this time.</string>
+    <string name="incall_error_cannot_add_call">Call cannot be added at this time.  You can try to reach out by sending a message.</string>
     <!-- In-call screen: message displayed in an error dialog -->
     <string name="incall_error_supp_service_unknown">Service not supported</string>
     <!-- In-call screen: message displayed in an error dialog -->
diff --git a/res/xml/network_setting_fragment.xml b/res/xml/network_setting_fragment.xml
index 0ea42bd..42a8e47 100644
--- a/res/xml/network_setting_fragment.xml
+++ b/res/xml/network_setting_fragment.xml
@@ -50,6 +50,28 @@
         android:persistent="false"
         android:summary="@string/enhanced_4g_lte_mode_summary"/>
 
+    <PreferenceCategory
+        android:key="calling"
+        android:title="@string/call_category">
+
+        <PreferenceScreen
+            android:key="wifi_calling_key"
+            android:title="@string/wifi_calling_settings_title">
+
+            <intent android:action="android.intent.action.MAIN"
+                    android:targetPackage="com.android.settings"
+                    android:targetClass="com.android.settings.Settings$WifiCallingSettingsActivity"/>
+
+        </PreferenceScreen>
+
+        <SwitchPreference
+            android:key="video_calling_key"
+            android:title="@string/video_calling_settings_title"
+            android:persistent="true"/>
+
+    </PreferenceCategory>
+
+
     <PreferenceScreen
         android:key="carrier_settings_euicc_key"
         android:title="@string/carrier_settings_euicc" />
diff --git a/src/com/android/phone/CallNotifier.java b/src/com/android/phone/CallNotifier.java
index 476ff06..d084e92 100644
--- a/src/com/android/phone/CallNotifier.java
+++ b/src/com/android/phone/CallNotifier.java
@@ -44,10 +44,15 @@
 import android.util.ArrayMap;
 import android.util.Log;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
+import com.android.internal.telephony.SubscriptionController;
+
 /**
  * Phone app module that listens for phone state changes and various other
  * events from the telephony layer, and triggers any resulting UI behavior
@@ -68,7 +73,8 @@
 
     private Map<Integer, CallNotifierPhoneStateListener> mPhoneStateListeners =
             new ArrayMap<Integer, CallNotifierPhoneStateListener>();
-
+    private Map<Integer, Boolean> mCFIStatus = new ArrayMap<Integer, Boolean>();
+    private Map<Integer, Boolean> mMWIStatus = new ArrayMap<Integer, Boolean>();
     private PhoneGlobals mApplication;
     private CallManager mCM;
     private BluetoothHeadset mBluetoothHeadset;
@@ -140,7 +146,7 @@
                 new OnSubscriptionsChangedListener() {
                     @Override
                     public void onSubscriptionsChanged() {
-                        updatePhoneStateListeners();
+                        updatePhoneStateListeners(true);
                     }
                 });
     }
@@ -571,14 +577,26 @@
                 SHOW_MESSAGE_NOTIFICATION_TIME);
     }
 
-    public void updatePhoneStateListeners() {
+    public void updatePhoneStateListeners(boolean isRefresh) {
         List<SubscriptionInfo> subInfos = mSubscriptionManager.getActiveSubscriptionInfoList();
 
-        // Unregister phone listeners for inactive subscriptions.
-        Iterator<Integer> itr = mPhoneStateListeners.keySet().iterator();
-        while (itr.hasNext()) {
-            int subId = itr.next();
+        // Sort sub id list based on slot id, so that CFI/MWI notifications will be updated for
+        // slot 0 first then slot 1. This is needed to ensure that when CFI or MWI is enabled for
+        // both slots, user always sees icon related to slot 0 on left side followed by that of
+        // slot 1.
+        List<Integer> subIdList = new ArrayList<Integer>(mPhoneStateListeners.keySet());
+        Collections.sort(subIdList, new Comparator<Integer>() {
+            public int compare(Integer sub1, Integer sub2) {
+                int slotId1 = SubscriptionController.getInstance().getSlotIndex(sub1);
+                int slotId2 = SubscriptionController.getInstance().getSlotIndex(sub2);
+                return slotId1 > slotId2 ? 0 : -1;
+            }
+        });
+
+        for (int subIdCounter = (subIdList.size() - 1); subIdCounter >= 0; subIdCounter--) {
+            int subId = subIdList.get(subIdCounter);
             if (subInfos == null || !containsSubId(subInfos, subId)) {
+                Log.d(LOG_TAG, "updatePhoneStateListeners: Hide the outstanding notifications.");
                 // Hide the outstanding notifications.
                 mApplication.notificationMgr.updateMwi(subId, false);
                 mApplication.notificationMgr.updateCfi(subId, false);
@@ -586,7 +604,16 @@
                 // Listening to LISTEN_NONE removes the listener.
                 mTelephonyManager.listen(
                         mPhoneStateListeners.get(subId), PhoneStateListener.LISTEN_NONE);
-                itr.remove();
+                mPhoneStateListeners.remove(subId);
+            } else {
+                Log.d(LOG_TAG, "updatePhoneStateListeners: update CF notifications.");
+
+                if (mCFIStatus.containsKey(subId)) {
+                    mApplication.notificationMgr.updateCfi(subId, mCFIStatus.get(subId));
+                }
+                if (mMWIStatus.containsKey(subId)) {
+                    mApplication.notificationMgr.updateMwi(subId, mMWIStatus.get(subId), isRefresh);
+                }
             }
         }
 
@@ -757,13 +784,16 @@
         @Override
         public void onMessageWaitingIndicatorChanged(boolean visible) {
             if (VDBG) log("onMessageWaitingIndicatorChanged(): " + this.mSubId + " " + visible);
-            mApplication.notificationMgr.updateMwi(this.mSubId, visible);
+            mMWIStatus.put(this.mSubId, visible);
+            updatePhoneStateListeners(false);
         }
 
         @Override
         public void onCallForwardingIndicatorChanged(boolean visible) {
-            if (VDBG) log("onCallForwardingIndicatorChanged(): " + this.mSubId + " " + visible);
-            mApplication.notificationMgr.updateCfi(this.mSubId, visible);
+            Log.i(LOG_TAG, "onCallForwardingIndicatorChanged(): subId=" + this.mSubId
+                    + ", visible=" + (visible ? "Y" : "N"));
+            mCFIStatus.put(this.mSubId, visible);
+            updatePhoneStateListeners(false);
         }
     };
 
diff --git a/src/com/android/phone/EmergencyCallbackModeExitDialog.java b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
index f5509b9..765c52d 100644
--- a/src/com/android/phone/EmergencyCallbackModeExitDialog.java
+++ b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
@@ -24,7 +24,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.DialogInterface.OnDismissListener;
+import android.content.DialogInterface.OnCancelListener;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
@@ -48,7 +48,7 @@
  *
  * @see EmergencyCallbackModeService
  */
-public class EmergencyCallbackModeExitDialog extends Activity implements OnDismissListener {
+public class EmergencyCallbackModeExitDialog extends Activity implements OnCancelListener {
 
     private static final String TAG = "EmergencyCallbackMode";
 
@@ -246,7 +246,7 @@
                                     finish();
                                 }
                             }).create();
-            mAlertDialog.setOnDismissListener(this);
+            mAlertDialog.setOnCancelListener(this);
             return mAlertDialog;
 
         case EXIT_ECM_IN_EMERGENCY_CALL_DIALOG:
@@ -263,7 +263,7 @@
                                     finish();
                                 }
                             }).create();
-            mAlertDialog.setOnDismissListener(this);
+            mAlertDialog.setOnCancelListener(this);
             return mAlertDialog;
 
         case EXIT_ECM_PROGRESS_DIALOG:
@@ -299,10 +299,10 @@
     }
 
     /**
-     * Closes activity when dialog is dismissed
+     * Closes activity when dialog is canceled
      */
     @Override
-    public void onDismiss(DialogInterface dialog) {
+    public void onCancel(DialogInterface dialog) {
         EmergencyCallbackModeExitDialog.this.setResult(RESULT_OK, (new Intent())
                 .putExtra(EXTRA_EXIT_ECM_RESULT, false));
         finish();
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index febc9f5..03865fe 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -27,6 +27,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.net.Uri;
 import android.os.AsyncResult;
 import android.os.Bundle;
@@ -37,10 +38,13 @@
 import android.os.UserManager;
 import android.preference.ListPreference;
 import android.preference.Preference;
+import android.preference.PreferenceCategory;
 import android.preference.PreferenceFragment;
 import android.preference.PreferenceScreen;
 import android.preference.SwitchPreference;
 import android.provider.Settings;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
@@ -56,11 +60,13 @@
 import android.view.ViewGroup;
 import android.widget.TabHost;
 
+import com.android.ims.ImsConfig;
 import com.android.ims.ImsManager;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.TelephonyIntents;
+import com.android.phone.settings.PhoneAccountSettingsFragment;
 import com.android.settingslib.RestrictedLockUtils;
 
 import java.util.ArrayList;
@@ -176,6 +182,9 @@
         private static final String BUTTON_CDMA_SYSTEM_SELECT_KEY = "cdma_system_select_key";
         private static final String BUTTON_CARRIER_SETTINGS_EUICC_KEY =
                 "carrier_settings_euicc_key";
+        private static final String BUTTON_WIFI_CALLING_KEY = "wifi_calling_key";
+        private static final String BUTTON_VIDEO_CALLING_KEY = "video_calling_key";
+        private static final String CATEGORY_CALLING_KEY = "calling";
 
         private final BroadcastReceiver mPhoneChangeReceiver = new PhoneChangeReceiver();
 
@@ -196,6 +205,9 @@
         private SwitchPreference mButton4glte;
         private Preference mLteDataServicePref;
         private Preference mEuiccSettingsPref;
+        private PreferenceCategory mCallingCategory;
+        private Preference mWiFiCallingPref;
+        private SwitchPreference mVideoCallingPref;
 
         private static final String iface = "rmnet0"; //TODO: this will go away
         private List<SubscriptionInfo> mActiveSubInfos;
@@ -315,6 +327,8 @@
                 Intent intent = new Intent(EuiccManager.ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS);
                 startActivity(intent);
                 return true;
+            } else if (preference == mWiFiCallingPref || preference == mVideoCallingPref) {
+                return false;
             } else {
                 // if the button is anything but the simple toggle preference,
                 // we'll need to disable all preferences to reject all click
@@ -514,6 +528,10 @@
             mButton4glte = (SwitchPreference)findPreference(BUTTON_4G_LTE_KEY);
             mButton4glte.setOnPreferenceChangeListener(this);
 
+            mCallingCategory = (PreferenceCategory) findPreference(CATEGORY_CALLING_KEY);
+            mWiFiCallingPref = findPreference(BUTTON_WIFI_CALLING_KEY);
+            mVideoCallingPref = (SwitchPreference) findPreference(BUTTON_VIDEO_CALLING_KEY);
+
             try {
                 Context con = activity.createPackageContext("com.android.systemui", 0);
                 int id = con.getResources().getIdentifier("config_show4GForLTE",
@@ -622,6 +640,9 @@
                     && ImsManager.isNonTtyOrTtyOnVolteEnabled(activity);
             mButton4glte.setChecked(enh4glteMode);
 
+            // Video calling and WiFi calling state might have changed.
+            updateCallingCategory();
+
             mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener);
 
             Log.i(LOG_TAG, "onResume:-");
@@ -826,6 +847,8 @@
                 }
             }
 
+            updateCallingCategory();
+
             ActionBar actionBar = activity.getActionBar();
             if (actionBar != null) {
                 // android.R.id.home will be triggered in onOptionsItemSelected()
@@ -913,6 +936,10 @@
             if (ps != null) {
                 ps.setEnabled(hasActiveSubscriptions);
             }
+            ps = findPreference(CATEGORY_CALLING_KEY);
+            if (ps != null) {
+                ps.setEnabled(hasActiveSubscriptions);
+            }
         }
 
         @Override
@@ -1066,6 +1093,17 @@
                     mPhone.setDataRoamingEnabled(false);
                 }
                 return true;
+            } else if (preference == mVideoCallingPref) {
+                // If mButton4glte is not checked, mVideoCallingPref should be disabled.
+                // So it only makes sense to call phoneMgr.enableVideoCalling if it's checked.
+                if (mButton4glte.isChecked()) {
+                    PhoneGlobals.getInstance().phoneMgr.enableVideoCalling((boolean) objValue);
+                    return true;
+                } else {
+                    loge("mVideoCallingPref should be disabled if mButton4glte is not checked.");
+                    mVideoCallingPref.setEnabled(false);
+                    return false;
+                }
             }
 
             updateBody();
@@ -1400,6 +1438,117 @@
             }
         }
 
+        private void updateWiFiCallState() {
+            if (mWiFiCallingPref == null || mCallingCategory == null) {
+                return;
+            }
+
+            boolean removePref = false;
+            final PhoneAccountHandle simCallManager =
+                    TelecomManager.from(getContext()).getSimCallManager();
+
+            if (simCallManager != null) {
+                Intent intent = PhoneAccountSettingsFragment.buildPhoneAccountConfigureIntent(
+                        getContext(), simCallManager);
+                if (intent != null) {
+                    PackageManager pm = mPhone.getContext().getPackageManager();
+                    List<ResolveInfo> resolutions = pm.queryIntentActivities(intent, 0);
+                    if (!resolutions.isEmpty()) {
+                        mWiFiCallingPref.setTitle(resolutions.get(0).loadLabel(pm));
+                        mWiFiCallingPref.setSummary(null);
+                        mWiFiCallingPref.setIntent(intent);
+                    } else {
+                        removePref = true;
+                    }
+                } else {
+                    removePref = true;
+                }
+            } else if (!ImsManager.isWfcEnabledByPlatform(mPhone.getContext())
+                    || !ImsManager.isWfcProvisionedOnDevice(mPhone.getContext())) {
+                removePref = true;
+            } else {
+                int resId = com.android.internal.R.string.wifi_calling_off_summary;
+                if (ImsManager.isWfcEnabledByUser(mPhone.getContext())) {
+                    boolean isRoaming = mButtonDataRoam.isChecked();
+                    int wfcMode = ImsManager.getWfcMode(mPhone.getContext(), isRoaming);
+                    switch (wfcMode) {
+                        case ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY:
+                            resId = com.android.internal.R.string.wfc_mode_wifi_only_summary;
+                            break;
+                        case ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED:
+                            resId = com.android.internal.R.string
+                                    .wfc_mode_cellular_preferred_summary;
+                            break;
+                        case ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED:
+                            resId = com.android.internal.R.string.wfc_mode_wifi_preferred_summary;
+                            break;
+                        default:
+                            if (DBG) log("Unexpected WFC mode value: " + wfcMode);
+                    }
+                }
+                mWiFiCallingPref.setSummary(resId);
+            }
+
+            if (removePref) {
+                mCallingCategory.removePreference(mWiFiCallingPref);
+            } else {
+                mCallingCategory.addPreference(mWiFiCallingPref);
+            }
+        }
+
+        private void updateVideoCallState() {
+            if (mVideoCallingPref == null || mCallingCategory == null) {
+                return;
+            }
+
+            PersistableBundle carrierConfig = PhoneGlobals.getInstance()
+                    .getCarrierConfigForSubId(mPhone.getSubId());
+
+            boolean removePref = false;
+
+            if (ImsManager.isVtEnabledByPlatform(mPhone.getContext())
+                    && ImsManager.isVtProvisionedOnDevice(mPhone.getContext())
+                    && (carrierConfig.getBoolean(
+                            CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS)
+                            || mPhone.mDcTracker.isDataEnabled())) {
+                boolean enhanced4gLteEnabled = mButton4glte.isChecked();
+                mVideoCallingPref.setEnabled(enhanced4gLteEnabled);
+                boolean currentValue = enhanced4gLteEnabled
+                        ? PhoneGlobals.getInstance().phoneMgr.isVideoCallingEnabled(
+                        getContext().getOpPackageName()) : false;
+                mVideoCallingPref.setChecked(currentValue);
+                if (enhanced4gLteEnabled) {
+                    mVideoCallingPref.setOnPreferenceChangeListener(this);
+                }
+            } else {
+                removePref = true;
+            }
+
+            if (removePref) {
+                mCallingCategory.removePreference(mVideoCallingPref);
+            } else {
+                mCallingCategory.addPreference(mVideoCallingPref);
+            }
+        }
+
+        private void updateCallingCategory() {
+            if (mCallingCategory == null) {
+                return;
+            }
+
+            updateWiFiCallState();
+            updateVideoCallState();
+
+            // If all items in calling category is removed, we remove it from
+            // the screen. Otherwise we'll see title of the category but nothing
+            // is in there.
+            if (mCallingCategory.getPreferenceCount() == 0) {
+                getPreferenceScreen().removePreference(mCallingCategory);
+            } else {
+                getPreferenceScreen().addPreference(mCallingCategory);
+            }
+        }
+
         private static void log(String msg) {
             Log.d(LOG_TAG, msg);
         }
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index 9a90f5b..1764d4c 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -133,27 +133,6 @@
         mSubscriptionManager = SubscriptionManager.from(mContext);
         mTelecomManager = TelecomManager.from(mContext);
         mTelephonyManager = (TelephonyManager) app.getSystemService(Context.TELEPHONY_SERVICE);
-
-        mSubscriptionManager.addOnSubscriptionsChangedListener(
-                new OnSubscriptionsChangedListener() {
-                    @Override
-                    public void onSubscriptionsChanged() {
-                        updateActivePhonesMwi();
-                    }
-                });
-    }
-
-    public void updateActivePhonesMwi() {
-        List<SubscriptionInfo> subInfos = mSubscriptionManager.getActiveSubscriptionInfoList();
-
-        if (subInfos == null) {
-            return;
-        }
-
-        for (int i = 0; i < subInfos.size(); i++) {
-            int subId = subInfos.get(i).getSubscriptionId();
-            refreshMwi(subId);
-        }
     }
 
     /**
@@ -205,7 +184,7 @@
         if (mMwiVisible.containsKey(subId)) {
             boolean mwiVisible = mMwiVisible.get(subId);
             if (mwiVisible) {
-                updateMwi(subId, mwiVisible, true /* isRefresh */);
+                mApp.notifier.updatePhoneStateListeners(true);
             }
         }
     }
@@ -273,6 +252,10 @@
             }
 
             int resId = android.R.drawable.stat_notify_voicemail;
+            if (mTelephonyManager.getPhoneCount() > 1) {
+                resId = (phone.getPhoneId() == 0) ? R.drawable.stat_notify_voicemail_sub1
+                        : R.drawable.stat_notify_voicemail_sub2;
+            }
 
             // This Notification can get a lot fancier once we have more
             // information about the current voicemail messages.
@@ -473,7 +456,7 @@
      * @param visible true if there are messages waiting
      */
     /* package */ void updateCfi(int subId, boolean visible) {
-        if (DBG) log("updateCfi(): " + visible);
+        logi("updateCfi: subId= " + subId + ", visible=" + (visible ? "Y" : "N"));
         if (visible) {
             // If Unconditional Call Forwarding (forward all calls) for VOICE
             // is enabled, just show a notification.  We'll default to expanded
@@ -493,14 +476,18 @@
             }
 
             String notificationTitle;
+            int resId = R.drawable.stat_sys_phone_call_forward;
             if (mTelephonyManager.getPhoneCount() > 1) {
+                int slotId = SubscriptionManager.getSlotIndex(subId);
+                resId = (slotId == 0) ? R.drawable.stat_sys_phone_call_forward_sub1
+                        : R.drawable.stat_sys_phone_call_forward_sub2;
                 notificationTitle = subInfo.getDisplayName().toString();
             } else {
                 notificationTitle = mContext.getString(R.string.labelCF);
             }
 
             Notification.Builder builder = new Notification.Builder(mContext)
-                    .setSmallIcon(R.drawable.stat_sys_phone_call_forward)
+                    .setSmallIcon(resId)
                     .setColor(subInfo.getIconTint())
                     .setContentTitle(notificationTitle)
                     .setContentText(mContext.getString(R.string.sum_cfu_enabled_indicator))
@@ -531,10 +518,17 @@
                         userHandle);
             }
         } else {
-            mNotificationManager.cancelAsUser(
-                    Integer.toString(subId) /* tag */,
-                    CALL_FORWARD_NOTIFICATION,
-                    UserHandle.ALL);
+            List<UserInfo> users = mUserManager.getUsers(true);
+            for (UserInfo user : users) {
+                if (user.isManagedProfile()) {
+                    continue;
+                }
+                UserHandle userHandle = user.getUserHandle();
+                mNotificationManager.cancelAsUser(
+                        Integer.toString(subId) /* tag */,
+                        CALL_FORWARD_NOTIFICATION,
+                        userHandle);
+            }
         }
     }
 
@@ -691,4 +685,8 @@
     private void log(String msg) {
         Log.d(LOG_TAG, msg);
     }
+
+    private void logi(String msg) {
+        Log.i(LOG_TAG, msg);
+    }
 }
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index a420100..48a283a 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -67,6 +67,7 @@
                 return DisconnectCause.LOCAL;
 
             case android.telephony.DisconnectCause.NORMAL:
+            case android.telephony.DisconnectCause.NORMAL_UNSPECIFIED:
                 return DisconnectCause.REMOTE;
 
             case android.telephony.DisconnectCause.OUTGOING_CANCELED: