Merge "Support hiding manage IMS conference call button"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a5df742..69620cd 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -173,6 +173,8 @@
          presses home. -->
     <uses-permission android:name="android.permission.STOP_APP_SWITCHES" />
     <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
+    <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
+    <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
 
     <application android:name="PhoneApp"
             android:persistent="true"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8366ae3..3140d16 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -533,6 +533,8 @@
     <string name="data_usage_title">Data usage</string>
     <!-- Summary about how much data has been used in a date range [CHAR LIMIT=100] -->
     <string name="data_usage_template"><xliff:g name="amount" example="200 MB">%1$s</xliff:g> mobile data used between <xliff:g name="date_range" example="Jan 1 -- Feb 2">%2$s</xliff:g></string>
+    <!-- Mobile network settings screen, Advanced button to show more items when clicked [CHAR LIMIT=50] -->
+    <string name="advanced_options_title">Advanced</string>
     <!-- Mobile network settings screen, name of the option to manage carrier profiles on devices which support embedded carrier profiles -->
     <string name="carrier_settings_euicc">Carrier</string>
     <!-- Keywords used to search the carrier menu for managing carrier profiles on devices which support embedded carrier profiles. eSIM/eUICC is embedded SIM card used to store this data.  -->
@@ -543,6 +545,14 @@
     <string name="mobile_data_settings_title">Mobile Data</string>
     <!-- Mobile network settings screen, title of Mobile Data switch preference -->
     <string name="mobile_data_settings_summary">Access data using mobile network</string>
+    <!-- Message to show when user trying to turn off mobile data, in single sim mode [CHAR LIMIT=100]-->
+    <string name="data_usage_disable_mobile">Turn off mobile data?</string>
+    <!-- When a SIM preference hasn't been selected yet, this string is displayed as the pref summary until the user chooses a SIM subscription from the preference list [CHAR LIMIT=50] -->
+    <string name="sim_selection_required_pref">Selection required</string>
+    <!-- Title asking user if they wish to change the default sim for cellular data.  [CHAR LIMIT=30] -->
+    <string name="sim_change_data_title">Change data SIM?</string>
+    <!-- Message confirming the user wishes to change the default data SIM from one to another.  [CHAR LIMIT=NONE] -->
+    <string name="sim_change_data_message">Use <xliff:g id="new_sim">%1$s</xliff:g> instead of <xliff:g id="old_sim">%2$s</xliff:g> for mobile data?</string>
     <!-- Mobile network settings screen, title of Wi-Fi calling setting -->
     <string name="wifi_calling_settings_title">Wi-Fi calling</string>
     <!-- Mobile network settings screen, title of Video calling setting -->
diff --git a/res/values/styles_preference.xml b/res/values/styles_preference.xml
index 02c5cb7..ceea4a6 100644
--- a/res/values/styles_preference.xml
+++ b/res/values/styles_preference.xml
@@ -30,7 +30,7 @@
     </style>
 
     <style name="SettingsPreferenceCategory" parent="@*android:style/Preference.DeviceDefault.Category">
-        <item name="android:layout">@layout/preference_category_material_settings</item>
+        <item name="android:layout">@layout/preference_category_material_settings_with_divider</item>
     </style>
 
     <style name="SettingsDialogPreference" parent="@*android:style/Preference.DeviceDefault.DialogPreference">
diff --git a/res/xml/gsm_umts_options.xml b/res/xml/gsm_umts_options.xml
index 4c74d73..3b054d6 100644
--- a/res/xml/gsm_umts_options.xml
+++ b/res/xml/gsm_umts_options.xml
@@ -33,14 +33,15 @@
             android:persistent="false"/>
     </com.android.phone.NetworkOperators>
 
-    <PreferenceScreen
-        android:key="button_apn_key"
-        android:title="@string/apn_settings"
-        android:persistent="false">
-
-        <!-- The launching Intent will be defined thru code as we need to pass some Extra -->
-
-    </PreferenceScreen>
+    <!--We want separate APN setting from reset of settings because-->
+    <!--we want user to change it with caution.-->
+    <PreferenceCategory
+        android:key="category_apn_key">
+        <Preference
+            android:key="button_apn_key"
+            android:title="@string/apn_settings"
+            android:persistent="false" />
+    </PreferenceCategory>
 
     <PreferenceScreen
         android:key="carrier_settings_key"
diff --git a/res/xml/network_setting_fragment.xml b/res/xml/network_setting_fragment.xml
index 42a8e47..106d3cb 100644
--- a/res/xml/network_setting_fragment.xml
+++ b/res/xml/network_setting_fragment.xml
@@ -21,6 +21,11 @@
         android:title="@string/cdma_lte_data_service">
     </PreferenceScreen>
 
+    <com.android.phone.MobileDataPreference
+        android:key="mobile_data_enable"
+        android:title="@string/mobile_data_settings_title"
+        android:summary="@string/mobile_data_settings_summary"/>
+
     <com.android.phone.RestrictedSwitchPreference
         android:key="button_roaming_key"
         android:title="@string/roaming"
@@ -28,6 +33,19 @@
         android:summaryOn="@string/roaming_enable"
         android:summaryOff="@string/roaming_disable"/>
 
