Merge "Fix Wifi off state UI"
diff --git a/Android.mk b/Android.mk
index a573378..6b0d077 100644
--- a/Android.mk
+++ b/Android.mk
@@ -25,13 +25,10 @@
     androidx.slice_slice-core \
     androidx.slice_slice-view \
     androidx.core_core \
-    androidx.legacy_legacy-support-v4 \
-    androidx.legacy_legacy-support-v13 \
     androidx.appcompat_appcompat \
     androidx.cardview_cardview \
     androidx.preference_preference \
     androidx.recyclerview_recyclerview \
-    androidx.legacy_legacy-preference-v14 \
     com.google.android.material_material \
 
 LOCAL_JAVA_LIBRARIES := \
diff --git a/res/layout/settings_homepage.xml b/res/layout/settings_homepage.xml
index c36cf8b..fb00c7d 100644
--- a/res/layout/settings_homepage.xml
+++ b/res/layout/settings_homepage.xml
@@ -43,7 +43,7 @@
                 android:id="@+id/search_fab"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:src="@drawable/ic_search_24dp"
+                android:src="@drawable/ic_search_floating_24dp"
                 app:backgroundTint="@android:color/white"
                 app:layout_anchor="@id/bar" />
 
diff --git a/res/values/aliases.xml b/res/values/aliases.xml
index 060ba1d..1be4350 100644
--- a/res/values/aliases.xml
+++ b/res/values/aliases.xml
@@ -23,5 +23,6 @@
      <item name="fingerprint_enroll_enrolling" type="layout">@layout/fingerprint_enroll_enrolling_base</item>
      <item name="fingerprint_enroll_finish" type="layout">@layout/fingerprint_enroll_finish_base</item>
      <item name="choose_lock_pattern" type="layout">@layout/choose_lock_pattern_common</item>
+     <item name="ic_search_floating_24dp" type="drawable">@drawable/ic_search_24dp</item>
 </resources>
 
diff --git a/res/values/bools.xml b/res/values/bools.xml
index b406605..08bb08c 100644
--- a/res/values/bools.xml
+++ b/res/values/bools.xml
@@ -32,6 +32,9 @@
          Can be overridden for specific product builds. -->
     <bool name="auto_confirm_bluetooth_activation_dialog">false</bool>
 
+    <!-- Whether the device name is shown in About device or not -->
+    <bool name="config_show_device_name">true</bool>
+
     <!-- Whether to show a preference item for the manual in About phone -->
     <bool name="config_show_manual">false</bool>
     <!-- Whether to show a preference item for regulatory information in About phone -->
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f284e30..2acf28b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -841,7 +841,9 @@
     <string name="disabled_by_administrator_summary">Disabled by admin</string>
     <!-- In the security screen, the header title for security statuses -->
     <string name="security_status_title">Security status</string>
-    <!-- Summary for Security settings, explaining a few important settings under it [CHAR LIMIT=NONE]-->
+    <!-- Summary for Security settings, explaining a few important settings under it [CHAR LIMIT=NONE] -->
+    <string name="security_dashboard_summary_face">Screen lock, face unlock</string>
+    <!-- Summary for Security settings, explaining a few important settings under it [CHAR LIMIT=NONE] -->
     <string name="security_dashboard_summary">Screen lock, fingerprint</string>
     <!-- Summary for Security settings when fingerprint is not supported [CHAR LIMIT=NONE]-->
     <string name="security_dashboard_summary_no_fingerprint">Screen lock</string>
@@ -5089,6 +5091,9 @@
         <item quantity="other">Limiting battery usage for %1$d apps</item>
     </plurals>
 
+    <!-- Summary for restricted app to show the restriction time [CHAR LIMIT=NONE] -->
+    <string name="restricted_app_time_summary">Restricted <xliff:g id="time" example="5 days ago">%1$s</xliff:g></string>
+
     <!-- Footer message for restrict app details page -->
     <string name="restricted_app_detail_footer">These apps have been using battery in the background. Restricted apps may not work properly and notifications may be delayed.</string>
 
@@ -5943,7 +5948,7 @@
 
     <!-- Activity title for network data usage summary. [CHAR LIMIT=25] -->
     <string name="data_usage_summary_title">Data usage</string>
-    <!-- Activity title Mobile data & WI-FI summary. [CHAR LIMIT=25] -->
+    <!-- Activity title Mobile data & WI-FI summary. [CHAR LIMIT=40] -->
     <string name="data_usage_app_summary_title">Mobile data &amp; Wi\u2011Fi</string>
     <!-- Message about carrier data accounting.  [CHAR LIMIT=100] -->
     <string name="data_usage_accounting">Carrier data accounting may differ from your device.</string>
diff --git a/res/values/themes_suw.xml b/res/values/themes_suw.xml
index 11ef373..f09b2b1 100644
--- a/res/values/themes_suw.xml
+++ b/res/values/themes_suw.xml
@@ -18,8 +18,8 @@
 <!-- SUW related themes -->
 <resources>
     <style name="GlifTheme" parent="SuwThemeGlif">
-        <!-- For all Alert Dialogs -->
-        <item name="android:alertDialogTheme">@style/ThemeOverlay.AlertDialog</item>
+        <!-- For all AndroidX Alert Dialogs -->
+        <item name="alertDialogTheme">@style/ThemeOverlay.AlertDialog</item>
         <item name="android:windowBackground">?android:attr/colorBackground</item>
         <item name="*android:preferencePanelStyle">@*android:style/PreferencePanel.Dialog</item>
         <item name="fingerprint_layout_theme">@style/FingerprintLayoutTheme</item>
@@ -37,8 +37,8 @@
     </style>
 
     <style name="GlifTheme.Light" parent="SuwThemeGlif.Light">
-        <!-- For all Alert Dialogs -->
-        <item name="android:alertDialogTheme">@style/ThemeOverlay.AlertDialog</item>
+        <!-- For all AndroidX Alert Dialogs -->
+        <item name="alertDialogTheme">@style/ThemeOverlay.AlertDialog</item>
         <item name="android:windowBackground">?android:attr/colorBackground</item>
         <item name="*android:preferencePanelStyle">@*android:style/PreferencePanel.Dialog</item>
         <item name="fingerprint_layout_theme">@style/FingerprintLayoutTheme</item>
@@ -56,8 +56,8 @@
     </style>
 
     <style name="GlifV2Theme" parent="SuwThemeGlifV2">
-        <!-- For all Alert Dialogs -->
-        <item name="android:alertDialogTheme">@style/GlifV2ThemeAlertDialog</item>
+        <!-- For all AndroidX Alert Dialogs -->
+        <item name="alertDialogTheme">@style/GlifV2ThemeAlertDialog</item>
         <item name="android:windowBackground">?android:attr/colorBackground</item>
         <item name="*android:preferencePanelStyle">@*android:style/PreferencePanel.Dialog</item>
         <item name="fingerprint_layout_theme">@style/FingerprintLayoutTheme</item>
@@ -75,8 +75,8 @@
     </style>
 
     <style name="GlifV2Theme.Light" parent="SuwThemeGlifV2.Light">
-        <!-- For all Alert Dialogs -->
-        <item name="android:alertDialogTheme">@style/GlifV2ThemeAlertDialog.Light</item>
+        <!-- For all AndroidX Alert Dialogs -->
+        <item name="alertDialogTheme">@style/GlifV2ThemeAlertDialog.Light</item>
         <item name="android:windowBackground">?android:attr/colorBackground</item>
         <item name="*android:preferencePanelStyle">@*android:style/PreferencePanel.Dialog</item>
         <item name="fingerprint_layout_theme">@style/FingerprintLayoutTheme</item>
@@ -94,8 +94,8 @@
     </style>
 
     <style name="GlifV3Theme" parent="SuwThemeGlifV3">
-        <!-- For all Alert Dialogs -->
-        <item name="android:alertDialogTheme">@style/GlifV2ThemeAlertDialog</item>
+        <!-- For all AndroidX Alert Dialogs -->
+        <item name="alertDialogTheme">@style/GlifV2ThemeAlertDialog</item>
         <item name="android:windowBackground">?android:attr/colorBackground</item>
         <item name="*android:preferencePanelStyle">@*android:style/PreferencePanel.Dialog</item>
         <item name="fingerprint_layout_theme">@style/FingerprintLayoutTheme</item>
@@ -113,8 +113,8 @@
     </style>
 
     <style name="GlifV3Theme.Light" parent="SuwThemeGlifV3.Light">
-        <!-- For all Alert Dialogs -->
-        <item name="android:alertDialogTheme">@style/GlifV2ThemeAlertDialog.Light</item>
+        <!-- For all AndroidX Alert Dialogs -->
+        <item name="alertDialogTheme">@style/GlifV2ThemeAlertDialog.Light</item>
         <item name="android:windowBackground">?android:attr/colorBackground</item>
         <item name="*android:preferencePanelStyle">@*android:style/PreferencePanel.Dialog</item>
         <item name="fingerprint_layout_theme">@style/FingerprintLayoutTheme</item>
@@ -145,11 +145,11 @@
         <item name="android:windowAnimationStyle">@null</item>
     </style>
 
-    <style name="GlifV2ThemeAlertDialog" parent="SuwAlertDialogTheme">
+    <style name="GlifV2ThemeAlertDialog" parent="SuwAlertDialogThemeCompat">
         <item name="android:windowSoftInputMode">adjustResize</item>
     </style>
 
-    <style name="GlifV2ThemeAlertDialog.Light" parent="SuwAlertDialogTheme.Light">
+    <style name="GlifV2ThemeAlertDialog.Light" parent="SuwAlertDialogThemeCompat.Light">
         <item name="android:windowSoftInputMode">adjustResize</item>
     </style>
 
@@ -190,4 +190,16 @@
         <item name="preferenceTheme">@style/PreferenceTheme</item>
         <item name="switchBarTheme">@style/ThemeOverlay.SwitchBar.Settings</item>
     </style>
+
+    <style name="SuwAlertDialogThemeCompat" parent="@style/Theme.AppCompat.Dialog.Alert">
+        <!-- copied from Theme.DeviceDefault.Light.Dialog.Alert -->
+        <item name="colorAccent">@*android:color/accent_device_default_light</item>
+        <item name="dialogCornerRadius">@*android:dimen/config_dialogCornerRadius</item>
+    </style>
+
+    <style name="SuwAlertDialogThemeCompat.Light" parent="@style/Theme.AppCompat.Light.Dialog.Alert">
+        <!-- copied from Theme.DeviceDefault.Light.Dialog.Alert -->
+        <item name="colorAccent">@*android:color/accent_device_default_light</item>
+        <item name="dialogCornerRadius">@*android:dimen/config_dialogCornerRadius</item>
+    </style>
 </resources>
\ No newline at end of file
diff --git a/res/xml/my_device_info.xml b/res/xml/my_device_info.xml
index b70b613..22c1844 100644
--- a/res/xml/my_device_info.xml
+++ b/res/xml/my_device_info.xml
@@ -133,6 +133,14 @@
         android:summary="@string/summary_placeholder"
         android:selectable="false"/>
 
+    <!-- Device up time -->
+    <Preference
+        android:key="up_time"
+        android:order="37"
+        android:title="@string/status_up_time"
+        android:summary="@string/summary_placeholder"
+        android:selectable="false" />
+
     <!-- Safety & regulatory manual -->
     <Preference
         android:key="safety_info"
diff --git a/res/xml/power_usage_summary.xml b/res/xml/power_usage_summary.xml
index 4ff67b7..b4db4ed 100644
--- a/res/xml/power_usage_summary.xml
+++ b/res/xml/power_usage_summary.xml
@@ -23,12 +23,16 @@
 
     <com.android.settings.applications.LayoutPreference
         android:key="battery_header"
+        android:title="@string/summary_placeholder"
         android:selectable="false"
-        android:layout="@layout/battery_header" />
+        android:layout="@layout/battery_header"
+        settings:controller="com.android.settings.fuelgauge.BatteryHeaderPreferenceController" />
 
     <PreferenceCategory
         android:key="battery_tip"
-        android:layout="@layout/preference_category_no_label" />
+        android:title="@string/summary_placeholder"
+        android:layout="@layout/preference_category_no_label"
+        settings:controller="com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController" />
 
     <Preference
         android:fragment="com.android.settings.fuelgauge.batterysaver.BatterySaverSettings"
@@ -47,7 +51,8 @@
     <SwitchPreference
         android:key="battery_percentage"
         android:title="@string/battery_percentage"
-        android:summary="@string/battery_percentage_description" />
+        android:summary="@string/battery_percentage_description"
+        settings:controller="com.android.settings.display.BatteryPercentagePreferenceController" />
 
 
     <com.android.settings.fuelgauge.PowerGaugePreference
diff --git a/src/com/android/settings/FallbackHome.java b/src/com/android/settings/FallbackHome.java
index 7d5948e..59347ad 100644
--- a/src/com/android/settings/FallbackHome.java
+++ b/src/com/android/settings/FallbackHome.java
@@ -19,6 +19,7 @@
 import android.app.Activity;
 import android.app.WallpaperColors;
 import android.app.WallpaperManager;
+import android.app.WallpaperManager.OnColorsChangedListener;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -44,6 +45,7 @@
     private static final int PROGRESS_TIMEOUT = 2000;
 
     private boolean mProvisioned;
+    private WallpaperManager mWallManager;
 
     private final Runnable mProgressTimeoutRunnable = () -> {
         View v = getLayoutInflater().inflate(
@@ -59,6 +61,18 @@
         getWindow().addFlags(LayoutParams.FLAG_KEEP_SCREEN_ON);
     };
 
+    private final OnColorsChangedListener mColorsChangedListener = new OnColorsChangedListener() {
+        @Override
+        public void onColorsChanged(WallpaperColors colors, int which) {
+            if (colors != null) {
+                View decorView = getWindow().getDecorView();
+                decorView.setSystemUiVisibility(
+                        updateVisibilityFlagsFromColors(colors, decorView.getSystemUiVisibility()));
+                mWallManager.removeOnColorsChangedListener(this);
+            }
+        }
+    };
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -78,13 +92,17 @@
         }
 
         // Set the system ui flags to light status bar if the wallpaper supports dark text to match
-        // current system ui color tints.
-        final WallpaperColors colors = getSystemService(WallpaperManager.class)
-                .getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
-        if (colors != null
-                && (colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0) {
-            flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
-                    | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
+        // current system ui color tints. Use a listener to wait for colors if not ready yet.
+        mWallManager = getSystemService(WallpaperManager.class);
+        if (mWallManager == null) {
+            Log.w(TAG, "Wallpaper manager isn't ready, can't listen to color changes!");
+        } else {
+            WallpaperColors colors = mWallManager.getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
+            if (colors == null) {
+                mWallManager.addOnColorsChangedListener(mColorsChangedListener, null /* handler */);
+            } else {
+                flags = updateVisibilityFlagsFromColors(colors, flags);
+            }
         }
         getWindow().getDecorView().setSystemUiVisibility(flags);
 
@@ -109,6 +127,9 @@
     protected void onDestroy() {
         super.onDestroy();
         unregisterReceiver(mReceiver);
+        if (mWallManager != null) {
+            mWallManager.removeOnColorsChangedListener(mColorsChangedListener);
+        }
     }
 
     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -141,6 +162,15 @@
         }
     }
 
+    private int updateVisibilityFlagsFromColors(WallpaperColors colors, int flags) {
+        if ((colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0) {
+            return flags | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
+                    | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
+        }
+        return flags & ~(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR)
+                & ~(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
+    }
+
     private Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
diff --git a/src/com/android/settings/accounts/AccountPreferenceController.java b/src/com/android/settings/accounts/AccountPreferenceController.java
index 904dea3..46a3e6b 100644
--- a/src/com/android/settings/accounts/AccountPreferenceController.java
+++ b/src/com/android/settings/accounts/AccountPreferenceController.java
@@ -192,12 +192,10 @@
                         data.screenTitle = screenTitle;
                         rawData.add(data);
                     }
-                    {
-                        SearchIndexableRaw data = new SearchIndexableRaw(mContext);
-                        data.title = res.getString(R.string.managed_profile_settings_title);
-                        data.screenTitle = screenTitle;
-                        rawData.add(data);
-                    }
+                    SearchIndexableRaw data = new SearchIndexableRaw(mContext);
+                    data.title = res.getString(R.string.managed_profile_settings_title);
+                    data.screenTitle = screenTitle;
+                    rawData.add(data);
                 }
             }
         }
