Merge "Update task affinity and parent activity for all exported activities."
diff --git a/res/layout/data_usage_summary_preference.xml b/res/layout/data_usage_summary_preference.xml
new file mode 100644
index 0000000..445e7cd
--- /dev/null
+++ b/res/layout/data_usage_summary_preference.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2018 The Android Open Source Project
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at"+
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingStart="@dimen/preference_no_icon_padding_start"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:orientation="vertical"
+    android:background="@drawable/selectable_card_grey"
+    android:selectable="false"
+    style="@style/EntityHeader">
+
+    <TextView
+        android:id="@+id/usage_title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+        android:textColor="?android:attr/textColorSecondary"
+        android:paddingBottom="5dp"
+        android:text="@string/data_usage_title" />
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="5dp"
+        android:fontFamily="@*android:string/config_headlineFontFamily"
+        android:textColor="?android:attr/colorAccent"
+        android:textAppearance="@android:style/TextAppearance.Material.Large" />
+
+    <TextView
+        android:id="@android:id/summary"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+        android:textColor="?android:attr/textColorSecondary"
+        android:paddingBottom="5dp" />
+
+    <com.android.settings.widget.LinearColorBar
+        android:id="@+id/color_bar"
+        android:layout_width="match_parent"
+        android:layout_height="28dp" />
+
+    <LinearLayout
+        android:id="@+id/label_bar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="2dp"
+        android:orientation="horizontal">
+
+        <TextView android:id="@android:id/text1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+            android:textColor="?android:attr/textColorSecondary" />
+
+        <Space
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1" />
+
+        <TextView android:id="@android:id/text2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+            android:textColor="?android:attr/textColorSecondary" />
+
+    </LinearLayout>
+
+    <TextView
+        android:id="@+id/cycle_left_time"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingBottom="5dp" />
+
+    <TextView
+        android:id="@+id/carrier_and_update"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingBottom="5dp" />
+
+    <Button
+        android:id="@+id/launch_mdp_app_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="left"
+        android:text="@string/launch_mdp_app_text"
+        style="@style/ActionPrimaryButton" />
+
+    <TextView
+        android:id="@+id/data_limits"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingBottom="5dp" />
+
+</LinearLayout>
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2540640..72db253 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -5844,6 +5844,8 @@
     <string name="data_usage_enable_3g">2G-3G data</string>
     <!-- Toggle switch title for enabling 4G data network connection. [CHAR LIMIT=32] -->
     <string name="data_usage_enable_4g">4G data</string>
+    <!-- Toggle switch title for enabling roaming on the primary data SIM card. [CHAR LIMIT=32] -->
+    <string name="data_roaming_enable_mobile">Roaming</string>
 
     <!-- Data Usage Foreground label.  [CHAR LIMIT=40] -->
     <string name="data_usage_forground_label">Foreground:</string>
@@ -8655,6 +8657,27 @@
         <item quantity="other"><xliff:g id="count" example="10">%1$d</xliff:g> apps allowed to use unrestricted data when Data Saver is on</item>
     </plurals>
 
+    <!-- Data usage title text [CHAR LIMIT=30] -->
+    <string name="data_usage_title">Primary data</string>
+
+    <!-- Data usage string [CHAR LIMIT=30] -->
+    <string name="data_used"><xliff:g name="bytes" example="2 GB">^1</xliff:g> used</string>
+
+    <!-- Optional part of data usage showing the remaining amount [CHAR LIMIT=30] -->
+    <string name="data_remaining"><xliff:g name="bytes" example="2 GB">, ^1</xliff:g> left</string>
+
+    <!-- Informational text about time left in billing cycle [CHAR LIMIT=30] -->
+    <string name="cycle_left_time_text"><xliff:g name="time" example="2d">%1$s</xliff:g> left in this cycle</string>
+
+    <!-- Informational text about carrier and update time [CHAR LIMIT=30] -->
+    <string name="carrier_and_update_text">Updated by <xliff:g name="carrier" example="T-mobile">%1$s</xliff:g> <xliff:g name="time" example="3m">%2$s</xliff:g></string>
+
+    <!-- Informational text about update time only, without carrier [CHAR LIMIT=30] -->
+    <string name="no_carrier_update_text">Updated <xliff:g name="time" example="3m">%1$s</xliff:g></string>
+
+    <!-- Button to launch external data plan app [CHAR LIMIT=30] -->
+    <string name="launch_mdp_app_text">VIEW PLAN</string>
+
     <!-- Name of Data Saver screens [CHAR LIMIT=30] -->
     <string name="data_saver_title">Data saver</string>
 
diff --git a/res/xml/battery_saver_settings.xml b/res/xml/battery_saver_settings.xml
index 47199c2..9e32440 100644
--- a/res/xml/battery_saver_settings.xml
+++ b/res/xml/battery_saver_settings.xml
@@ -16,6 +16,7 @@
 
 <PreferenceScreen
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:title="@string/battery_saver"
     android:key="battery_saver">
 
@@ -23,12 +24,15 @@
     <SwitchPreference
         android:key="auto_battery_saver"
         android:title="@string/battery_saver_auto_title"
-        android:summary="@string/battery_saver_auto_summary"/>
+        android:summary="@string/battery_saver_auto_summary"
+        settings:controller="com.android.settings.fuelgauge.batterysaver.AutoBatterySaverPreferenceController"/>
+
     <com.android.settings.widget.SeekBarPreference
         android:key="battery_saver_seek_bar"
         android:title="@string/battery_saver_seekbar_title"
         android:max="75"
         android:min="5"/>
+
     <com.android.settings.applications.LayoutPreference
         android:key="battery_saver_button_container"
         android:selectable="false"
diff --git a/res/xml/connected_devices_advanced.xml b/res/xml/connected_devices_advanced.xml
index 0b75abf..83a63e4 100644
--- a/res/xml/connected_devices_advanced.xml
+++ b/res/xml/connected_devices_advanced.xml
@@ -25,8 +25,8 @@
       android:title="@string/bluetooth_settings_title"
       android:icon="@drawable/ic_settings_bluetooth"
       android:summary="@string/bluetooth_pref_summary"
-      settings:controller="com.android.settings.bluetooth.BluetoothSwitchPreferenceController"
-      android:order="-7"/>
+      android:order="-7"
+      settings:controller="com.android.settings.bluetooth.BluetoothSwitchPreferenceController"/>
 
     <SwitchPreference
         android:key="toggle_nfc"
@@ -54,6 +54,7 @@
         android:title="@string/bluetooth_on_while_driving_pref"
         android:icon="@drawable/ic_settings_bluetooth"
         android:summary="@string/bluetooth_on_while_driving_summary"
+        settings:controller="com.android.settings.connecteddevice.BluetoothOnWhileDrivingPreferenceController"
         android:order="-2"/>
 
     <Preference