+    <com.android.phone.DataUsagePreference
+        android:key="data_usage_summary"
+        android:title="@string/data_usage_title" />
+
+    <com.android.phone.AdvancedOptionsPreference
+        android:key="advanced_options"/>
+
+    <SwitchPreference
+        android:key="enhanced_4g_lte"
+        android:title="@string/enhanced_4g_lte_mode_title"
+        android:persistent="false"
+        android:summary="@string/enhanced_4g_lte_mode_summary"/>
+
     <ListPreference
         android:key="preferred_network_mode_key"
         android:title="@string/preferred_network_mode_title"
@@ -44,11 +62,9 @@
         android:entryValues="@array/enabled_networks_values"
         android:dialogTitle="@string/preferred_network_mode_dialogtitle" />
 
-    <SwitchPreference
-        android:key="enhanced_4g_lte"
-        android:title="@string/enhanced_4g_lte_mode_title"
-        android:persistent="false"
-        android:summary="@string/enhanced_4g_lte_mode_summary"/>
+    <Preference
+        android:key="carrier_settings_euicc_key"
+        android:title="@string/carrier_settings_euicc" />
 
     <PreferenceCategory
         android:key="calling"
@@ -71,9 +87,4 @@
 
     </PreferenceCategory>
 
-
-    <PreferenceScreen
-        android:key="carrier_settings_euicc_key"
-        android:title="@string/carrier_settings_euicc" />
-
 </PreferenceScreen>