@@ -300,6 +298,7 @@
         final ProfileData data = mProfiles.get(userInfo.id);
         if (data != null) {
             data.pendingRemoval = false;
+            data.userInfo = userInfo;
             if (userInfo.isEnabled()) {
                 // recreate the authentication helper to refresh the list of enabled accounts
                 data.authenticatorHelper =
diff --git a/src/com/android/settings/core/SettingsBaseActivity.java b/src/com/android/settings/core/SettingsBaseActivity.java
index 9672694..23eb860 100644
--- a/src/com/android/settings/core/SettingsBaseActivity.java
+++ b/src/com/android/settings/core/SettingsBaseActivity.java
@@ -38,7 +38,7 @@
 import androidx.fragment.app.FragmentActivity;
 
 import com.android.settings.R;
-import com.android.settingslib.drawer.CategoryManager;
+import com.android.settings.dashboard.CategoryManager;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -172,10 +172,6 @@
         new CategoriesUpdateTask().execute();
     }
 
-    public String getSettingPkg() {
-        return CategoryManager.SETTING_PKG;
-    }
-
     public interface CategoryListener {
         void onCategoriesChanged();
     }
@@ -190,7 +186,7 @@
 
         @Override
         protected Void doInBackground(Void... params) {
-            mCategoryManager.reloadAllCategories(SettingsBaseActivity.this, getSettingPkg());
+            mCategoryManager.reloadAllCategories(SettingsBaseActivity.this);
             return null;
         }
 
diff --git a/src/com/android/settings/dashboard/CategoryManager.java b/src/com/android/settings/dashboard/CategoryManager.java
new file mode 100644
index 0000000..4072072
--- /dev/null
+++ b/src/com/android/settings/dashboard/CategoryManager.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2016 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.dashboard;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settingslib.applications.InterestingConfigChanges;
+import com.android.settingslib.drawer.CategoryKey;
+import com.android.settingslib.drawer.DashboardCategory;
+import com.android.settingslib.drawer.Tile;
+import com.android.settingslib.drawer.TileUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+public class CategoryManager {
+
+    private static final String TAG = "CategoryManager";
+
+    private static CategoryManager sInstance;
+    private final InterestingConfigChanges mInterestingConfigChanges;
+
+    // Tile cache (key: <packageName, activityName>, value: tile)
+    private final Map<Pair<String, String>, Tile> mTileByComponentCache;
+
+    // Tile cache (key: category key, value: category)
+    private final Map<String, DashboardCategory> mCategoryByKeyMap;
+
+    private List<DashboardCategory> mCategories;
+    private String mExtraAction;
+
+    public static CategoryManager get(Context context) {
+        return get(context, null);
+    }
+
+    public static CategoryManager get(Context context, String action) {
+        if (sInstance == null) {
+            sInstance = new CategoryManager(context, action);
+        }
+        return sInstance;
+    }
+
+    CategoryManager(Context context, String action) {
+        mTileByComponentCache = new ArrayMap<>();
+        mCategoryByKeyMap = new ArrayMap<>();
+        mInterestingConfigChanges = new InterestingConfigChanges();
+        mInterestingConfigChanges.applyNewConfig(context.getResources());
+        mExtraAction = action;
+    }
+
+    public synchronized DashboardCategory getTilesByCategory(Context context, String categoryKey) {
+        tryInitCategories(context);
+
+        return mCategoryByKeyMap.get(categoryKey);
+    }
+
+    public synchronized List<DashboardCategory> getCategories(Context context) {
+        tryInitCategories(context);
+        return mCategories;
+    }
+
+    public synchronized void reloadAllCategories(Context context) {
+        final boolean forceClearCache = mInterestingConfigChanges.applyNewConfig(
+                context.getResources());
+        mCategories = null;
+        tryInitCategories(context, forceClearCache);
+    }
+
+    public synchronized void updateCategoryFromBlacklist(Set<ComponentName> tileBlacklist) {
+        if (mCategories == null) {
+            Log.w(TAG, "Category is null, skipping blacklist update");
+        }
+        for (int i = 0; i < mCategories.size(); i++) {
+            DashboardCategory category = mCategories.get(i);
+            for (int j = 0; j < category.getTilesCount(); j++) {
+                Tile tile = category.getTile(j);
+                if (tileBlacklist.contains(tile.intent.getComponent())) {
+                    category.removeTile(j--);
+                }
+            }
+        }
+    }
+
+    private synchronized void tryInitCategories(Context context) {
+        // Keep cached tiles by default. The cache is only invalidated when InterestingConfigChange
+        // happens.
+        tryInitCategories(context, false /* forceClearCache */);
+    }
+
+    private synchronized void tryInitCategories(Context context, boolean forceClearCache) {
+        if (mCategories == null) {
+            if (forceClearCache) {
+                mTileByComponentCache.clear();
+            }
+            mCategoryByKeyMap.clear();
+            mCategories = TileUtils.getCategories(context, mTileByComponentCache, mExtraAction);
+            for (DashboardCategory category : mCategories) {
+                mCategoryByKeyMap.put(category.key, category);
+            }
+            backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
+            sortCategories(context, mCategoryByKeyMap);
+            filterDuplicateTiles(mCategoryByKeyMap);
+        }
+    }
+
+    @VisibleForTesting
+    synchronized void backwardCompatCleanupForCategory(
+            Map<Pair<String, String>, Tile> tileByComponentCache,
+            Map<String, DashboardCategory> categoryByKeyMap) {
+        // A package can use a) CategoryKey, b) old category keys, c) both.
+        // Check if a package uses old category key only.
+        // If yes, map them to new category key.
+
+        // Build a package name -> tile map first.
+        final Map<String, List<Tile>> packageToTileMap = new HashMap<>();
+        for (Entry<Pair<String, String>, Tile> tileEntry : tileByComponentCache.entrySet()) {
+            final String packageName = tileEntry.getKey().first;
+            List<Tile> tiles = packageToTileMap.get(packageName);
+            if (tiles == null) {
+                tiles = new ArrayList<>();
+                packageToTileMap.put(packageName, tiles);
+            }
+            tiles.add(tileEntry.getValue());
+        }
+
+        for (Entry<String, List<Tile>> entry : packageToTileMap.entrySet()) {
+            final List<Tile> tiles = entry.getValue();
+            // Loop map, find if all tiles from same package uses old key only.
+            boolean useNewKey = false;
+            boolean useOldKey = false;
+            for (Tile tile : tiles) {
+                if (CategoryKey.KEY_COMPAT_MAP.containsKey(tile.category)) {
+                    useOldKey = true;
+                } else {
+                    useNewKey = true;
+                    break;
+                }
+            }
+            // Uses only old key, map them to new keys one by one.
+            if (useOldKey && !useNewKey) {
+                for (Tile tile : tiles) {
+                    final String newCategoryKey = CategoryKey.KEY_COMPAT_MAP.get(tile.category);
+                    tile.category = newCategoryKey;
+                    // move tile to new category.
+                    DashboardCategory newCategory = categoryByKeyMap.get(newCategoryKey);
+                    if (newCategory == null) {
+                        newCategory = new DashboardCategory();
+                        categoryByKeyMap.put(newCategoryKey, newCategory);
+                    }
+                    newCategory.addTile(tile);
+                }
+            }
+        }
+    }
+
+    /**
+     * Sort the tiles injected from all apps such that if they have the same priority value,
+     * they wil lbe sorted by package name.
+     * <p/>
+     * A list of tiles are considered sorted when their priority value decreases in a linear
+     * scan.
+     */
+    @VisibleForTesting
+    synchronized void sortCategories(Context context,
+            Map<String, DashboardCategory> categoryByKeyMap) {
+        for (Entry<String, DashboardCategory> categoryEntry : categoryByKeyMap.entrySet()) {
+            categoryEntry.getValue().sortTiles(context.getPackageName());
+        }
+    }
+
+    /**
+     * Filter out duplicate tiles from category. Duplicate tiles are the ones pointing to the
+     * same intent.
+     */
+    @VisibleForTesting
+    synchronized void filterDuplicateTiles(Map<String, DashboardCategory> categoryByKeyMap) {
+        for (Entry<String, DashboardCategory> categoryEntry : categoryByKeyMap.entrySet()) {
+            final DashboardCategory category = categoryEntry.getValue();
+            final int count = category.getTilesCount();
+            final Set<ComponentName> components = new ArraySet<>();
+            for (int i = count - 1; i >= 0; i--) {
+                final Tile tile = category.getTile(i);
+                if (tile.intent == null) {
+                    continue;
+                }
+                final ComponentName tileComponent = tile.intent.getComponent();
+                if (components.contains(tileComponent)) {
+                    category.removeTile(i);
+                } else {
+                    components.add(tileComponent);
+                }
+            }
+        }
+    }
+
+    /**
+     * Sort priority value for tiles within a single {@code DashboardCategory}.
+     *
+     * @see #sortCategories(Context, Map)
+     */
+    private synchronized void sortCategoriesForExternalTiles(Context context,
+            DashboardCategory dashboardCategory) {
+        dashboardCategory.sortTiles(context.getPackageName());
+
+    }
+}
diff --git a/src/com/android/settings/dashboard/DashboardAdapter.java b/src/com/android/settings/dashboard/DashboardAdapter.java
index a76414d..b278f60 100644
--- a/src/com/android/settings/dashboard/DashboardAdapter.java
+++ b/src/com/android/settings/dashboard/DashboardAdapter.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.service.settings.suggestions.Suggestion;
 import android.text.TextUtils;
@@ -314,8 +315,9 @@
 
     @VisibleForTesting
     void onBindTile(DashboardItemHolder holder, Tile tile) {
-        Drawable icon = mCache.getIcon(tile.icon);
-        if (!TextUtils.equals(tile.icon.getResPackage(), mContext.getPackageName())
+        Icon tileIcon = tile.getIcon(mContext);
+        Drawable icon = mCache.getIcon(tileIcon);
+        if (!TextUtils.equals(tileIcon.getResPackage(), mContext.getPackageName())
                 && !(icon instanceof RoundedHomepageIcon)) {
             icon = new RoundedHomepageIcon(mContext, icon);
             try {
@@ -324,7 +326,7 @@
                             TileUtils.META_DATA_PREFERENCE_ICON_BACKGROUND_HINT, 0 /* default */);
                     if (colorRes != 0) {
                         final int bgColor = mContext.getPackageManager()
-                                .getResourcesForApplication(tile.icon.getResPackage())
+                                .getResourcesForApplication(tileIcon.getResPackage())
                                 .getColor(colorRes, null /* theme */);
                         ((RoundedHomepageIcon) icon).setBackgroundColor(bgColor);
                     }
@@ -332,7 +334,7 @@
             } catch (PackageManager.NameNotFoundException e) {
                 Log.e(TAG, "Failed to set background color for " + tile.intent.getPackage());
             }
-            mCache.updateIcon(tile.icon, icon);
+            mCache.updateIcon(tileIcon, icon);
         }
         holder.icon.setImageDrawable(icon);
         holder.title.setText(tile.title);
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
index a443355..a3410bd 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
@@ -34,13 +34,15 @@
 import android.util.Log;
 import android.util.Pair;
 
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
-import com.android.settingslib.drawer.CategoryManager;
 import com.android.settingslib.drawer.DashboardCategory;
 import com.android.settingslib.drawer.ProfileSelectDialog;
 import com.android.settingslib.drawer.Tile;
@@ -51,9 +53,6 @@
 import java.util.List;
 import java.util.Map;
 
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-
 /**
  * Impl for {@code DashboardFeatureProvider}.
  */
@@ -239,8 +238,9 @@
 
     @VisibleForTesting
     void bindIcon(Preference preference, Tile tile) {
-        if (tile.icon != null) {
-            preference.setIcon(tile.icon.loadDrawable(preference.getContext()));
+        final Icon tileIcon = tile.getIcon(mContext);
+        if (tileIcon != null) {
+            preference.setIcon(tileIcon.loadDrawable(preference.getContext()));
         } else if (tile.metaData != null
                 && tile.metaData.containsKey(META_DATA_PREFERENCE_ICON_URI)) {
             ThreadUtils.postOnBackgroundThread(() -> {
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index 2a962c1..fceec3b 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -24,6 +24,11 @@
 import android.util.ArraySet;
 import android.util.Log;
 
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+
 import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.core.PreferenceControllerListHelper;
@@ -43,11 +48,6 @@
 import java.util.Map;
 import java.util.Set;
 
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceManager;
-import androidx.preference.PreferenceScreen;
-
 /**
  * Base fragment for dashboard style UI containing a list of static and dynamic setting items.
  */
@@ -256,7 +256,8 @@
 
     @VisibleForTesting
     boolean tintTileIcon(Tile tile) {
-        if (tile.icon == null) {
+        final Context context = getContext();
+        if (tile.getIcon(context) == null) {
             return false;
         }
         // First check if the tile has set the icon tintable metadata.
@@ -265,7 +266,7 @@
                 && metadata.containsKey(TileUtils.META_DATA_PREFERENCE_ICON_TINTABLE)) {
             return metadata.getBoolean(TileUtils.META_DATA_PREFERENCE_ICON_TINTABLE);
         }
-        final String pkgName = getContext().getPackageName();
+        final String pkgName = context.getPackageName();
         // If this drawable is coming from outside Settings, tint it to match the color.
         return pkgName != null && tile.intent != null
                 && !pkgName.equals(tile.intent.getComponent().getPackageName());
@@ -330,7 +331,7 @@
     /**
      * Refresh preference items backed by DashboardCategory.
      */
-    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    @VisibleForTesting
     void refreshDashboardTiles(final String TAG) {
         final PreferenceScreen screen = getPreferenceScreen();
 
@@ -370,7 +371,7 @@
                 continue;
             }
             if (tintTileIcon(tile)) {
-                tile.icon.setTint(tintColor);
+                tile.getIcon(context).setTint(tintColor);
             }
             if (mDashboardTilePrefKeys.contains(key)) {
                 // Have the key already, will rebind.
diff --git a/src/com/android/settings/deviceinfo/DeviceNamePreferenceController.java b/src/com/android/settings/deviceinfo/DeviceNamePreferenceController.java
index 0d4df99..558e7cb 100644
--- a/src/com/android/settings/deviceinfo/DeviceNamePreferenceController.java
+++ b/src/com/android/settings/deviceinfo/DeviceNamePreferenceController.java
@@ -27,6 +27,7 @@
 
 import com.android.settings.bluetooth.BluetoothLengthDeviceNameFilter;
 import com.android.settings.core.BasePreferenceController;
+import com.android.settings.R;
 import com.android.settings.widget.ValidatedEditTextPreference;
 import com.android.settings.wifi.tether.WifiDeviceNameTextValidator;
 import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
@@ -90,7 +91,9 @@
 
     @Override
     public int getAvailabilityStatus() {
-        return AVAILABLE;
+        return mContext.getResources().getBoolean(R.bool.config_show_device_name)
+                ? AVAILABLE
+                : UNSUPPORTED_ON_DEVICE;
     }
 
     @Override
diff --git a/src/com/android/settings/deviceinfo/UptimePreferenceController.java b/src/com/android/settings/deviceinfo/UptimePreferenceController.java
new file mode 100644
index 0000000..4f02594
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/UptimePreferenceController.java
@@ -0,0 +1,35 @@
+/*
+ * 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.deviceinfo;
+
+import android.content.Context;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.deviceinfo.AbstractUptimePreferenceController;
+
+/**
+ * Concrete subclass of uptime preference controller
+ */
+public class UptimePreferenceController extends AbstractUptimePreferenceController
+        implements PreferenceControllerMixin {
+    public UptimePreferenceController(Context context, Lifecycle lifecycle) {
+        super(context, lifecycle);
+    }
+
+    // This space intentionally left blank
+}
\ No newline at end of file
diff --git a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
index 976a254..29acf45 100644
--- a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
+++ b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
@@ -46,6 +46,7 @@
 import com.android.settings.deviceinfo.PhoneNumberPreferenceController;
 import com.android.settings.deviceinfo.RegulatoryInfoPreferenceController;
 import com.android.settings.deviceinfo.SafetyInfoPreferenceController;
+import com.android.settings.deviceinfo.UptimePreferenceController;
 import com.android.settings.deviceinfo.WifiMacAddressPreferenceController;
 import com.android.settings.deviceinfo.firmwareversion.FirmwareVersionPreferenceController;
 import com.android.settings.deviceinfo.imei.ImeiInfoPreferenceController;
@@ -134,6 +135,7 @@
         controllers.add(new FccEquipmentIdPreferenceController(context));
         controllers.add(
                 new BuildNumberPreferenceController(context, activity, fragment, lifecycle));
+        controllers.add(new UptimePreferenceController(context, lifecycle));
         return controllers;
     }
 
diff --git a/src/com/android/settings/display/BatteryPercentagePreferenceController.java b/src/com/android/settings/display/BatteryPercentagePreferenceController.java
index 0bd4445..50fbc64 100644
--- a/src/com/android/settings/display/BatteryPercentagePreferenceController.java
+++ b/src/com/android/settings/display/BatteryPercentagePreferenceController.java
@@ -21,8 +21,8 @@
 import android.provider.Settings;
 
 import com.android.internal.R;
+import com.android.settings.core.BasePreferenceController;
 import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.core.AbstractPreferenceController;
 
 import androidx.preference.Preference;
 import androidx.preference.SwitchPreference;
@@ -31,24 +31,18 @@
  * A controller to manage the switch for showing battery percentage in the status bar.
  */
 
-public class BatteryPercentagePreferenceController extends AbstractPreferenceController implements
+public class BatteryPercentagePreferenceController extends BasePreferenceController implements
         PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
 
-    private static final String KEY_BATTERY_PERCENTAGE = "battery_percentage";
-
-    public BatteryPercentagePreferenceController(Context context) {
-        super(context);
+    public BatteryPercentagePreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
     }
 
     @Override
-    public boolean isAvailable() {
-        return mContext.getResources()
-                .getBoolean(R.bool.config_battery_percentage_setting_available);
-    }
-
-    @Override
-    public String getPreferenceKey() {
-        return KEY_BATTERY_PERCENTAGE;
+    public int getAvailabilityStatus() {
+        return mContext.getResources().getBoolean(
+                R.bool.config_battery_percentage_setting_available) ? AVAILABLE
+                : UNSUPPORTED_ON_DEVICE;
     }
 
     @Override
diff --git a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
index 71eb554..5b5f50a 100644
--- a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
@@ -27,6 +27,7 @@
 
 import com.android.settings.R;
 import com.android.settings.applications.LayoutPreference;
+import com.android.settings.core.BasePreferenceController;
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.widget.EntityHeaderController;
 import com.android.settingslib.Utils;
@@ -42,7 +43,7 @@
 /**
  * Controller that update the battery header view
  */
-public class BatteryHeaderPreferenceController extends AbstractPreferenceController
+public class BatteryHeaderPreferenceController extends BasePreferenceController
         implements PreferenceControllerMixin, LifecycleObserver, OnStart {
     @VisibleForTesting
     static final String KEY_BATTERY_HEADER = "battery_header";
@@ -56,30 +57,35 @@
     @VisibleForTesting
     TextView mSummary2;
 
-    private final Activity mActivity;
-    private final PreferenceFragmentCompat mHost;
-    private final Lifecycle mLifecycle;
+    private Activity mActivity;
+    private PreferenceFragmentCompat mHost;
+    private Lifecycle mLifecycle;
     private final PowerManager mPowerManager;
 
     private LayoutPreference mBatteryLayoutPref;
 
-    public BatteryHeaderPreferenceController(Context context, Activity activity,
-            PreferenceFragmentCompat host, Lifecycle lifecycle) {
-        super(context);
-        mActivity = activity;
-        mHost = host;
-        mLifecycle = lifecycle;
-        if (mLifecycle != null) {
-            mLifecycle.addObserver(this);
-        }
+    public BatteryHeaderPreferenceController(Context context, String key) {
+        super(context, key);
         mPowerManager = context.getSystemService(PowerManager.class);
     }
 
+    public void setActivity(Activity activity) {
+        mActivity = activity;
+    }
+
+    public void setFragment(PreferenceFragmentCompat fragment) {
+        mHost = fragment;
+    }
+
+    public void setLifecycle(Lifecycle lifecycle) {
+        mLifecycle = lifecycle;
+    }
+
     @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
-        mBatteryLayoutPref = (LayoutPreference) screen.findPreference(KEY_BATTERY_HEADER);
-        mBatteryMeterView = (BatteryMeterView) mBatteryLayoutPref
+        mBatteryLayoutPref = (LayoutPreference) screen.findPreference(getPreferenceKey());
+        mBatteryMeterView = mBatteryLayoutPref
                 .findViewById(R.id.battery_header_icon);
         mBatteryPercentText = mBatteryLayoutPref.findViewById(R.id.battery_percent);
         mSummary1 = mBatteryLayoutPref.findViewById(R.id.summary1);
@@ -89,13 +95,8 @@
     }
 
     @Override
-    public boolean isAvailable() {
-        return true;
-    }
-
-    @Override
-    public String getPreferenceKey() {
-        return KEY_BATTERY_HEADER;
+    public int getAvailabilityStatus() {
+        return AVAILABLE_UNSEARCHABLE;
     }
 
     @Override
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index 9e920c4..3676761 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -38,11 +38,14 @@
 import com.android.internal.os.BatteryStatsHelper;
 import com.android.internal.util.ArrayUtils;
 import com.android.settings.R;
+import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper;
 import com.android.settings.fuelgauge.batterytip.AnomalyInfo;
+import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager;
 import com.android.settings.fuelgauge.batterytip.StatsManagerConfig;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.fuelgauge.PowerWhitelistBackend;
 import com.android.settingslib.utils.PowerUtil;
+import com.android.settingslib.utils.ThreadUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -101,8 +104,8 @@
         mContext = context;
         mPackageManager = context.getPackageManager();
         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
-        mPowerUsageFeatureProvider = FeatureFactory.getFactory(
-                context).getPowerUsageFeatureProvider(context);
+        mPowerUsageFeatureProvider = FeatureFactory.getFactory(context)
+                .getPowerUsageFeatureProvider(context);
     }
 
     public long getProcessTimeMs(@StatusType int type, @Nullable BatteryStats.Uid uid,
@@ -400,6 +403,18 @@
         }
         // Control whether app could run jobs in the background
         mAppOpsManager.setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName, mode);
+
+        ThreadUtils.postOnBackgroundThread(() -> {
+            final BatteryDatabaseManager batteryDatabaseManager = BatteryDatabaseManager
+                    .getInstance(mContext);
+            if (mode == AppOpsManager.MODE_IGNORED) {
+                batteryDatabaseManager.insertAction(AnomalyDatabaseHelper.ActionType.RESTRICTION,
+                        uid, packageName, System.currentTimeMillis());
+            } else if (mode == AppOpsManager.MODE_ALLOWED) {
+                batteryDatabaseManager.deleteAction(AnomalyDatabaseHelper.ActionType.RESTRICTION,
+                        uid, packageName);
+            }
+        });
     }
 
     public boolean isForceAppStandbyEnabled(int uid, String packageName) {
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 843aeec..2ae5876 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -25,7 +25,6 @@
 import android.provider.SearchIndexableResource;
 import android.text.BidiFormatter;
 import android.text.format.Formatter;
-import android.util.SparseArray;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -40,19 +39,15 @@
 import com.android.settings.applications.LayoutPreference;
 import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.dashboard.SummaryLoader;
-import com.android.settings.display.BatteryPercentagePreferenceController;
 import com.android.settings.fuelgauge.batterytip.BatteryTipLoader;
 import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.search.SearchIndexable;
 import com.android.settingslib.utils.PowerUtil;
 import com.android.settingslib.utils.StringUtil;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
@@ -198,6 +193,22 @@
             };
 
     @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+        final SettingsActivity activity = (SettingsActivity) getActivity();
+
+        mBatteryHeaderPreferenceController = use(BatteryHeaderPreferenceController.class);
+        mBatteryHeaderPreferenceController.setActivity(activity);
+        mBatteryHeaderPreferenceController.setFragment(this);
+        mBatteryHeaderPreferenceController.setLifecycle(getSettingsLifecycle());
+
+        mBatteryTipPreferenceController = use(BatteryTipPreferenceController.class);
+        mBatteryTipPreferenceController.setActivity(activity);
+        mBatteryTipPreferenceController.setFragment(this);
+        mBatteryTipPreferenceController.setBatteryTipListener(this::onBatteryTipHandled);
+    }
+
+    @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
         setAnimationAllowed(true);
@@ -232,22 +243,6 @@
     }
 
     @Override
-    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
-        final Lifecycle lifecycle = getSettingsLifecycle();
-        final SettingsActivity activity = (SettingsActivity) getActivity();
-        final List<AbstractPreferenceController> controllers = new ArrayList<>();
-        mBatteryHeaderPreferenceController = new BatteryHeaderPreferenceController(
-                context, activity, this /* host */, lifecycle);
-        controllers.add(mBatteryHeaderPreferenceController);
-        mBatteryTipPreferenceController = new BatteryTipPreferenceController(context,
-                KEY_BATTERY_TIP, (SettingsActivity) getActivity(), this /* fragment */, this /*
-                BatteryTipListener */);
-        controllers.add(mBatteryTipPreferenceController);
-        controllers.add(new BatteryPercentagePreferenceController(context));
-        return controllers;
-    }
-
-    @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         if (DEBUG) {
             menu.add(Menu.NONE, MENU_STATS_TYPE, Menu.NONE, R.string.menu_stats_total)
diff --git a/src/com/android/settings/fuelgauge/RestrictedAppDetails.java b/src/com/android/settings/fuelgauge/RestrictedAppDetails.java
index 4934bce..b64a707 100644
--- a/src/com/android/settings/fuelgauge/RestrictedAppDetails.java
+++ b/src/com/android/settings/fuelgauge/RestrictedAppDetails.java
@@ -22,6 +22,8 @@
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.util.IconDrawableFactory;
+import android.util.Log;
+import android.util.SparseLongArray;
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
@@ -29,7 +31,9 @@
 import com.android.settings.core.InstrumentedPreferenceFragment;
 import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper;
 import com.android.settings.fuelgauge.batterytip.AppInfo;
+import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager;
 import com.android.settings.fuelgauge.batterytip.BatteryTipDialogFragment;
 import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
@@ -37,6 +41,7 @@
 import com.android.settings.fuelgauge.batterytip.tips.UnrestrictAppTip;
 import com.android.settings.widget.AppCheckBoxPreference;
 import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.utils.StringUtil;
 import com.android.settingslib.widget.FooterPreferenceMixinCompat;
 
 import java.util.List;
@@ -57,6 +62,7 @@
     @VisibleForTesting
     static final String EXTRA_APP_INFO_LIST = "app_info_list";
     private static final String KEY_PREF_RESTRICTED_APP_LIST = "restrict_app_list";
+    private static final long TIME_NULL = -1;
 
     @VisibleForTesting
     List<AppInfo> mAppInfos;
@@ -68,6 +74,8 @@
     BatteryUtils mBatteryUtils;
     @VisibleForTesting
     PackageManager mPackageManager;
+    @VisibleForTesting
+    BatteryDatabaseManager mBatteryDatabaseManager;
     private final FooterPreferenceMixinCompat mFooterPreferenceMixin =
             new FooterPreferenceMixinCompat(this, getSettingsLifecycle());
 
@@ -96,6 +104,7 @@
         mPackageManager = context.getPackageManager();
         mIconDrawableFactory = IconDrawableFactory.newInstance(context);
         mBatteryUtils = BatteryUtils.getInstance(context);
+        mBatteryDatabaseManager = BatteryDatabaseManager.getInstance(context);
 
         refreshUi();
     }
@@ -135,6 +144,9 @@
     void refreshUi() {
         mRestrictedAppListGroup.removeAll();
         final Context context = getPrefContext();
+        final SparseLongArray timestampArray = mBatteryDatabaseManager
+                .queryActionTime(AnomalyDatabaseHelper.ActionType.RESTRICTION);
+        final long now = System.currentTimeMillis();
 
         for (int i = 0, size = mAppInfos.size(); i < size; i++) {
             final CheckBoxPreference checkBoxPreference = new AppCheckBoxPreference(context);
@@ -158,9 +170,16 @@
 
                     return false;
                 });
+
+                final long timestamp = timestampArray.get(appInfo.uid, TIME_NULL);
+                if (timestamp != TIME_NULL) {
+                    checkBoxPreference.setSummary(getString(R.string.restricted_app_time_summary,
+                            StringUtil.formatRelativeTime(context, now - timestamp, false)));
+                }
+                final CharSequence test = checkBoxPreference.getSummaryOn();
                 mRestrictedAppListGroup.addPreference(checkBoxPreference);
             } catch (PackageManager.NameNotFoundException e) {
-                e.printStackTrace();
+                Log.e(TAG, "Can't find package: " + appInfo.packageName);
             }
         }
     }
diff --git a/src/com/android/settings/fuelgauge/batterytip/AnomalyDatabaseHelper.java b/src/com/android/settings/fuelgauge/batterytip/AnomalyDatabaseHelper.java
index bc332b6..bd1633f 100644
--- a/src/com/android/settings/fuelgauge/batterytip/AnomalyDatabaseHelper.java
+++ b/src/com/android/settings/fuelgauge/batterytip/AnomalyDatabaseHelper.java
@@ -33,7 +33,7 @@
     private static final String TAG = "BatteryDatabaseHelper";
 
     private static final String DATABASE_NAME = "battery_settings.db";
-    private static final int DATABASE_VERSION = 4;
+    private static final int DATABASE_VERSION = 5;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({State.NEW,
@@ -45,8 +45,15 @@
         int AUTO_HANDLED = 2;
     }
 
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({ActionType.RESTRICTION})
+    public @interface ActionType {
+        int RESTRICTION = 0;
+    }
+
     public interface Tables {
         String TABLE_ANOMALY = "anomaly";
+        String TABLE_ACTION = "action";
     }
 
     public interface AnomalyColumns {
@@ -91,6 +98,42 @@
                     + AnomalyColumns.ANOMALY_STATE + "," + AnomalyColumns.TIME_STAMP_MS + ")"
                     + ")";
 
+
+    public interface ActionColumns {
+        /**
+         * The package name of an app been performed an action
+         */
+        String PACKAGE_NAME = "package_name";
+        /**
+         * The uid of an app been performed an action
+         */
+        String UID = "uid";
+        /**
+         * The type of user action
+         * @see ActionType
+         */
+        String ACTION_TYPE = "action_type";
+        /**
+         * The time when action been performed
+         */
+        String TIME_STAMP_MS = "time_stamp_ms";
+    }
+
+    private static final String CREATE_ACTION_TABLE =
+            "CREATE TABLE " + Tables.TABLE_ACTION +
+                    "(" +
+                    ActionColumns.UID +
+                    " INTEGER NOT NULL, " +
+                    ActionColumns.PACKAGE_NAME +
+                    " TEXT, " +
+                    ActionColumns.ACTION_TYPE +
+                    " INTEGER NOT NULL, " +
+                    ActionColumns.TIME_STAMP_MS +
+                    " INTEGER NOT NULL, " +
+                    " PRIMARY KEY (" + ActionColumns.ACTION_TYPE + "," + ActionColumns.UID + ","
+                    + ActionColumns.PACKAGE_NAME + ")"
+                    + ")";
+
     private static AnomalyDatabaseHelper sSingleton;
 
     public static synchronized AnomalyDatabaseHelper getInstance(Context context) {
@@ -109,11 +152,6 @@
         bootstrapDB(db);
     }
 
-    private void bootstrapDB(SQLiteDatabase db) {
-        db.execSQL(CREATE_ANOMALY_TABLE);
-        Log.i(TAG, "Bootstrapped database");
-    }
-
     @Override
     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
         if (oldVersion < DATABASE_VERSION) {
@@ -137,7 +175,14 @@
         bootstrapDB(db);
     }
 
+    private void bootstrapDB(SQLiteDatabase db) {
+        db.execSQL(CREATE_ANOMALY_TABLE);
+        db.execSQL(CREATE_ACTION_TABLE);
+        Log.i(TAG, "Bootstrapped database");
+    }
+
     private void dropTables(SQLiteDatabase db) {
         db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_ANOMALY);
+        db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_ACTION);
     }
 }
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java b/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java
index 910b368..513244e 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java
@@ -17,6 +17,8 @@
 package com.android.settings.fuelgauge.batterytip;
 
 import static android.database.sqlite.SQLiteDatabase.CONFLICT_IGNORE;
+import static android.database.sqlite.SQLiteDatabase.CONFLICT_REPLACE;
+
 import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns
         .ANOMALY_STATE;
 import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns
@@ -26,6 +28,7 @@
 import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns
         .TIME_STAMP_MS;
 import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns.UID;
+import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.Tables.TABLE_ACTION;
 import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.Tables.TABLE_ANOMALY;
 
 import android.content.ContentValues;
@@ -34,12 +37,15 @@
 import android.database.sqlite.SQLiteDatabase;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.SparseLongArray;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
+import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.ActionColumns;
+
 import androidx.annotation.VisibleForTesting;
 
 /**
@@ -158,4 +164,65 @@
             }
         }
     }
+
+    /**
+     * Query latest timestamps when an app has been performed action {@code type}
+     *
+     * @param type of action been performed
+     * @return {@link SparseLongArray} where key is uid and value is timestamp
+     */
+    public synchronized SparseLongArray queryActionTime(
+            @AnomalyDatabaseHelper.ActionType int type) {
+        final SparseLongArray timeStamps = new SparseLongArray();
+        try (SQLiteDatabase db = mDatabaseHelper.getReadableDatabase()) {
+            final String[] projection = {ActionColumns.UID, ActionColumns.TIME_STAMP_MS};
+            final String selection = ActionColumns.ACTION_TYPE + " = ? ";
+            final String[] selectionArgs = new String[]{String.valueOf(type)};
+
+            try (Cursor cursor = db.query(TABLE_ACTION, projection, selection, selectionArgs,
+                    null /* groupBy */, null /* having */, null /* orderBy */)) {
+                final int uidIndex = cursor.getColumnIndex(ActionColumns.UID);
+                final int timestampIndex = cursor.getColumnIndex(ActionColumns.TIME_STAMP_MS);
+
+                while (cursor.moveToNext()) {
+                    final int uid = cursor.getInt(uidIndex);
+                    final long timeStamp = cursor.getLong(timestampIndex);
+                    timeStamps.append(uid, timeStamp);
+                }
+            }
+        }
+
+        return timeStamps;
+    }
+
+    /**
+     * Insert an action, or update it if already existed
+     */
+    public synchronized boolean insertAction(@AnomalyDatabaseHelper.ActionType int type,
+            int uid, String packageName, long timestampMs) {
+        try (SQLiteDatabase db = mDatabaseHelper.getWritableDatabase()) {
+            final ContentValues values = new ContentValues();
+            values.put(ActionColumns.UID, uid);
+            values.put(ActionColumns.PACKAGE_NAME, packageName);
+            values.put(ActionColumns.ACTION_TYPE, type);
+            values.put(ActionColumns.TIME_STAMP_MS, timestampMs);
+            return db.insertWithOnConflict(TABLE_ACTION, null, values, CONFLICT_REPLACE) != -1;
+        }
+    }
+
+    /**
+     * Remove an action
+     */
+    public synchronized boolean deleteAction(@AnomalyDatabaseHelper.ActionType int type,
+            int uid, String packageName) {
+        try (SQLiteDatabase db = mDatabaseHelper.getWritableDatabase()) {
+            final String where =
+                    ActionColumns.ACTION_TYPE + " = ? AND " + ActionColumns.UID + " = ? AND "
+                            + ActionColumns.PACKAGE_NAME + " = ? ";
+            final String[] whereArgs = new String[]{String.valueOf(type), String.valueOf(uid),
+                    String.valueOf(packageName)};
+
+            return db.delete(TABLE_ACTION, where, whereArgs) != 0;
+        }
+    }
 }
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java
index 0a9a4c7..158ffd4 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java
@@ -59,24 +59,27 @@
     InstrumentedPreferenceFragment mFragment;
 
     public BatteryTipPreferenceController(Context context, String preferenceKey) {
-        this(context, preferenceKey, null, null, null);
-    }
-
-    public BatteryTipPreferenceController(Context context, String preferenceKey,
-            SettingsActivity settingsActivity, InstrumentedPreferenceFragment fragment,
-            BatteryTipListener batteryTipListener) {
         super(context, preferenceKey);
-        mBatteryTipListener = batteryTipListener;
         mBatteryTipMap = new HashMap<>();
-        mFragment = fragment;
-        mSettingsActivity = settingsActivity;
         mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
         mNeedUpdate = true;
     }
 