diff --git a/res/xml/data_usage.xml b/res/xml/data_usage.xml
index 958459c..88d7f32 100644
--- a/res/xml/data_usage.xml
+++ b/res/xml/data_usage.xml
@@ -20,24 +20,8 @@
     android:key="data_usage_screen"
     android:title="@string/data_usage_summary_title">
 
-    <PreferenceCategory
-        android:key="data_usage_category"
-        android:title="@string/usage">
-
-        <com.android.settings.SummaryPreference
+    <com.android.settings.datausage.DataUsageSummaryPreference
             android:key="status_header"
             android:selectable="false" />
 
-        <Preference
-            android:key="limit_summary"
-            android:selectable="false"
-            settings:allowDividerBelow="true" />
-
-        <com.android.settings.datausage.DataSaverPreference
-            android:key="restrict_background"
-            android:title="@string/data_saver_title"
-            android:fragment="com.android.settings.datausage.DataSaverSummary" />
-
-    </PreferenceCategory>
-
 </PreferenceScreen>
diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml
index 4d0c992..3cafc3f 100644
--- a/res/xml/display_settings.xml
+++ b/res/xml/display_settings.xml
@@ -43,8 +43,9 @@
     <com.android.settingslib.RestrictedSwitchPreference
         android:key="auto_brightness"
         android:title="@string/auto_brightness_title"
-        settings:keywords="@string/keywords_display_auto_brightness"
         android:summary="@string/auto_brightness_summary"
+        settings:keywords="@string/keywords_display_auto_brightness"
+        settings:controller="com.android.settings.display.AutoBrightnessPreferenceController"
         settings:useAdminDisabledSummary="true"
         settings:userRestriction="no_config_brightness" />
 
diff --git a/res/xml/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml
index dafd36c..00eaa7e 100644
--- a/res/xml/security_dashboard_settings.xml
+++ b/res/xml/security_dashboard_settings.xml
@@ -79,7 +79,8 @@
         <SwitchPreference
             android:key="visiblepattern_profile"
             android:summary="@string/summary_placeholder"
-            android:title="@string/lockpattern_settings_enable_visible_pattern_title_profile" />
+            android:title="@string/lockpattern_settings_enable_visible_pattern_title_profile"
+            settings:controller="com.android.settings.security.VisiblePatternProfilePreferenceController"/>
 
         <Preference
             android:key="fingerprint_settings_profile"
@@ -103,7 +104,8 @@
         <SwitchPreference
             android:key="show_password"
             android:title="@string/show_password"
-            android:summary="@string/show_password_summary" />
+            android:summary="@string/show_password_summary"
+            settings:controller="com.android.settings.security.ShowPasswordPreferenceController"/>
 
     </PreferenceCategory>
 
diff --git a/res/xml/security_lockscreen_settings.xml b/res/xml/security_lockscreen_settings.xml
index 1da1de5..3d3bfd0 100644
--- a/res/xml/security_lockscreen_settings.xml
+++ b/res/xml/security_lockscreen_settings.xml
@@ -16,6 +16,7 @@
 
 <PreferenceScreen
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:key="security_lockscreen_settings_screen"
     android:title="@string/lockscreen_settings_title">
 
@@ -36,7 +37,8 @@
     <SwitchPreference
         android:key="security_setting_lockdown_enabled"
         android:title="@string/lockdown_settings_title"
-        android:summary="@string/lockdown_settings_summary" />
+        android:summary="@string/lockdown_settings_summary"
+        settings:controller="com.android.settings.security.LockdownButtonPreferenceController"/>
 
     <PreferenceCategory
         android:key="security_setting_lock_screen_notif_work_header"
diff --git a/src/com/android/settings/core/BasePreferenceController.java b/src/com/android/settings/core/BasePreferenceController.java
index 01d98b8..4bd7ba4 100644
--- a/src/com/android/settings/core/BasePreferenceController.java
+++ b/src/com/android/settings/core/BasePreferenceController.java
@@ -30,6 +30,8 @@
  * Abstract class to consolidate utility between preference controllers and act as an interface
  * for Slices. The abstract classes that inherit from this class will act as the direct interfaces
  * for each type when plugging into Slices.
+ *
+ * TODO (b/73074893) Add Lifecycle Setting method.
  */
 public abstract class BasePreferenceController extends AbstractPreferenceController {
 
diff --git a/src/com/android/settings/datausage/DataUsageSummary.java b/src/com/android/settings/datausage/DataUsageSummary.java
index b63cee3..339de7c 100644
--- a/src/com/android/settings/datausage/DataUsageSummary.java
+++ b/src/com/android/settings/datausage/DataUsageSummary.java
@@ -18,7 +18,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.net.NetworkPolicyManager;
 import android.net.NetworkTemplate;
 import android.os.Bundle;
 import android.os.UserManager;
@@ -28,6 +27,7 @@
 import android.support.v7.preference.PreferenceScreen;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionPlan;
 import android.text.BidiFormatter;
 import android.text.Spannable;
 import android.text.SpannableString;
@@ -40,7 +40,6 @@
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
-import com.android.settings.SummaryPreference;
 import com.android.settings.Utils;
 import com.android.settings.dashboard.SummaryLoader;
 import com.android.settings.search.BaseSearchIndexProvider;
@@ -65,7 +64,6 @@
     public static final String KEY_RESTRICT_BACKGROUND = "restrict_background";
 
     private static final String KEY_STATUS_HEADER = "status_header";
-    private static final String KEY_LIMIT_SUMMARY = "limit_summary";
 
     // Mobile data keys
     public static final String KEY_MOBILE_USAGE_TITLE = "mobile_category";
@@ -77,13 +75,9 @@
     public static final String KEY_WIFI_USAGE_TITLE = "wifi_category";
     public static final String KEY_WIFI_DATA_USAGE = "wifi_data_usage";
 
-    private DataUsageController mDataUsageController;
-    private DataUsageInfoController mDataInfoController;
-    private SummaryPreference mSummaryPreference;
-    private Preference mLimitPreference;
+    private DataUsageSummaryPreference mSummaryPreference;
+    private DataUsageSummaryPreferenceController mSummaryController;
     private NetworkTemplate mDefaultTemplate;
-    private int mDataUsageTemplate;
-    private NetworkPolicyEditor mPolicyEditor;
 
     @Override
     public int getHelpResource() {
@@ -95,25 +89,20 @@
         super.onCreate(icicle);
 
         final Context context = getContext();
-        NetworkPolicyManager policyManager = NetworkPolicyManager.from(context);
-        mPolicyEditor = new NetworkPolicyEditor(policyManager);
 
         boolean hasMobileData = DataUsageUtils.hasMobileData(context);
-        mDataUsageController = new DataUsageController(context);
-        mDataInfoController = new DataUsageInfoController();
 
         int defaultSubId = DataUsageUtils.getDefaultSubscriptionId(context);
         if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
             hasMobileData = false;
         }
         mDefaultTemplate = DataUsageUtils.getDefaultTemplate(context, defaultSubId);
-        mSummaryPreference = (SummaryPreference) findPreference(KEY_STATUS_HEADER);
+        mSummaryPreference = (DataUsageSummaryPreference) findPreference(KEY_STATUS_HEADER);
 
         if (!hasMobileData || !isAdmin()) {
             removePreference(KEY_RESTRICT_BACKGROUND);
         }
         if (hasMobileData) {
-            mLimitPreference = findPreference(KEY_LIMIT_SUMMARY);
             List<SubscriptionInfo> subscriptions =
                     services.mSubscriptionManager.getActiveSubscriptionInfoList();
             if (subscriptions == null || subscriptions.size() == 0) {
@@ -127,10 +116,6 @@
                     addMobileSection(subInfo.getSubscriptionId());
                 }
             }
-            mSummaryPreference.setSelectable(true);
-        } else {
-            removePreference(KEY_LIMIT_SUMMARY);
-            mSummaryPreference.setSelectable(false);
         }
         boolean hasWifiRadio = DataUsageUtils.hasWifiRadio(context);
         if (hasWifiRadio) {
@@ -139,10 +124,6 @@
         if (hasEthernet(context)) {
             addEthernetSection();
         }
-        mDataUsageTemplate = hasMobileData ? R.string.cell_data_template
-                : hasWifiRadio ? R.string.wifi_data_template
-                : R.string.ethernet_data_template;
-
         setHasOptionsMenu(true);
     }
 