diff --git a/src/com/android/phone/AdvancedOptionsPreference.java b/src/com/android/phone/AdvancedOptionsPreference.java
new file mode 100644
index 0000000..1987395
--- /dev/null
+++ b/src/com/android/phone/AdvancedOptionsPreference.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+package com.android.phone;
+
+import android.content.Context;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * Customized preference class representing the "Advanced" button that expands to fields that
+ * are hidden by default.
+ */
+public class AdvancedOptionsPreference extends Preference {
+    public AdvancedOptionsPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onBindView(View view) {
+        super.onBindView(view);
+
+        setIcon(R.drawable.ic_expand_more);
+        setTitle(R.string.advanced_options_title);
+        TextView summary = view.findViewById(android.R.id.summary);
+        summary.setMaxLines(1);
+    }
+}
diff --git a/src/com/android/phone/DataUsagePreference.java b/src/com/android/phone/DataUsagePreference.java
new file mode 100644
index 0000000..174ff6a
--- /dev/null
+++ b/src/com/android/phone/DataUsagePreference.java
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+package com.android.phone;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.net.NetworkTemplate;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+import android.text.format.Formatter;
+import android.util.AttributeSet;
+
+import com.android.settingslib.net.DataUsageController;
+
+/**
+ * The preference that shows mobile data usage summary and
+ * leads to mobile data usage list page.
+ */
+public class DataUsagePreference extends Preference {
+
+    private NetworkTemplate mTemplate;
+    private int mSubId;
+
+    public DataUsagePreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    /**
+     * After creating this preference, this functions needs to be called to
+     * initialize which subID it connects to.
+     */
+    public void initialize(int subId) {
+        Activity activity = (Activity) getContext();
+
+        mSubId = subId;
+        mTemplate = getNetworkTemplate(activity, subId);
+
+        DataUsageController controller = new DataUsageController(activity);
+
+        DataUsageController.DataUsageInfo usageInfo = controller.getDataUsageInfo(mTemplate);
+        setSummary(activity.getString(R.string.data_usage_template,
+                Formatter.formatFileSize(activity, usageInfo.usageLevel), usageInfo.period));
+        setIntent(getIntent());
+    }
+
+    @Override
+    public Intent getIntent() {
+        Bundle args = new Bundle();
+        Intent intent = new Intent(Settings.ACTION_MOBILE_DATA_USAGE);
+
+        intent.putExtra(Settings.EXTRA_NETWORK_TEMPLATE, mTemplate);
+        intent.putExtra(Settings.EXTRA_SUB_ID, mSubId);
+
+        return intent;
+    }
+
+    private NetworkTemplate getNetworkTemplate(Activity activity, int subId) {
+        TelephonyManager tm = (TelephonyManager) activity
+                .getSystemService(Context.TELEPHONY_SERVICE);
+        NetworkTemplate mobileAll = NetworkTemplate.buildTemplateMobileAll(
+                tm.getSubscriberId(subId));
+        return NetworkTemplate.normalize(mobileAll,
+                tm.getMergedSubscriberIds());
+    }
+}
diff --git a/src/com/android/phone/GsmUmtsOptions.java b/src/com/android/phone/GsmUmtsOptions.java
index 697fca8..909e9bd 100644
--- a/src/com/android/phone/GsmUmtsOptions.java
+++ b/src/com/android/phone/GsmUmtsOptions.java
@@ -35,13 +35,15 @@
 public class GsmUmtsOptions {
     private static final String LOG_TAG = "GsmUmtsOptions";
 
-    private PreferenceScreen mButtonAPNExpand;
+    private Preference mButtonAPNExpand;
+    private Preference mCategoryAPNExpand;
     private TwoStatePreference mButtonAutoSelect;
     private NetworkSelectListPreference mButtonOperatorSelection;
 
     private NetworkOperators mNetworkOperator;
 
     private static final String BUTTON_APN_EXPAND_KEY = "button_apn_key";
+    private static final String CATEGORY_APN_EXPAND_KEY = "category_apn_key";
     private static final String BUTTON_CARRIER_SETTINGS_KEY = "carrier_settings_key";
 
     public static final String EXTRA_SUB_ID = "sub_id";
@@ -61,7 +63,8 @@
 
     protected void create() {
         mPrefFragment.addPreferencesFromResource(R.xml.gsm_umts_options);
-        mButtonAPNExpand = (PreferenceScreen) mPrefScreen.findPreference(BUTTON_APN_EXPAND_KEY);
+        mButtonAPNExpand = mPrefScreen.findPreference(BUTTON_APN_EXPAND_KEY);
+        mCategoryAPNExpand = mPrefScreen.findPreference(CATEGORY_APN_EXPAND_KEY);
 
         mNetworkOperator = (NetworkOperators) mPrefScreen
                 .findPreference(NetworkOperators.CATEGORY_NETWORK_OPERATORS_KEY);
@@ -71,7 +74,7 @@
         boolean removedNetworkOperatorsCategory = false;
         if (PhoneFactory.getDefaultPhone().getPhoneType() != PhoneConstants.PHONE_TYPE_GSM) {
             log("Not a GSM phone");
-            mButtonAPNExpand.setEnabled(false);
+            mCategoryAPNExpand.setEnabled(false);
             mNetworkOperator.setEnabled(false);
         } else {
             log("Not a CDMA phone");
@@ -85,8 +88,7 @@
             // Note: these settings used to be controlled with overlays in
             // Telephony/res/values/config.xml
             if (!carrierConfig.getBoolean(CarrierConfigManager.KEY_APN_EXPAND_BOOL)
-                    && mButtonAPNExpand != null) {
-                mPrefScreen.removePreference(mButtonAPNExpand);
+                    && mCategoryAPNExpand != null) {
                 removedAPNExpand = true;
             }
             if (!carrierConfig.getBoolean(
@@ -134,6 +136,8 @@
                             return true;
                         }
             });
+        } else {
+            mPrefScreen.removePreference(mCategoryAPNExpand);
         }
 
         if (!removedNetworkOperatorsCategory) {
diff --git a/src/com/android/phone/MobileDataPreference.java b/src/com/android/phone/MobileDataPreference.java
new file mode 100644
index 0000000..e1d0528
--- /dev/null
+++ b/src/com/android/phone/MobileDataPreference.java
@@ -0,0 +1,304 @@
+/*
+ * 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.
+ */
+
+package com.android.phone;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.preference.DialogPreference;
+import android.preference.PreferenceScreen;
+import android.provider.Settings.Global;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.Checkable;
+
+import java.util.List;
+
+/**
+ * Customized Preference to enable / disable mobile data.
+ * Basically copy of with com.android.settings.CellDataPreference.
+ */
+public class MobileDataPreference extends DialogPreference {
+
+    private static final boolean DBG = false;
+    private static final String TAG = "MobileDataPreference";
+
+    public int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+    public boolean mChecked;
+    public boolean mMultiSimDialog;
+    private TelephonyManager mTelephonyManager;
+    private SubscriptionManager mSubscriptionManager;
+
+    public MobileDataPreference(Context context, AttributeSet attrs) {
+        super(context, attrs, com.android.internal.R.attr.switchPreferenceStyle);
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Parcelable s) {
+        CellDataState state = (CellDataState) s;
+        super.onRestoreInstanceState(state.getSuperState());
+        mTelephonyManager = TelephonyManager.from(getContext());
+        mChecked = state.mChecked;
+        mMultiSimDialog = state.mMultiSimDialog;
+        if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            mSubId = state.mSubId;
+            setKey(getKey() + mSubId);
+        }
+        notifyChanged();
+    }
+
+    @Override
+    protected Parcelable onSaveInstanceState() {
+        CellDataState state = new CellDataState(super.onSaveInstanceState());
+        state.mChecked = mChecked;
+        state.mMultiSimDialog = mMultiSimDialog;
+        state.mSubId = mSubId;
+        return state;
+    }
+
+    @Override
+    protected void onAttachedToActivity() {
+        super.onAttachedToActivity();
+        mListener.setListener(true, mSubId, getContext());
+    }
+
+    @Override
+    protected void onPrepareForRemoval() {
+        mListener.setListener(false, mSubId, getContext());
+        super.onPrepareForRemoval();
+    }
+
+    /**
+     * Initialize this preference with subId.
+     */
+    public void initialize(int subId) {
+        if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            throw new IllegalArgumentException("MobileDataPreference needs a SubscriptionInfo");
+        }
+        mSubscriptionManager = SubscriptionManager.from(getContext());
+        mTelephonyManager = TelephonyManager.from(getContext());
+        if (mSubId != subId) {
+            mSubId = subId;
+            setKey(getKey() + subId);
+        }
+        updateChecked();
+    }
+
+    private void updateChecked() {
+        setChecked(mTelephonyManager.getDataEnabled(mSubId));
+    }
+
+    @Override
+    public void performClick(PreferenceScreen preferenceScreen) {
+        final SubscriptionInfo currentSir = mSubscriptionManager.getActiveSubscriptionInfo(
+                mSubId);
+        final SubscriptionInfo nextSir = mSubscriptionManager.getDefaultDataSubscriptionInfo();
+        boolean isMultiSim = (mTelephonyManager.getSimCount() > 1);
+        if (mChecked) {
+            // If the device is single SIM or is enabling data on the active data SIM then forgo
+            // the pop-up.
+            if (isMultiSim || (nextSir != null && currentSir != null
+                    && currentSir.getSubscriptionId() == nextSir.getSubscriptionId())) {
+                setMobileDataEnabled(false);
+                if (nextSir != null && currentSir != null
+                        && currentSir.getSubscriptionId() == nextSir.getSubscriptionId()) {
+                    disableDataForOtherSubscriptions(mSubId);
+                }
+                return;
+            }
+            // disabling data; show confirmation dialog which eventually
+            // calls setMobileDataEnabled() once user confirms.
+            mMultiSimDialog = false;
+            super.performClick(preferenceScreen);
+        } else {
+            // If we are showing the Sim Card tile then we are a Multi-Sim device.
+            if (isMultiSim) {
+                mMultiSimDialog = true;
+                if (nextSir != null && currentSir != null
+                        && currentSir.getSubscriptionId() == nextSir.getSubscriptionId()) {
+                    setMobileDataEnabled(true);
+                    disableDataForOtherSubscriptions(mSubId);
+                    return;
+                }
+                super.performClick(preferenceScreen);
+            } else {
+                setMobileDataEnabled(true);
+            }
+        }
+    }
+
+    private void setMobileDataEnabled(boolean enabled) {
+        if (DBG) Log.d(TAG, "setMobileDataEnabled(" + enabled + "," + mSubId + ")");
+        mTelephonyManager.setDataEnabled(mSubId, enabled);
+        setChecked(enabled);
+    }
+
+    private void setChecked(boolean checked) {
+        if (mChecked == checked) return;
+        mChecked = checked;
+        notifyChanged();
+    }
+
+    @Override
+    protected void onBindView(View view) {
+        super.onBindView(view);
+        View checkableView = view.findViewById(com.android.internal.R.id.switch_widget);
+        checkableView.setClickable(false);
+        ((Checkable) checkableView).setChecked(mChecked);
+    }
+
+    @Override
+    protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
+        if (mMultiSimDialog) {
+            showMultiSimDialog(builder);
+        } else {
+            showDisableDialog(builder);
+        }
+    }
+
+    private void showDisableDialog(AlertDialog.Builder builder) {
+        builder.setTitle(null)
+                .setMessage(R.string.data_usage_disable_mobile)
+                .setPositiveButton(android.R.string.ok, this)
+                .setNegativeButton(android.R.string.cancel, null);
+    }
+
+    private void showMultiSimDialog(AlertDialog.Builder builder) {
+        final SubscriptionInfo currentSir = mSubscriptionManager.getActiveSubscriptionInfo(mSubId);
+        final SubscriptionInfo nextSir = mSubscriptionManager.getDefaultDataSubscriptionInfo();
+
+        final String previousName = (nextSir == null)
+                ? getContext().getResources().getString(R.string.sim_selection_required_pref)
+                : nextSir.getDisplayName().toString();
+
+        builder.setTitle(R.string.sim_change_data_title);
+        builder.setMessage(getContext().getString(R.string.sim_change_data_message,
+                String.valueOf(currentSir != null ? currentSir.getDisplayName() : null),
+                previousName));
+
+        builder.setPositiveButton(R.string.ok, this);
+        builder.setNegativeButton(R.string.cancel, null);
+    }
+
+    private void disableDataForOtherSubscriptions(int subId) {
+        List<SubscriptionInfo> subInfoList = mSubscriptionManager.getActiveSubscriptionInfoList();
+        if (subInfoList != null) {
+            for (SubscriptionInfo subInfo : subInfoList) {
+                if (subInfo.getSubscriptionId() != subId) {
+                    mTelephonyManager.setDataEnabled(subInfo.getSubscriptionId(), false);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        if (which != DialogInterface.BUTTON_POSITIVE) {
+            return;
+        }
+        if (mMultiSimDialog) {
+            mSubscriptionManager.setDefaultDataSubId(mSubId);
+            setMobileDataEnabled(true);
+            disableDataForOtherSubscriptions(mSubId);
+        } else {
+            // TODO: extend to modify policy enabled flag.
+            setMobileDataEnabled(false);
+        }
+    }
+
+    private final DataStateListener mListener = new DataStateListener() {
+        @Override
+        public void onChange(boolean selfChange) {
+            updateChecked();
+        }
+    };
+
+    /**
+     * Listener that listens mobile data state change.
+     */
+    public abstract static class DataStateListener extends ContentObserver {
+        public DataStateListener() {
+            super(new Handler(Looper.getMainLooper()));
+        }
+
+        /**
+         * Set / Unset data state listening, specifying subId.
+         */
+        public void setListener(boolean listening, int subId, Context context) {
+            if (listening) {
+                Uri uri = Global.getUriFor(Global.MOBILE_DATA);
+                if (TelephonyManager.getDefault().getSimCount() != 1) {
+                    uri = Global.getUriFor(Global.MOBILE_DATA + subId);
+                }
+                context.getContentResolver().registerContentObserver(uri, false, this);
+            } else {
+                context.getContentResolver().unregisterContentObserver(this);
+            }
+        }
+    }
+
+    /**
+     * Class that represents state of mobile data state.
+     * Used by onSaveInstanceState and onRestoreInstanceState.
+     */
+    public static class CellDataState extends BaseSavedState {
+        public int mSubId;
+        public boolean mChecked;
+        public boolean mMultiSimDialog;
+
+        public CellDataState(Parcelable base) {
+            super(base);
+        }
+
+        public CellDataState(Parcel source) {
+            super(source);
+            mChecked = source.readByte() != 0;
+            mMultiSimDialog = source.readByte() != 0;
+            mSubId = source.readInt();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeByte((byte) (mChecked ? 1 : 0));
+            dest.writeByte((byte) (mMultiSimDialog ? 1 : 0));
+            dest.writeInt(mSubId);
+        }
+
+        public static final Creator<CellDataState> CREATOR = new Creator<CellDataState>() {
+            @Override
+            public CellDataState createFromParcel(Parcel source) {
+                return new CellDataState(source);
+            }
+
+            @Override
+            public CellDataState[] newArray(int size) {
+                return new CellDataState[size];
+            }
+        };
+    }
+}
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index cca6703..8743e55 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -67,6 +67,8 @@
 import com.android.ims.ImsConfig;
 import com.android.ims.ImsException;
 import com.android.ims.ImsManager;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneFactory;
@@ -181,14 +183,17 @@
         private static final String BUTTON_ENABLED_NETWORKS_KEY = "enabled_networks_key";
         private static final String BUTTON_4G_LTE_KEY = "enhanced_4g_lte";
         private static final String BUTTON_CELL_BROADCAST_SETTINGS = "cell_broadcast_settings";
-        private static final String BUTTON_APN_EXPAND_KEY = "button_apn_key";
         private static final String BUTTON_CARRIER_SETTINGS_KEY = "carrier_settings_key";
         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 BUTTON_MOBILE_DATA_ENABLE_KEY = "mobile_data_enable";
+        private static final String BUTTON_DATA_USAGE_KEY = "data_usage_summary";
+        private static final String BUTTON_ADVANCED_OPTIONS_KEY = "advanced_options";
         private static final String CATEGORY_CALLING_KEY = "calling";
+        private static final String CATEGORY_APN_EXPAND_KEY = "category_apn_key";
 
         private final BroadcastReceiver mPhoneChangeReceiver = new PhoneChangeReceiver();
 
@@ -199,10 +204,14 @@
         private static final String UP_ACTIVITY_CLASS =
                 "com.android.settings.Settings$WirelessSettingsActivity";
 
+        //Information that needs to save into Bundle.
+        private static final String EXPAND_ADVANCED_FIELDS = "expand_advanced_fields";
+
         private SubscriptionManager mSubscriptionManager;
         private TelephonyManager mTelephonyManager;
 
         //UI objects
+        private AdvancedOptionsPreference mAdvancedOptions;
         private ListPreference mButtonPreferredNetworkMode;
         private ListPreference mButtonEnabledNetworks;
         private RestrictedSwitchPreference mButtonDataRoam;
@@ -213,6 +222,8 @@
         private Preference mWiFiCallingPref;
         private SwitchPreference mVideoCallingPref;
         private NetworkSelectListPreference mButtonNetworkSelect;
+        private MobileDataPreference mMobileDataPref;
+        private DataUsagePreference mDataUsagePref;
 
         private static final String iface = "rmnet0"; //TODO: this will go away
         private List<SubscriptionInfo> mActiveSubInfos;
@@ -222,6 +233,7 @@
         private ImsManager mImsMgr;
         private MyHandler mHandler;
         private boolean mOkClicked;
+        private boolean mExpandAdvancedFields;
 
         // We assume the the value returned by mTabHost.getCurrentTab() == slotId
         private TabHost mTabHost;
@@ -322,6 +334,8 @@
         @Override
         public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
                                              Preference preference) {
+            sendMetricsEventPreferenceClicked(preferenceScreen, preference);
+
             /** TODO: Refactor and get rid of the if's using subclasses */
             final int phoneSubId = mPhone.getSubId();
             if (preference.getKey().equals(BUTTON_4G_LTE_KEY)) {
@@ -380,8 +394,13 @@
                 Intent intent = new Intent(EuiccManager.ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS);
                 startActivity(intent);
                 return true;
-            } else if (preference == mWiFiCallingPref || preference == mVideoCallingPref) {
+            } else if (preference == mWiFiCallingPref || preference == mVideoCallingPref
+                    || preference == mMobileDataPref || preference == mDataUsagePref) {
                 return false;
+            } else if (preference == mAdvancedOptions) {
+                mExpandAdvancedFields = true;
+                updateBody();
+                return true;
             } else {
                 // if the button is anything but the simple toggle preference,
                 // we'll need to disable all preferences to reject all click
@@ -561,6 +580,15 @@
         }
 
         @Override
+        public void onSaveInstanceState(Bundle outState) {
+            super.onSaveInstanceState(outState);
+
+            // If advanced fields are already expanded, we save it and expand it
+            // when it's re-created.
+            outState.putBoolean(EXPAND_ADVANCED_FIELDS, mExpandAdvancedFields);
+        }
+
+        @Override
         public void onCreate(Bundle icicle) {
             Log.i(LOG_TAG, "onCreate:+");
             super.onCreate(icicle);
@@ -577,6 +605,10 @@
             mTelephonyManager = (TelephonyManager) activity.getSystemService(
                             Context.TELEPHONY_SERVICE);
 
+            if (icicle != null) {
+                mExpandAdvancedFields = icicle.getBoolean(EXPAND_ADVANCED_FIELDS, false);
+            }
+
             bindNetworkQueryService();
 
             if (mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
@@ -593,6 +625,8 @@
             mCallingCategory = (PreferenceCategory) findPreference(CATEGORY_CALLING_KEY);
             mWiFiCallingPref = findPreference(BUTTON_WIFI_CALLING_KEY);
             mVideoCallingPref = (SwitchPreference) findPreference(BUTTON_VIDEO_CALLING_KEY);
+            mMobileDataPref = (MobileDataPreference) findPreference(BUTTON_MOBILE_DATA_ENABLE_KEY);
+            mDataUsagePref = (DataUsagePreference) findPreference(BUTTON_DATA_USAGE_KEY);
 
             try {
                 Context con = activity.createPackageContext("com.android.systemui", 0);
@@ -613,6 +647,8 @@
                     BUTTON_PREFERED_NETWORK_MODE);
             mButtonEnabledNetworks = (ListPreference) prefSet.findPreference(
                     BUTTON_ENABLED_NETWORKS_KEY);
+            mAdvancedOptions = (AdvancedOptionsPreference) prefSet.findPreference(
+                    BUTTON_ADVANCED_OPTIONS_KEY);
             mButtonDataRoam.setOnPreferenceChangeListener(this);
 
             mLteDataServicePref = prefSet.findPreference(BUTTON_CDMA_LTE_DATA_SERVICE_KEY);
@@ -624,6 +660,8 @@
             int max = mSubscriptionManager.getActiveSubscriptionInfoCountMax();
             mActiveSubInfos = new ArrayList<SubscriptionInfo>(max);
 
+            setAndvancedButtonSummary();
+
             IntentFilter intentFilter = new IntentFilter(
                     TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
             activity.registerReceiver(mPhoneChangeReceiver, intentFilter);
@@ -716,35 +754,83 @@
             return mActiveSubInfos.size() > 0;
         }
 
+        private void updateBodyBasicFields(Activity activity, PreferenceScreen prefSet,
+                int phoneSubId, boolean hasActiveSubscriptions) {
+            Context context = activity.getApplicationContext();
+
+            prefSet.addPreference(mMobileDataPref);
+            prefSet.addPreference(mButtonDataRoam);
+            prefSet.addPreference(mDataUsagePref);
+
+            // Customized preferences needs to be initialized with subId.
+            mMobileDataPref.initialize(phoneSubId);
+            mDataUsagePref.initialize(phoneSubId);
+
+            // Initialize states of mButtonDataRoam.
+            mButtonDataRoam.setChecked(mPhone.getDataRoamingEnabled());
+            mButtonDataRoam.setDisabledByAdmin(false);
+            if (mButtonDataRoam.isEnabled()) {
+                if (RestrictedLockUtils.hasBaseUserRestriction(context,
+                        UserManager.DISALLOW_DATA_ROAMING, UserHandle.myUserId())) {
+                    mButtonDataRoam.setEnabled(false);
+                } else {
+                    mButtonDataRoam.checkRestrictionAndSetDisabled(
+                            UserManager.DISALLOW_DATA_ROAMING);
+                }
+            }
+
+            mMobileDataPref.setEnabled(hasActiveSubscriptions);
+            mButtonDataRoam.setEnabled(hasActiveSubscriptions);
+            mDataUsagePref.setEnabled(hasActiveSubscriptions);
+        }
+
         private void updateBody() {
             final Activity activity = getActivity();
+            final PreferenceScreen prefSet = getPreferenceScreen();
+            final int phoneSubId = mPhone.getSubId();
+            final boolean hasActiveSubscriptions = hasActiveSubscriptions();
+
             if (activity == null || activity.isDestroyed()) {
                 Log.e(LOG_TAG, "updateBody with no valid activity.");
                 return;
             }
-            Context context = activity.getApplicationContext();
-            PreferenceScreen prefSet = getPreferenceScreen();
+
+            if (prefSet == null) {
+                Log.e(LOG_TAG, "updateBody with no null prefSet.");
+                return;
+            }
+
+            prefSet.removeAll();
+
+            updateBodyBasicFields(activity, prefSet, phoneSubId, hasActiveSubscriptions);
+
+            if (mExpandAdvancedFields) {
+                updateBodyAdvancedFields(activity, prefSet, phoneSubId, hasActiveSubscriptions);
+            } else {
+                prefSet.addPreference(mAdvancedOptions);
+                mAdvancedOptions.setEnabled(hasActiveSubscriptions);
+            }
+        }
+
+        private void updateBodyAdvancedFields(Activity activity, PreferenceScreen prefSet,
+                int phoneSubId, boolean hasActiveSubscriptions) {
             boolean isLteOnCdma = mPhone.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE;
-            final int phoneSubId = mPhone.getSubId();
 
             if (DBG) {
                 log("updateBody: isLteOnCdma=" + isLteOnCdma + " phoneSubId=" + phoneSubId);
             }
 
-            if (prefSet != null) {
-                prefSet.removeAll();
-                prefSet.addPreference(mButtonDataRoam);
-                prefSet.addPreference(mButtonPreferredNetworkMode);
-                prefSet.addPreference(mButtonEnabledNetworks);
-                prefSet.addPreference(mButton4glte);
-                if (showEuiccSettings(getActivity())) {
-                    prefSet.addPreference(mEuiccSettingsPref);
-                    String spn = mTelephonyManager.getSimOperatorName();
-                    if (TextUtils.isEmpty(spn)) {
-                        mEuiccSettingsPref.setSummary(null);
-                    } else {
-                        mEuiccSettingsPref.setSummary(spn);
-                    }
+            prefSet.addPreference(mButtonPreferredNetworkMode);
+            prefSet.addPreference(mButtonEnabledNetworks);
+            prefSet.addPreference(mButton4glte);
+
+            if (showEuiccSettings(getActivity())) {
+                prefSet.addPreference(mEuiccSettingsPref);
+                String spn = mTelephonyManager.getSimOperatorName();
+                if (TextUtils.isEmpty(spn)) {
+                    mEuiccSettingsPref.setSummary(null);
+                } else {
+                    mEuiccSettingsPref.setSummary(spn);
                 }
             }
 
@@ -942,7 +1028,6 @@
             }
 
             // Get the networkMode from Settings.System and displays it
-            mButtonDataRoam.setChecked(mPhone.getDataRoamingEnabled());
             mButtonEnabledNetworks.setValue(Integer.toString(settingsNetworkMode));
             mButtonPreferredNetworkMode.setValue(Integer.toString(settingsNetworkMode));
             UpdatePreferredNetworkModeSummary(settingsNetworkMode);
@@ -960,7 +1045,6 @@
              * but you do need to remember that this all needs to work when subscriptions
              * change dynamically such as when hot swapping sims.
              */
-            boolean hasActiveSubscriptions = hasActiveSubscriptions();
             boolean canChange4glte =
                     (mTelephonyManager.getCallState() == TelephonyManager.CALL_STATE_IDLE)
                             && ImsManager.isNonTtyOrTtyOnVolteEnabled(
@@ -972,17 +1056,7 @@
             int enhanced4glteModeTitleId = useVariant4glteTitle ?
                     R.string.enhanced_4g_lte_mode_title_variant :
                     R.string.enhanced_4g_lte_mode_title;
-            mButtonDataRoam.setDisabledByAdmin(false);
-            mButtonDataRoam.setEnabled(hasActiveSubscriptions);
-            if (mButtonDataRoam.isEnabled()) {
-                if (RestrictedLockUtils.hasBaseUserRestriction(context,
-                        UserManager.DISALLOW_DATA_ROAMING, UserHandle.myUserId())) {
-                    mButtonDataRoam.setEnabled(false);
-                } else {
-                    mButtonDataRoam.checkRestrictionAndSetDisabled(
-                            UserManager.DISALLOW_DATA_ROAMING);
-                }
-            }
+
             mButtonPreferredNetworkMode.setEnabled(hasActiveSubscriptions);
             mButtonEnabledNetworks.setEnabled(hasActiveSubscriptions);
             mButton4glte.setTitle(enhanced4glteModeTitleId);
@@ -994,7 +1068,7 @@
             if (ps != null) {
                 ps.setEnabled(hasActiveSubscriptions);
             }
-            ps = findPreference(BUTTON_APN_EXPAND_KEY);
+            ps = findPreference(CATEGORY_APN_EXPAND_KEY);
             if (ps != null) {
                 ps.setEnabled(hasActiveSubscriptions);
             }
@@ -1685,8 +1759,8 @@
                 mGsmUmtsOptions = new GsmUmtsOptions(this, prefSet, mPhone.getSubId(),
                         mNetworkQueryService);
             }
-            PreferenceScreen apnExpand =
-                    (PreferenceScreen) prefSet.findPreference(BUTTON_APN_EXPAND_KEY);
+            PreferenceCategory apnExpand =
+                    (PreferenceCategory) prefSet.findPreference(CATEGORY_APN_EXPAND_KEY);
             PreferenceCategory networkOperatorCategory =
                     (PreferenceCategory) prefSet.findPreference(
                             NetworkOperators.CATEGORY_NETWORK_OPERATORS_KEY);
@@ -1741,6 +1815,40 @@
             }
             return false;
         }
+
+        private void sendMetricsEventPreferenceClicked(
+                PreferenceScreen preferenceScreen, Preference preference) {
+            if (preference == mMobileDataPref) {
+                MetricsLogger.action(getContext(),
+                        MetricsEvent.ACTION_MOBILE_NETWORK_MOBILE_DATA_TOGGLE,
+                        ((MobileDataPreference) preference).mChecked);
+            } else if (preference == mDataUsagePref) {
+                MetricsLogger.action(getContext(),
+                        MetricsEvent.ACTION_MOBILE_NETWORK_DATA_USAGE);
+            }
+            // TODO: add Metrics constants for other preferences and send events here accordingly.
+        }
+
+        private void setAndvancedButtonSummary() {
+            if (mAdvancedOptions == null) {
+                return;
+            }
+
+            StringBuilder summary = new StringBuilder();
+            summary.append(mButton4glte.getTitle());
+            summary.append(", ");
+            summary.append(mButtonPreferredNetworkMode.getTitle());
+            summary.append(", ");
+            summary.append(mButtonEnabledNetworks.getTitle());
+            summary.append(", ");
+            summary.append(mEuiccSettingsPref.getTitle());
+            summary.append(", ");
+            summary.append(mWiFiCallingPref.getTitle());
+            summary.append(", ");
+            summary.append(mVideoCallingPref.getTitle());
+            mAdvancedOptions.setSummary(summary.toString());
+        }
+
     }
 }
 
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index d3dd93c..46bca71 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -39,8 +39,8 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
-import android.os.Process;
 import android.os.PersistableBundle;
+import android.os.Process;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -77,8 +77,9 @@
 import android.util.Slog;
 
 import com.android.ims.ImsManager;
-import com.android.ims.internal.IImsServiceController;
-import com.android.ims.internal.IImsServiceFeatureListener;
+import com.android.ims.internal.IImsMMTelFeature;
+import com.android.ims.internal.IImsRcsFeature;
+import com.android.ims.internal.IImsServiceFeatureCallback;
 import com.android.internal.telephony.CallManager;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.CellNetworkScanResult;
@@ -2646,16 +2647,37 @@
     }
 
     /**
-     * Returns the {@link IImsServiceController} that corresponds to the given slot Id and IMS
-     * feature or {@link null} if the service is not available. If an ImsServiceController is
-     * available, the {@link IImsServiceFeatureListener} callback is registered as a listener for
-     * feature updates.
+     * Returns the {@link IImsMMTelFeature} that corresponds to the given slot Id for the MMTel
+     * feature or {@link null} if the service is not available. If the feature is available, the
+     * {@link IImsServiceFeatureCallback} callback is registered as a listener for feature updates.
      */
-    public IImsServiceController getImsServiceControllerAndListen(int slotIndex, int feature,
-            IImsServiceFeatureListener callback) {
+    public IImsMMTelFeature getMMTelFeatureAndListen(int slotId,
+            IImsServiceFeatureCallback callback) {
         enforceModifyPermission();
-        return PhoneFactory.getImsResolver().getImsServiceControllerAndListen(slotIndex, feature,
-                callback);
+        return PhoneFactory.getImsResolver().getMMTelFeatureAndListen(slotId, callback);
+    }
+
+    /**
+     * Returns the {@link IImsMMTelFeature} that corresponds to the given slot Id for the MMTel
+     * feature during emergency calling or {@link null} if the service is not available. If the
+     * feature is available, the {@link IImsServiceFeatureCallback} callback is registered as a
+     * listener for feature updates.
+     */
+    public IImsMMTelFeature getEmergencyMMTelFeatureAndListen(int slotId,
+            IImsServiceFeatureCallback callback) {
+        enforceModifyPermission();
+        return PhoneFactory.getImsResolver().getEmergencyMMTelFeatureAndListen(slotId, callback);
+    }
+
+    /**
+     * Returns the {@link IImsRcsFeature} that corresponds to the given slot Id for the RCS
+     * feature during emergency calling or {@link null} if the service is not available. If the
+     * feature is available, the {@link IImsServiceFeatureCallback} callback is registered as a
+     * listener for feature updates.
+     */
+    public IImsRcsFeature getRcsFeatureAndListen(int slotId, IImsServiceFeatureCallback callback) {
+        enforceModifyPermission();
+        return PhoneFactory.getImsResolver().getRcsFeatureAndListen(slotId, callback);
     }
 
     public void setImsRegistrationState(boolean registered) {
diff --git a/src/com/android/phone/settings/VoicemailSettingsActivity.java b/src/com/android/phone/settings/VoicemailSettingsActivity.java
index 4d55421..74b8e4e 100644
--- a/src/com/android/phone/settings/VoicemailSettingsActivity.java
+++ b/src/com/android/phone/settings/VoicemailSettingsActivity.java
@@ -32,6 +32,7 @@
 import android.preference.SwitchPreference;
 import android.provider.ContactsContract.CommonDataKinds;
 import android.provider.Settings;
+import android.telecom.PhoneAccountHandle;
 import android.telephony.CarrierConfigManager;
 import android.telephony.TelephonyManager;
 import android.text.BidiFormatter;
@@ -48,6 +49,7 @@
 import com.android.internal.telephony.util.NotificationChannelController;
 import com.android.phone.EditPhoneNumberPreference;
 import com.android.phone.PhoneGlobals;
+import com.android.phone.PhoneUtils;
 import com.android.phone.R;
 import com.android.phone.SubscriptionInfoHelper;
 
@@ -222,6 +224,12 @@
         mShowVoicemailPreference = (icicle == null) &&
                 TextUtils.equals(getIntent().getAction(), ACTION_ADD_VOICEMAIL);
 
+        PhoneAccountHandle phoneAccountHandle = (PhoneAccountHandle)
+                getIntent().getParcelableExtra(TelephonyManager.EXTRA_PHONE_ACCOUNT_HANDLE);
+        if (phoneAccountHandle != null) {
+            getIntent().putExtra(SubscriptionInfoHelper.SUB_ID_EXTRA,
+                    PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccountHandle));
+        }
         mSubscriptionInfoHelper = new SubscriptionInfoHelper(this, getIntent());
         mSubscriptionInfoHelper.setActionBarTitle(
                 getActionBar(), getResources(), R.string.voicemail_settings_with_label);