+    public void setActivity(SettingsActivity activity) {
+        mSettingsActivity = activity;
+    }
+
+    public void setFragment(InstrumentedPreferenceFragment fragment) {
+        mFragment = fragment;
+    }
+
+    public void setBatteryTipListener(BatteryTipListener lsn) {
+        mBatteryTipListener = lsn;
+    }
+
     @Override
     public int getAvailabilityStatus() {
-        return AVAILABLE;
+        return AVAILABLE_UNSEARCHABLE;
     }
 
     @Override
diff --git a/src/com/android/settings/homepage/HomepageFragment.java b/src/com/android/settings/homepage/HomepageFragment.java
index 9ccb8e2..ff89dd5 100644
--- a/src/com/android/settings/homepage/HomepageFragment.java
+++ b/src/com/android/settings/homepage/HomepageFragment.java
@@ -87,6 +87,8 @@
         final int screenWidthpx = getResources().getDisplayMetrics().widthPixels;
         final View searchbar = activity.findViewById(R.id.search_bar_container);
         final View bottombar = activity.findViewById(R.id.bar);
+        final Toolbar searchActionBar = (Toolbar) activity.findViewById(R.id.search_action_bar);
+        searchActionBar.setNavigationIcon(R.drawable.ic_search_floating_24dp);
 
 
         mBottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
diff --git a/src/com/android/settings/network/NetworkDashboardFragment.java b/src/com/android/settings/network/NetworkDashboardFragment.java
index 27e1a98..d5ef9aa 100644
--- a/src/com/android/settings/network/NetworkDashboardFragment.java
+++ b/src/com/android/settings/network/NetworkDashboardFragment.java
@@ -24,6 +24,7 @@
 import android.icu.text.ListFormatter;
 import android.provider.SearchIndexableResource;
 import android.text.BidiFormatter;
+import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.logging.nano.MetricsProto;
@@ -153,21 +154,25 @@
 
         private final Context mContext;
         private final SummaryLoader mSummaryLoader;