@@ -189,7 +170,11 @@
 
     @Override
     protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
-        return null;
+        final ArrayList<AbstractPreferenceController> controllers = new ArrayList<>();
+        mSummaryController =
+                new DataUsageSummaryPreferenceController(context);
+        controllers.add(mSummaryController);
+        return controllers;
     }
 
     private void addMobileSection(int subId) {
@@ -269,36 +254,6 @@
     }
 
     private void updateState() {
-        DataUsageController.DataUsageInfo info = mDataUsageController.getDataUsageInfo(
-                mDefaultTemplate);
-        Context context = getContext();
-        mDataInfoController.updateDataLimit(info,
-                services.mPolicyEditor.getPolicy(mDefaultTemplate));
-
-        if (mSummaryPreference != null) {
-            mSummaryPreference.setTitle(
-                    formatUsage(context, getString(mDataUsageTemplate), info.usageLevel));
-            final long limit = mDataInfoController.getSummaryLimit(info);
-            mSummaryPreference.setSummary(info.period);
-            if (limit <= 0) {
-                mSummaryPreference.setChartEnabled(false);
-            } else {
-                mSummaryPreference.setChartEnabled(true);
-                mSummaryPreference.setLabels(Formatter.formatFileSize(context, 0),
-                        Formatter.formatFileSize(context, limit));
-                mSummaryPreference.setRatios(info.usageLevel / (float) limit, 0,
-                        (limit - info.usageLevel) / (float) limit);
-            }
-        }
-        if (mLimitPreference != null && (info.warningLevel > 0 || info.limitLevel > 0)) {
-            String warning = Formatter.formatFileSize(context, info.warningLevel);
-            String limit = Formatter.formatFileSize(context, info.limitLevel);
-            mLimitPreference.setSummary(getString(info.limitLevel <= 0 ? R.string.cell_warning_only
-                    : R.string.cell_warning_and_limit, warning, limit));
-        } else if (mLimitPreference != null) {
-            mLimitPreference.setSummary(null);
-        }
-
         PreferenceScreen screen = getPreferenceScreen();
         for (int i = 1; i < screen.getPreferenceCount(); i++) {
             ((TemplatePreferenceCategory) screen.getPreference(i)).pushTemplates(services);
@@ -323,6 +278,7 @@
     @Override
     public void updateDataUsage() {
         updateState();
+        mSummaryController.updateState(mSummaryPreference);
     }
 
     private static class SummaryProvider
@@ -341,17 +297,39 @@
         @Override
         public void setListening(boolean listening) {
             if (listening) {
-                DataUsageController.DataUsageInfo info = mDataController.getDataUsageInfo();
-                String used;
-                if (info == null) {
-                    used = Formatter.formatFileSize(mActivity, 0);
-                } else if (info.limitLevel <= 0) {
-                    used = Formatter.formatFileSize(mActivity, info.usageLevel);
-                } else {
-                    used = Utils.formatPercentage(info.usageLevel, info.limitLevel);
-                }
                 mSummaryLoader.setSummary(this,
-                        mActivity.getString(R.string.data_usage_summary_format, used));
+                        mActivity.getString(R.string.data_usage_summary_format, formatUsedData()));
+            }
+        }
+
+        private String formatUsedData() {
+            SubscriptionManager subscriptionManager = (SubscriptionManager) mActivity
+                .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+            int defaultSubId = subscriptionManager.getDefaultSubscriptionId();
+            if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+                return formatFallbackData();
+            }
+            SubscriptionPlan dfltPlan = DataUsageSummaryPreferenceController
+                    .getPrimaryPlan(subscriptionManager, defaultSubId);
+            if (dfltPlan == null) {
+                return formatFallbackData();
+            }
+            if (DataUsageSummaryPreferenceController.unlimited(dfltPlan.getDataLimitBytes())) {
+                return Formatter.formatFileSize(mActivity, dfltPlan.getDataUsageBytes());
+            } else {
+                return Utils.formatPercentage(dfltPlan.getDataUsageBytes(),
+                    dfltPlan.getDataLimitBytes());
+            }
+        }
+
+        private String formatFallbackData() {
+            DataUsageController.DataUsageInfo info = mDataController.getDataUsageInfo();
+            if (info == null) {
+                return Formatter.formatFileSize(mActivity, 0);
+            } else if (info.limitLevel <= 0) {
+                return Formatter.formatFileSize(mActivity, info.usageLevel);
+            } else {
+                return Utils.formatPercentage(info.usageLevel, info.limitLevel);
             }
         }
     }
diff --git a/src/com/android/settings/datausage/DataUsageSummaryPreference.java b/src/com/android/settings/datausage/DataUsageSummaryPreference.java
new file mode 100644
index 0000000..984df02
--- /dev/null
+++ b/src/com/android/settings/datausage/DataUsageSummaryPreference.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2018 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.settings.datausage;
+
+import android.content.Context;
+import android.content.Intent;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settings.SummaryPreference;
+import com.android.settingslib.utils.StringUtil;
+
+import libcore.util.Objects;
+
+/**
+ * Provides a summary of data usage.
+ */
+public class DataUsageSummaryPreference extends SummaryPreference {
+
+    private int mNumPlans;
+    /** The ending time of the billing cycle in milliseconds since epoch. */
+    private long mCycleEndTimeMs;
+    /** The time of the last update in standard milliseconds since the epoch */
+    private long mSnapshotTimeMs;
+    /** Name of carrier, or null if not available */
+    private CharSequence mCarrierName;
+    private String mLimitInfoText;
+    private Intent mLaunchIntent;
+
+    public DataUsageSummaryPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setLayoutResource(R.layout.data_usage_summary_preference);
+    }
+
+    public void setLimitInfo(String text) {
+        if (!Objects.equal(text, mLimitInfoText)) {
+            mLimitInfoText = text;
+            notifyChanged();
+        }
+    }
+
+    public void setUsageInfo(long cycleEnd, long snapshotTime, CharSequence carrierName,
+            int numPlans, Intent launchIntent) {
+        mCycleEndTimeMs = cycleEnd;
+        mSnapshotTimeMs = snapshotTime;
+        mCarrierName = carrierName;
+        mNumPlans = numPlans;
+        mLaunchIntent = launchIntent;
+        notifyChanged();
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+
+        TextView usageTitle = (TextView) holder.findViewById(R.id.usage_title);
+        usageTitle.setVisibility(mNumPlans > 1 ? View.VISIBLE : View.GONE);
+
+        TextView cycleTime = (TextView) holder.findViewById(R.id.cycle_left_time);
+        cycleTime.setText(getContext().getString(R.string.cycle_left_time_text,
+                StringUtil.formatElapsedTime(getContext(),
+                        mCycleEndTimeMs - System.currentTimeMillis(),false /* withSeconds */)));
+
+        TextView carrierInfo = (TextView) holder.findViewById(R.id.carrier_and_update);
+        setCarrierInfo(carrierInfo, mCarrierName, mSnapshotTimeMs);
+
+        Button launchButton = (Button) holder.findViewById(R.id.launch_mdp_app_button);
+        launchButton.setOnClickListener((view) -> {
+            getContext().sendBroadcast(mLaunchIntent);
+        });
+        if (mLaunchIntent != null) {
+            launchButton.setVisibility(View.VISIBLE);
+        } else {
+            launchButton.setVisibility(View.GONE);
+        }
+
+        TextView limitInfo = (TextView) holder.findViewById(R.id.data_limits);
+        limitInfo.setVisibility(
+                mLimitInfoText == null || mLimitInfoText.isEmpty() ? View.GONE : View.VISIBLE);
+        limitInfo.setText(mLimitInfoText);
+    }
+
+    private void setCarrierInfo(TextView carrierInfo, CharSequence carrierName, long updateAge) {
+        if (mNumPlans > 0 && updateAge >= 0L) {
+            carrierInfo.setVisibility(View.VISIBLE);
+            if (carrierName != null) {
+                carrierInfo.setText(getContext().getString(R.string.carrier_and_update_text,
+                        carrierName, StringUtil.formatRelativeTime(
+                                getContext(), updateAge, false /* withSeconds */)));
+            } else {
+                carrierInfo.setText(getContext().getString(R.string.no_carrier_update_text,
+                        StringUtil.formatRelativeTime(
+                                getContext(), updateAge, false /* withSeconds */)));
+            }
+        } else {
+            carrierInfo.setVisibility(View.GONE);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java b/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java
new file mode 100644
index 0000000..11da829
--- /dev/null
+++ b/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2018 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.settings.datausage;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.NetworkPolicyManager;
+import android.net.NetworkTemplate;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.preference.Preference;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionPlan;
+import android.text.BidiFormatter;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.format.Formatter;
+import android.text.style.RelativeSizeSpan;
+import android.util.Log;
+import android.util.RecurrenceRule;
+
+import com.android.internal.util.CollectionUtils;
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.NetworkPolicyEditor;
+import com.android.settingslib.net.DataUsageController;
+
+import java.util.List;
+
+/**
+ * This is the controller for the top of the data usage screen that retrieves carrier data from the
+ * new subscriptions framework API if available. The controller reads subscription information from
+ * the framework and falls back to legacy usage data if none are available.
+ */
+public class DataUsageSummaryPreferenceController extends BasePreferenceController {
+
+    private static final String TAG = "DataUsageController";
+    private static final String KEY = "status_header";
+    private static final long PETA = 1000000000000000L;
+    private static final float RELATIVE_SIZE_LARGE = 1.25f * 1.25f;  // (1/0.8)^2
+    private static final float RELATIVE_SIZE_SMALL = 1.0f / RELATIVE_SIZE_LARGE;  // 0.8^2
+
+    private final DataUsageController mDataUsageController;
+    private final DataUsageInfoController mDataInfoController;
+    private final NetworkTemplate mDefaultTemplate;
+    private final NetworkPolicyEditor mPolicyEditor;
+    private final int mDataUsageTemplate;
+    private final boolean mHasMobileData;
+    private final SubscriptionManager mSubscriptionManager;
+
+    /** Name of the carrier, or null if not available */
+    private CharSequence mCarrierName;
+
+    /** The number of registered plans, [0,N] */
+    private int mDataplanCount;
+
+    /** The time of the last update in milliseconds since the epoch, or -1 if unknown */
+    private long mSnapshotTime;
+
+    /**
+     * The size of the first registered plan if one exists or the size of the warning if it is set.
+     * -1 if no information is available.
+     */
+    private long mDataplanSize;
+    /** The number of bytes used since the start of the cycle. */
+    private long mDataplanUse;
+    /** The starting time of the billing cycle in ms since the epoch */
+    private long mCycleStart;
+    /** The ending time of the billing cycle in ms since the epoch */
+    private long mCycleEnd;
+
+    private Intent mManageSubscriptionIntent;
+
+    public DataUsageSummaryPreferenceController(Context context) {
+        super(context, KEY);
+
+        final int defaultSubId = DataUsageUtils.getDefaultSubscriptionId(context);
+        mDefaultTemplate = DataUsageUtils.getDefaultTemplate(context, defaultSubId);
+        NetworkPolicyManager policyManager = NetworkPolicyManager.from(context);
+        mPolicyEditor = new NetworkPolicyEditor(policyManager);
+
+        mHasMobileData = DataUsageUtils.hasMobileData(context)
+                && defaultSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+        mDataUsageController = new DataUsageController(context);
+        mDataInfoController = new DataUsageInfoController();
+
+        if (mHasMobileData) {
+            mDataUsageTemplate = R.string.cell_data_template;
+        } else if (DataUsageUtils.hasWifiRadio(context)) {
+            mDataUsageTemplate = R.string.wifi_data_template;
+        } else {
+            mDataUsageTemplate = R.string.ethernet_data_template;
+        }
+
+        mSubscriptionManager = (SubscriptionManager)
+                mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+    }
+
+    @VisibleForTesting
+    DataUsageSummaryPreferenceController(
+            Context context,
+            DataUsageController dataUsageController,
+            DataUsageInfoController dataInfoController,
+            NetworkTemplate defaultTemplate,
+            NetworkPolicyEditor policyEditor,
+            int dataUsageTemplate,
+            boolean hasMobileData,
+            SubscriptionManager subscriptionManager) {
+        super(context, KEY);
+        mDataUsageController = dataUsageController;
+        mDataInfoController = dataInfoController;
+        mDefaultTemplate = defaultTemplate;
+        mPolicyEditor = policyEditor;
+        mDataUsageTemplate = dataUsageTemplate;
+        mHasMobileData = hasMobileData;
+        mSubscriptionManager = subscriptionManager;
+    }
+
+    @VisibleForTesting
+    void setPlanValues(int dataPlanCount, long dataPlanSize, long dataPlanUse) {
+        mDataplanCount = dataPlanCount;
+        mDataplanSize = dataPlanSize;
+        mDataplanUse = dataPlanUse;
+    }
+
+    @VisibleForTesting
+    void setCarrierValues(String carrierName, long snapshotTime, long cycleEnd, Intent intent) {
+        mCarrierName = carrierName;
+        mSnapshotTime = snapshotTime;
+        mCycleEnd = cycleEnd;
+        mManageSubscriptionIntent = intent;
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        DataUsageSummaryPreference summaryPreference = (DataUsageSummaryPreference) preference;
+        DataUsageController.DataUsageInfo info = mDataUsageController.getDataUsageInfo(
+                mDefaultTemplate);
+
+        mDataInfoController.updateDataLimit(info, mPolicyEditor.getPolicy(mDefaultTemplate));
+
+        if (mSubscriptionManager != null) {
+            refreshDataplanInfo(info);
+        }
+
+        if (mDataplanCount == 0 && (info.warningLevel > 0 || info.limitLevel > 0)) {
+            final String warning = Formatter.formatFileSize(mContext, info.warningLevel);
+            final String limit = Formatter.formatFileSize(mContext, info.limitLevel);
+            summaryPreference.setLimitInfo(mContext.getString(info.limitLevel <= 0
+                    ? R.string.cell_warning_only
+                    : R.string.cell_warning_and_limit, warning, limit));
+        } else {
+            summaryPreference.setLimitInfo(null);
+        }
+
+        final StringBuilder title = new StringBuilder();
+        if (mHasMobileData) {
+            title.append(formatUsage(mContext, mContext.getString(R.string.data_used),
+                    mDataplanUse));
+            if (mDataplanCount >= 0 && mDataplanSize > 0L) {
+                title.append(formatUsage(mContext, mContext.getString(R.string.data_remaining),
+                        mDataplanSize - mDataplanUse));
+            }
+        } else {
+            title.append(formatUsage(mContext, mContext.getString(mDataUsageTemplate),
+                    mDataplanUse));
+        }
+        summaryPreference.setTitle(title.toString());
+
+        if (mDataplanSize <= 0) {
+            summaryPreference.setChartEnabled(false);
+        } else {
+            summaryPreference.setChartEnabled(true);
+            summaryPreference.setLabels(Formatter.formatFileSize(mContext, 0 /* sizeBytes */),
+                    Formatter.formatFileSize(mContext, mDataplanSize));
+            summaryPreference.setRatios(mDataplanUse / (float) mDataplanSize, 0 /* middle */,
+                    (mDataplanSize - mDataplanUse) / (float) mDataplanSize);
+        }
+        summaryPreference.setUsageInfo(mCycleEnd, mSnapshotTime, mCarrierName,
+                mDataplanCount, mManageSubscriptionIntent);
+    }
+
+    // TODO(b/70950124) add test for this method once the robolectric shadow run script is
+    // completed (b/3526807)
+    private void refreshDataplanInfo(DataUsageController.DataUsageInfo info) {
+        // reset data before overwriting
+        mCarrierName = null;
+        mDataplanCount = 0;
+        mDataplanSize = mDataInfoController.getSummaryLimit(info);
+        mDataplanUse = info.usageLevel;
+        mCycleStart = info.cycleStart;
+        mCycleEnd = info.cycleEnd;
+        mSnapshotTime = -1L;
+
+        final int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
+        final SubscriptionInfo subInfo = mSubscriptionManager.getDefaultDataSubscriptionInfo();
+        if (subInfo != null && mHasMobileData) {
+            mCarrierName = subInfo.getCarrierName();
+            List<SubscriptionPlan> plans = mSubscriptionManager.getSubscriptionPlans(defaultSubId);
+            final SubscriptionPlan primaryPlan = getPrimaryPlan(mSubscriptionManager, defaultSubId);
+            if (primaryPlan != null) {
+                mDataplanCount = plans.size();
+                mDataplanSize = primaryPlan.getDataLimitBytes();
+                if (unlimited(mDataplanSize)) {
+                    mDataplanSize = 0L;
+                }
+                mDataplanUse = primaryPlan.getDataUsageBytes();
+
+                RecurrenceRule rule = primaryPlan.getCycleRule();
+                if (rule != null && rule.start != null && rule.end != null) {
+                    mCycleStart = rule.start.toEpochSecond() * 1000L;
+                    mCycleEnd = rule.end.toEpochSecond() * 1000L;
+                }
+                mSnapshotTime = System.currentTimeMillis() - primaryPlan.getDataUsageTime();
+            }
+        }
+        mManageSubscriptionIntent =
+                mSubscriptionManager.createManageSubscriptionIntent(defaultSubId);
+        Log.i(TAG, "Have " + mDataplanCount + " plans, dflt sub-id " + defaultSubId
+                + ", intent " + mManageSubscriptionIntent);
+    }
+
+    public static SubscriptionPlan getPrimaryPlan(SubscriptionManager subManager, int primaryId) {
+        List<SubscriptionPlan> plans = subManager.getSubscriptionPlans(primaryId);
+        if (CollectionUtils.isEmpty(plans)) {
+            return null;
+        }
+        // First plan in the list is the primary plan
+        SubscriptionPlan plan = plans.get(0);
+        return plan.getDataLimitBytes() > 0
+                && saneSize(plan.getDataUsageBytes())
+                && plan.getCycleRule() != null ? plan : null;
+    }
+
+    private static boolean saneSize(long value) {
+        return value >= 0L && value < PETA;
+    }
+
+    public static boolean unlimited(long size) {
+        return size == SubscriptionPlan.BYTES_UNLIMITED;
+    }
+
+    @VisibleForTesting
+    private static CharSequence formatUsage(Context context, String template, long usageLevel) {
+        final int FLAGS = Spannable.SPAN_INCLUSIVE_INCLUSIVE;
+
+        final Formatter.BytesResult usedResult = Formatter.formatBytes(context.getResources(),
+                usageLevel, Formatter.FLAG_CALCULATE_ROUNDED);
+        final SpannableString enlargedValue = new SpannableString(usedResult.value);
+        enlargedValue.setSpan(
+                new RelativeSizeSpan(RELATIVE_SIZE_LARGE), 0, enlargedValue.length(), FLAGS);
+
+        final SpannableString amountTemplate = new SpannableString(
+                context.getString(com.android.internal.R.string.fileSizeSuffix)
+                        .replace("%1$s", "^1").replace("%2$s", "^2"));
+        final CharSequence formattedUsage = TextUtils.expandTemplate(amountTemplate,
+                enlargedValue, usedResult.units);
+
+        final SpannableString fullTemplate = new SpannableString(template);
+        fullTemplate.setSpan(
+                new RelativeSizeSpan(RELATIVE_SIZE_SMALL), 0, fullTemplate.length(), FLAGS);
+        return TextUtils.expandTemplate(fullTemplate,
+                BidiFormatter.getInstance().unicodeWrap(formattedUsage.toString()));
+    }
+}
diff --git a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
index 2095f25..2f93d0a 100644
--- a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
@@ -62,7 +62,8 @@
  */
 public class BatteryAppListPreferenceController extends AbstractPreferenceController
         implements PreferenceControllerMixin, LifecycleObserver, OnPause, OnDestroy {
-    private static final boolean USE_FAKE_DATA = true;
+    @VisibleForTesting
+    static final boolean USE_FAKE_DATA = false;
     private static final int MAX_ITEMS_TO_LIST = USE_FAKE_DATA ? 30 : 10;
     private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
     private static final int STATS_TYPE = BatteryStats.STATS_SINCE_CHARGED;
diff --git a/src/com/android/settings/security/VisiblePatternProfilePreferenceController.java b/src/com/android/settings/security/VisiblePatternProfilePreferenceController.java
index a9e56f4..55448e2 100644
--- a/src/com/android/settings/security/VisiblePatternProfilePreferenceController.java
+++ b/src/com/android/settings/security/VisiblePatternProfilePreferenceController.java
@@ -44,6 +44,11 @@
 
     private Preference mPreference;
 
+    public VisiblePatternProfilePreferenceController(Context context) {
+         this(context, null /* lifecycle */);
+    }
+
+    // TODO (b/73074893) Replace this constructor without Lifecycle using setter method instead.
     public VisiblePatternProfilePreferenceController(Context context, Lifecycle lifecycle) {
         super(context, KEY_VISIBLE_PATTERN_PROFILE);
         mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
diff --git a/tests/robotests/assets/grandfather_slice_controller_not_in_xml b/tests/robotests/assets/grandfather_slice_controller_not_in_xml
new file mode 100644
index 0000000..f11027e
--- /dev/null
+++ b/tests/robotests/assets/grandfather_slice_controller_not_in_xml
@@ -0,0 +1 @@
+com.android.settings.testutils.FakeToggleController
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java
new file mode 100644
index 0000000..ea1d29b
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2018 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.settings.datausage;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.NetworkTemplate;
+
+import com.android.settings.R;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.NetworkPolicyEditor;
+import com.android.settingslib.net.DataUsageController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.util.concurrent.TimeUnit;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class DataUsageSummaryPreferenceControllerTest {
+    private static final long UPDATE_BACKOFF_MS = TimeUnit.MINUTES.toMillis(13);
+    private static final long CYCLE_BACKOFF_MS = TimeUnit.DAYS.toMillis(6);
+    private static final long CYCLE_LENGTH_MS = TimeUnit.DAYS.toMillis(30);
+    private static final long USAGE1 =  373000000L;
+    private static final long LIMIT1 = 1000000000L;
+    private static final String CARRIER_NAME = "z-mobile";
+    private static final String PERIOD = "Feb";
+
+    @Mock
+    private DataUsageController mDataUsageController;
+    @Mock
+    private DataUsageInfoController mDataInfoController;
+    @Mock
+    private DataUsageSummaryPreference mSummaryPreference;
+    @Mock
+    private NetworkPolicyEditor mPolicyEditor;
+    @Mock
+    private NetworkTemplate mNetworkTemplate;
+
+    private Context mContext;
+    private DataUsageSummaryPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+
+        mController = new DataUsageSummaryPreferenceController(
+                mContext,
+                mDataUsageController,
+                mDataInfoController,
+                mNetworkTemplate,
+                mPolicyEditor,
+                R.string.cell_data_template,
+                true,
+                null);
+    }
+
+    @Test
+    public void testSummaryUpdate_onePlan_basic() {
+        final long now = System.currentTimeMillis();
+        final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
+
+        final Intent intent = new Intent();
+
+        when(mDataUsageController.getDataUsageInfo()).thenReturn(info);
+        mController.setPlanValues(1 /* dataPlanCount */, LIMIT1, USAGE1);
+        mController.setCarrierValues(CARRIER_NAME, now - UPDATE_BACKOFF_MS, info.cycleEnd, intent);
+
+        mController.updateState(mSummaryPreference);
+        verify(mSummaryPreference).setLimitInfo(null);
+        verify(mSummaryPreference).setUsageInfo(info.cycleEnd, now - UPDATE_BACKOFF_MS,
+                CARRIER_NAME, 1 /* numPlans */, intent);
+        verify(mSummaryPreference).setChartEnabled(true);
+    }
+
+    @Test
+    public void testSummaryUpdate_noPlan_basic() {
+        final long now = System.currentTimeMillis();
+        final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
+
+        final Intent intent = new Intent();
+
+        when(mDataUsageController.getDataUsageInfo(any())).thenReturn(info);
+        mController.setPlanValues(0 /* dataPlanCount */, LIMIT1, USAGE1);
+        mController.setCarrierValues(CARRIER_NAME, now - UPDATE_BACKOFF_MS, info.cycleEnd, intent);
+
+        mController.updateState(mSummaryPreference);
+        verify(mSummaryPreference).setLimitInfo("500 MB Data warning / 1.00 GB Data limit");
+        verify(mSummaryPreference).setUsageInfo(info.cycleEnd, now - UPDATE_BACKOFF_MS,
+                CARRIER_NAME, 0 /* numPlans */, intent);
+        verify(mSummaryPreference).setChartEnabled(true);
+    }
+
+    @Test
+    public void testSummaryUpdate_noCarrier_basic() {
+        final long now = System.currentTimeMillis();
+        final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
+
+        when(mDataUsageController.getDataUsageInfo(any())).thenReturn(info);
+        mController.setPlanValues(0 /* dataPlanCount */, LIMIT1, USAGE1);
+        mController.setCarrierValues(null /* carrierName */, -1L /* snapshotTime */,
+                info.cycleEnd, null /* intent */);
+        mController.updateState(mSummaryPreference);
+
+        verify(mSummaryPreference).setLimitInfo("500 MB Data warning / 1.00 GB Data limit");
+        verify(mSummaryPreference).setUsageInfo(
+                info.cycleEnd,
+                -1L /* snapshotTime */,
+                null /* carrierName */,
+                0 /* numPlans */,
+                null /* launchIntent */);
+        verify(mSummaryPreference).setChartEnabled(true);
+    }
+
+    @Test
+    public void testSummaryUpdate_noPlanData_basic() {
+        final long now = System.currentTimeMillis();
+
+        final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
+
+        when(mDataUsageController.getDataUsageInfo(any())).thenReturn(info);
+        mController.setPlanValues(0 /* dataPlanCount */, -1L /* dataPlanSize */, USAGE1);
+        mController.setCarrierValues(null /* carrierName */, -1L /* snapshotTime */,
+                info.cycleEnd, null /* intent */);
+        mController.updateState(mSummaryPreference);
+
+        verify(mSummaryPreference).setLimitInfo("500 MB Data warning / 1.00 GB Data limit");
+        verify(mSummaryPreference).setUsageInfo(
+                info.cycleEnd,
+                -1L /* snapshotTime */,
+                null /* carrierName */,
+                0 /* numPlans */,
+                null /* launchIntent */);
+        verify(mSummaryPreference).setChartEnabled(false);
+    }
+
+    private DataUsageController.DataUsageInfo createTestDataUsageInfo(long now) {
+        DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo();
+        info.carrier = CARRIER_NAME;
+        info.period = PERIOD;
+        info.startDate = now;
+        info.limitLevel = LIMIT1;
+        info.warningLevel = LIMIT1 >> 1;
+        info.usageLevel = USAGE1;
+        info.cycleStart = now - CYCLE_BACKOFF_MS;
+        info.cycleEnd = info.cycleStart + CYCLE_LENGTH_MS;
+        return info;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java
new file mode 100644
index 0000000..769d9e7
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2018 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.settings.datausage;
+
+import android.content.Context;
+import android.content.Intent;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.SettingsShadowResourcesImpl;
+import com.android.settingslib.utils.StringUtil;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, shadows =
+        SettingsShadowResourcesImpl.class)
+public class DataUsageSummaryPreferenceTest {
+    private static final long CYCLE_DURATION_MILLIS = 1000000000L;
+    private static final long UPDATE_LAG_MILLIS = 10000000L;
+    private static final String DUMMY_CARRIER = "z-mobile";
+
+    private Context mContext;
+    private PreferenceViewHolder mHolder;
+    private DataUsageSummaryPreference mSummaryPreference;
+    private TextView mUsageTitle;
+    private TextView mCycleTime;
+    private TextView mCarrierInfo;
+    private TextView mDataLimits;
+    private Button mLaunchButton;
+
+    private long mCycleEnd;
+    private long mUpdateTime;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        mSummaryPreference = new DataUsageSummaryPreference(mContext, null /* attrs */);
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        View view = inflater.inflate(mSummaryPreference.getLayoutResource(), null /* root */,
+                false /* attachToRoot */);
+
+        mHolder = PreferenceViewHolder.createInstanceForTests(view);
+
+        final long now = System.currentTimeMillis();
+        mCycleEnd = now + CYCLE_DURATION_MILLIS;
+        mUpdateTime = now - UPDATE_LAG_MILLIS;
+    }
+
+    @Test
+    public void testSetUsageInfo_withLaunchIntent_launchButtonShown() {
+        mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 0 /* numPlans */,
+                new Intent());
+
+        bindViewHolder();
+        assertThat(mLaunchButton.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void testSetUsageInfo_withoutLaunchIntent_launchButtonNotShown() {
+        mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 0 /* numPlans */,
+                null /* launchIntent */);
+
+        bindViewHolder();
+        assertThat(mLaunchButton.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void testSetUsageInfo_withDataPlans_carrierInfoShown() {
+        mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 1 /* numPlans */,
+                new Intent());
+
+        bindViewHolder();
+        assertThat(mCarrierInfo.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void testSetUsageInfo_withNoDataPlans_carrierInfoNotShown() {
+        mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 0 /* numPlans */,
+                new Intent());
+
+        bindViewHolder();
+        assertThat(mCarrierInfo.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void testSetUsageInfo_withNoDataPlans_usageTitleNotShown() {
+        mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 0 /* numPlans */,
+                new Intent());
+
+        bindViewHolder();
+        assertThat(mUsageTitle.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void testSetUsageInfo_withMultipleDataPlans_usageTitleShown() {
+        mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 2 /* numPlans */,
+                new Intent());
+
+        bindViewHolder();
+        assertThat(mUsageTitle.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void testSetUsageInfo_cycleRemainingTimeShown() {
+        mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 0 /* numPlans */,
+                new Intent());
+        String cyclePrefix = StringUtil.formatElapsedTime(mContext, CYCLE_DURATION_MILLIS,
+                false /* withSeconds */).toString();
+        String text = mContext.getString(R.string.cycle_left_time_text, cyclePrefix);
+
+        bindViewHolder();
+        assertThat(mCycleTime.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mCycleTime.getText()).isEqualTo(text);
+    }
+
+    @Test
+    public void testSetLimitInfo_withLimitInfo_dataLimitsShown() {
+        final String limitText = "test limit text";
+        mSummaryPreference.setLimitInfo(limitText);
+
+        bindViewHolder();
+        assertThat(mDataLimits.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mDataLimits.getText()).isEqualTo(limitText);
+    }
+
+    @Test
+    public void testSetLimitInfo_withNullLimitInfo_dataLimitsNotShown() {
+        mSummaryPreference.setLimitInfo(null);
+
+        bindViewHolder();
+        assertThat(mDataLimits.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    private void bindViewHolder() {
+        mSummaryPreference.onBindViewHolder(mHolder);
+        mUsageTitle = (TextView) mHolder.findViewById(R.id.usage_title);
+        mCycleTime = (TextView) mHolder.findViewById(R.id.cycle_left_time);
+        mCarrierInfo = (TextView) mHolder.findViewById(R.id.carrier_and_update);
+        mDataLimits = (TextView) mHolder.findViewById(R.id.data_limits);
+        mLaunchButton = (Button) mHolder.findViewById(R.id.launch_mdp_app_button);
+    }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java
index a814989..cee84de 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java
@@ -220,4 +220,9 @@
 
         assertThat(mPreferenceController.isAvailable()).isFalse();
     }
+
+    @Test
+    public void testNeverUseFakeData() {
+        assertThat(BatteryAppListPreferenceController.USE_FAKE_DATA).isFalse();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java b/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java
index 6c6d7ab..260e3ae 100644
--- a/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java
+++ b/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java
@@ -137,7 +137,6 @@
         final List<String> nonIndexableKeys = provider
                 .getNonIndexableKeys(RuntimeEnvironment.application);
 
-        assertThat(nonIndexableKeys).containsAllOf("status_header", "limit_summary",
-                "restrict_background");
+        assertThat(nonIndexableKeys).contains("status_header");
     }
 }
diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
index 340d04b..3512ded 100644
--- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
@@ -31,6 +31,7 @@
 
 import com.android.settings.TestConfig;
 import com.android.settings.testutils.DatabaseTestUtils;
+import com.android.settings.testutils.FakeToggleController;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 
 import org.junit.After;
diff --git a/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java
index f5d5ff0..1c5899d 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java
@@ -31,6 +31,7 @@
 import com.android.settings.search.SearchFeatureProvider;
 import com.android.settings.search.SearchFeatureProviderImpl;
 import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.FakeToggleController;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 
 import org.junit.After;
diff --git a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
index 0923571..88e4695 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
@@ -29,6 +29,7 @@
 import com.android.settings.R;
 import com.android.settings.TestConfig;
 import com.android.settings.core.BasePreferenceController;
+import com.android.settings.testutils.FakeToggleController;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 
 import org.junit.Before;
diff --git a/tests/robotests/src/com/android/settings/slices/SliceControllerInXmlTest.java b/tests/robotests/src/com/android/settings/slices/SliceControllerInXmlTest.java
new file mode 100644
index 0000000..66ed459
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/slices/SliceControllerInXmlTest.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2018 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.settings.slices;
+
+import static com.android.settings.TestConfig.SDK_VERSION;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.content.res.XmlResourceParser;
+import android.provider.SearchIndexableResource;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Xml;
+
+import com.android.settings.TestConfig;
+import com.android.settings.core.TogglePreferenceController;
+import com.android.settings.core.codeinspection.ClassScanner;
+import com.android.settings.core.codeinspection.CodeInspector;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.search.DatabaseIndexingUtils;
+import com.android.settings.search.Indexable;
+import com.android.settings.search.SearchFeatureProvider;
+import com.android.settings.search.SearchFeatureProviderImpl;
+import com.android.settings.search.XmlParserUtils;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = SDK_VERSION)
+public class SliceControllerInXmlTest {
+
+    private static final List<Class> mSliceControllerClasses = new ArrayList<>(Arrays.asList(
+            TogglePreferenceController.class
+    ));
+
+    private final List<String> mXmlDeclaredControllers = new ArrayList<>();
+    private final List<String> mGrandfatheredClasses = new ArrayList<>();
+
+    private final String ERROR_MISSING_CONTROLLER =
+            "The following controllers were expected to be declared by "
+                    + "'settings:controller=Controller_Class_Name' in their corresponding Xml. "
+                    + "If it should not appear in XML, add the controller's classname to "
+                    + "grandfather_slice_controller_not_in_xml. Controllers:\n";
+
+    private Context mContext;
+
+    SearchFeatureProvider mSearchProvider;
+    private FakeFeatureFactory mFakeFeatureFactory;
+
+    @Before
+    public void setUp() {
+        mContext = spy(RuntimeEnvironment.application);
+
+        mSearchProvider = new SearchFeatureProviderImpl();
+        mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
+        mFakeFeatureFactory.searchFeatureProvider = mSearchProvider;
+
+        CodeInspector.initializeGrandfatherList(mGrandfatheredClasses,
+                "grandfather_slice_controller_not_in_xml");
+        initDeclaredControllers();
+    }
+
+    private void initDeclaredControllers() {
+        final List<Integer> xmlResources = getIndexableXml();
+        XmlResourceParser parser;
+
+        for (int xmlResId : xmlResources) {
+            try {
+                parser = mContext.getResources().getXml(xmlResId);
+
+                int type;
+                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                        && type != XmlPullParser.START_TAG) {
+                    // Parse next until start tag is found
+                }
+
+                final int outerDepth = parser.getDepth();
+                final AttributeSet attrs = Xml.asAttributeSet(parser);
+                String controllerClassName;
+                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                        && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                    if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                        continue;
+                    }
+                    controllerClassName = XmlParserUtils.getController(mContext, attrs);
+
+                    if (!TextUtils.isEmpty(controllerClassName)) {
+                        mXmlDeclaredControllers.add(controllerClassName);
+                    }
+                }
+            } catch (Exception e) {
+                // Assume an issue with robolectric resources
+            }
+        }
+    }
+
+    @Test
+    public void testAllControllersDeclaredInXml() throws Exception {
+        final List<Class<?>> classes = new ClassScanner().getClassesForPackage(
+                mContext.getPackageName());
+        final List<String> missingControllersInXml = new ArrayList<>();
+
+        for (Class<?> clazz : classes) {
+            if (!isInlineSliceClass(clazz)) {
+                // Only care about inline-slice controller classes.
+                continue;
+            }
+
+            if (!mXmlDeclaredControllers.contains(clazz.getName())) {
+                // Class clazz should have been declared in XML (unless whitelisted).
+                missingControllersInXml.add(clazz.getName());
+            }
+        }
+
+        // Removed whitelisted classes
+        missingControllersInXml.removeAll(mGrandfatheredClasses);
+
+        final String missingControllerError = buildErrorMessage(ERROR_MISSING_CONTROLLER,
+                missingControllersInXml);
+
+        assertWithMessage(missingControllerError).that(missingControllersInXml).isEmpty();
+    }
+
+    private boolean isInlineSliceClass(Class clazz) {
+        while (clazz != null) {
+            clazz = clazz.getSuperclass();
+            if (mSliceControllerClasses.contains(clazz)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private String buildErrorMessage(String errorSummary, List<String> errorClasses) {
+        final StringBuilder error = new StringBuilder(errorSummary);
+        for (String c : errorClasses) {
+            error.append(c).append("\n");
+        }
+        return error.toString();
+    }
+
+    private List<Integer> getIndexableXml() {
+        final List<Integer> xmlResSet = new ArrayList<>();
+
+        final Collection<Class> indexableClasses = FeatureFactory.getFactory(
+                mContext).getSearchFeatureProvider().getSearchIndexableResources()
+                .getProviderValues();
+
+        for (Class clazz : indexableClasses) {
+
+            Indexable.SearchIndexProvider provider = DatabaseIndexingUtils.getSearchIndexProvider(
+                    clazz);
+
+            if (provider == null) {
+                continue;
+            }
+
+            List<SearchIndexableResource> resources = provider.getXmlResourcesToIndex(mContext,
+                    true);
+
+            if (resources == null) {
+                continue;
+            }
+
+            for (SearchIndexableResource resource : resources) {
+                // Add '0's anyway. It won't break the test.
+                xmlResSet.add(resource.xmlResId);
+            }
+        }
+        return xmlResSet;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/slices/FakeToggleController.java b/tests/robotests/src/com/android/settings/testutils/FakeToggleController.java
similarity index 97%
rename from tests/robotests/src/com/android/settings/slices/FakeToggleController.java
rename to tests/robotests/src/com/android/settings/testutils/FakeToggleController.java
index 1b08e35..c984c6c 100644
--- a/tests/robotests/src/com/android/settings/slices/FakeToggleController.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeToggleController.java
@@ -15,7 +15,7 @@
  *
  */
 
-package com.android.settings.slices;
+package com.android.settings.testutils;
 
 import android.content.Context;
 import android.provider.Settings;