+        private final WifiMasterSwitchPreferenceController mWifiPreferenceController;
         private final MobileNetworkPreferenceController mMobileNetworkPreferenceController;
         private final TetherPreferenceController mTetherPreferenceController;
 
         public SummaryProvider(Context context, SummaryLoader summaryLoader) {
             this(context, summaryLoader,
+                    new WifiMasterSwitchPreferenceController(context, null),
                     new MobileNetworkPreferenceController(context),
                     new TetherPreferenceController(context, null /* lifecycle */));
         }
 
         @VisibleForTesting(otherwise = VisibleForTesting.NONE)
         SummaryProvider(Context context, SummaryLoader summaryLoader,
+                WifiMasterSwitchPreferenceController wifiPreferenceController,
                 MobileNetworkPreferenceController mobileNetworkPreferenceController,
                 TetherPreferenceController tetherPreferenceController) {
             mContext = context;
             mSummaryLoader = summaryLoader;
+            mWifiPreferenceController = wifiPreferenceController;
             mMobileNetworkPreferenceController = mobileNetworkPreferenceController;
             mTetherPreferenceController = tetherPreferenceController;
         }
@@ -176,20 +181,27 @@
         @Override
         public void setListening(boolean listening) {
             if (listening) {
-                final List<String> summaries = new ArrayList<>();
+                final String wifiSummary = BidiFormatter.getInstance()
+                    .unicodeWrap(mContext.getString(R.string.wifi_settings_title));
+                final String mobileSummary = mContext.getString(
+                    R.string.network_dashboard_summary_mobile);
+                final String dataUsageSummary = mContext.getString(
+                    R.string.network_dashboard_summary_data_usage);
+                final String hotspotSummary = mContext.getString(
+                    R.string.network_dashboard_summary_hotspot);
 
-                summaries.add(BidiFormatter.getInstance()
-                        .unicodeWrap(mContext.getString(R.string.wifi_settings_title)));
-                if (mMobileNetworkPreferenceController.isAvailable()) {
-                    summaries.add(mContext.getString(
-                            R.string.network_dashboard_summary_mobile));
+                final List<String> summaries = new ArrayList<>();
+                if (mWifiPreferenceController.isAvailable() && !TextUtils.isEmpty(wifiSummary)) {
+                    summaries.add(wifiSummary);
                 }
-                final String dataUsageSettingSummary = mContext.getString(
-                        R.string.network_dashboard_summary_data_usage);
-                summaries.add(dataUsageSettingSummary);
-                if (mTetherPreferenceController.isAvailable()) {
-                    summaries.add(mContext.getString(
-                            R.string.network_dashboard_summary_hotspot));
+                if (mMobileNetworkPreferenceController.isAvailable() && !TextUtils.isEmpty(mobileSummary)) {
+                    summaries.add(mobileSummary);
+                }
+                if (!TextUtils.isEmpty(dataUsageSummary)) {
+                    summaries.add(dataUsageSummary);
+                }
+                if (mTetherPreferenceController.isAvailable() && !TextUtils.isEmpty(hotspotSummary)) {
+                    summaries.add(hotspotSummary);
                 }
                 mSummaryLoader.setSummary(this, ListFormatter.getInstance().format(summaries));
             }
diff --git a/src/com/android/settings/overlay/SupportFeatureProvider.java b/src/com/android/settings/overlay/SupportFeatureProvider.java
index 0988fd4..a9b66d6 100644
--- a/src/com/android/settings/overlay/SupportFeatureProvider.java
+++ b/src/com/android/settings/overlay/SupportFeatureProvider.java
@@ -67,9 +67,4 @@
      * @param activity Calling activity.
      */
     void startSupportV2(Activity activity);
-
-    /**
-     * Returns a url with information to introduce user to new device.
-     */
-    String getNewDeviceIntroUrl(Context context);
 }
diff --git a/src/com/android/settings/print/PrintServiceSettingsFragment.java b/src/com/android/settings/print/PrintServiceSettingsFragment.java
index 1311be0..345b4ae 100644
--- a/src/com/android/settings/print/PrintServiceSettingsFragment.java
+++ b/src/com/android/settings/print/PrintServiceSettingsFragment.java
@@ -286,7 +286,7 @@
 
     @Override
     public Loader<List<PrintServiceInfo>> onCreateLoader(int id, Bundle args) {
-        return new PrintServicesLoader(
+        return new SettingsPrintServicesLoader(
                 (PrintManager) getContext().getSystemService(Context.PRINT_SERVICE), getContext(),
                 PrintManager.ALL_SERVICES);
     }
diff --git a/src/com/android/settings/print/PrintServicesLoader.java b/src/com/android/settings/print/PrintServicesLoader.java
deleted file mode 100644
index 57cddb9..0000000
--- a/src/com/android/settings/print/PrintServicesLoader.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * 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.print;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.os.Handler;
-import android.os.Message;
-import android.print.PrintManager;
-import android.printservice.PrintServiceInfo;
-
-import com.android.internal.util.Preconditions;
-
-import java.util.List;
-
-import androidx.loader.content.Loader;
-
-/**
- * Loader for the list of print services. Can be parametrized to select a subset.
- *
- */
-public class PrintServicesLoader extends Loader<List<PrintServiceInfo>> {
-    /** What type of services to load. */
-    private final int mSelectionFlags;
-
-    /** The print manager to be used by this object */
-    private final @NonNull PrintManager mPrintManager;
-
-    /** Handler to sequentialize the delivery of the results to the main thread */
-    private final @NonNull Handler mHandler;
-
-    /** Listens for updates to the data from the platform */
-    private PrintManager.PrintServicesChangeListener mListener;
-
-    /**
-     * Create a new PrintServicesLoader.
-     *
-     * @param printManager   The print manager supplying the data
-     * @param context        Context of the using object
-     * @param selectionFlags What type of services to load.
-     */
-    public PrintServicesLoader(@NonNull PrintManager printManager, @NonNull Context context,
-            int selectionFlags) {
-        super(Preconditions.checkNotNull(context));
-        mHandler = new MyHandler();
-        mPrintManager = Preconditions.checkNotNull(printManager);
-        mSelectionFlags = Preconditions.checkFlagsArgument(selectionFlags,
-                PrintManager.ALL_SERVICES);
-    }
-
-    @Override
-    protected void onForceLoad() {
-        queueNewResult();
-    }
-
-    /**
-     * Read the print services and queue it to be delivered on the main thread.
-     */
-    private void queueNewResult() {
-        Message m = mHandler.obtainMessage(0);
-        m.obj = mPrintManager.getPrintServices(mSelectionFlags);
-        mHandler.sendMessage(m);
-    }
-
-    @Override
-    protected void onStartLoading() {
-        mListener = new PrintManager.PrintServicesChangeListener() {
-            @Override public void onPrintServicesChanged() {
-                queueNewResult();
-            }
-        };
-
-        mPrintManager.addPrintServicesChangeListener(mListener, null);
-
-        // Immediately deliver a result
-        deliverResult(mPrintManager.getPrintServices(mSelectionFlags));
-    }
-
-    @Override
-    protected void onStopLoading() {
-        if (mListener != null) {
-            mPrintManager.removePrintServicesChangeListener(mListener);
-            mListener = null;
-        }
-
-        mHandler.removeMessages(0);
-    }
-
-    @Override
-    protected void onReset() {
-        onStopLoading();
-    }
-
-    /**
-     * Handler to sequentialize all the updates to the main thread.
-     */
-    private class MyHandler extends Handler {
-        /**
-         * Create a new handler on the main thread.
-         */
-        public MyHandler() {
-            super(getContext().getMainLooper());
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            if (isStarted()) {
-                deliverResult((List<PrintServiceInfo>) msg.obj);
-            }
-        }
-    }
-}
diff --git a/src/com/android/settings/print/PrintSettingsFragment.java b/src/com/android/settings/print/PrintSettingsFragment.java
index a6b3d7e..899acc7 100644
--- a/src/com/android/settings/print/PrintSettingsFragment.java
+++ b/src/com/android/settings/print/PrintSettingsFragment.java
@@ -168,7 +168,7 @@
             PrintManager printManager =
                     (PrintManager) getContext().getSystemService(Context.PRINT_SERVICE);
             if (printManager != null) {
-                return new PrintServicesLoader(printManager, getContext(),
+                return new SettingsPrintServicesLoader(printManager, getContext(),
                         PrintManager.ALL_SERVICES);
             } else {
                 return null;
diff --git a/src/com/android/settings/print/SettingsPrintServicesLoader.java b/src/com/android/settings/print/SettingsPrintServicesLoader.java
new file mode 100644
index 0000000..758f4d3
--- /dev/null
+++ b/src/com/android/settings/print/SettingsPrintServicesLoader.java
@@ -0,0 +1,82 @@
+/*
+ * 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.print;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.print.PrintManager;
+import android.print.PrintServicesLoader;
+import android.printservice.PrintServiceInfo;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+import androidx.loader.content.Loader;
+
+/**
+ * Loader for the list of print services. Can be parametrized to select a subset.
+ */
+public class SettingsPrintServicesLoader extends Loader<List<PrintServiceInfo>> {
+
+    private PrintServicesLoader mLoader;
+
+    public SettingsPrintServicesLoader(@NonNull PrintManager printManager, @NonNull Context context,
+            int selectionFlags) {
+        super(Preconditions.checkNotNull(context));
+
+        mLoader = new PrintServicesLoader(printManager, context, selectionFlags) {
+            @Override
+            public void deliverResult(List<PrintServiceInfo> data) {
+                super.deliverResult(data);
+
+                // deliver the result to outer Loader class
+                SettingsPrintServicesLoader.this.deliverResult(data);
+            }
+        };
+    }
+
+    @Override
+    protected void onForceLoad() {
+        mLoader.forceLoad();
+    }
+
+    @Override
+    protected void onStartLoading() {
+        mLoader.startLoading();
+    }
+
+    @Override
+    protected void onStopLoading() {
+        mLoader.stopLoading();
+    }
+
+    @Override
+    protected boolean onCancelLoad() {
+        return mLoader.cancelLoad();
+    }
+
+    @Override
+    protected void onAbandon() {
+        mLoader.abandon();
+    }
+
+    @Override
+    protected void onReset() {
+        mLoader.reset();
+    }
+}
diff --git a/src/com/android/settings/security/ChangeScreenLockPreferenceController.java b/src/com/android/settings/security/ChangeScreenLockPreferenceController.java
index 156e230..1284b6a 100644
--- a/src/com/android/settings/security/ChangeScreenLockPreferenceController.java
+++ b/src/com/android/settings/security/ChangeScreenLockPreferenceController.java
@@ -84,8 +84,7 @@
     @Override
     public void updateState(Preference preference) {
         if (mPreference != null && mPreference instanceof GearPreference) {
-            if (mLockPatternUtils.isSecure(mUserId)
-                    || !mLockPatternUtils.isLockScreenDisabled(mUserId)) {
+            if (mLockPatternUtils.isSecure(mUserId)) {
                 ((GearPreference) mPreference).setOnGearClickListener(this);
             } else {
                 ((GearPreference) mPreference).setOnGearClickListener(null);
diff --git a/src/com/android/settings/security/SecuritySettings.java b/src/com/android/settings/security/SecuritySettings.java
index effbd51..72dd91b 100644
--- a/src/com/android/settings/security/SecuritySettings.java
+++ b/src/com/android/settings/security/SecuritySettings.java
@@ -21,6 +21,7 @@
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
+import android.hardware.face.FaceManager;
 import android.hardware.fingerprint.FingerprintManager;
 import android.provider.SearchIndexableResource;
 
@@ -181,7 +182,12 @@
             if (listening) {
                 final FingerprintManager fpm =
                         Utils.getFingerprintManagerOrNull(mContext);
-                if (fpm != null && fpm.isHardwareDetected()) {
+                final FaceManager faceManager =
+                        Utils.getFaceManagerOrNull(mContext);
+                if (faceManager != null && faceManager.isHardwareDetected()) {
+                    mSummaryLoader.setSummary(this,
+                            mContext.getString(R.string.security_dashboard_summary_face));
+                } else if (fpm != null && fpm.isHardwareDetected()) {
                     mSummaryLoader.setSummary(this,
                             mContext.getString(R.string.security_dashboard_summary));
                 } else {
diff --git a/src/com/android/settings/widget/AppCheckBoxPreference.java b/src/com/android/settings/widget/AppCheckBoxPreference.java
index a0d95e9..bd643ba 100644
--- a/src/com/android/settings/widget/AppCheckBoxPreference.java
+++ b/src/com/android/settings/widget/AppCheckBoxPreference.java
@@ -17,11 +17,16 @@
 package com.android.settings.widget;
 
 import android.content.Context;
+import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
 
 import com.android.settings.R;
 
 import androidx.preference.CheckBoxPreference;
+import androidx.preference.PreferenceViewHolder;
 
 /**
  * {@link CheckBoxPreference} that used only to display app
@@ -36,4 +41,20 @@
         super(context);
         setLayoutResource(R.layout.preference_app);
     }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+
+        final TextView appendix = (TextView) holder.findViewById(R.id.appendix);
+        if (appendix != null) {
+            appendix.setVisibility(View.GONE);
+        }
+
+        final LinearLayout layout = (LinearLayout) holder.findViewById(R.id.summary_container);
+        if (layout != null) {
+            // If summary doesn't exist, make it gone
+            layout.setVisibility(TextUtils.isEmpty(getSummary()) ? View.GONE : View.VISIBLE);
+        }
+    }
 }
diff --git a/tests/robotests/assets/grandfather_not_sharing_pref_controllers_with_search_provider b/tests/robotests/assets/grandfather_not_sharing_pref_controllers_with_search_provider
index b329072..e69de29 100644
--- a/tests/robotests/assets/grandfather_not_sharing_pref_controllers_with_search_provider
+++ b/tests/robotests/assets/grandfather_not_sharing_pref_controllers_with_search_provider
@@ -1 +0,0 @@
-com.android.settings.fuelgauge.PowerUsageSummary
diff --git a/tests/robotests/res/values-mcc999/config.xml b/tests/robotests/res/values-mcc999/config.xml
index 2d95b65..6d82451 100644
--- a/tests/robotests/res/values-mcc999/config.xml
+++ b/tests/robotests/res/values-mcc999/config.xml
@@ -61,6 +61,7 @@
     <bool name="config_show_wifi_ip_address">false</bool>
     <bool name="config_show_wifi_mac_address">false</bool>
     <bool name="config_disable_uninstall_update">true</bool>
+    <bool name="config_show_device_name">false</bool>
 
     <!-- List of a11y components on the device allowed to be enabled by Settings Slices -->
     <string-array name="config_settings_slices_accessibility_components" translatable="false">
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
index 36b6b80..33ac5b6 100644
--- a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
@@ -16,6 +16,7 @@
 package com.android.settings.accounts;
 
 import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.mock;
@@ -25,11 +26,14 @@
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Bundle;
 import android.os.UserHandle;
 
+import androidx.preference.Preference;
+
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.dashboard.DashboardFeatureProviderImpl;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -44,8 +48,6 @@
 import org.robolectric.Shadows;
 import org.robolectric.util.ReflectionHelpers;
 
-import androidx.preference.Preference;
-
 @RunWith(SettingsRobolectricTestRunner.class)
 public class AccountDetailDashboardFragmentTest {
 
@@ -72,12 +74,12 @@
     @Test
     public void testCategory_isAccountDetail() {
         assertThat(new AccountDetailDashboardFragment().getCategoryKey())
-            .isEqualTo(CategoryKey.CATEGORY_ACCOUNT_DETAIL);
+                .isEqualTo(CategoryKey.CATEGORY_ACCOUNT_DETAIL);
     }
 
     @Test
     public void refreshDashboardTiles_HasAccountType_shouldDisplay() {
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(new ActivityInfo());
         final Bundle metaData = new Bundle();
         metaData.putString(METADATA_CATEGORY, CategoryKey.CATEGORY_ACCOUNT_DETAIL);
         metaData.putString(METADATA_ACCOUNT_TYPE, "com.abc");
@@ -88,7 +90,7 @@
 
     @Test
     public void refreshDashboardTiles_NoAccountType_shouldNotDisplay() {
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(new ActivityInfo());
         final Bundle metaData = new Bundle();
         metaData.putString(METADATA_CATEGORY, CategoryKey.CATEGORY_ACCOUNT_DETAIL);
         tile.metaData = metaData;
@@ -98,7 +100,7 @@
 
     @Test
     public void refreshDashboardTiles_OtherAccountType_shouldNotDisplay() {
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(new ActivityInfo());
         final Bundle metaData = new Bundle();
         metaData.putString(METADATA_CATEGORY, CategoryKey.CATEGORY_ACCOUNT_DETAIL);
         metaData.putString(METADATA_ACCOUNT_TYPE, "com.other");
@@ -114,9 +116,9 @@
         final PackageManager packageManager = mock(PackageManager.class);
         ReflectionHelpers.setField(dashboardFeatureProvider, "mPackageManager", packageManager);
         when(packageManager.resolveActivity(any(Intent.class), anyInt()))
-            .thenReturn(mock(ResolveInfo.class));
+                .thenReturn(mock(ResolveInfo.class));
 
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(new ActivityInfo());
         tile.key = "key";
         tile.metaData = new Bundle();
         tile.metaData.putString(METADATA_CATEGORY, CategoryKey.CATEGORY_ACCOUNT);
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
index de558b3..e7902182 100644
--- a/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
@@ -563,6 +563,45 @@
         verify(preferenceGroup, times(1)).removePreference(argThat(titleMatches("Acct12")));
     }
 
+    @Test
+    public void onResume_userReEnabled_shouldAddOneAccountPreference() {
+        final List<UserInfo> infos = new ArrayList<>();
+        infos.add(new UserInfo(1, "user 1", UserInfo.FLAG_DISABLED));
+        when(mUserManager.isManagedProfile()).thenReturn(false);
+        when(mUserManager.isRestrictedProfile()).thenReturn(false);
+        when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
+
+        Account[] accounts = {new Account("Acct1", "com.acct1")};
+        when(mAccountManager.getAccountsAsUser(1)).thenReturn(accounts);
+        when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
+            .thenReturn(accounts);
+
+        AuthenticatorDescription[] authDescs = {
+            new AuthenticatorDescription("com.acct1", "com.android.settings",
+                R.string.account_settings_title, 0 /* iconId */, 0 /* smallIconId */,
+                0 /* prefId */, false /* customTokens */)
+        };
+        when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(authDescs);
+
+        AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
+        when(preferenceGroup.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
+        when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class)))
+            .thenReturn(preferenceGroup);
+
+        // First time resume will build the UI with no account
+        mController.onResume();
+        verify(preferenceGroup, never()).addPreference(argThat(titleMatches("Acct1")));
+
+        // Enable the user
+        infos.remove(0 /* index */);
+        infos.add(new UserInfo(1, "user 1", 0 /* flags */));
+
+        // Resume should show the account for the user
+        mController.onResume();
+
+        verify(preferenceGroup).addPreference(argThat(titleMatches("Acct1")));
+    }
+
     private static ArgumentMatcher<Preference> titleMatches(String expected) {
         return preference -> TextUtils.equals(expected, preference.getTitle());
     }
diff --git a/tests/robotests/src/com/android/settings/dashboard/CategoryManagerTest.java b/tests/robotests/src/com/android/settings/dashboard/CategoryManagerTest.java
new file mode 100644
index 0000000..3bb4a65
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/dashboard/CategoryManagerTest.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2016 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.dashboard;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.util.Pair;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.drawer.CategoryKey;
+import com.android.settingslib.drawer.DashboardCategory;
+import com.android.settingslib.drawer.Tile;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class CategoryManagerTest {
+
+    private ActivityInfo mActivityInfo;
+    private Context mContext;
+    private CategoryManager mCategoryManager;
+    private Map<Pair<String, String>, Tile> mTileByComponentCache;
+    private Map<String, DashboardCategory> mCategoryByKeyMap;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mActivityInfo = new ActivityInfo();
+        mActivityInfo.applicationInfo = new ApplicationInfo();
+        mTileByComponentCache = new HashMap<>();
+        mCategoryByKeyMap = new HashMap<>();
+        mCategoryManager = CategoryManager.get(mContext);
+    }
+
+    @Test
+    public void getInstance_shouldBeSingleton() {
+        assertThat(mCategoryManager).isSameAs(CategoryManager.get(mContext));
+    }
+
+    @Test
+    public void backwardCompatCleanupForCategory_shouldNotChangeCategoryForNewKeys() {
+        final Tile tile1 = new Tile(mActivityInfo);
+        final Tile tile2 = new Tile(mActivityInfo);
+        tile1.category = CategoryKey.CATEGORY_ACCOUNT;
+        tile2.category = CategoryKey.CATEGORY_ACCOUNT;
+        final DashboardCategory category = new DashboardCategory();
+        category.addTile(tile1);
+        category.addTile(tile2);
+        mCategoryByKeyMap.put(CategoryKey.CATEGORY_ACCOUNT, category);
+        mTileByComponentCache.put(new Pair<>("PACKAGE", "1"), tile1);
+        mTileByComponentCache.put(new Pair<>("PACKAGE", "2"), tile2);
+
+        mCategoryManager.backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
+
+        assertThat(mCategoryByKeyMap.size()).isEqualTo(1);
+        assertThat(mCategoryByKeyMap.get(CategoryKey.CATEGORY_ACCOUNT)).isNotNull();
+    }
+
+    @Test
+    public void backwardCompatCleanupForCategory_shouldNotChangeCategoryForMixedKeys() {
+        final Tile tile1 = new Tile(mActivityInfo);
+        final Tile tile2 = new Tile(mActivityInfo);
+        final String oldCategory = "com.android.settings.category.wireless";
+        tile1.category = CategoryKey.CATEGORY_ACCOUNT;
+        tile2.category = oldCategory;
+        final DashboardCategory category1 = new DashboardCategory();
+        category1.addTile(tile1);
+        final DashboardCategory category2 = new DashboardCategory();
+        category2.addTile(tile2);
+        mCategoryByKeyMap.put(CategoryKey.CATEGORY_ACCOUNT, category1);
+        mCategoryByKeyMap.put(oldCategory, category2);
+        mTileByComponentCache.put(new Pair<>("PACKAGE", "CLASS1"), tile1);
+        mTileByComponentCache.put(new Pair<>("PACKAGE", "CLASS2"), tile2);
+
+        mCategoryManager.backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
+
+        assertThat(mCategoryByKeyMap.size()).isEqualTo(2);
+        assertThat(
+                mCategoryByKeyMap.get(CategoryKey.CATEGORY_ACCOUNT).getTilesCount()).isEqualTo(1);
+        assertThat(mCategoryByKeyMap.get(oldCategory).getTilesCount()).isEqualTo(1);
+    }
+
+    @Test
+    public void backwardCompatCleanupForCategory_shouldChangeCategoryForOldKeys() {
+        final Tile tile1 = new Tile(mActivityInfo);
+        final String oldCategory = "com.android.settings.category.wireless";
+        tile1.category = oldCategory;
+        final DashboardCategory category1 = new DashboardCategory();
+        category1.addTile(tile1);
+        mCategoryByKeyMap.put(oldCategory, category1);
+        mTileByComponentCache.put(new Pair<>("PACKAGE", "CLASS1"), tile1);
+
+        mCategoryManager.backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
+
+        // Added 1 more category to category map.
+        assertThat(mCategoryByKeyMap.size()).isEqualTo(2);
+        // The new category map has CATEGORY_NETWORK type now, which contains 1 tile.
+        assertThat(
+                mCategoryByKeyMap.get(CategoryKey.CATEGORY_NETWORK).getTilesCount()).isEqualTo(1);
+        // Old category still exists.
+        assertThat(mCategoryByKeyMap.get(oldCategory).getTilesCount()).isEqualTo(1);
+    }
+
+    @Test
+    public void sortCategories_singlePackage_shouldReorderBasedOnPriority() {
+        // Create some fake tiles that are not sorted.
+        final String testPackage = "com.android.test";
+        final DashboardCategory category = new DashboardCategory();
+        final Tile tile1 = new Tile(mActivityInfo);
+        tile1.intent =
+                new Intent().setComponent(new ComponentName(testPackage, "class1"));
+        tile1.priority = 100;
+        final Tile tile2 = new Tile(mActivityInfo);
+        tile2.intent =
+                new Intent().setComponent(new ComponentName(testPackage, "class2"));
+        tile2.priority = 50;
+        final Tile tile3 = new Tile(mActivityInfo);
+        tile3.intent =
+                new Intent().setComponent(new ComponentName(testPackage, "class3"));
+        tile3.priority = 200;
+        category.addTile(tile1);
+        category.addTile(tile2);
+        category.addTile(tile3);
+        mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
+
+        // Sort their priorities
+        mCategoryManager.sortCategories(ShadowApplication.getInstance().getApplicationContext(),
+                mCategoryByKeyMap);
+
+        // Verify they are now sorted.
+        assertThat(category.getTile(0)).isSameAs(tile3);
+        assertThat(category.getTile(1)).isSameAs(tile1);
+        assertThat(category.getTile(2)).isSameAs(tile2);
+    }
+
+    @Test
+    public void sortCategories_multiPackage_shouldReorderBasedOnPackageAndPriority() {
+        // Create some fake tiles that are not sorted.
+        final String testPackage1 = "com.android.test1";
+        final String testPackage2 = "com.android.test2";
+        final DashboardCategory category = new DashboardCategory();
+        final Tile tile1 = new Tile(mActivityInfo);
+        tile1.intent =
+                new Intent().setComponent(new ComponentName(testPackage2, "class1"));
+        tile1.priority = 100;
+        final Tile tile2 = new Tile(mActivityInfo);
+        tile2.intent =
+                new Intent().setComponent(new ComponentName(testPackage1, "class2"));
+        tile2.priority = 100;
+        final Tile tile3 = new Tile(mActivityInfo);
+        tile3.intent =
+                new Intent().setComponent(new ComponentName(testPackage1, "class3"));
+        tile3.priority = 50;
+        category.addTile(tile1);
+        category.addTile(tile2);
+        category.addTile(tile3);
+        mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
+
+        // Sort their priorities
+        mCategoryManager.sortCategories(mContext, mCategoryByKeyMap);
+
+        // Verify they are now sorted.
+        assertThat(category.getTile(0)).isSameAs(tile2);
+        assertThat(category.getTile(1)).isSameAs(tile1);
+        assertThat(category.getTile(2)).isSameAs(tile3);
+    }
+
+    @Test
+    public void sortCategories_internalPackageTiles_shouldSkipTileForInternalPackage() {
+        // Create some fake tiles that are not sorted.
+        final String testPackage = mContext.getPackageName();
+        final DashboardCategory category = new DashboardCategory();
+        final Tile tile1 = new Tile(mActivityInfo);
+        tile1.intent =
+                new Intent().setComponent(new ComponentName(testPackage, "class1"));
+        tile1.priority = 100;
+        final Tile tile2 = new Tile(mActivityInfo);
+        tile2.intent =
+                new Intent().setComponent(new ComponentName(testPackage, "class2"));
+        tile2.priority = 100;
+        final Tile tile3 = new Tile(mActivityInfo);
+        tile3.intent =
+                new Intent().setComponent(new ComponentName(testPackage, "class3"));
+        tile3.priority = 50;
+        category.addTile(tile1);
+        category.addTile(tile2);
+        category.addTile(tile3);
+        mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
+
+        // Sort their priorities
+        mCategoryManager.sortCategories(mContext, mCategoryByKeyMap);
+
+        // Verify the sorting order is not changed
+        assertThat(category.getTile(0)).isSameAs(tile1);
+        assertThat(category.getTile(1)).isSameAs(tile2);
+        assertThat(category.getTile(2)).isSameAs(tile3);
+    }
+
+    @Test
+    public void sortCategories_internalAndExternalPackageTiles_shouldRetainPriorityOrdering() {
+        // Inject one external tile among internal tiles.
+        final String testPackage = mContext.getPackageName();
+        final String testPackage2 = "com.google.test2";
+        final DashboardCategory category = new DashboardCategory();
+        final Tile tile1 = new Tile(mActivityInfo);
+        tile1.intent = new Intent().setComponent(new ComponentName(testPackage, "class1"));
+        tile1.priority = 2;
+        final Tile tile2 = new Tile(mActivityInfo);
+        tile2.intent = new Intent().setComponent(new ComponentName(testPackage, "class2"));
+        tile2.priority = 1;
+        final Tile tile3 = new Tile(mActivityInfo);
+        tile3.intent = new Intent().setComponent(new ComponentName(testPackage2, "class0"));
+        tile3.priority = 0;
+        final Tile tile4 = new Tile(mActivityInfo);
+        tile4.intent = new Intent().setComponent(new ComponentName(testPackage, "class3"));
+        tile4.priority = -1;
+        category.addTile(tile1);
+        category.addTile(tile2);
+        category.addTile(tile3);
+        category.addTile(tile4);
+        mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
+
+        // Sort their priorities
+        mCategoryManager.sortCategories(mContext, mCategoryByKeyMap);
+
+        // Verify the sorting order is not changed
+        assertThat(category.getTile(0)).isSameAs(tile1);
+        assertThat(category.getTile(1)).isSameAs(tile2);
+        assertThat(category.getTile(2)).isSameAs(tile3);
+        assertThat(category.getTile(3)).isSameAs(tile4);
+    }
+
+    @Test
+    public void sortCategories_samePriority_internalPackageTileShouldTakePrecedence() {
+        // Inject one external tile among internal tiles with same priority.
+        final String testPackage = mContext.getPackageName();
+        final String testPackage2 = "com.google.test2";
+        final String testPackage3 = "com.abcde.test3";
+        final DashboardCategory category = new DashboardCategory();
+        final Tile tile1 = new Tile(mActivityInfo);
+        tile1.intent = new Intent().setComponent(new ComponentName(testPackage2, "class1"));
+        tile1.priority = 1;
+        final Tile tile2 = new Tile(mActivityInfo);
+        tile2.intent = new Intent().setComponent(new ComponentName(testPackage, "class2"));
+        tile2.priority = 1;
+        final Tile tile3 = new Tile(mActivityInfo);
+        tile3.intent = new Intent().setComponent(new ComponentName(testPackage3, "class3"));
+        tile3.priority = 1;
+        category.addTile(tile1);
+        category.addTile(tile2);
+        category.addTile(tile3);
+        mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
+
+        // Sort their priorities
+        mCategoryManager.sortCategories(mContext, mCategoryByKeyMap);
+
+        // Verify the sorting order is internal first, follow by package name ordering
+        assertThat(category.getTile(0)).isSameAs(tile2);
+        assertThat(category.getTile(1)).isSameAs(tile3);
+        assertThat(category.getTile(2)).isSameAs(tile1);
+    }
+
+    @Test
+    public void filterTiles_noDuplicate_noChange() {
+        // Create some unique tiles
+        final String testPackage = mContext.getPackageName();
+        final DashboardCategory category = new DashboardCategory();
+        final Tile tile1 = new Tile(mActivityInfo);
+        tile1.intent =
+                new Intent().setComponent(new ComponentName(testPackage, "class1"));
+        tile1.priority = 100;
+        final Tile tile2 = new Tile(mActivityInfo);
+        tile2.intent =
+                new Intent().setComponent(new ComponentName(testPackage, "class2"));
+        tile2.priority = 100;
+        final Tile tile3 = new Tile(mActivityInfo);
+        tile3.intent =
+                new Intent().setComponent(new ComponentName(testPackage, "class3"));
+        tile3.priority = 50;
+        category.addTile(tile1);
+        category.addTile(tile2);
+        category.addTile(tile3);
+        mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
+
+        mCategoryManager.filterDuplicateTiles(mCategoryByKeyMap);
+
+        assertThat(category.getTilesCount()).isEqualTo(3);
+    }
+
+    @Test
+    public void filterTiles_hasDuplicate_shouldOnlyKeepUniqueTiles() {
+        // Create tiles pointing to same intent.
+        final String testPackage = mContext.getPackageName();
+        final DashboardCategory category = new DashboardCategory();
+        final Tile tile1 = new Tile(mActivityInfo);
+        tile1.intent =
+                new Intent().setComponent(new ComponentName(testPackage, "class1"));
+        tile1.priority = 100;
+        final Tile tile2 = new Tile(mActivityInfo);
+        tile2.intent =
+                new Intent().setComponent(new ComponentName(testPackage, "class1"));
+        tile2.priority = 100;
+        final Tile tile3 = new Tile(mActivityInfo);
+        tile3.intent =
+                new Intent().setComponent(new ComponentName(testPackage, "class1"));
+        tile3.priority = 50;
+        category.addTile(tile1);
+        category.addTile(tile2);
+        category.addTile(tile3);
+        mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
+
+        mCategoryManager.filterDuplicateTiles(mCategoryByKeyMap);
+
+        assertThat(category.getTilesCount()).isEqualTo(1);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java
index f6786b8..c823433 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java
@@ -16,6 +16,7 @@
 package com.android.settings.dashboard;
 
 import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
@@ -28,6 +29,7 @@
 
 import android.app.PendingIntent;
 import android.content.Context;
+import android.content.pm.ActivityInfo;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
@@ -39,6 +41,8 @@
 import android.view.WindowManager;
 import android.widget.TextView;
 
+import androidx.recyclerview.widget.RecyclerView;
+
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.dashboard.conditional.Condition;
@@ -63,8 +67,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import androidx.recyclerview.widget.RecyclerView;
-
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(shadows = SettingsShadowResources.SettingsShadowTheme.class)
 public class DashboardAdapterTest {
@@ -79,6 +81,7 @@
     private Resources mResources;
     @Mock
     private WindowManager mWindowManager;
+    private ActivityInfo mActivityInfo;
     private FakeFeatureFactory mFactory;
     private DashboardAdapter mDashboardAdapter;
     private List<Condition> mConditionList;
@@ -87,6 +90,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mFactory = FakeFeatureFactory.setupForTest();
+        mActivityInfo = new ActivityInfo();
         when(mFactory.dashboardFeatureProvider.shouldTintIcon()).thenReturn(true);
 
         when(mContext.getSystemService(Context.WINDOW_SERVICE)).thenReturn(mWindowManager);
@@ -123,7 +127,6 @@
 
         adapter.onBindSuggestion(holder, 0);
 
-        final DashboardData dashboardData = adapter.mDashboardData;
         reset(adapter); // clear interactions tracking
 
         final Suggestion suggestionToRemove = suggestions.get(1);
@@ -154,12 +157,12 @@
     @Test
     public void onSuggestionClosed_notInSuggestionList_shouldNotUpdateSuggestionList() {
         final DashboardAdapter adapter =
-            spy(new DashboardAdapter(mContext, null /* savedInstanceState */,
-                null /* conditions */, null /* suggestionControllerMixin */,
-                null /* lifecycle */));
+                spy(new DashboardAdapter(mContext, null /* savedInstanceState */,
+                        null /* conditions */, null /* suggestionControllerMixin */,
+                        null /* lifecycle */));
         final List<Suggestion> suggestions = makeSuggestionsV2("pkg1");
         adapter.setSuggestions(suggestions);
-        final DashboardData dashboardData = adapter.mDashboardData;
+
         reset(adapter); // clear interactions tracking
 
         adapter.onSuggestionClosed(mock(Suggestion.class));
@@ -198,10 +201,12 @@
         final View view = LayoutInflater.from(context).inflate(R.layout.dashboard_tile, null);
         final DashboardAdapter.DashboardItemHolder holder =
                 new DashboardAdapter.DashboardItemHolder(view);
-        final Tile tile = new Tile();
-        tile.icon = Icon.createWithResource(context, R.drawable.ic_settings);
+        final Tile tile = spy(new Tile(mActivityInfo));
+        doReturn(Icon.createWithResource(context, R.drawable.ic_settings))
+                .when(tile).getIcon(context);
         final IconCache iconCache = mock(IconCache.class);
-        when(iconCache.getIcon(tile.icon)).thenReturn(context.getDrawable(R.drawable.ic_settings));
+        when(iconCache.getIcon(tile.getIcon(context)))
+                .thenReturn(context.getDrawable(R.drawable.ic_settings));
 
         mDashboardAdapter = new DashboardAdapter(context, null /* savedInstanceState */,
                 null /* conditions */, null /* suggestionControllerMixin */, null /* lifecycle */);
@@ -217,9 +222,9 @@
         final View view = LayoutInflater.from(context).inflate(R.layout.dashboard_tile, null);
         final DashboardAdapter.DashboardItemHolder holder =
                 new DashboardAdapter.DashboardItemHolder(view);
-        final Tile tile = new Tile();
-        tile.icon = Icon.createWithResource(context, R.drawable.ic_settings);
-        when(tile.icon.getResPackage()).thenReturn("another.package");
+        final Tile tile = spy(new Tile(mActivityInfo));
+        final Icon icon = Icon.createWithResource(context, R.drawable.ic_settings);
+        doReturn(icon).when(tile).getIcon(context);
 
         final IconCache iconCache = new IconCache(context);
 
@@ -230,7 +235,8 @@
         doReturn("another.package").when(context).getPackageName();
         mDashboardAdapter.onBindTile(holder, tile);
 
-        assertThat(iconCache.getIcon(tile.icon)).isInstanceOf(RoundedHomepageIcon.class);
+        assertThat(iconCache.getIcon(tile.getIcon(context)))
+                .isInstanceOf(RoundedHomepageIcon.class);
     }
 
     @Test
@@ -239,11 +245,12 @@
         final View view = LayoutInflater.from(context).inflate(R.layout.dashboard_tile, null);
         final DashboardAdapter.DashboardItemHolder holder =
                 new DashboardAdapter.DashboardItemHolder(view);
-        final Tile tile = new Tile();
+        final Tile tile = spy(new Tile(mActivityInfo));
         tile.metaData = new Bundle();
         tile.metaData.putInt(TileUtils.META_DATA_PREFERENCE_ICON_BACKGROUND_HINT,
                 R.color.memory_critical);
-        tile.icon = Icon.createWithResource(context, R.drawable.ic_settings);
+        doReturn(Icon.createWithResource(context, R.drawable.ic_settings))
+                .when(tile).getIcon(context);
         final IconCache iconCache = new IconCache(context);
         mDashboardAdapter = new DashboardAdapter(context, null /* savedInstanceState */,
                 null /* conditions */, null /* suggestionControllerMixin */, null /* lifecycle */);
@@ -252,7 +259,8 @@
         doReturn("another.package").when(context).getPackageName();
         mDashboardAdapter.onBindTile(holder, tile);
 
-        final RoundedHomepageIcon homepageIcon = (RoundedHomepageIcon) iconCache.getIcon(tile.icon);
+        final RoundedHomepageIcon homepageIcon = (RoundedHomepageIcon) iconCache.getIcon(
+                tile.getIcon(context));
         assertThat(homepageIcon.mBackgroundColor)
                 .isEqualTo(RuntimeEnvironment.application.getColor(R.color.memory_critical));
     }
@@ -263,12 +271,12 @@
         final View view = LayoutInflater.from(context).inflate(R.layout.dashboard_tile, null);
         final DashboardAdapter.DashboardItemHolder holder =
                 new DashboardAdapter.DashboardItemHolder(view);
-        final Tile tile = new Tile();
-        tile.icon = mock(Icon.class);
-        when(tile.icon.getResPackage()).thenReturn("another.package");
+        final Tile tile = spy(new Tile(mActivityInfo));
+        doReturn(mock(Icon.class)).when(tile).getIcon(context);
+        when(tile.getIcon(context).getResPackage()).thenReturn("another.package");
 
         final IconCache iconCache = mock(IconCache.class);
-        when(iconCache.getIcon(tile.icon)).thenReturn(mock(RoundedHomepageIcon.class));
+        when(iconCache.getIcon(tile.getIcon(context))).thenReturn(mock(RoundedHomepageIcon.class));
 
         mDashboardAdapter = new DashboardAdapter(context, null /* savedInstanceState */,
                 null /* conditions */, null /* suggestionControllerMixin */, null /* lifecycle */);
@@ -276,7 +284,8 @@
 
         mDashboardAdapter.onBindTile(holder, tile);
 
-        verify(iconCache, never()).updateIcon(eq(tile.icon), any(RoundedHomepageIcon.class));
+        verify(iconCache, never()).updateIcon(eq(tile.getIcon(context)),
+                any(RoundedHomepageIcon.class));
     }
 
     private List<Suggestion> makeSuggestionsV2(String... pkgNames) {
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
index bf1e0ff..963411d 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
@@ -19,7 +19,9 @@
 import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_PROFILE;
 import static com.android.settingslib.drawer.TileUtils.PROFILE_ALL;
 import static com.android.settingslib.drawer.TileUtils.PROFILE_PRIMARY;
+
 import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
@@ -35,6 +37,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.graphics.Bitmap;
@@ -43,6 +46,8 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 
+import androidx.preference.Preference;
+
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
@@ -53,7 +58,6 @@
 import com.android.settings.testutils.shadow.ShadowUserManager;
 import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
 import com.android.settingslib.drawer.CategoryKey;
-import com.android.settingslib.drawer.CategoryManager;
 import com.android.settingslib.drawer.DashboardCategory;
 import com.android.settingslib.drawer.Tile;
 import com.android.settingslib.drawer.TileUtils;
@@ -74,8 +78,6 @@
 
 import java.util.ArrayList;
 
-import androidx.preference.Preference;
-
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(shadows = ShadowUserManager.class)
 public class DashboardFeatureProviderImplTest {
@@ -91,15 +93,17 @@
     private FakeFeatureFactory mFeatureFactory;
 
     private Context mContext;
+    private ActivityInfo mActivityInfo;
     private DashboardFeatureProviderImpl mImpl;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = spy(RuntimeEnvironment.application);
+        mActivityInfo = new ActivityInfo();
         doReturn(mPackageManager).when(mContext).getPackageManager();
         when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
-            .thenReturn(new ResolveInfo());
+                .thenReturn(new ResolveInfo());
         mFeatureFactory = FakeFeatureFactory.setupForTest();
         mImpl = new DashboardFeatureProviderImpl(mContext);
     }
@@ -112,10 +116,11 @@
     @Test
     public void bindPreference_shouldBindAllData() {
         final Preference preference = new Preference(RuntimeEnvironment.application);
-        final Tile tile = new Tile();
+        final Tile tile = spy(new Tile(mActivityInfo));
         tile.title = "title";
         tile.summary = "summary";
-        tile.icon = Icon.createWithBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565));
+        doReturn(Icon.createWithBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565)))
+                .when(tile).getIcon(any(Context.class));
         tile.metaData = new Bundle();
         tile.metaData.putString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS, "HI");
         tile.priority = 10;
@@ -133,7 +138,7 @@
     @Test
     public void bindPreference_noFragmentMetadata_shouldBindIntent() {
         final Preference preference = new Preference(RuntimeEnvironment.application);
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.metaData = new Bundle();
         tile.priority = 10;
         tile.intent = new Intent();
@@ -150,7 +155,7 @@
     @Test
     public void bindPreference_noFragmentMetadata_shouldBindToProfileSelector() {
         final Preference preference = new Preference(RuntimeEnvironment.application);
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.metaData = new Bundle();
         tile.userHandle = new ArrayList<>();
         tile.userHandle.add(mock(UserHandle.class));
@@ -171,7 +176,7 @@
     @Test
     public void bindPreference_noFragmentMetadataSingleUser_shouldBindToDirectLaunchIntent() {
         final Preference preference = new Preference(RuntimeEnvironment.application);
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.metaData = new Bundle();
         tile.userHandle = new ArrayList<>();
         tile.userHandle.add(mock(UserHandle.class));
@@ -196,7 +201,7 @@
     @Test
     public void bindPreference_toInternalSettingActivity_shouldBindToDirectLaunchIntentAndNotLog() {
         final Preference preference = new Preference(RuntimeEnvironment.application);
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.metaData = new Bundle();
         tile.userHandle = new ArrayList<>();
         tile.userHandle.add(mock(UserHandle.class));
@@ -232,7 +237,7 @@
     @Test
     public void bindPreference_withNullKeyNullPriority_shouldGenerateKeyAndPriority() {
         final Preference preference = new Preference(RuntimeEnvironment.application);
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.intent = new Intent();
         tile.intent.setComponent(new ComponentName("pkg", "class"));
         mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN,
@@ -245,7 +250,7 @@
     @Test
     public void bindPreference_noSummary_shouldSetSummaryToPlaceholder() {
         final Preference preference = new Preference(RuntimeEnvironment.application);
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.intent = new Intent();
         tile.intent.setComponent(new ComponentName("pkg", "class"));
         mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN,
@@ -258,7 +263,7 @@
     @Test
     public void bindPreference_hasSummary_shouldSetSummary() {
         final Preference preference = new Preference(RuntimeEnvironment.application);
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.summary = "test";
         tile.intent = new Intent();
         tile.intent.setComponent(new ComponentName("pkg", "class"));
@@ -272,7 +277,7 @@
     @Config(shadows = {ShadowTileUtils.class, ShadowThreadUtils.class})
     public void bindPreference_hasSummaryUri_shouldLoadSummaryFromContentProvider() {
         final Preference preference = new Preference(RuntimeEnvironment.application);
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.intent = new Intent();
         tile.intent.setComponent(new ComponentName("pkg", "class"));
         tile.metaData = new Bundle();
@@ -288,7 +293,7 @@
     @Test
     public void bindPreference_withNullKeyTileKey_shouldUseTileKey() {
         final Preference preference = new Preference(RuntimeEnvironment.application);
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.key = "key";
         tile.intent = new Intent();
         tile.intent.setComponent(new ComponentName("pkg", "class"));
@@ -302,7 +307,7 @@
     @Config(shadows = {ShadowTileUtils.class, ShadowThreadUtils.class})
     public void bindPreference_withIconUri_shouldLoadIconFromContentProvider() {
         final Preference preference = new Preference(RuntimeEnvironment.application);
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.key = "key";
         tile.intent = new Intent();
         tile.intent.setComponent(
@@ -319,7 +324,7 @@
     public void bindPreference_withBaseOrder_shouldOffsetPriority() {
         final int baseOrder = 100;
         final Preference preference = new Preference(RuntimeEnvironment.application);
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.metaData = new Bundle();
         tile.priority = 10;
         mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN,
@@ -332,7 +337,7 @@
     public void bindPreference_withOrderMetadata_shouldUseOrderInMetadata() {
         final Preference preference = new Preference(RuntimeEnvironment.application);
         final int testOrder = -30;
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.metaData = new Bundle();
         tile.metaData.putInt(mImpl.META_DATA_KEY_ORDER, testOrder);
         tile.priority = 10;
@@ -345,7 +350,7 @@
     @Test
     public void bindPreference_invalidOrderMetadata_shouldIgnore() {
         final Preference preference = new Preference(RuntimeEnvironment.application);
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.metaData = new Bundle();
         tile.metaData.putString(mImpl.META_DATA_KEY_ORDER, "hello");
         tile.priority = 10;
@@ -359,7 +364,7 @@
     public void bindPreference_withIntentActionMetadata_shouldSetLaunchAction() {
         Activity activity = Robolectric.buildActivity(Activity.class).get();
         final Preference preference = new Preference(RuntimeEnvironment.application);
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.key = "key";
         tile.intent = new Intent();
         tile.intent.setComponent(new ComponentName("pkg", "class"));
@@ -385,7 +390,7 @@
         Activity activity = Robolectric.buildActivity(Activity.class).get();
         final ShadowApplication application = ShadowApplication.getInstance();
         final Preference preference = new Preference(application.getApplicationContext());
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.key = "key";
         tile.intent = new Intent();
         tile.intent.setComponent(new ComponentName("pkg", "class"));
@@ -432,7 +437,7 @@
         mImpl = new DashboardFeatureProviderImpl(mActivity);
         ReflectionHelpers.setField(mImpl, "mCategoryManager", mCategoryManager);
         final DashboardCategory category = new DashboardCategory();
-        category.addTile(new Tile());
+        category.addTile(new Tile(mActivityInfo));
         when(mCategoryManager
                 .getTilesByCategory(any(Context.class), eq(CategoryKey.CATEGORY_HOMEPAGE)))
                 .thenReturn(category);
@@ -462,7 +467,7 @@
 
     @Test
     public void openTileIntent_profileSelectionDialog_shouldShow() {
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.metaData = new Bundle();
         tile.intent = new Intent();
         tile.intent.setComponent(new ComponentName("pkg", "class"));
@@ -473,13 +478,13 @@
         mImpl.openTileIntent(mActivity, tile);
 
         verify(mActivity, never())
-            .startActivityForResult(any(Intent.class), eq(0));
+                .startActivityForResult(any(Intent.class), eq(0));
         verify(mActivity).getFragmentManager();
     }
 
     @Test
     public void openTileIntent_profileSelectionDialog_explicitMetadataShouldShow() {
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.metaData = new Bundle();
         tile.metaData.putString(META_DATA_KEY_PROFILE, PROFILE_ALL);
         tile.intent = new Intent();
@@ -491,12 +496,13 @@
         mImpl.openTileIntent(mActivity, tile);
 
         verify(mActivity, never())
-            .startActivityForResult(any(Intent.class), eq(0));
+                .startActivityForResult(any(Intent.class), eq(0));
         verify(mActivity).getFragmentManager();
     }
+
     @Test
     public void openTileIntent_profileSelectionDialog_shouldNotShow() {
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.metaData = new Bundle();
         tile.metaData.putString(META_DATA_KEY_PROFILE, PROFILE_PRIMARY);
         tile.intent = new Intent();
@@ -508,7 +514,7 @@
         mImpl.openTileIntent(mActivity, tile);
 
         verify(mActivity)
-            .startActivityForResult(any(Intent.class), eq(0));
+                .startActivityForResult(any(Intent.class), eq(0));
         verify(mActivity, never()).getFragmentManager();
     }
 }
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
index 3a2f00f..8c1b99b 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
@@ -16,7 +16,10 @@
 package com.android.settings.dashboard;
 
 import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -27,9 +30,14 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
 
+import androidx.preference.Preference;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -50,15 +58,12 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import androidx.preference.Preference;
-import androidx.preference.PreferenceManager;
-import androidx.preference.PreferenceScreen;
-
 @RunWith(SettingsRobolectricTestRunner.class)
 public class DashboardFragmentTest {
 
     @Mock
     private FakeFeatureFactory mFakeFeatureFactory;
+    private ActivityInfo mActivityInfo;
     private DashboardCategory mDashboardCategory;
     private Context mContext;
     private TestFragment mTestFragment;
@@ -67,9 +72,10 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = spy(RuntimeEnvironment.application);
+        mActivityInfo = new ActivityInfo();
         mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
         mDashboardCategory = new DashboardCategory();
-        mDashboardCategory.addTile(new Tile());
+        mDashboardCategory.addTile(new Tile(mActivityInfo));
         mTestFragment = new TestFragment(RuntimeEnvironment.application);
         when(mFakeFeatureFactory.dashboardFeatureProvider
                 .getTilesForCategory(nullable(String.class)))
@@ -177,8 +183,8 @@
 
     @Test
     public void tintTileIcon_hasMetadata_shouldReturnIconTintableMetadata() {
-        final Tile tile = new Tile();
-        tile.icon = mock(Icon.class);
+        final Tile tile = spy(new Tile(mActivityInfo));
+        doReturn(mock(Icon.class)).when(tile).getIcon(any(Context.class));
         final Bundle metaData = new Bundle();
         tile.metaData = metaData;
 
@@ -191,7 +197,7 @@
 
     @Test
     public void tintTileIcon_noIcon_shouldReturnFalse() {
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(mActivityInfo);
         tile.metaData = new Bundle();
 
         assertThat(mTestFragment.tintTileIcon(tile)).isFalse();
@@ -199,12 +205,12 @@
 
     @Test
     public void tintTileIcon_noMetadata_shouldReturnPackageNameCheck() {
-        final Tile tile = new Tile();
-        tile.icon = mock(Icon.class);
+        final Tile tile = spy(new Tile(mActivityInfo));
+        doReturn(mock(Icon.class)).when(tile).getIcon(any(Context.class));
         final Intent intent = new Intent();
         tile.intent = intent;
         intent.setComponent(
-            new ComponentName(RuntimeEnvironment.application.getPackageName(), "TestClass"));
+                new ComponentName(RuntimeEnvironment.application.getPackageName(), "TestClass"));
         assertThat(mTestFragment.tintTileIcon(tile)).isFalse();
 
         intent.setComponent(new ComponentName("OtherPackage", "TestClass"));
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardItemAnimatorTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardItemAnimatorTest.java
index ee19654..b1d2031 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardItemAnimatorTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardItemAnimatorTest.java
@@ -18,9 +18,12 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.content.pm.ActivityInfo;
 import android.view.View;
 import android.widget.TextView;
 
+import androidx.recyclerview.widget.RecyclerView;
+
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settingslib.drawer.Tile;
 
@@ -29,8 +32,6 @@
 import org.junit.runner.RunWith;
 import org.robolectric.RuntimeEnvironment;
 
-import androidx.recyclerview.widget.RecyclerView;
-
 @RunWith(SettingsRobolectricTestRunner.class)
 public class DashboardItemAnimatorTest {
 
@@ -41,20 +42,20 @@
     public void SetUp() {
         mDashboardItemAnimator = new DashboardItemAnimator();
         mViewHolder = new ViewHolder(new TextView(RuntimeEnvironment.application));
-        mViewHolder.itemView.setTag(new Tile());
+        mViewHolder.itemView.setTag(new Tile(new ActivityInfo()));
     }
 
     @Test
     public void testAnimateChange_NoPositionChange_NoPendingAnimation() {
         final boolean hasPendingAnimation =
-            mDashboardItemAnimator.animateChange(mViewHolder, mViewHolder, 0, 1, 0, 1);
+                mDashboardItemAnimator.animateChange(mViewHolder, mViewHolder, 0, 1, 0, 1);
         assertThat(hasPendingAnimation).isFalse();
     }
 
     @Test
     public void testAnimateChange_HasPositionChange_HasPendingAnimation() {
         final boolean hasPendingAnimation =
-            mDashboardItemAnimator.animateChange(mViewHolder, mViewHolder, 0, 0, 1, 1);
+                mDashboardItemAnimator.animateChange(mViewHolder, mViewHolder, 0, 0, 1, 1);
         assertThat(hasPendingAnimation).isTrue();
     }
 
@@ -64,7 +65,7 @@
         mDashboardItemAnimator.animateMove(mViewHolder, 0, 0, 1, 1);
 
         final boolean hasPendingAnimation =
-            mDashboardItemAnimator.animateChange(mViewHolder, mViewHolder, 0, 1, 0, 1);
+                mDashboardItemAnimator.animateChange(mViewHolder, mViewHolder, 0, 1, 0, 1);
         assertThat(hasPendingAnimation).isFalse();
     }
 
diff --git a/tests/robotests/src/com/android/settings/dashboard/SummaryLoaderTest.java b/tests/robotests/src/com/android/settings/dashboard/SummaryLoaderTest.java
index 0fac2fc..053bc9c 100644
--- a/tests/robotests/src/com/android/settings/dashboard/SummaryLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/SummaryLoaderTest.java
@@ -17,11 +17,13 @@
 package com.android.settings.dashboard;
 
 import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 import android.app.Activity;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
 
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -51,7 +53,7 @@
         MockitoAnnotations.initMocks(this);
         mFeatureFactory = FakeFeatureFactory.setupForTest();
 
-        mTile = new Tile();
+        mTile = new Tile(new ActivityInfo());
         mTile.summary = SUMMARY_1;
         mCallbackInvoked = false;
 
@@ -84,7 +86,7 @@
     public void testUpdateSummaryToCache_hasCache_shouldUpdate() {
         final String testSummary = "test_summary";
         final DashboardCategory category = new DashboardCategory();
-        final Tile tile = new Tile();
+        final Tile tile = new Tile(new ActivityInfo());
         tile.key = "123";
         tile.intent = new Intent();
         category.addTile(tile);
diff --git a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java
index b1c256f..70fc9d4 100644
--- a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java
@@ -17,6 +17,7 @@
 package com.android.settings.dashboard.suggestions;
 
 import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
@@ -27,6 +28,7 @@
 
 import android.app.ActivityManager;
 import android.content.Context;
+import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.hardware.fingerprint.FingerprintManager;
 import android.service.settings.suggestions.Suggestion;
@@ -45,7 +47,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RuntimeEnvironment;
@@ -58,7 +59,7 @@
 @Config(shadows = ShadowSecureSettings.class)
 public class SuggestionFeatureProviderImplTest {
 
-    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    @Mock
     private Context mContext;
     @Mock
     private SuggestionControllerMixinCompat mSuggestionControllerMixin;
@@ -71,6 +72,7 @@
     @Mock
     private FingerprintManager mFingerprintManager;
 
+    private ActivityInfo mActivityInfo;
     private FakeFeatureFactory mFactory;
     private SuggestionFeatureProviderImpl mProvider;
 
@@ -78,6 +80,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mFactory = FakeFeatureFactory.setupForTest();
+        mActivityInfo = new ActivityInfo();
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
         // Explicit casting to object due to MockitoCast bug
         when((Object) mContext.getSystemService(FingerprintManager.class))
@@ -145,13 +148,13 @@
     @Test
     public void filterExclusiveSuggestions_shouldOnlyKeepFirst3() {
         final List<Tile> suggestions = new ArrayList<>();
-        suggestions.add(new Tile());
-        suggestions.add(new Tile());
-        suggestions.add(new Tile());
-        suggestions.add(new Tile());
-        suggestions.add(new Tile());
-        suggestions.add(new Tile());
-        suggestions.add(new Tile());
+        suggestions.add(new Tile(mActivityInfo));
+        suggestions.add(new Tile(mActivityInfo));
+        suggestions.add(new Tile(mActivityInfo));
+        suggestions.add(new Tile(mActivityInfo));
+        suggestions.add(new Tile(mActivityInfo));
+        suggestions.add(new Tile(mActivityInfo));
+        suggestions.add(new Tile(mActivityInfo));
 
         mProvider.filterExclusiveSuggestions(suggestions);
 
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/DeviceNamePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/DeviceNamePreferenceControllerTest.java
index 0e6bf8d..68b48a8 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/DeviceNamePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/DeviceNamePreferenceControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.deviceinfo;
 
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
 import static com.google.common.truth.Truth.assertThat;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
@@ -41,6 +43,7 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowApplication;
 
 import androidx.preference.PreferenceScreen;
@@ -80,6 +83,17 @@
     }
 
     @Test
+    public void getAvailibilityStatus_availableByDefault() {
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+    }
+
+    @Test
+    @Config(qualifiers = "mcc999")
+    public void getAvailabilityStatus_unsupportedWhenSet() {
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+    }
+
+    @Test
     public void constructor_defaultDeviceNameIsModelName() {
         assertThat(mController.getSummary()).isEqualTo(Build.MODEL);
     }
diff --git a/tests/robotests/src/com/android/settings/display/BatteryPercentagePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/BatteryPercentagePreferenceControllerTest.java
index 673abb0..140fc5c 100644
--- a/tests/robotests/src/com/android/settings/display/BatteryPercentagePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/BatteryPercentagePreferenceControllerTest.java
@@ -32,13 +32,15 @@
 @RunWith(SettingsRobolectricTestRunner.class)
 public class BatteryPercentagePreferenceControllerTest {
 
+    private static final String PREF_KEY = "battery_percentage";
+
     private Context mContext;
     private BatteryPercentagePreferenceController mController;
 
     @Before
     public void setup() {
         mContext = RuntimeEnvironment.application;
-        mController = new BatteryPercentagePreferenceController(mContext);
+        mController = new BatteryPercentagePreferenceController(mContext, PREF_KEY);
     }
 
     private int getPercentageSetting() {
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java
index 58bfe0e..41e77e9 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java
@@ -22,6 +22,7 @@
 
 import android.content.Context;
 import android.text.format.DateUtils;
+import android.util.SparseLongArray;
 
 import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper;
 import com.android.settings.fuelgauge.batterytip.AppInfo;
@@ -88,7 +89,7 @@
     }
 
     @Test
-    public void testAllFunctions() {
+    public void allAnomalyFunctions() {
         mBatteryDatabaseManager.insertAnomaly(UID_NEW, PACKAGE_NAME_NEW, TYPE_NEW,
                 AnomalyDatabaseHelper.State.NEW, NOW);
         mBatteryDatabaseManager.insertAnomaly(UID_OLD, PACKAGE_NAME_OLD, TYPE_OLD,
@@ -113,7 +114,7 @@
     }
 
     @Test
-    public void testUpdateAnomalies_updateSuccessfully() {
+    public void updateAnomalies_updateSuccessfully() {
         mBatteryDatabaseManager.insertAnomaly(UID_NEW, PACKAGE_NAME_NEW, TYPE_NEW,
                 AnomalyDatabaseHelper.State.NEW, NOW);
         mBatteryDatabaseManager.insertAnomaly(UID_OLD, PACKAGE_NAME_OLD, TYPE_OLD,
@@ -138,7 +139,7 @@
     }
 
     @Test
-    public void testQueryAnomalies_removeDuplicateByUid() {
+    public void queryAnomalies_removeDuplicateByUid() {
         mBatteryDatabaseManager.insertAnomaly(UID_NEW, PACKAGE_NAME_NEW, TYPE_NEW,
                 AnomalyDatabaseHelper.State.NEW, NOW);
         mBatteryDatabaseManager.insertAnomaly(UID_NEW, PACKAGE_NAME_NEW, TYPE_OLD,
@@ -149,4 +150,28 @@
                 AnomalyDatabaseHelper.State.NEW);
         assertThat(newAppInfos).containsExactly(mCombinedAppInfo);
     }
+
+    @Test
+    public void allActionFunctions() {
+        final long timestamp = System.currentTimeMillis();
+        mBatteryDatabaseManager.insertAction(AnomalyDatabaseHelper.ActionType.RESTRICTION, UID_OLD,
+                PACKAGE_NAME_OLD, 0);
+        mBatteryDatabaseManager.insertAction(AnomalyDatabaseHelper.ActionType.RESTRICTION, UID_OLD,
+                PACKAGE_NAME_OLD, 1);
+        mBatteryDatabaseManager.insertAction(AnomalyDatabaseHelper.ActionType.RESTRICTION, UID_NEW,
+                PACKAGE_NAME_NEW, timestamp);
+
+        final SparseLongArray timeArray = mBatteryDatabaseManager.queryActionTime(
+                AnomalyDatabaseHelper.ActionType.RESTRICTION);
+        assertThat(timeArray.size()).isEqualTo(2);
+        assertThat(timeArray.get(UID_OLD)).isEqualTo(1);
+        assertThat(timeArray.get(UID_NEW)).isEqualTo(timestamp);
+
+        mBatteryDatabaseManager.deleteAction(AnomalyDatabaseHelper.ActionType.RESTRICTION, UID_NEW,
+                PACKAGE_NAME_NEW);
+        final SparseLongArray recentTimeArray = mBatteryDatabaseManager.queryActionTime(
+                AnomalyDatabaseHelper.ActionType.RESTRICTION);
+        assertThat(recentTimeArray.size()).isEqualTo(1);
+        assertThat(timeArray.get(UID_OLD)).isEqualTo(1);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
index 91cb078..337b950 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
@@ -36,6 +36,7 @@
 
 import com.android.settings.R;
 import com.android.settings.applications.LayoutPreference;
+import com.android.settings.core.BasePreferenceController;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.testutils.shadow.SettingsShadowResources;
 import com.android.settings.testutils.shadow.SettingsShadowResourcesImpl;
@@ -68,6 +69,7 @@
         })
 public class BatteryHeaderPreferenceControllerTest {
 
+    private static final String PREF_KEY = "battery_header";
     private static final int BATTERY_LEVEL = 60;
     private static final String TIME_LEFT = "2h30min";
     private static final String BATTERY_STATUS = "Charging";
@@ -121,8 +123,11 @@
 
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
 
-        mController = new BatteryHeaderPreferenceController(
-                mContext, mActivity, mPreferenceFragment, mLifecycle);
+        mController = new BatteryHeaderPreferenceController(mContext, PREF_KEY);
+        mLifecycle.addObserver(mController);
+        mController.setActivity(mActivity);
+        mController.setFragment(mPreferenceFragment);
+        mController.setLifecycle(mLifecycle);
         mController.mBatteryMeterView = mBatteryMeterView;
         mController.mBatteryPercentText = mBatteryPercentText;
         mController.mSummary1 = mSummary;
@@ -207,4 +212,10 @@
             assertThat(mBatteryMeterView.getPowerSave()).isEqualTo(value);
         }
     }
+
+    @Test
+    public void getAvailabilityStatus_returnAvailableUnsearchable() {
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(
+                BasePreferenceController.AVAILABLE_UNSEARCHABLE);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
index df34b78..b274492 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
@@ -51,9 +51,12 @@
 
 import com.android.internal.os.BatterySipper;
 import com.android.internal.os.BatteryStatsHelper;
+import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper;
 import com.android.settings.fuelgauge.batterytip.AnomalyInfo;
+import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager;
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.ShadowThreadUtils;
 import com.android.settingslib.fuelgauge.PowerWhitelistBackend;
 
 import org.junit.Before;
@@ -148,6 +151,8 @@
     private ApplicationInfo mLowApplicationInfo;
     @Mock
     private PowerWhitelistBackend mPowerWhitelistBackend;
+    @Mock
+    private BatteryDatabaseManager mBatteryDatabaseManager;
     private AnomalyInfo mAnomalyInfo;
     private BatteryUtils mBatteryUtils;
     private FakeFeatureFactory mFeatureFactory;
@@ -225,6 +230,8 @@
             .thenReturn(TOTAL_BATTERY_USAGE + BATTERY_SCREEN_USAGE);
         when(mBatteryStatsHelper.getStats().getDischargeAmount(anyInt()))
             .thenReturn(DISCHARGE_AMOUNT);
+        BatteryDatabaseManager.setUpForTest(mBatteryDatabaseManager);
+        ShadowThreadUtils.setIsMainThread(true);
     }
 
     @Test
@@ -570,6 +577,23 @@
     }
 
     @Test
+    public void testSetForceAppStandby_restrictApp_recordTime() {
+        mBatteryUtils.setForceAppStandby(UID, HIGH_SDK_PACKAGE, AppOpsManager.MODE_IGNORED);
+
+        verify(mBatteryDatabaseManager).insertAction(
+                eq(AnomalyDatabaseHelper.ActionType.RESTRICTION), eq(UID),
+                eq(HIGH_SDK_PACKAGE), anyLong());
+    }
+
+    @Test
+    public void testSetForceAppStandby_unrestrictApp_deleteTime() {
+        mBatteryUtils.setForceAppStandby(UID, HIGH_SDK_PACKAGE, AppOpsManager.MODE_ALLOWED);
+
+        verify(mBatteryDatabaseManager).deleteAction(AnomalyDatabaseHelper.ActionType.RESTRICTION,
+                UID, HIGH_SDK_PACKAGE);
+    }
+
+    @Test
     public void testIsForceAppStandbyEnabled_enabled_returnTrue() {
         when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
                 PACKAGE_NAME)).thenReturn(AppOpsManager.MODE_IGNORED);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
index 97e272b..68d9994 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
@@ -223,21 +223,6 @@
     }
 
     @Test
-    public void preferenceControllers_getPreferenceKeys_existInPreferenceScreen() {
-        final Context context = RuntimeEnvironment.application;
-        final PowerUsageSummary fragment = new PowerUsageSummary();
-        final List<String> preferenceScreenKeys =
-            XmlTestUtils.getKeysFromPreferenceXml(context, fragment.getPreferenceScreenResId());
-        final List<String> preferenceKeys = new ArrayList<>();
-
-        for (AbstractPreferenceController controller : fragment.createPreferenceControllers(context)) {
-            preferenceKeys.add(controller.getPreferenceKey());
-        }
-
-        assertThat(preferenceScreenKeys).containsAllIn(preferenceKeys);
-    }
-
-    @Test
     public void restartBatteryTipLoader() {
         //TODO: add policy logic here when BatteryTipPolicy is implemented
         doReturn(mLoaderManager).when(mFragment).getLoaderManager();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java
index b9ed509..7219f18 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java
@@ -28,10 +28,13 @@
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.util.IconDrawableFactory;
+import android.util.SparseLongArray;
 
 import com.android.settings.SettingsActivity;
 import com.android.settings.core.InstrumentedPreferenceFragment;
+import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper;
 import com.android.settings.fuelgauge.batterytip.AppInfo;
+import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager;
 import com.android.settings.fuelgauge.batterytip.BatteryTipDialogFragment;
 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
 import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip;
@@ -52,6 +55,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 import androidx.appcompat.app.AlertDialog;
 import androidx.preference.CheckBoxPreference;
@@ -76,6 +80,8 @@
     private IconDrawableFactory mIconDrawableFactory;
     @Mock
     private InstrumentedPreferenceFragment mFragment;
+    @Mock
+    private BatteryDatabaseManager mBatteryDatabaseManager;
     private PreferenceManager mPreferenceManager;
     private RestrictedAppDetails mRestrictedAppDetails;
     private Context mContext;
@@ -98,12 +104,14 @@
 
         doReturn(mPreferenceManager).when(mRestrictedAppDetails).getPreferenceManager();
         doReturn(mContext).when(mFragment).getContext();
+        doReturn(mContext).when(mRestrictedAppDetails).getContext();
         mRestrictedAppDetails.mPackageManager = mPackageManager;
         mRestrictedAppDetails.mIconDrawableFactory = mIconDrawableFactory;
         mRestrictedAppDetails.mAppInfos = new ArrayList<>();
         mRestrictedAppDetails.mAppInfos.add(mAppInfo);
         mRestrictedAppDetails.mRestrictedAppListGroup = spy(new PreferenceCategory(mContext));
         mRestrictedAppDetails.mBatteryUtils = spy(new BatteryUtils(mContext));
+        mRestrictedAppDetails.mBatteryDatabaseManager = mBatteryDatabaseManager;
         doReturn(mPreferenceManager).when(
                 mRestrictedAppDetails.mRestrictedAppListGroup).getPreferenceManager();
 
@@ -118,6 +126,10 @@
         doReturn(APP_NAME).when(mPackageManager).getApplicationLabel(mApplicationInfo);
         doReturn(true).when(mRestrictedAppDetails.mBatteryUtils).isForceAppStandbyEnabled(UID,
                 PACKAGE_NAME);
+        final SparseLongArray timestampArray = new SparseLongArray();
+        timestampArray.put(UID, System.currentTimeMillis() - TimeUnit.HOURS.toMillis(5));
+        doReturn(timestampArray).when(mBatteryDatabaseManager)
+                .queryActionTime(AnomalyDatabaseHelper.ActionType.RESTRICTION);
 
         mRestrictedAppDetails.refreshUi();
 
@@ -126,6 +138,7 @@
                 (CheckBoxPreference) mRestrictedAppDetails.mRestrictedAppListGroup.getPreference(0);
         assertThat(preference.getTitle()).isEqualTo(APP_NAME);
         assertThat(preference.isChecked()).isTrue();
+        assertThat(preference.getSummary()).isEqualTo("Restricted 5 hours ago");
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java
index 7e9ffeb..e7aafef 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java
@@ -31,6 +31,7 @@
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
+import com.android.settings.core.BasePreferenceController;
 import com.android.settings.core.InstrumentedPreferenceFragment;
 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
 import com.android.settings.fuelgauge.batterytip.tips.SummaryTip;
@@ -100,8 +101,7 @@
         mNewBatteryTips = new ArrayList<>();
         mNewBatteryTips.add(new SummaryTip(BatteryTip.StateType.INVISIBLE, AVERAGE_TIME_MS));
 
-        mBatteryTipPreferenceController = new BatteryTipPreferenceController(mContext, KEY_PREF,
-                mSettingsActivity, mFragment, mBatteryTipListener);
+        mBatteryTipPreferenceController = buildBatteryTipPreferenceController();
         mBatteryTipPreferenceController.mPreferenceGroup = mPreferenceGroup;
         mBatteryTipPreferenceController.mPrefContext = mContext;
     }
@@ -139,8 +139,7 @@
         final Bundle bundle = new Bundle();
         mBatteryTipPreferenceController.saveInstanceState(bundle);
 
-        final BatteryTipPreferenceController controller = new BatteryTipPreferenceController(
-                mContext, KEY_PREF, mSettingsActivity, mFragment, mBatteryTipListener);
+        final BatteryTipPreferenceController controller = buildBatteryTipPreferenceController();
         controller.mPreferenceGroup = mPreferenceGroup;
         controller.mPrefContext = mContext;
         controller.restoreInstanceState(bundle);
@@ -154,8 +153,7 @@
         // Battery tip list is null at this time
         mBatteryTipPreferenceController.saveInstanceState(bundle);
 
-        final BatteryTipPreferenceController controller = new BatteryTipPreferenceController(
-                mContext, KEY_PREF, mSettingsActivity, mFragment, mBatteryTipListener);
+        final BatteryTipPreferenceController controller = buildBatteryTipPreferenceController();
 
         // Should not crash
         controller.restoreInstanceState(bundle);
@@ -176,6 +174,12 @@
         verify(mBatteryTipListener).onBatteryTipHandled(mBatteryTip);
     }
 
+    @Test
+    public void getAvailabilityStatus_returnAvailableUnsearchable() {
+        assertThat(mBatteryTipPreferenceController.getAvailabilityStatus()).isEqualTo(
+                BasePreferenceController.AVAILABLE_UNSEARCHABLE);
+    }
+
     private void assertOnlyContainsSummaryTip(final PreferenceGroup preferenceGroup) {
         assertThat(preferenceGroup.getPreferenceCount()).isEqualTo(1);
 
@@ -185,4 +189,14 @@
         assertThat(preference.getSummary()).isEqualTo(
                 mContext.getString(R.string.battery_tip_summary_summary));
     }
+
+    private BatteryTipPreferenceController buildBatteryTipPreferenceController() {
+        final BatteryTipPreferenceController controller = new BatteryTipPreferenceController(
+                mContext, KEY_PREF);
+        controller.setActivity(mSettingsActivity);
+        controller.setFragment(mFragment);
+        controller.setBatteryTipListener(mBatteryTipListener);
+
+        return controller;
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/network/NetworkDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/network/NetworkDashboardFragmentTest.java
index 187f0dc..d6310ab 100644
--- a/tests/robotests/src/com/android/settings/network/NetworkDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/network/NetworkDashboardFragmentTest.java
@@ -26,6 +26,7 @@
 
 import com.android.settings.dashboard.SummaryLoader;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.wifi.WifiMasterSwitchPreferenceController;
 import com.android.settingslib.drawer.CategoryKey;
 
 import org.junit.Before;
@@ -66,6 +67,8 @@
 
     @Test
     public void summaryProviderSetListening_hasMobileAndHotspot_shouldReturnMobileSummary() {
+        final WifiMasterSwitchPreferenceController wifiPreferenceController =
+                mock(WifiMasterSwitchPreferenceController.class);
         final MobileNetworkPreferenceController mobileNetworkPreferenceController =
                 mock(MobileNetworkPreferenceController.class);
         final TetherPreferenceController tetherPreferenceController =
@@ -74,12 +77,14 @@
         final SummaryLoader summaryLoader = mock(SummaryLoader.class);
         final SummaryLoader.SummaryProvider provider =
                 new NetworkDashboardFragment.SummaryProvider(mContext, summaryLoader,
-                        mobileNetworkPreferenceController, tetherPreferenceController);
+                        wifiPreferenceController, mobileNetworkPreferenceController,
+                        tetherPreferenceController);
 
         provider.setListening(false);
 
         verifyZeroInteractions(summaryLoader);
 
+        when(wifiPreferenceController.isAvailable()).thenReturn(true);
         when(mobileNetworkPreferenceController.isAvailable()).thenReturn(true);
         when(tetherPreferenceController.isAvailable()).thenReturn(true);
 
@@ -90,6 +95,8 @@
 
     @Test
     public void summaryProviderSetListening_noMobileOrHotspot_shouldReturnSimpleSummary() {
+        final WifiMasterSwitchPreferenceController wifiPreferenceController =
+                mock(WifiMasterSwitchPreferenceController.class);
         final MobileNetworkPreferenceController mobileNetworkPreferenceController =
                 mock(MobileNetworkPreferenceController.class);
         final TetherPreferenceController tetherPreferenceController =
@@ -98,12 +105,14 @@
         final SummaryLoader summaryLoader = mock(SummaryLoader.class);
         final SummaryLoader.SummaryProvider provider =
                 new NetworkDashboardFragment.SummaryProvider(mContext, summaryLoader,
-                        mobileNetworkPreferenceController, tetherPreferenceController);
+                        wifiPreferenceController, mobileNetworkPreferenceController,
+                        tetherPreferenceController);
 
         provider.setListening(false);
 
         verifyZeroInteractions(summaryLoader);
 
+        when(wifiPreferenceController.isAvailable()).thenReturn(true);
         when(mobileNetworkPreferenceController.isAvailable()).thenReturn(false);
         when(tetherPreferenceController.isAvailable()).thenReturn(false);
 
diff --git a/tests/robotests/src/com/android/settings/security/ChangeScreenLockPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/ChangeScreenLockPreferenceControllerTest.java
index 6cc1704..fda5942 100644
--- a/tests/robotests/src/com/android/settings/security/ChangeScreenLockPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/security/ChangeScreenLockPreferenceControllerTest.java
@@ -17,17 +17,28 @@
 package com.android.settings.security;
 
 import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.os.UserManager;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.preference.PreferenceScreen;
+import androidx.preference.PreferenceViewHolder;
 
 import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.R;
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.testutils.shadow.ShadowUtils;
+import com.android.settings.widget.GearPreference;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -47,10 +58,15 @@
     private UserManager mUserManager;
     @Mock
     private DevicePolicyManager mDevicePolicyManager;
+    @Mock
+    private PreferenceScreen mPreferenceScreen;
 
     private Context mContext;
     private FakeFeatureFactory mFeatureFactory;
     private ChangeScreenLockPreferenceController mController;
+    private View mGearView;
+    private GearPreference mGearPreference;
+    private PreferenceViewHolder mPreferenceViewHolder;
 
     @Before
     public void setUp() {
@@ -75,4 +91,149 @@
     public void testDeviceAdministrators_ifDisabled_shouldNotBeShown() {
         assertThat(mController.isAvailable()).isFalse();
     }
+
+    @Test
+    public void updateState_notSecureDisableKeyguard_shouldNotShowGear() {
+        when(mLockPatternUtils.isSecure(anyInt())).thenReturn(false);
+        when(mLockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(true);
+        mockGearPreferenceAndViewHolder();
+
+        showPreference();
+
+        assertThat(mGearView.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void updateState_notSecureDisableKeyguard_summaryShouldShowOff() {
+        when(mLockPatternUtils.isSecure(anyInt())).thenReturn(false);
+        when(mLockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(true);
+        mockGearPreferenceAndViewHolder();
+
+        showPreference();
+
+        assertThat(mGearPreference.getSummary())
+                .isEqualTo(mContext.getString(R.string.unlock_set_unlock_mode_off));
+    }
+
+    @Test
+    public void updateState_notSecureWithSwipeKeyguard_shouldNotShowGear() {
+        when(mLockPatternUtils.isSecure(anyInt())).thenReturn(false);
+        when(mLockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(false);
+        mockGearPreferenceAndViewHolder();
+
+        showPreference();
+
+        assertThat(mGearView.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void updateState_notSecureWithSwipeKeyguard_summaryShouldShowSwipe() {
+        when(mLockPatternUtils.isSecure(anyInt())).thenReturn(false);
+        when(mLockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(false);
+        mockGearPreferenceAndViewHolder();
+
+        showPreference();
+
+        assertThat(mGearPreference.getSummary())
+                .isEqualTo(mContext.getString(R.string.unlock_set_unlock_mode_none));
+    }
+
+    @Test
+    public void updateState_secureWithPinKeyguard_shouldShowGear() {
+        when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
+        when(mLockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(false);
+        doReturn(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX).when(mLockPatternUtils)
+                .getKeyguardStoredPasswordQuality(anyInt());
+        mockGearPreferenceAndViewHolder();
+
+        showPreference();
+
+        assertThat(mGearView.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void updateState_secureWithPinKeyguard_summaryShouldShowPin() {
+        when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
+        when(mLockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(false);
+        doReturn(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX).when(mLockPatternUtils)
+                .getKeyguardStoredPasswordQuality(anyInt());
+
+        mockGearPreferenceAndViewHolder();
+
+        showPreference();
+
+        assertThat(mGearPreference.getSummary())
+                .isEqualTo(mContext.getString(R.string.unlock_set_unlock_mode_pin));
+    }
+
+    @Test
+    public void updateState_secureWithPasswordKeyguard_shouldShowGear() {
+        when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
+        when(mLockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(false);
+        doReturn(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX).when(mLockPatternUtils)
+                .getKeyguardStoredPasswordQuality(anyInt());
+        mockGearPreferenceAndViewHolder();
+
+        showPreference();
+
+        assertThat(mGearView.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void updateState_secureWithPasswordKeyguard_summaryShouldShowPassword() {
+        when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
+        when(mLockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(false);
+        doReturn(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX).when(mLockPatternUtils)
+                .getKeyguardStoredPasswordQuality(anyInt());
+        mockGearPreferenceAndViewHolder();
+
+        showPreference();
+
+        assertThat(mGearPreference.getSummary())
+                .isEqualTo(mContext.getString(R.string.unlock_set_unlock_mode_password));
+    }
+
+    @Test
+    public void updateState_secureWithPatternKeyguard_shouldShowGear() {
+        when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
+        when(mLockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(false);
+        doReturn(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING).when(mLockPatternUtils)
+                .getKeyguardStoredPasswordQuality(anyInt());
+        mockGearPreferenceAndViewHolder();
+
+        showPreference();
+
+        assertThat(mGearView.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void updateState_secureWithPatternKeyguard_summaryShouldShowPattern() {
+        when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
+        when(mLockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(false);
+        doReturn(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING).when(mLockPatternUtils)
+                .getKeyguardStoredPasswordQuality(anyInt());
+        mockGearPreferenceAndViewHolder();
+
+        showPreference();
+
+        assertThat(mGearPreference.getSummary())
+                .isEqualTo(mContext.getString(R.string.unlock_set_unlock_mode_pattern));
+    }
+
+    private void mockGearPreferenceAndViewHolder() {
+        mGearPreference = new GearPreference(mContext, null);
+        mGearView = new View(mContext);
+        PreferenceViewHolder viewHolder = PreferenceViewHolder.createInstanceForTests(
+                LayoutInflater.from(mContext).inflate(
+                        mGearPreference.getLayoutResource(), null, false));
+        mPreferenceViewHolder = spy(viewHolder);
+        doReturn(mGearView).when(mPreferenceViewHolder).findViewById(R.id.settings_button);
+        when(mPreferenceScreen.findPreference(anyString())).thenReturn(mGearPreference);
+    }
+
+    private void showPreference() {
+        mController.displayPreference(mPreferenceScreen);
+        mController.updateState(mGearPreference);
+        mGearPreference.onBindViewHolder(mPreferenceViewHolder);
+    }
 }
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/security/SecuritySettingsTest.java b/tests/robotests/src/com/android/settings/security/SecuritySettingsTest.java
index 7d93ec2..f3cc459 100644
--- a/tests/robotests/src/com/android/settings/security/SecuritySettingsTest.java
+++ b/tests/robotests/src/com/android/settings/security/SecuritySettingsTest.java
@@ -22,6 +22,7 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.hardware.face.FaceManager;
 import android.hardware.fingerprint.FingerprintManager;
 
 import com.android.settings.R;
@@ -44,6 +45,8 @@
     private SummaryLoader mSummaryLoader;
     @Mock
     private FingerprintManager mFingerprintManager;
+    @Mock
+    private FaceManager mFaceManager;
     private SecuritySettings.SummaryProvider mSummaryProvider;
 
     @Before
@@ -51,7 +54,8 @@
         MockitoAnnotations.initMocks(this);
         when(mContext.getSystemService(Context.FINGERPRINT_SERVICE))
                 .thenReturn(mFingerprintManager);
-
+        when(mContext.getSystemService(Context.FACE_SERVICE))
+                .thenReturn(mFaceManager);
         mSummaryProvider = new SecuritySettings.SummaryProvider(mContext, mSummaryLoader);
     }
 
@@ -63,7 +67,20 @@
     }
 
     @Test
+    public void testSummaryProvider_hasFace_hasStaticSummary() {
+        when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE))
+                .thenReturn(true);
+        when(mFaceManager.isHardwareDetected()).thenReturn(true);
+
+        mSummaryProvider.setListening(true);
+
+        verify(mContext).getString(R.string.security_dashboard_summary_face);
+    }
+
+    @Test
     public void testSummaryProvider_hasFingerPrint_hasStaticSummary() {
+        when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE))
+                .thenReturn(false);
         when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
                 .thenReturn(true);
         when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
@@ -74,9 +91,11 @@
     }
 
     @Test
-    public void testSummaryProvider_noFpFeature_shouldSetSummaryWithNoFingerprint() {
+    public void testSummaryProvider_noFpFeature_shouldSetSummaryWithNoBiometrics() {
         when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
                 .thenReturn(false);
+        when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE))
+                .thenReturn(false);
 
         mSummaryProvider.setListening(true);
 
@@ -84,7 +103,9 @@
     }
 
     @Test
-    public void testSummaryProvider_noFpHardware_shouldSetSummaryWithNoFingerprint() {
+    public void testSummaryProvider_noFpHardware_shouldSetSummaryWithNoBiometrics() {
+        when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE))
+                .thenReturn(false);
         when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
                 .thenReturn(true);
         when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
@@ -93,4 +114,29 @@
 
         verify(mContext).getString(R.string.security_dashboard_summary_no_fingerprint);
     }
+
+    @Test
+    public void testSummaryProvider_noFaceFeature_shouldSetSummaryWithNoBiometrics() {
+        when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+                .thenReturn(false);
+        when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE))
+                .thenReturn(false);
+
+        mSummaryProvider.setListening(true);
+
+        verify(mContext).getString(R.string.security_dashboard_summary_no_fingerprint);
+    }
+
+    @Test
+    public void testSummaryProvider_noFaceHardware_shouldSetSummaryWithNoBiometrics() {
+        when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE))
+                .thenReturn(true);
+        when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+                .thenReturn(false);
+        when(mFaceManager.isHardwareDetected()).thenReturn(false);
+
+        mSummaryProvider.setListening(true);
+
+        verify(mContext).getString(R.string.security_dashboard_summary_no_fingerprint);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/wallpaper/FallbackHomeActivityTest.java b/tests/robotests/src/com/android/settings/wallpaper/FallbackHomeActivityTest.java
new file mode 100644
index 0000000..57d7798
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wallpaper/FallbackHomeActivityTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.wallpaper;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.WallpaperColors;
+import android.app.WallpaperManager;
+import android.app.WallpaperManager.OnColorsChangedListener;
+import android.os.Handler;
+
+import com.android.settings.FallbackHome;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.android.controller.ActivityController;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadow.api.Shadow;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Build/Install/Run:
+ *     make RunSettingsRoboTests -j40 ROBOTEST_FILTER=FallbackHomeActivityTest
+ */
+@RunWith(SettingsRobolectricTestRunner.class)
+public class FallbackHomeActivityTest {
+
+    private ActivityController<FallbackHome> mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mController = Robolectric.buildActivity(FallbackHome.class);
+    }
+
+    @Test
+    @Config(shadows = ShadowWallpaperManager.class)
+    public void wallpaperColorsChangedListener_ensured_removed() {
+        // onCreate adds the first color listener by WallpaperManager returning null colors
+        ActivityController controller = mController.setup();
+        ShadowWallpaperManager shadowManager = Shadow.extract(RuntimeEnvironment.application
+                .getSystemService(WallpaperManager.class));
+        assertThat(shadowManager.size()).isEqualTo(1);
+
+        // Assert onDestroy will remove the original listener
+        controller.destroy();
+        assertThat(shadowManager.size()).isEqualTo(0);
+    }
+
+    @Implements(WallpaperManager.class)
+    public static class ShadowWallpaperManager {
+
+        private final List<OnColorsChangedListener> mListener = new ArrayList<>();
+
+        public int size() {
+            return mListener.size();
+        }
+
+        @Implementation
+        public boolean isWallpaperServiceEnabled() {
+            return true;
+        }
+
+        @Implementation
+        public @Nullable WallpaperColors getWallpaperColors(int which) {
+            return null;
+        }
+
+        @Implementation
+        public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener,
+                @NonNull Handler handler) {
+            mListener.add(listener);
+        }
+
+        @Implementation
+        public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener listener) {
+            mListener.remove(listener);
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/widget/AppCheckBoxPreferenceTest.java b/tests/robotests/src/com/android/settings/widget/AppCheckBoxPreferenceTest.java
index af867e6..e20520f 100644
--- a/tests/robotests/src/com/android/settings/widget/AppCheckBoxPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/widget/AppCheckBoxPreferenceTest.java
@@ -19,6 +19,8 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
 
 import com.android.settings.R;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -28,18 +30,25 @@
 import org.junit.runner.RunWith;
 import org.robolectric.RuntimeEnvironment;
 
+import androidx.preference.PreferenceViewHolder;
+
 @RunWith(SettingsRobolectricTestRunner.class)
 public class AppCheckBoxPreferenceTest {
 
+    private static final String SUMMARY = "summary info";
+
     private Context mContext;
     private AppCheckBoxPreference mPreference;
     private AppCheckBoxPreference mAttrPreference;
+    private PreferenceViewHolder mPreferenceViewHolder;
 
     @Before
     public void setUp() {
         mContext = RuntimeEnvironment.application;
         mPreference = new AppCheckBoxPreference(mContext);
         mAttrPreference = new AppCheckBoxPreference(mContext, null /* attrs */);
+        mPreferenceViewHolder = PreferenceViewHolder.createInstanceForTests(
+                LayoutInflater.from(mContext).inflate(R.layout.preference_app, null));
     }
 
     @Test
@@ -47,4 +56,32 @@
         assertThat(mPreference.getLayoutResource()).isEqualTo(R.layout.preference_app);
         assertThat(mAttrPreference.getLayoutResource()).isEqualTo(R.layout.preference_app);
     }
+
+    @Test
+    public void onBindViewHolder_noSummary_layoutGone() {
+        mPreference.setSummary("");
+
+        mPreference.onBindViewHolder(mPreferenceViewHolder);
+
+        assertThat(mPreferenceViewHolder.findViewById(R.id.summary_container).getVisibility())
+                .isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void onBindViewHolder_hasSummary_layoutVisible() {
+        mPreference.setSummary(SUMMARY);
+
+        mPreference.onBindViewHolder(mPreferenceViewHolder);
+
+        assertThat(mPreferenceViewHolder.findViewById(R.id.summary_container).getVisibility())
+                .isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void onBindViewHolder_appendixGone() {
+        mPreference.onBindViewHolder(mPreferenceViewHolder);
+
+        assertThat(mPreferenceViewHolder.findViewById(R.id.appendix).getVisibility())
+                .isEqualTo(View.GONE);
+    }
 }