Merge "Polish on mobile network settings"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index aa98c62..eb3be0e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -911,7 +911,7 @@
 
         <activity android:name=".Settings$MyDeviceInfoActivity"
                   android:label="@string/about_settings"
-                  android:icon="@drawable/ic_settings_about"
+                  android:icon="@drawable/ic_homepage_about"
                   android:parentActivityName="Settings">
             <intent-filter android:priority="1">
                 <action android:name="android.settings.DEVICE_INFO_SETTINGS" />
@@ -922,14 +922,6 @@
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="com.android.settings.SHORTCUT" />
             </intent-filter>
-            <intent-filter>
-                <action android:name="com.android.settings.action.SETTINGS" />
-            </intent-filter>
-            <meta-data android:name="com.android.settings.order" android:value="-270"/>
-            <meta-data android:name="com.android.settings.category"
-                       android:value="com.android.settings.category.ia.system" />
-            <meta-data android:name="com.android.settings.title"
-                       android:resource="@string/about_settings" />
             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
                        android:value="com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment" />
             <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
@@ -1161,7 +1153,7 @@
         <activity
             android:name="Settings$LocationSettingsActivity"
             android:label="@string/location_settings_title"
-            android:icon="@drawable/ic_settings_location"
+            android:icon="@drawable/ic_homepage_location"
             android:configChanges="orientation|keyboardHidden|screenSize"
             android:parentActivityName="Settings">
             <intent-filter android:priority="1">
@@ -1180,7 +1172,7 @@
         <activity
             android:name="Settings$ScanningSettingsActivity"
             android:label="@string/location_scanning_screen_title"
-            android:icon="@drawable/ic_settings_location"
+            android:icon="@drawable/ic_homepage_location"
             android:configChanges="orientation|keyboardHidden|screenSize"
             android:parentActivityName="Settings">
             <intent-filter android:priority="1">
@@ -2962,16 +2954,6 @@
                        android:value="true" />
         </activity>
 
-        <activity android:name="Settings$DirectoryAccessSettingsActivity"
-                android:label="@string/directory_access">
-            <intent-filter>
-                <action android:name="android.settings.STORAGE_VOLUME_ACCESS_SETTINGS" />
-                <category android:name="android.intent.category.DEFAULT" />
-            </intent-filter>
-            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
-                android:value="com.android.settings.applications.manageapplications.ManageApplications" />
-        </activity>
-
         <provider android:name=".slices.SettingsSliceProvider"
                   android:authorities="com.android.settings.slices;android.settings.slices"
                   android:exported="true"
diff --git a/color-check-baseline.xml b/color-check-baseline.xml
index 62c7915..3672e2d 100644
--- a/color-check-baseline.xml
+++ b/color-check-baseline.xml
@@ -1029,7 +1029,7 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="    &lt;color name=&quot;homepage_connected_device_background&quot;>#71A234&lt;/color>"
+        errorLine1="    &lt;color name=&quot;homepage_connected_device_background&quot;>#72B70F&lt;/color>"
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
@@ -1077,7 +1077,7 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="    &lt;color name=&quot;homepage_display_background&quot;>#FFB600&lt;/color>"
+        errorLine1="    &lt;color name=&quot;homepage_display_background&quot;>#FFA727&lt;/color>"
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
@@ -1173,7 +1173,7 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="    &lt;color name=&quot;homepage_system_background&quot;>#757575&lt;/color>"
+        errorLine1="    &lt;color name=&quot;homepage_system_background&quot;>#9E9E9E&lt;/color>"
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
@@ -1221,11 +1221,43 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="    &lt;color name=&quot;homepage_location_background&quot;>#1A73E8&lt;/color>"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/values/colors.xml"
+            line="128"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="    &lt;color name=&quot;homepage_about_background&quot;>#9FA8DA&lt;/color>"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/values/colors.xml"
+            line="129"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
         errorLine1="    &lt;color name=&quot;battery_good_color_light&quot;>#43a047&lt;/color> &lt;!-- Material Green 600 -->"
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="132"
+            line="134"
             column="5"/>
     </issue>
 
@@ -1241,7 +1273,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="133"
+            line="135"
             column="5"/>
     </issue>
 
@@ -1257,7 +1289,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="134"
+            line="136"
             column="5"/>
     </issue>
 
@@ -1273,7 +1305,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="135"
+            line="137"
             column="5"/>
     </issue>
 
@@ -1289,7 +1321,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="136"
+            line="138"
             column="5"/>
     </issue>
 
@@ -1305,7 +1337,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="137"
+            line="139"
             column="5"/>
     </issue>
 
@@ -1321,7 +1353,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="140"
+            line="142"
             column="5"/>
     </issue>
 
@@ -1337,7 +1369,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="141"
+            line="143"
             column="5"/>
     </issue>
 
@@ -1353,7 +1385,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="142"
+            line="144"
             column="5"/>
     </issue>
 
@@ -1369,7 +1401,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="143"
+            line="145"
             column="5"/>
     </issue>
 
@@ -1385,7 +1417,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="144"
+            line="146"
             column="5"/>
     </issue>
 
@@ -1685,6 +1717,22 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="                android:color=&quot;@color/homepage_about_background&quot; />"
+        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/ic_homepage_about.xml"
+            line="23"
+            column="17"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
         errorLine1="                android:color=&quot;@color/homepage_accessibility_background&quot; />"
         errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
@@ -1861,6 +1909,38 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="                android:color=&quot;@color/homepage_location_background&quot; />"
+        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/ic_homepage_location.xml"
+            line="23"
+            column="17"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="                android:color=&quot;@color/homepage_location_background&quot; />"
+        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/ic_preference_location.xml"
+            line="23"
+            column="17"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
         errorLine1="                android:color=&quot;@color/homepage_support_background&quot; />"
         errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
diff --git a/libs/contextualcards.aar b/libs/contextualcards.aar
index 5e855fa..892a6be 100755
--- a/libs/contextualcards.aar
+++ b/libs/contextualcards.aar
Binary files differ
diff --git a/proguard.flags b/proguard.flags
index 82e8e58..b66a786 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -60,4 +60,9 @@
 # Keep classes that implements CustomSliceable, which are used by reflection.
 -keepclasseswithmembers class * implements com.android.settings.slices.CustomSliceable {
     public <init>(android.content.Context);
-}
\ No newline at end of file
+}
+
+# Keep classes that extends SliceBackgroundWorker, which are used by reflection.
+-keepclasseswithmembers class * extends com.android.settings.slices.SliceBackgroundWorker {
+    public <init>(android.content.Context, android.net.Uri);
+}
diff --git a/protos/contextual_card_list.proto b/protos/contextual_card_list.proto
index 89e6c13..ea82408 100644
--- a/protos/contextual_card_list.proto
+++ b/protos/contextual_card_list.proto
@@ -8,12 +8,24 @@
 }
 
 message ContextualCard {
-  // Slice uri of the contextual card
+
+  /**
+   * The category of a card: this is a hint for how a card should be collected,
+   * ranked, and presented
+   */
+  enum Category {
+    DEFAULT = 0;
+    SUGGESTION = 1;
+    POSSIBLE = 2;
+    IMPORTANT = 3;
+    EXCLUSIVE = 4;
+  }
+
+  /** Slice uri of the contextual card */
   optional string sliceUri = 1;
 
-  // {@link ContextualCardCategory}.
-  optional int32 category = 2;
-
-  // Name of the card. It should be identical in every app
+  /** Name of the card. It should be identical in every app */
   optional string cardName = 3;
-}
\ No newline at end of file
+
+  optional Category card_category = 4;
+}
diff --git a/res/drawable/ic_account_circle_24dp.xml b/res/drawable/ic_account_circle_24dp.xml
new file mode 100644
index 0000000..8445adc
--- /dev/null
+++ b/res/drawable/ic_account_circle_24dp.xml
@@ -0,0 +1,27 @@
+<!--
+  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.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="32dp"
+    android:height="32dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#ff4285f4"
+      android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM7.07,18.28c0.43,-0.9 3.05,-1.78 4.93,-1.78s4.51,0.88 4.93,1.78C15.57,19.36 13.86,20 12,20S8.43,19.36 7.07,18.28zM18.36,16.83c-1.43,-1.74 -4.9,-2.33 -6.36,-2.33s-4.93,0.59 -6.36,2.33C4.62,15.49 4,13.82 4,12c0,-4.41 3.59,-8 8,-8c4.41,0 8,3.59 8,8C20,13.82 19.38,15.49 18.36,16.83z"/>
+  <path
+      android:fillColor="#ff4285f4"
+      android:pathData="M12,6c-1.94,0 -3.5,1.56 -3.5,3.5S10.06,13 12,13c1.94,0 3.5,-1.56 3.5,-3.5S13.94,6 12,6zM12,11c-0.83,0 -1.5,-0.67 -1.5,-1.5C10.5,8.67 11.17,8 12,8c0.83,0 1.5,0.67 1.5,1.5C13.5,10.33 12.83,11 12,11z"/>
+</vector>
diff --git a/res/drawable/ic_content_copy_grey600_24dp.xml b/res/drawable/ic_content_copy_grey600_24dp.xml
new file mode 100644
index 0000000..827c66e
--- /dev/null
+++ b/res/drawable/ic_content_copy_grey600_24dp.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z"
+      android:fillColor="#757575"/>
+</vector>
diff --git a/res/drawable/ic_homepage_about.xml b/res/drawable/ic_homepage_about.xml
new file mode 100644
index 0000000..d47a740
--- /dev/null
+++ b/res/drawable/ic_homepage_about.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item>
+        <shape android:shape="oval">
+            <solid
+                android:color="@color/homepage_about_background" />
+            <size
+                android:width="@dimen/dashboard_tile_image_size"
+                android:height="@dimen/dashboard_tile_image_size" />
+        </shape>
+    </item>
+
+    <item
+        android:width="@dimen/dashboard_tile_foreground_image_size"
+        android:height="@dimen/dashboard_tile_foreground_image_size"
+        android:start="@dimen/dashboard_tile_foreground_image_inset"
+        android:top="@dimen/dashboard_tile_foreground_image_inset"
+        android:drawable="@drawable/ic_phone_info" />
+</layer-list>
diff --git a/res/drawable/ic_homepage_location.xml b/res/drawable/ic_homepage_location.xml
new file mode 100644
index 0000000..413801b
--- /dev/null
+++ b/res/drawable/ic_homepage_location.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item>
+        <shape android:shape="oval">
+            <solid
+                android:color="@color/homepage_location_background"/>
+            <size
+                android:width="@dimen/dashboard_tile_image_size"
+                android:height="@dimen/dashboard_tile_image_size"/>
+        </shape>
+    </item>
+
+    <item
+        android:width="@dimen/dashboard_tile_foreground_image_size"
+        android:height="@dimen/dashboard_tile_foreground_image_size"
+        android:start="@dimen/dashboard_tile_foreground_image_inset"
+        android:top="@dimen/dashboard_tile_foreground_image_inset"
+        android:drawable="@drawable/ic_settings_location"/>
+</layer-list>
diff --git a/res/drawable/ic_phone_info.xml b/res/drawable/ic_phone_info.xml
new file mode 100644
index 0000000..7aee3e8
--- /dev/null
+++ b/res/drawable/ic_phone_info.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,21H7v-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7zM11,7h2v2h-2V7zM11,11h2v6h-2V11z"/>
+</vector>
diff --git a/res/drawable/ic_preference_location.xml b/res/drawable/ic_preference_location.xml
new file mode 100644
index 0000000..e37d629
--- /dev/null
+++ b/res/drawable/ic_preference_location.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item>
+        <shape android:shape="oval">
+            <solid
+                android:color="@color/homepage_location_background"/>
+            <size
+                android:width="@android:dimen/app_icon_size"
+                android:height="@android:dimen/app_icon_size"/>
+        </shape>
+    </item>
+
+    <item
+        android:width="@dimen/dashboard_tile_foreground_image_size"
+        android:height="@dimen/dashboard_tile_foreground_image_size"
+        android:start="@dimen/preference_icon_foreground_image_inset"
+        android:top="@dimen/preference_icon_foreground_image_inset"
+        android:drawable="@drawable/ic_settings_location"/>
+</layer-list>
diff --git a/res/drawable/ic_settings_location.xml b/res/drawable/ic_settings_location.xml
index 34bd4f0..b7cfd6f 100644
--- a/res/drawable/ic_settings_location.xml
+++ b/res/drawable/ic_settings_location.xml
@@ -17,8 +17,7 @@
         android:width="24.0dp"
         android:height="24.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13C19,5.13 15.87,2 12,2zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9z"/>
diff --git a/res/layout-sw320dp/settings_entity_header.xml b/res/layout-sw320dp/settings_entity_header.xml
deleted file mode 100644
index 9a46adf..0000000
--- a/res/layout-sw320dp/settings_entity_header.xml
+++ /dev/null
@@ -1,113 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  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.
-  -->
-
-<!-- Entity header -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/entity_header"
-    style="@style/EntityHeader"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:paddingTop="24dp"
-    android:paddingBottom="24dp">
-
-    <LinearLayout
-        android:id="@+id/entity_header_content"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:background="?android:attr/selectableItemBackground"
-        android:orientation="horizontal"
-        android:paddingStart="56dp">
-
-        <ImageView
-            android:id="@+id/entity_header_icon"
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            android:scaleType="fitCenter"
-            android:layout_gravity="center_horizontal"
-            android:antialias="true" />
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical"
-            android:paddingStart="16dp"
-            android:paddingEnd="16dp"
-            android:orientation="vertical">
-
-            <TextView
-                android:id="@+id/entity_header_title"
-                style="@style/TextAppearance.EntityHeaderTitle"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:singleLine="false"
-                android:ellipsize="marquee"
-                android:gravity="start"
-                android:textDirection="locale" />
-
-            <TextView
-                android:id="@+id/install_type"
-                style="@style/TextAppearance.EntityHeaderSummary"
-                android:visibility="gone"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-
-            <TextView
-                android:id="@+id/entity_header_summary"
-                style="@style/TextAppearance.EntityHeaderSummary"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content" />
-
-            <TextView
-                android:id="@+id/entity_header_second_summary"
-                style="@style/TextAppearance.EntityHeaderSummary"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content" />
-
-        </LinearLayout>
-    </LinearLayout>
-
-    <LinearLayout
-        android:id="@+id/entity_header_links"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:orientation="vertical">
-
-        <ImageButton
-            android:id="@android:id/button1"
-            style="?android:attr/actionOverflowButtonStyle"
-            android:layout_width="wrap_content"
-            android:layout_weight="1"
-            android:layout_height="0dp"
-            android:minWidth="@dimen/min_tap_target_size"
-            android:src="@null"
-            android:tint="?android:attr/colorAccent" />
-
-        <ImageButton
-            android:id="@android:id/button2"
-            style="?android:attr/actionOverflowButtonStyle"
-            android:layout_width="wrap_content"
-            android:layout_weight="1"
-            android:layout_height="0dp"
-            android:minWidth="@dimen/min_tap_target_size"
-            android:src="@null"
-            android:tint="?android:attr/colorAccent" />
-
-    </LinearLayout>
-
-</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/admin_support_details_dialog.xml b/res/layout/admin_support_details_dialog.xml
index 8c33b1a..922451f 100644
--- a/res/layout/admin_support_details_dialog.xml
+++ b/res/layout/admin_support_details_dialog.xml
@@ -27,8 +27,6 @@
         <ImageView android:id="@+id/admin_support_icon"
                 android:layout_width="@dimen/admin_details_dialog_icon_size"
                 android:layout_height="@dimen/admin_details_dialog_icon_size"
-                android:tint="?android:attr/colorAccent"
-                android:src="@*android:drawable/ic_info"
                 android:scaleType="fitCenter"
                 android:contentDescription="@null" />
         <TextView android:id="@+id/admin_support_dialog_title"
diff --git a/res/layout/homepage_condition_full_tile.xml b/res/layout/homepage_condition_full_tile.xml
new file mode 100644
index 0000000..415defc
--- /dev/null
+++ b/res/layout/homepage_condition_full_tile.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<androidx.cardview.widget.CardView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    style="@style/ContextualCardStyle">
+
+    <LinearLayout
+        android:id="@+id/content"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="@dimen/homepage_card_padding_start"
+        android:paddingEnd="@dimen/homepage_card_padding_end"
+        android:paddingTop="@dimen/homepage_condition_full_card_padding_top"
+        android:paddingBottom="@dimen/homepage_condition_full_card_padding_bottom"
+        android:orientation="horizontal"
+        android:gravity="center_vertical">
+
+        <ImageView
+            android:id="@android:id/icon"
+            android:layout_width="@dimen/homepage_card_icon_size"
+            android:layout_height="@dimen/homepage_card_icon_size"
+            android:tint="?android:attr/colorAccent"/>
+
+        <LinearLayout
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:paddingStart="@dimen/homepage_condition_full_card_padding_start"
+            android:paddingEnd="@dimen/homepage_condition_full_card_padding_end"
+            android:orientation="vertical">
+
+            <TextView
+                android:id="@android:id/title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="@dimen/homepage_condition_card_title_margin_bottom"
+                style="@style/TextAppearance.ConditionCardTitle"/>
+
+            <TextView
+                android:id="@android:id/summary"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                style="@style/TextAppearance.ConditionCardSummary"/>
+
+        </LinearLayout>
+
+        <include layout="@layout/vertical_divider"/>
+
+        <Button
+            android:id="@+id/first_action"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            style="@style/ConditionFullCardBorderlessButton"/>
+
+    </LinearLayout>
+
+</androidx.cardview.widget.CardView>
diff --git a/res/layout/homepage_condition_half_tile.xml b/res/layout/homepage_condition_half_tile.xml
new file mode 100644
index 0000000..0b7eec7
--- /dev/null
+++ b/res/layout/homepage_condition_half_tile.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<androidx.cardview.widget.CardView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/homepage_condition_half_card_height"
+    style="@style/ContextualCardStyle">
+
+    <LinearLayout
+        android:id="@+id/content"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="@dimen/homepage_card_padding_start"
+        android:paddingEnd="@dimen/homepage_card_padding_end"
+        android:paddingTop="@dimen/homepage_condition_half_card_padding_top"
+        android:orientation="vertical">
+
+        <ImageView
+            android:id="@android:id/icon"
+            android:layout_width="@dimen/homepage_card_icon_size"
+            android:layout_height="@dimen/homepage_card_icon_size"
+            android:tint="?android:attr/colorAccent"/>
+
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:maxLines="1"
+            android:ellipsize="end"
+            android:layout_marginTop="@dimen/homepage_condition_half_card_title_margin_top"
+            android:layout_marginBottom="@dimen/homepage_condition_card_title_margin_bottom"
+            style="@style/TextAppearance.ConditionCardTitle"/>
+
+        <TextView
+            android:id="@android:id/summary"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:maxLines="1"
+            android:ellipsize="end"
+            android:layout_marginBottom="@dimen/homepage_condition_half_card_summary_margin_bottom"
+            style="@style/TextAppearance.ConditionCardSummary"/>
+
+        <include layout="@layout/horizontal_divider"/>
+
+        <Button
+            android:id="@+id/first_action"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            style="@style/ConditionHalfCardBorderlessButton"/>
+
+    </LinearLayout>
+
+</androidx.cardview.widget.CardView>
\ No newline at end of file
diff --git a/res/layout/homepage_condition_tile.xml b/res/layout/homepage_condition_tile.xml
deleted file mode 100644
index ed76094..0000000
--- a/res/layout/homepage_condition_tile.xml
+++ /dev/null
@@ -1,97 +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.
--->
-
-<androidx.cardview.widget.CardView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    style="@style/ContextualCardStyle">
-
-    <LinearLayout
-        android:id="@+id/content"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical">
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:minHeight="@dimen/condition_header_height"
-            android:background="?android:attr/selectableItemBackground"
-            android:orientation="horizontal">
-
-            <ImageView
-                android:id="@android:id/icon"
-                android:layout_width="@dimen/suggestion_card_icon_size"
-                android:layout_height="@dimen/suggestion_card_icon_size"
-                android:layout_marginTop="12dp"
-                android:layout_marginStart="14dp"
-                android:layout_marginEnd="24dp"
-                android:tint="?android:attr/colorAccent"/>
-
-            <TextView
-                android:id="@android:id/title"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="14dp"
-                android:textAppearance="?android:attr/textAppearanceSmall"
-                android:textColor="?android:attr/textColorPrimary"/>
-
-        </LinearLayout>
-
-        <TextView
-            android:id="@android:id/summary"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingStart="62dp"
-            android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-            android:paddingBottom="8dp"
-            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
-            android:alpha=".7"
-            android:textColor="?android:attr/textColorPrimary"/>
-
-        <androidx.appcompat.widget.ButtonBarLayout
-            android:id="@+id/buttonBar"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingStart="62dp"
-            android:paddingBottom="1dp"
-            style="?android:attr/buttonBarStyle"
-            android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
-
-            <Button
-                android:id="@+id/first_action"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:paddingStart="0dp"
-                android:alpha=".8"
-                android:textAlignment="viewStart"
-                android:textColor="?android:attr/textColorPrimary"
-                style="?android:attr/buttonBarButtonStyle"/>
-
-            <Space
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"/>
-
-        </androidx.appcompat.widget.ButtonBarLayout>
-
-        <include layout="@layout/horizontal_divider"/>
-
-    </LinearLayout>
-
-</androidx.cardview.widget.CardView>
diff --git a/res/layout/homepage_suggestion_tile.xml b/res/layout/homepage_suggestion_tile.xml
new file mode 100644
index 0000000..36ad45c
--- /dev/null
+++ b/res/layout/homepage_suggestion_tile.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<androidx.cardview.widget.CardView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/suggestion_card"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    style="@style/ContextualCardStyle">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="112dp"
+        android:paddingBottom="8dp"
+        android:orientation="vertical">
+
+        <RelativeLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+
+            <ImageView
+                android:id="@android:id/icon"
+                android:layout_width="@dimen/homepage_card_icon_size"
+                android:layout_height="@dimen/homepage_card_icon_size"
+                style="@style/SuggestionCardIcon"
+                android:layout_marginTop="16dp"
+                android:layout_marginBottom="6dp"/>
+
+        </RelativeLayout>
+
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            style="@style/SuggestionCardText"
+            android:layout_marginStart="12dp"
+            android:layout_marginEnd="12dp"
+            android:singleLine="true"
+            android:textAppearance="@style/TextAppearance.SuggestionTitle"
+            android:fadingEdge="horizontal"/>
+
+        <TextView
+            android:id="@android:id/summary"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            style="@style/SuggestionCardText"
+            android:layout_marginStart="12dp"
+            android:layout_marginEnd="12dp"
+            android:singleLine="true"
+            android:textAppearance="@style/TextAppearance.SuggestionSummary"/>
+
+    </LinearLayout>
+
+</androidx.cardview.widget.CardView>
\ No newline at end of file
diff --git a/res/layout/horizontal_divider.xml b/res/layout/horizontal_divider.xml
index e4a277d..a134423 100644
--- a/res/layout/horizontal_divider.xml
+++ b/res/layout/horizontal_divider.xml
@@ -19,5 +19,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/divider"
     android:layout_width="match_parent"
-    android:layout_height=".75dp"
-    android:background="?android:attr/dividerHorizontal" />
\ No newline at end of file
+    android:layout_height="@dimen/horizontal_divider_height"
+    android:layout_marginTop="@dimen/horizontal_divider_margin_top"
+    android:layout_marginBottom="@dimen/horizontal_divider_margin_bottom"
+    android:background="?android:attr/dividerHorizontal"/>
\ No newline at end of file
diff --git a/res/layout/search_bar.xml b/res/layout/search_bar.xml
index 9e64db7..1ba64ad 100644
--- a/res/layout/search_bar.xml
+++ b/res/layout/search_bar.xml
@@ -45,5 +45,12 @@
                 android:layout_height="wrap_content"
                 android:text="@string/search_menu"/>
         </Toolbar>
+        <ImageView
+            android:id="@+id/account_avatar"
+            android:layout_marginStart="@dimen/search_bar_avatar_start_margin"
+            android:layout_marginEnd="@dimen/search_bar_avatar_end_margin"
+            android:layout_width="@dimen/search_bar_avatar_size"
+            android:layout_height="@dimen/search_bar_avatar_size"
+            android:layout_gravity="end|center_vertical"/>
     </androidx.cardview.widget.CardView>
 </FrameLayout>
\ No newline at end of file
diff --git a/res/layout/settings_entity_header.xml b/res/layout/settings_entity_header.xml
index 6698f3f..5f5fe00 100644
--- a/res/layout/settings_entity_header.xml
+++ b/res/layout/settings_entity_header.xml
@@ -16,60 +16,58 @@
   -->
 
 <!-- Entity header -->
-<LinearLayout
+<RelativeLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/entity_header"
     style="@style/EntityHeader"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:paddingStart="@dimen/preference_no_icon_padding_start"
-    android:paddingTop="24dp"
-    android:paddingBottom="32dp"
     android:orientation="horizontal">
 
     <LinearLayout
         android:id="@+id/entity_header_content"
-        android:layout_width="0dp"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:background="?android:attr/selectableItemBackground"
+        android:layout_centerHorizontal="true"
+        android:gravity="center_horizontal"
         android:orientation="vertical">
 
         <ImageView
             android:id="@+id/entity_header_icon"
             android:layout_width="48dp"
             android:layout_height="48dp"
-            android:layout_marginBottom="16dp"
             android:scaleType="fitXY"
-            android:antialias="true" />
+            android:antialias="true"/>
 
         <TextView
             android:id="@+id/entity_header_title"
             style="@style/TextAppearance.EntityHeaderTitle"
-            android:layout_width="match_parent"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:singleLine="false"
             android:ellipsize="marquee"
-            android:gravity="start"
-            android:textDirection="locale" />
+            android:textDirection="locale"
+            android:layout_marginTop="8dp"/>
 
         <TextView
             android:id="@+id/install_type"
             style="@style/TextAppearance.EntityHeaderSummary"
             android:visibility="gone"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="2dp"/>
 
         <TextView
             android:id="@+id/entity_header_summary"
             style="@style/TextAppearance.EntityHeaderSummary"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="2dp"/>
 
         <TextView
             android:id="@+id/entity_header_second_summary"
             style="@style/TextAppearance.EntityHeaderSummary"
-            android:layout_width="match_parent"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content" />
 
     </LinearLayout>
@@ -78,6 +76,8 @@
         android:id="@+id/entity_header_links"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
+        android:layout_centerVertical="true"
+        android:layout_alignParentEnd="true"
         android:orientation="vertical">
 
         <ImageButton
@@ -102,4 +102,4 @@
 
     </LinearLayout>
 
-</LinearLayout>
+</RelativeLayout>
diff --git a/res/layout/settings_homepage.xml b/res/layout/settings_homepage.xml
index bd54717..0140ced 100644
--- a/res/layout/settings_homepage.xml
+++ b/res/layout/settings_homepage.xml
@@ -27,32 +27,5 @@
         android:layout_height="match_parent"
         android:layoutAnimation="@anim/layout_animation_fall_down"/>
 
-    <RelativeLayout
-        android:id="@+id/suggestion_footer"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/condition_header_height"
-        android:layout_centerHorizontal="true">
-
-        <ImageView
-            android:id="@+id/expand_indicator"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_alignParentEnd="true"
-            android:paddingTop="4dp"
-            android:paddingStart="16dp"
-            android:paddingEnd="16dp"/>
-
-        <TextView
-            android:id="@+id/expand_summary"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="8dp"
-            android:layout_toStartOf="@id/expand_indicator"
-            android:layout_centerVertical="true"
-            android:gravity="end"
-            android:textAppearance="@style/TextAppearance.SuggestionTitle"
-            android:textColor="?android:attr/colorAccent"/>
-
-    </RelativeLayout>
     <include layout="@layout/horizontal_divider"/>
 </LinearLayout>
diff --git a/res/xml/directory_access_details.xml b/res/layout/vertical_divider.xml
similarity index 65%
rename from res/xml/directory_access_details.xml
rename to res/layout/vertical_divider.xml
index 4448ba6..4f1cc43 100644
--- a/res/xml/directory_access_details.xml
+++ b/res/layout/vertical_divider.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
+<!--
+     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.
@@ -14,7 +15,9 @@
      limitations under the License.
 -->
 
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:settings="http://schemas.android.com/apk/res-auto"
-        android:key="directory_access_details"
-        android:title="@string/directory_access"/>
+<View
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/divider"
+    android:layout_width="@dimen/vertical_divider_width"
+    android:layout_height="match_parent"
+    android:background="?android:attr/dividerVertical"/>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 94d915c..c3faaba 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -215,10 +215,12 @@
     <string-array name="wifi_security">
         <!-- The Wi-Fi network does not have any security. -->
         <item>@string/wifi_security_none</item>
+        <item translatable="false">@string/wifi_security_owe</item>
         <item translatable="false">@string/wifi_security_wep</item>
         <item translatable="false">@string/wifi_security_psk_generic</item>
+        <item translatable="false">@string/wifi_security_sae</item>
         <item translatable="false">@string/wifi_security_eap</item>
-
+        <item translatable="false">@string/wifi_security_eap_suiteb</item>
     </string-array>
 
     <!-- Match this with the constants in AccessPoint. --> <skip />
@@ -228,6 +230,7 @@
         <item>@string/wifi_security_none</item>
         <item translatable="false">@string/wifi_security_wep</item>
         <item translatable="false">@string/wifi_security_psk_generic</item>
+        <item translatable="false">@string/wifi_security_sae</item>
     </string-array>
 
     <!-- Security types for wireless tether -->
diff --git a/res/values/colors.xml b/res/values/colors.xml
index f398d92..11c1aaf 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -113,18 +113,20 @@
 
     <!-- Dashboard/homepage icon background colors -->
     <color name="homepage_network_background">#2196F3</color>
-    <color name="homepage_connected_device_background">#71A234</color>
+    <color name="homepage_connected_device_background">#72B70F</color>
     <color name="homepage_app_and_notification_background">#FF7E0F</color>
     <color name="homepage_battery_background">#258982</color>
-    <color name="homepage_display_background">#FFB600</color>
+    <color name="homepage_display_background">#FFA727</color>
     <color name="homepage_sound_background">#01B1AF</color>
     <color name="homepage_storage_background">#C14CE6</color>
     <color name="homepage_security_background">#0F9D58</color>
     <color name="homepage_accounts_background">#F15B8D</color>
     <color name="homepage_accessibility_background">#5011C1</color>
-    <color name="homepage_system_background">#757575</color>
+    <color name="homepage_system_background">#9E9E9E</color>
     <color name="homepage_support_background">#26459C</color>
     <color name="homepage_generic_icon_background">#1A73E8</color>
+    <color name="homepage_location_background">#2EC7DC</color>
+    <color name="homepage_about_background">#9FA8DA</color>
     <!-- End of dashboard/homepage icon background colors -->
 
     <color name="glif_error_color">@*android:color/material_red_A700</color>
diff --git a/res/values/config.xml b/res/values/config.xml
index b496080..a9fe35d 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -134,14 +134,15 @@
          have distinct intensity levels -->
     <bool name="config_vibration_supports_multiple_intensities">false</bool>
 
+    <!--
+        Whether or not the homepage should be powered by legacy suggestion (versus contextual cards)
+        Default to true as not all devices support contextual cards.
+    -->
+    <bool name="config_use_legacy_suggestion">true</bool>
+
+    <!-- Whether or not homepage should display user's account avatar -->
+    <bool name="config_show_avatar_in_homepage">false</bool>
+
     <!-- Whether or not TopLevelSettings should force rounded icon for injected tiles -->
     <bool name="config_force_rounded_icon_TopLevelSettings">true</bool>
-
-    <!-- TODO(b/115429501): move those 3 configs to framework-->
-    <!-- Show enabled lte option for lte device -->
-    <bool name="config_enabled_lte" translatable="false">false</bool>
-    <!-- Show enabled tdscdma option for device -->
-    <bool name="config_support_tdscdma" translatable="false">false</bool>
-    <!-- Show enabled tdscdma option for device when connect roaming network -->
-    <string-array name="config_support_tdscdma_roaming_on_networks" translatable="false"></string-array>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 9b33388..caaea90 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -88,6 +88,9 @@
     <!-- Dashboard foreground image inset (from background edge to foreground edge) -->
     <dimen name="dashboard_tile_foreground_image_inset">6dp</dimen>
 
+    <!-- Preference icon foreground image inset (from background edge to foreground edge) -->
+    <dimen name="preference_icon_foreground_image_inset">12dp</dimen>
+
     <!-- SwitchBar sub settings margin start / end -->
     <dimen name="switchbar_subsettings_margin_start">72dp</dimen>
     <dimen name="switchbar_subsettings_margin_end">16dp</dimen>
@@ -103,6 +106,9 @@
     <dimen name="search_bar_text_size">16dp</dimen>
     <dimen name="search_bar_card_elevation">2dp</dimen>
     <dimen name="search_bar_content_inset">64dp</dimen>
+    <dimen name="search_bar_avatar_size">32dp</dimen>
+    <dimen name="search_bar_avatar_start_margin">4dp</dimen>
+    <dimen name="search_bar_avatar_end_margin">16dp</dimen>
 
     <!-- Dimensions for Wifi Assistant Card -->
     <dimen name="wifi_assistant_padding_top_bottom">16dp</dimen>
@@ -297,17 +303,6 @@
     <dimen name="suggestion_condition_header_padding_expanded">5dp</dimen>
     <dimen name="condition_header_height">36dp</dimen>
 
-    <!-- Suggestion cards size and padding -->
-    <dimen name="suggestion_card_icon_size">24dp</dimen>
-    <dimen name="suggestion_card_outer_margin">14dp</dimen>
-    <dimen name="suggestion_card_inner_margin">12dp</dimen>
-    <dimen name="suggestion_card_padding_bottom_one_card">16dp</dimen>
-    <dimen name="suggestion_card_corner_radius">2dp</dimen>
-    <dimen name="suggestion_card_icon_side_margin">12dp</dimen>
-    <dimen name="suggestion_card_button_side_margin">8dp</dimen>
-    <dimen name="suggestion_card_button_top_margin">16dp</dimen>
-    <dimen name="suggestion_card_button_bottom_margin">18dp</dimen>
-
     <!-- Condition cards size and padding -->
     <dimen name="condition_card_elevation">2dp</dimen>
 
@@ -325,16 +320,34 @@
     <dimen name="homepage_bottombar_fab_cradle">68dp</dimen>
 
     <!-- Homepage cards size and padding -->
+    <dimen name="homepage_card_icon_size">24dp</dimen>
     <dimen name="homepage_card_corner_radius">8dp</dimen>
     <dimen name="homepage_card_elevation">2dp</dimen>
-    <dimen name="homepage_card_vertical_margin">6dp</dimen>
-    <dimen name="homepage_card_side_margin">16dp</dimen>
+    <dimen name="homepage_card_vertical_margin">4dp</dimen>
+    <dimen name="homepage_card_side_margin">8dp</dimen>
     <dimen name="homepage_card_padding_start">16dp</dimen>
     <dimen name="homepage_card_padding_end">16dp</dimen>
 
+    <!-- Horizontal divider size and margin -->
+    <dimen name="horizontal_divider_margin_top">4dp</dimen>
+    <dimen name="horizontal_divider_margin_bottom">8dp</dimen>
+    <dimen name="horizontal_divider_height">.75dp</dimen>
+
+    <!-- Vertical divider size -->
+    <dimen name="vertical_divider_width">.75dp</dimen>
+
     <!-- Signal icon in NetworkSelectSetting -->
     <dimen name="signal_strength_icon_size">24dp</dimen>
 
-
+    <!-- Condition cards size and padding -->
+    <dimen name="homepage_condition_card_title_margin_bottom">2dp</dimen>
+    <dimen name="homepage_condition_half_card_height">150dp</dimen>
+    <dimen name="homepage_condition_half_card_padding_top">12dp</dimen>
+    <dimen name="homepage_condition_half_card_title_margin_top">12dp</dimen>
+    <dimen name="homepage_condition_half_card_summary_margin_bottom">12dp</dimen>
+    <dimen name="homepage_condition_full_card_padding_start">24dp</dimen>
+    <dimen name="homepage_condition_full_card_padding_end">24dp</dimen>
+    <dimen name="homepage_condition_full_card_padding_top">12dp</dimen>
+    <dimen name="homepage_condition_full_card_padding_bottom">12dp</dimen>
 
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4ccb395..01c89aa 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -814,11 +814,13 @@
     <string name="location_settings_title">Location</string>
     <!-- Used in the location settings to control turning on/off the feature entirely -->
     <string name="location_settings_master_switch_title">Use location</string>
+    <!-- Summary for Location settings, explaining a few important settings under it [CHAR LIMIT=NONE]-->
+    <string name="location_settings_summary">Scanning, location history</string>
 
     <!-- Main Settings screen setting option title for the item to take you to the accounts screen [CHAR LIMIT=22] -->
     <string name="account_settings_title">Accounts</string>
     <!-- Main Settings screen setting option title for the item to take you to the security screen -->
-    <string name="security_settings_title">Security &amp; location</string>
+    <string name="security_settings_title">Security</string>
     <!-- Security Settings screen setting option title for the item to take you to the encryption and credential screen -->
     <string name="encryption_and_credential_settings_title">Encryption &amp; credentials</string>
     <!-- Security Settings screen Encryption and crendential summary -->
@@ -5655,12 +5657,18 @@
     <string name="remove_and_uninstall_device_admin">Deactivate &amp; uninstall</string>
     <!-- Label for screen showing to select device admin apps -->
     <string name="select_device_admin_msg">Device admin apps</string>
+
     <!-- Message when there are no available device admin apps to display -->
     <string name="no_device_admins">No device admin apps available</string>
     <!-- Title for personal device admin apps on the list [CHAR_LIMIT=25] -->
     <string name="personal_device_admin_title">Personal</string>
     <!-- Title for managed device admin apps on the list [CHAR_LIMIT=25] -->
     <string name="managed_device_admin_title">Work</string>
+    <!-- Title for whether to enable SMS access restriction [CHAR LIMIT=50]-->
+    <string name="sms_access_restriction_enabled">Restrict SMS &amp; call log access</string>
+    <!-- Summary for whether to enable SMS access restriction [CHAR LIMIT=NONE]-->
+    <string name="sms_access_restriction_enabled_summary">Only default phone and messaging apps have SMS &amp; call log permissions</string>
+
 
     <!-- Message when there are no available trust agents to display -->
     <string name="no_trust_agents">No available trust agents</string>
@@ -7272,9 +7280,9 @@
     <!-- Do not disturb: what to block option [CHAR LIMIT=NONE] -->
     <string name="zen_mode_block_effect_peek">Don\'t pop notifications on screen</string>
     <!-- Do not disturb: what to block option [CHAR LIMIT=NONE] -->
-    <string name="zen_mode_block_effect_status">Hide status bar icons</string>
+    <string name="zen_mode_block_effect_status">Hide status bar icons at top of screen</string>
     <!-- Do not disturb: what to block option [CHAR LIMIT=NONE] -->
-    <string name="zen_mode_block_effect_badge">Hide notification dots</string>
+    <string name="zen_mode_block_effect_badge">Hide notification dots on app icons</string>
     <!-- Do not disturb: what to block option [CHAR LIMIT=NONE] -->
     <string name="zen_mode_block_effect_ambient">Don\'t wake for notifications</string>
     <!-- Do not disturb: what to block option [CHAR LIMIT=NONE] -->
@@ -8937,12 +8945,6 @@
     <!-- Summary of payment screen [CHAR LIMIT=NONE] -->
     <string name="payment_summary"><xliff:g id="app_name" example="Payment App">%1$s</xliff:g> is default</string>
 
-    <!-- Summary of location on screen [CHAR LIMIT=NONE] -->
-    <string name="location_on_summary">On</string>
-
-    <!-- Location off [CHAR LIMIT=NONE] -->
-    <string name="location_off_summary">Off</string>
-
     <!-- Backup disabled summary [CHAR LIMIT=NONE] -->
     <string name="backup_disabled">Back up disabled</string>
 
@@ -9962,15 +9964,6 @@
     <!-- UI debug setting: ANGLE enabled app has been set [CHAR LIMIT=NONE] -->
     <string name="angle_enabled_app_set">ANGLE enabled application: <xliff:g id="app_name" example="com.company.app">%1$s</xliff:g></string>
 
-    <!-- Title for Directory Access settings -->
-    <string name="directory_access">Directory access</string>
-    <!-- Keywords for Directory Access settings -->
-    <string name="keywords_directory_access">directory access</string>
-
-    <!-- String used to describe the name of a directory in a volume; it must
-         show both names, with the directory name wrapped in parenthesis -->
-    <string name="directory_on_volume"><xliff:g id="volume" example="SD Card">%1$s</xliff:g> (<xliff:g id="directory" example="Movies">%2$s</xliff:g>)</string>
-
     <!-- Slices Strings -->
 
     <!-- Summary text on a card explaining that a setting does not exist / is not supported on the device [CHAR_LIMIT=NONE]-->
@@ -10008,11 +10001,6 @@
     <!-- Title for preference showing the name of the device. [CHAR LIMIT=60]-->
     <string name="my_device_info_device_name_preference_title">Device name</string>
 
-    <!-- Settings item title for automatic Bluetooth on while driving preference [CHAR LIMIT=35] -->
-    <string name="bluetooth_on_while_driving_pref">Use Bluetooth when driving</string>
-    <!-- Settings item summary for automatic Bluetooth on while driving preference [CHAR LIMIT=100] -->
-    <string name="bluetooth_on_while_driving_summary">Turn on Bluetooth automatically when driving</string>
-
     <!-- Title for Wifi Access settings [CHAR LIMIT=35] -->
     <string name="change_wifi_state_title">Wi-Fi control</string>
 
@@ -10058,7 +10046,7 @@
     <!-- Title for prevent ringing gesture screen -->
     <string name="gesture_prevent_ringing_screen_title">Prevent ringing</string>
     <!-- Title for prevent ringing setting -->
-    <string name="gesture_prevent_ringing_title">Press Power &amp; Volume Up together</string>
+    <string name="gesture_prevent_ringing_title">Press Power &amp; Volume Up together to</string>
     <!-- Title for prevent ringing setting -->
     <string name="gesture_prevent_ringing_sound_title">Shortcut to prevent ringing</string>
     <!-- Option for prevent ringing setting -->
@@ -10185,9 +10173,6 @@
     <!-- Text for Network global [CHAR LIMIT=NONE] -->
     <string name="network_global">Global</string>
 
-    <!-- Configuration setting for world mode Format is <true;GID if any to be checked> [CHAR LIMIT=NONE] -->
-    <string translatable="false" name="config_world_mode"/>
-
     <!-- Available networks screen title/heading [CHAR LIMIT=NONE] -->
     <string name="label_available">Available networks</string>
     <!-- Mobile network settings screen, toast when searching for available networks [CHAR LIMIT=NONE] -->
@@ -10281,4 +10266,9 @@
     </plurals>
     <!-- Title for no connected devices in connected device slice. [CHAR LIMIT=NONE] -->
     <string name="no_connected_devices">No connected devices</string>
+
+    <!-- UI debug setting: force desktop mode [CHAR LIMIT=50] -->
+    <string name="force_desktop_mode">Force desktop mode</string>
+    <!-- UI debug setting: force desktop mode summary [CHAR LIMIT=150] -->
+    <string name="force_desktop_mode_summary">Force experimental desktop mode on secondary displays</string>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 83971b6..a954c5e 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -308,10 +308,21 @@
         <item name="android:textColor">?android:attr/colorAccent</item>
     </style>
 
+    <style name="TextAppearance.ConditionCardTitle"
+           parent="@android:style/TextAppearance.Material.Body2">
+        <item name="android:textSize">16sp</item>
+    </style>
+
+    <style name="TextAppearance.ConditionCardSummary"
+           parent="@android:style/TextAppearance.Material.Body1">
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+    </style>
+
     <style name="TextAppearance.EntityHeaderTitle"
            parent="@android:style/TextAppearance.Material.Subhead">
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
-        <item name="android:textSize">16sp</item>
+        <item name="android:textSize">20sp</item>
     </style>
 
     <style name="TextAppearance.EntityHeaderSummary"
@@ -321,6 +332,7 @@
         <item name="android:gravity">start</item>
         <item name="android:singleLine">true</item>
         <item name="android:ellipsize">marquee</item>
+        <item name="android:textSize">14sp</item>
     </style>
 
     <style name="TextAppearance.ZenOnboardingButton">
@@ -340,16 +352,8 @@
     <style name="SuggestionCardIcon">
         <item name="android:layout_centerHorizontal">false</item>
         <item name="android:layout_alignParentStart">true</item>
-        <item name="android:layout_marginStart">@dimen/suggestion_card_icon_side_margin</item>
-        <item name="android:layout_marginEnd">@dimen/suggestion_card_icon_side_margin</item>
-    </style>
-
-    <style name="SuggestionCardButton">
-        <item name="android:layout_gravity">start</item>
-        <item name="android:layout_marginStart">@dimen/suggestion_card_button_side_margin</item>
-        <item name="android:layout_marginEnd">@dimen/suggestion_card_button_side_margin</item>
-        <item name="android:layout_marginTop">@dimen/suggestion_card_button_top_margin</item>
-        <item name="android:layout_marginBottom">@dimen/suggestion_card_button_bottom_margin</item>
+        <item name="android:layout_marginStart">12dp</item>
+        <item name="android:layout_marginEnd">12dp</item>
     </style>
 
     <style name="FingerprintLayoutTheme">
@@ -395,12 +399,10 @@
     </style>
 
     <style name="EntityHeader">
-        <item name="android:background">?android:attr/colorPrimary</item>
-        <item name="android:gravity">center_horizontal</item>
-        <item name="android:paddingTop">16dp</item>
-        <item name="android:paddingStart">16dp</item>
+        <item name="android:background">?android:attr/colorPrimaryDark</item>
+        <item name="android:paddingTop">24dp</item>
+        <item name="android:paddingBottom">16dp</item>
         <item name="android:paddingEnd">16dp</item>
-        <item name="android:paddingBottom">8dp</item>
     </style>
 
     <style name="ActionPrimaryButton" parent="android:Widget.DeviceDefault.Button.Colored"/>
@@ -463,4 +465,24 @@
         <item name="cardElevation">@dimen/homepage_card_elevation</item>
     </style>
 
+    <style name="ConditionCardBorderlessButton"
+           parent="android:Widget.DeviceDefault.Button.Borderless">
+        <item name="android:textColor">?android:attr/colorAccent</item>
+        <item name="android:textSize">14sp</item>
+        <item name="android:textAllCaps">false</item>
+        <item name="android:fontFamily">sans-serif-medium</item>
+    </style>
+
+    <style name="ConditionHalfCardBorderlessButton"
+           parent="@style/ConditionCardBorderlessButton">
+        <item name="android:textAlignment">viewStart</item>
+        <item name="android:paddingStart">0dp</item>
+    </style>
+
+    <style name="ConditionFullCardBorderlessButton"
+           parent="@style/ConditionCardBorderlessButton">
+        <item name="android:textAlignment">viewEnd</item>
+        <item name="android:paddingEnd">0dp</item>
+    </style>
+
 </resources>
diff --git a/res/xml/connected_devices_advanced.xml b/res/xml/connected_devices_advanced.xml
index a959d02..b5d2a99 100644
--- a/res/xml/connected_devices_advanced.xml
+++ b/res/xml/connected_devices_advanced.xml
@@ -44,14 +44,6 @@
         android:icon="@drawable/ic_android"
         android:order="-6"/>
 
-    <SwitchPreference
-        android:key="bluetooth_on_while_driving"
-        android:title="@string/bluetooth_on_while_driving_pref"
-        android:icon="@drawable/ic_settings_bluetooth"
-        android:summary="@string/bluetooth_on_while_driving_summary"
-        settings:controller="com.android.settings.connecteddevice.BluetoothOnWhileDrivingPreferenceController"
-        android:order="-4"/>
-
     <com.android.settingslib.RestrictedPreference
         android:key="connected_device_printing"
         android:title="@string/print_settings"
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index 3d08cd8..49018f8 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -510,9 +510,19 @@
             android:title="@string/enable_freeform_support"
             android:summary="@string/enable_freeform_support_summary" />
 
+        <SwitchPreference
+            android:key="force_desktop_mode_on_external_displays"
+            android:title="@string/force_desktop_mode"
+            android:summary="@string/force_desktop_mode_summary" />
+
         <Preference
             android:key="reset_shortcut_manager_throttling"
             android:title="@string/reset_shortcut_manager_throttling" />
+
+        <SwitchPreference
+            android:key="sms_access_restriction_enabled"
+            android:title="@string/sms_access_restriction_enabled"
+            android:summary="@string/sms_access_restriction_enabled_summary" />
     </PreferenceCategory>
 
     <com.android.settings.development.autofill.AutofillPreferenceCategory
diff --git a/res/xml/installed_app_details.xml b/res/xml/installed_app_details.xml
deleted file mode 100644
index 42822c0..0000000
--- a/res/xml/installed_app_details.xml
+++ /dev/null
@@ -1,93 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  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.
-  -->
-
-<PreferenceScreen
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:key="installed_app_detail_settings_screen"
-    app:initialExpandedChildrenCount="6">
-
-    <com.android.settings.applications.LayoutPreference
-        android:key="header_view"
-        android:layout="@layout/settings_entity_header"
-        android:selectable="false"
-        android:order="-10000"/>
-
-    <com.android.settings.applications.LayoutPreference
-        android:key="instant_app_buttons"
-        android:layout="@layout/instant_app_buttons"
-        android:selectable="false"
-        android:order="-9999"/>
-
-    <com.android.settings.widget.ActionButtonPreference
-        android:key="action_buttons"
-        android:order="-9998" />
-
-    <Preference
-        android:key="notification_settings"
-        android:title="@string/notifications_label"
-        android:selectable="true"/>
-
-    <com.android.settings.widget.FixedLineSummaryPreference
-        android:key="permission_settings"
-        android:title="@string/permissions_label"
-        android:summary="@string/summary_placeholder"
-        android:selectable="true"
-        app:summaryLineCount="1" />
-
-    <Preference
-        android:key="storage_settings"
-        android:title="@string/storage_settings"
-        android:summary="@string/summary_placeholder"
-        android:selectable="true"/>
-
-    <com.android.settings.applications.AppDomainsPreference
-        android:key="instant_app_launch_supported_domain_urls"
-        android:title="@string/app_launch_supported_domain_urls_title"
-        android:selectable="true" />
-
-    <Preference
-        android:key="data_settings"
-        android:title="@string/data_usage_summary_title"
-        android:summary="@string/summary_placeholder"
-        android:selectable="true"/>
-
-    <Preference
-        android:key="battery"
-        android:title="@string/power_usage_summary_title"
-        android:summary="@string/summary_placeholder"
-        android:selectable="true"/>
-
-    <Preference
-        android:key="preferred_settings"
-        android:title="@string/launch_by_default"
-        android:summary="@string/summary_placeholder"
-        android:selectable="true"/>
-
-    <Preference
-        android:key="memory"
-        android:title="@string/memory_settings_title"
-        android:summary="@string/summary_placeholder"
-        android:enabled="false"
-        android:selectable="true"/>
-
-    <Preference
-        android:key="app_version"
-        android:selectable="false"
-        android:order="9999"/>
-
-</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/prevent_ringing_gesture_settings.xml b/res/xml/prevent_ringing_gesture_settings.xml
index 5135664..62f0223 100644
--- a/res/xml/prevent_ringing_gesture_settings.xml
+++ b/res/xml/prevent_ringing_gesture_settings.xml
@@ -26,13 +26,8 @@
         app:animation="@raw/gesture_prevent_ringing"
         app:preview="@drawable/gesture_prevent_ringing" />
 
-    <ListPreference
-        android:key="gesture_prevent_ringing"
-        android:title="@string/gesture_prevent_ringing_title"
-        android:entries="@array/gesture_prevent_ringing_entries"
-        android:entryValues="@array/gesture_prevent_ringing_values"
-        app:controller="com.android.settings.gestures.PreventRingingPreferenceController"
-        app:keywords="@string/keywords_gesture"
-        app:allowDividerAbove="true" />
-
+    <PreferenceCategory
+        android:key="gesture_prevent_ringing_category"
+        android:title="@string/gesture_prevent_ringing_title">
+    </PreferenceCategory>
 </PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/print_job_settings.xml b/res/xml/print_job_settings.xml
index 32a80a7..877cd62 100644
--- a/res/xml/print_job_settings.xml
+++ b/res/xml/print_job_settings.xml
@@ -19,13 +19,16 @@
         android:title="@string/print_print_job">
 
     <Preference
-            android:key="print_job_preference">
+            android:key="print_job_preference"
+            android:title="@string/print_print_job"
+            settings:controller="com.android.settings.print.PrintJobPreferenceController">
     </Preference>
 
     <Preference
             android:key="print_job_message_preference"
             android:layout="@layout/print_job_summary"
-            android:selectable="false">
+            android:selectable="false"
+            settings:controller="com.android.settings.print.PrintJobMessagePreferenceController">
     </Preference>
 
 </PreferenceScreen>
diff --git a/res/xml/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml
index e543ad9..ce271cc 100644
--- a/res/xml/security_dashboard_settings.xml
+++ b/res/xml/security_dashboard_settings.xml
@@ -95,12 +95,6 @@
         android:key="security_settings_misc_category"
         android:title="@string/security_passwords_title">
 
-        <Preference
-            android:key="location"
-            android:title="@string/location_settings_title"
-            android:summary="@string/summary_placeholder"
-            android:fragment="com.android.settings.location.LocationSettings" />
-
         <SwitchPreference
             android:key="show_password"
             android:title="@string/show_password"
diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml
index a6c2159..57e673f 100644
--- a/res/xml/special_access.xml
+++ b/res/xml/special_access.xml
@@ -121,16 +121,6 @@
     </Preference>
 
     <Preference
-        android:key="special_app_directory_access"
-        android:title="@string/directory_access"
-        android:fragment="com.android.settings.applications.manageapplications.ManageApplications"
-        settings:keywords="@string/keywords_directory_access">
-        <extra
-            android:name="classname"
-            android:value="com.android.settings.Settings$DirectoryAccessSettingsActivity" />
-    </Preference>
-
-    <Preference
         android:key="change_wifi_state"
         android:title="@string/change_wifi_state_title"
         android:fragment="com.android.settings.applications.manageapplications.ManageApplications"
diff --git a/res/xml/top_level_settings.xml b/res/xml/top_level_settings.xml
index e11d84a..69c4bb8 100644
--- a/res/xml/top_level_settings.xml
+++ b/res/xml/top_level_settings.xml
@@ -26,7 +26,7 @@
         android:title="@string/network_dashboard_title"
         android:summary="@string/summary_placeholder"
         android:icon="@drawable/ic_homepage_network"
-        android:order="-110"
+        android:order="-120"
         android:fragment="com.android.settings.network.NetworkDashboardFragment"
         settings:controller="com.android.settings.network.TopLevelNetworkEntryPreferenceController"/>
 
@@ -35,7 +35,7 @@
         android:title="@string/connected_devices_dashboard_title"
         android:summary="@string/summary_placeholder"
         android:icon="@drawable/ic_homepage_connected_device"
-        android:order="-100"
+        android:order="-110"
         android:fragment="com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment"
         settings:controller="com.android.settings.connecteddevice.TopLevelConnectedDevicesPreferenceController"/>
 
@@ -44,7 +44,7 @@
         android:title="@string/app_and_notification_dashboard_title"
         android:summary="@string/app_and_notification_dashboard_summary"
         android:icon="@drawable/ic_homepage_apps"
-        android:order="-90"
+        android:order="-100"
         android:fragment="com.android.settings.applications.AppAndNotificationDashboardFragment"/>
 
     <Preference
@@ -53,7 +53,7 @@
         android:summary="@string/summary_placeholder"
         android:icon="@drawable/ic_homepage_battery"
         android:fragment="com.android.settings.fuelgauge.PowerUsageSummary"
-        android:order="-80"
+        android:order="-90"
         settings:controller="com.android.settings.fuelgauge.TopLevelBatteryPreferenceController"/>
 
     <Preference
@@ -61,7 +61,7 @@
         android:title="@string/display_settings"
         android:summary="@string/summary_placeholder"
         android:icon="@drawable/ic_homepage_display"
-        android:order="-70"
+        android:order="-80"
         android:fragment="com.android.settings.DisplaySettings"
         settings:controller="com.android.settings.display.TopLevelDisplayPreferenceController"/>
 
@@ -70,7 +70,7 @@
         android:title="@string/sound_settings"
         android:summary="@string/sound_dashboard_summary"
         android:icon="@drawable/ic_homepage_sound"
-        android:order="-60"
+        android:order="-70"
         android:fragment="com.android.settings.notification.SoundSettings"/>
 
     <Preference
@@ -78,11 +78,19 @@
         android:title="@string/storage_settings"
         android:summary="@string/summary_placeholder"
         android:icon="@drawable/ic_homepage_storage"
-        android:order="-50"
+        android:order="-60"
         android:fragment="com.android.settings.deviceinfo.StorageSettings"
         settings:controller="com.android.settings.deviceinfo.TopLevelStoragePreferenceController"/>
 
     <Preference
+        android:key="top_level_location"
+        android:title="@string/location_settings_title"
+        android:summary="@string/location_settings_summary"
+        android:icon="@drawable/ic_homepage_location"
+        android:order="-50"
+        android:fragment="com.android.settings.location.LocationSettings"/>
+
+    <Preference
         android:key="top_level_security"
         android:title="@string/security_settings_title"
         android:summary="@string/summary_placeholder"
@@ -117,6 +125,15 @@
         android:fragment="com.android.settings.system.SystemDashboardFragment"/>
 
     <Preference
+        android:key="top_level_about_device"
+        android:title="@string/about_settings"
+        android:summary="@string/summary_placeholder"
+        android:icon="@drawable/ic_homepage_about"
+        android:order="20"
+        android:fragment="com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment"
+        settings:controller="com.android.settings.deviceinfo.aboutphone.TopLevelAboutDevicePreferenceController"/>
+
+    <Preference
         android:key="top_level_support"
         android:summary="@string/support_summary"
         android:title="@string/page_tab_title_support"
diff --git a/res/xml/wifi_settings.xml b/res/xml/wifi_settings.xml
index 4ca9284..516ac0a 100644
--- a/res/xml/wifi_settings.xml
+++ b/res/xml/wifi_settings.xml
@@ -20,6 +20,9 @@
         android:title="@string/wifi_settings"
         settings:keywords="@string/keywords_wifi">
 
+    <com.android.settings.wifi.LinkablePreference
+        android:key="wifi_status_message"/>
+
     <PreferenceCategory
         android:key="connected_access_point"
         android:layout="@layout/preference_category_no_label"/>
@@ -28,17 +31,14 @@
         android:key="access_points"
         android:layout="@layout/preference_category_no_label"/>
 
-    <PreferenceCategory
-        android:key="additional_settings"
-        android:layout="@layout/preference_category_no_label">
-        <Preference
-                android:key="configure_settings"
-                android:title="@string/wifi_configure_settings_preference_title"
-                android:fragment="com.android.settings.wifi.ConfigureWifiSettings" />
+    <Preference
+        android:key="configure_settings"
+        android:title="@string/wifi_configure_settings_preference_title"
+        settings:allowDividerAbove="true"
+        android:fragment="com.android.settings.wifi.ConfigureWifiSettings"/>
 
-        <Preference
-                android:key="saved_networks"
-                android:title="@string/wifi_saved_access_points_label"
-                android:fragment="com.android.settings.wifi.savedaccesspoints.SavedAccessPointsWifiSettings" />
-    </PreferenceCategory>
+    <Preference
+        android:key="saved_networks"
+        android:title="@string/wifi_saved_access_points_label"
+        android:fragment="com.android.settings.wifi.savedaccesspoints.SavedAccessPointsWifiSettings"/>
 </PreferenceScreen>
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 952c519..8cff5f1 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -120,7 +120,6 @@
     public static class PhotosStorageActivity extends SettingsActivity {
         /* empty */
     }
-    public static class DirectoryAccessSettingsActivity extends SettingsActivity { /* empty */ }
 
     public static class ApnSettingsActivity extends SettingsActivity { /* empty */ }
     public static class WifiCallingSettingsActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 14a9e83..79caefe 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -979,4 +979,14 @@
             return packageManager.getDefaultActivityIcon();
         }
     }
+
+    /** Returns true if the current package is installed & enabled. */
+    public static boolean isPackageEnabled(Context context, String packageName) {
+        try {
+            return context.getPackageManager().getApplicationInfo(packageName, 0).enabled;
+        } catch (Exception e) {
+            Log.e(TAG, "Error while retrieving application info for package " + packageName, e);
+        }
+        return false;
+    }
 }
diff --git a/src/com/android/settings/accounts/AccountDetailDashboardFragment.java b/src/com/android/settings/accounts/AccountDetailDashboardFragment.java
index 18e9906..78a8614 100644
--- a/src/com/android/settings/accounts/AccountDetailDashboardFragment.java
+++ b/src/com/android/settings/accounts/AccountDetailDashboardFragment.java
@@ -92,18 +92,18 @@
 
     @VisibleForTesting
     void finishIfAccountMissing() {
-        AccountManager accountManager = (AccountManager) getContext().getSystemService(
-                Context.ACCOUNT_SERVICE);
-        boolean accountExists = false;
-        for (Account account : accountManager.getAccountsByType(mAccount.type)) {
-            if (account.equals(mAccount)) {
-                accountExists = true;
-                break;
+        final Context context = getContext();
+        final UserManager um = context.getSystemService(UserManager.class);
+        final AccountManager accountManager = (AccountManager) context.getSystemService(
+                AccountManager.class);
+        for (UserHandle userHandle : um.getUserProfiles()) {
+            for (Account account : accountManager.getAccountsAsUser(userHandle.getIdentifier())) {
+                if (account.equals(mAccount)) {
+                    return;
+                }
             }
         }
-        if (!accountExists) {
-            finish();
-        }
+        finish();
     }
 
     @Override
@@ -177,4 +177,4 @@
             accountTypePreferenceLoader.updatePreferenceIntents(prefs, mAccountType, mAccount);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/accounts/AccountFeatureProvider.java b/src/com/android/settings/accounts/AccountFeatureProvider.java
index 9829ca6..fd65095 100644
--- a/src/com/android/settings/accounts/AccountFeatureProvider.java
+++ b/src/com/android/settings/accounts/AccountFeatureProvider.java
@@ -18,8 +18,10 @@
 
 import android.accounts.Account;
 import android.content.Context;
+import android.content.Intent;
 
 public interface AccountFeatureProvider {
     String getAccountType();
     Account[] getAccounts(Context context);
+    Intent getAccountSettingsDeeplinkIntent();
 }
diff --git a/src/com/android/settings/accounts/AccountFeatureProviderImpl.java b/src/com/android/settings/accounts/AccountFeatureProviderImpl.java
index 90b581b..2e0f432 100644
--- a/src/com/android/settings/accounts/AccountFeatureProviderImpl.java
+++ b/src/com/android/settings/accounts/AccountFeatureProviderImpl.java
@@ -2,6 +2,7 @@
 
 import android.accounts.Account;
 import android.content.Context;
+import android.content.Intent;
 
 public class AccountFeatureProviderImpl implements AccountFeatureProvider {
     @Override
@@ -13,4 +14,9 @@
     public Account[] getAccounts(Context context) {
         return new Account[0];
     }
+
+    @Override
+    public Intent getAccountSettingsDeeplinkIntent() {
+        return null;
+    }
 }
diff --git a/src/com/android/settings/accounts/AvatarViewMixin.java b/src/com/android/settings/accounts/AvatarViewMixin.java
new file mode 100644
index 0000000..78750b1
--- /dev/null
+++ b/src/com/android/settings/accounts/AvatarViewMixin.java
@@ -0,0 +1,136 @@
+/*
+ * 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.accounts;
+
+import android.accounts.Account;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.widget.ImageView;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.OnLifecycleEvent;
+
+import com.android.settings.R;
+import com.android.settings.homepage.SettingsHomepageActivity;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.utils.ThreadUtils;
+
+import java.util.List;
+
+/**
+ * Avatar related work to the onStart method of registered observable classes
+ * in {@link SettingsHomepageActivity}.
+ */
+public class AvatarViewMixin implements LifecycleObserver {
+    private static final String TAG = "AvatarViewMixin";
+
+    @VisibleForTesting
+    static final Intent INTENT_GET_ACCOUNT_DATA =
+            new Intent("android.content.action.SETTINGS_ACCOUNT_DATA");
+
+    private static final String METHOD_GET_ACCOUNT_AVATAR = "getAccountAvatar";
+    private static final String KEY_AVATAR_BITMAP = "account_avatar";
+    private static final int REQUEST_CODE = 1013;
+
+    private final Context mContext;
+    private final ImageView mAvatarView;
+    private final MutableLiveData<Bitmap> mAvatarImage;
+
+    public AvatarViewMixin(SettingsHomepageActivity activity, ImageView avatarView) {
+        mContext = activity.getApplicationContext();
+        mAvatarView = avatarView;
+        mAvatarView.setOnClickListener(v -> {
+            if (hasAccount()) {
+                //TODO(b/117509285) launch the new page of the MeCard
+            } else {
+                final Intent intent = FeatureFactory.getFactory(mContext)
+                        .getAccountFeatureProvider()
+                        .getAccountSettingsDeeplinkIntent();
+
+                if (intent != null) {
+                    activity.startActivityForResult(intent, REQUEST_CODE);
+                }
+            }
+        });
+
+        mAvatarImage = new MutableLiveData<>();
+        mAvatarImage.observe(activity, bitmap -> {
+            avatarView.setImageBitmap(bitmap);
+        });
+    }
+
+    @OnLifecycleEvent(Lifecycle.Event.ON_START)
+    public void onStart() {
+        if (!mContext.getResources().getBoolean(R.bool.config_show_avatar_in_homepage)) {
+            Log.d(TAG, "Feature disabled. Skipping");
+            return;
+        }
+        if (hasAccount()) {
+            loadAvatar();
+        } else {
+            mAvatarView.setImageResource(R.drawable.ic_account_circle_24dp);
+        }
+    }
+
+    @VisibleForTesting
+    boolean hasAccount() {
+        final Account accounts[] = FeatureFactory.getFactory(
+                mContext).getAccountFeatureProvider().getAccounts(mContext);
+        return (accounts != null) && (accounts.length > 0);
+    }
+
+    private void loadAvatar() {
+        final String authority = queryProviderAuthority();
+        if (TextUtils.isEmpty(authority)) {
+            return;
+        }
+
+        ThreadUtils.postOnBackgroundThread(() -> {
+            final Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
+                    .authority(authority)
+                    .build();
+            final Bundle bundle = mContext.getContentResolver().call(uri,
+                    METHOD_GET_ACCOUNT_AVATAR, null /* arg */, null /* extras */);
+            final Bitmap bitmap = bundle.getParcelable(KEY_AVATAR_BITMAP);
+            mAvatarImage.postValue(bitmap);
+        });
+    }
+
+    @VisibleForTesting
+    String queryProviderAuthority() {
+        final List<ResolveInfo> providers =
+                mContext.getPackageManager().queryIntentContentProviders(INTENT_GET_ACCOUNT_DATA,
+                        PackageManager.MATCH_SYSTEM_ONLY);
+        if (providers.size() == 1) {
+            return providers.get(0).providerInfo.authority;
+        } else {
+            Log.w(TAG, "The size of the provider is " + providers.size());
+            return null;
+        }
+    }
+}
diff --git a/src/com/android/settings/applications/AppStateDirectoryAccessBridge.java b/src/com/android/settings/applications/AppStateDirectoryAccessBridge.java
deleted file mode 100644
index 1c2a0af..0000000
--- a/src/com/android/settings/applications/AppStateDirectoryAccessBridge.java
+++ /dev/null
@@ -1,99 +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.applications;
-
-import static android.os.storage.StorageVolume.ScopedAccessProviderContract.AUTHORITY;
-import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PACKAGES;
-import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PACKAGES_COLUMNS;
-import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PACKAGES_COL_PACKAGE;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.util.ArraySet;
-import android.util.Log;
-
-import com.android.settingslib.applications.ApplicationsState;
-import com.android.settingslib.applications.ApplicationsState.AppEntry;
-import com.android.settingslib.applications.ApplicationsState.AppFilter;
-
-import java.util.Set;
-
-// TODO(b/72055774): add unit tests
-public class AppStateDirectoryAccessBridge extends AppStateBaseBridge {
-
-    private static final String TAG = "DirectoryAccessBridge";
-
-    // TODO(b/72055774): set to false once feature is ready (or use Log.isLoggable)
-    static final boolean DEBUG = true;
-    static final boolean VERBOSE = true;
-
-    public AppStateDirectoryAccessBridge(ApplicationsState appState, Callback callback) {
-        super(appState, callback);
-    }
-
-    @Override
-    protected void loadAllExtraInfo() { }
-
-    @Override
-    protected void updateExtraInfo(AppEntry app, String pkg, int uid) { }
-
-    public static final AppFilter FILTER_APP_HAS_DIRECTORY_ACCESS = new AppFilter() {
-
-        private Set<String> mPackages;
-
-        @Override
-        public void init() {
-            throw new UnsupportedOperationException("Need to call constructor that takes context");
-        }
-
-        @Override
-        public void init(Context context) {
-            mPackages = null;
-            final Uri providerUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
-                    .authority(AUTHORITY).appendPath(TABLE_PACKAGES).appendPath("*")
-                    .build();
-            try (Cursor cursor = context.getContentResolver().query(providerUri,
-                    TABLE_PACKAGES_COLUMNS, null, null)) {
-                if (cursor == null) {
-                    Log.w(TAG, "Didn't get cursor for " + providerUri);
-                    return;
-                }
-                final int count = cursor.getCount();
-                if (count == 0) {
-                    if (DEBUG) {
-                        Log.d(TAG, "No packages anymore (was " + mPackages + ")");
-                    }
-                    return;
-                }
-                mPackages = new ArraySet<>(count);
-                while (cursor.moveToNext()) {
-                    mPackages.add(cursor.getString(TABLE_PACKAGES_COL_PACKAGE));
-                }
-                if (DEBUG) {
-                    Log.d(TAG, "init(): " + mPackages);
-                }
-            }
-        }
-
-
-        @Override
-        public boolean filterApp(AppEntry info) {
-            return mPackages != null && mPackages.contains(info.info.packageName);
-        }
-    };
-}
diff --git a/src/com/android/settings/applications/AppStorageSettings.java b/src/com/android/settings/applications/AppStorageSettings.java
index e24a210..c926da3 100644
--- a/src/com/android/settings/applications/AppStorageSettings.java
+++ b/src/com/android/settings/applications/AppStorageSettings.java
@@ -18,13 +18,10 @@
 
 import static android.content.pm.ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
 import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
-import static android.os.storage.StorageVolume.ScopedAccessProviderContract.AUTHORITY;
-import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS;
 
 import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.app.GrantedUriPermission;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -32,7 +29,6 @@
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.PackageManager;
 import android.content.pm.ProviderInfo;
-import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -461,17 +457,6 @@
                 Context.ACTIVITY_SERVICE);
         am.clearGrantedUriPermissions(packageName);
 
-
-        // Also update the Scoped Directory Access UI permissions
-        final Uri providerUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
-                .authority(AUTHORITY).appendPath(TABLE_PERMISSIONS).appendPath("*")
-                .build();
-        Log.v(TAG, "Asking " + providerUri + " to delete permissions for " + packageName);
-        final int deleted = context.getContentResolver().delete(providerUri, null, new String[] {
-                packageName
-        });
-        Log.d(TAG, "Deleted " + deleted + " entries for package " + packageName);
-
         // Update UI
         refreshGrantedUriPermissions();
     }
diff --git a/src/com/android/settings/applications/DirectoryAccessDetails.java b/src/com/android/settings/applications/DirectoryAccessDetails.java
deleted file mode 100644
index f158d81..0000000
--- a/src/com/android/settings/applications/DirectoryAccessDetails.java
+++ /dev/null
@@ -1,323 +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.applications;
-
-import static android.os.storage.StorageVolume.ScopedAccessProviderContract.AUTHORITY;
-import static android.os.storage.StorageVolume.ScopedAccessProviderContract.COL_GRANTED;
-import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS;
-import static android.os.storage.StorageVolume.ScopedAccessProviderContract
-        .TABLE_PERMISSIONS_COLUMNS;
-import static android.os.storage.StorageVolume.ScopedAccessProviderContract
-        .TABLE_PERMISSIONS_COL_DIRECTORY;
-import static android.os.storage.StorageVolume.ScopedAccessProviderContract
-        .TABLE_PERMISSIONS_COL_GRANTED;
-import static android.os.storage.StorageVolume.ScopedAccessProviderContract
-        .TABLE_PERMISSIONS_COL_PACKAGE;
-import static android.os.storage.StorageVolume.ScopedAccessProviderContract
-        .TABLE_PERMISSIONS_COL_VOLUME_UUID;
-
-import static com.android.settings.applications.AppStateDirectoryAccessBridge.DEBUG;
-import static com.android.settings.applications.AppStateDirectoryAccessBridge.VERBOSE;
-
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.storage.StorageManager;
-import android.os.storage.VolumeInfo;
-import android.util.IconDrawableFactory;
-import android.util.Log;
-import android.util.Pair;
-
-import androidx.appcompat.app.AlertDialog;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceScreen;
-import androidx.preference.SwitchPreference;
-
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settings.R;
-import com.android.settings.widget.EntityHeaderController;
-import com.android.settings.widget.EntityHeaderController.ActionType;
-import com.android.settingslib.applications.AppUtils;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Detailed settings for an app's directory access permissions (A.K.A Scoped Directory Access).
- *
- * <p>Currently, it shows the entry for which the user denied access with the "Do not ask again"
- * flag checked on: the user than can use the settings toggle to reset that deniel.
- *
- * <p>This fragments dynamically lists all such permissions, starting with one preference per
- * directory in the primary storage, then adding additional entries for the external volumes (one
- * entry for the whole volume).
- */
-// TODO(b/72055774): add unit tests
-public class DirectoryAccessDetails extends AppInfoBase {
-
-    @SuppressWarnings("hiding")
-    private static final String TAG = "DirectoryAccessDetails";
-
-    private boolean mCreated;
-
-    @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
-
-        if (mCreated) {
-            Log.w(TAG, "onActivityCreated(): ignoring duplicate call");
-            return;
-        }
-        mCreated = true;
-        if (mPackageInfo == null) {
-            Log.w(TAG, "onActivityCreated(): no package info");
-            return;
-        }
-        final Activity activity = getActivity();
-        final Preference pref = EntityHeaderController
-                .newInstance(activity, this, /* header= */ null )
-                .setRecyclerView(getListView(), getSettingsLifecycle())
-                .setIcon(IconDrawableFactory.newInstance(getPrefContext())
-                        .getBadgedIcon(mPackageInfo.applicationInfo))
-                .setLabel(mPackageInfo.applicationInfo.loadLabel(mPm))
-                .setIsInstantApp(AppUtils.isInstant(mPackageInfo.applicationInfo))
-                .setPackageName(mPackageName)
-                .setUid(mPackageInfo.applicationInfo.uid)
-                .setHasAppInfoLink(false)
-                .setButtonActions(ActionType.ACTION_NONE, ActionType.ACTION_NONE)
-                .done(activity, getPrefContext());
-        getPreferenceScreen().addPreference(pref);
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        addPreferencesFromResource(R.xml.directory_access_details);
-
-    }
-
-    @Override
-    protected boolean refreshUi() {
-        final Context context = getPrefContext();
-        final PreferenceScreen prefsGroup = getPreferenceScreen();
-        prefsGroup.removeAll();
-
-        final Map<String, ExternalVolume> externalVolumes = new HashMap<>();
-
-        final Uri providerUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
-                .authority(AUTHORITY).appendPath(TABLE_PERMISSIONS).appendPath("*")
-                .build();
-        // Query provider for entries.
-        try (Cursor cursor = context.getContentResolver().query(providerUri,
-                TABLE_PERMISSIONS_COLUMNS, null, new String[] { mPackageName }, null)) {
-            if (cursor == null) {
-                Log.w(TAG, "Didn't get cursor for " + mPackageName);
-                return true;
-            }
-            final int count = cursor.getCount();
-            if (count == 0) {
-                // This setting screen should not be reached if there was no permission, so just
-                // ignore it
-                Log.w(TAG, "No permissions for " + mPackageName);
-                return true;
-            }
-
-            while (cursor.moveToNext()) {
-                final String pkg = cursor.getString(TABLE_PERMISSIONS_COL_PACKAGE);
-                final String uuid = cursor.getString(TABLE_PERMISSIONS_COL_VOLUME_UUID);
-                final String dir = cursor.getString(TABLE_PERMISSIONS_COL_DIRECTORY);
-                final boolean granted = cursor.getInt(TABLE_PERMISSIONS_COL_GRANTED) == 1;
-                if (VERBOSE) {
-                    Log.v(TAG, "Pkg:"  + pkg + " uuid: " + uuid + " dir: " + dir
-                            + " granted:" + granted);
-                }
-
-                if (!mPackageName.equals(pkg)) {
-                    // Sanity check, shouldn't happen
-                    Log.w(TAG, "Ignoring " + uuid + "/" + dir + " due to package mismatch: "
-                            + "expected " + mPackageName + ", got " + pkg);
-                    continue;
-                }
-
-                if (uuid == null) {
-                    if (dir == null) {
-                        // Sanity check, shouldn't happen
-                        Log.wtf(TAG, "Ignoring permission on primary storage root");
-                    } else {
-                        // Primary storage entry: add right away
-                        prefsGroup.addPreference(newPreference(context, dir, providerUri,
-                                /* uuid= */ null, dir, granted, /* children= */ null));
-                    }
-                } else {
-                    // External volume entry: save it for later.
-                    ExternalVolume externalVolume = externalVolumes.get(uuid);
-                    if (externalVolume == null) {
-                        externalVolume = new ExternalVolume(uuid);
-                        externalVolumes.put(uuid, externalVolume);
-                    }
-                    if (dir == null) {
-                        // Whole volume
-                        externalVolume.granted = granted;
-                    } else {
-                        // Directory only
-                        externalVolume.children.add(new Pair<>(dir, granted));
-                    }
-                }
-            }
-        }
-
-        if (VERBOSE) {
-            Log.v(TAG, "external volumes: " + externalVolumes);
-        }
-
-        if (externalVolumes.isEmpty()) {
-            // We're done!
-            return true;
-        }
-
-        // Add entries from external volumes
-
-        // Query StorageManager to get the user-friendly volume names.
-        final StorageManager sm = context.getSystemService(StorageManager.class);
-        final List<VolumeInfo> volumes = sm.getVolumes();
-        if (volumes.isEmpty()) {
-            Log.w(TAG, "StorageManager returned no secondary volumes");
-            return true;
-        }
-        final Map<String, String> volumeNames = new HashMap<>(volumes.size());
-        for (VolumeInfo volume : volumes) {
-            final String uuid = volume.getFsUuid();
-            if (uuid == null) continue; // Primary storage; not used.
-
-            String name = sm.getBestVolumeDescription(volume);
-            if (name == null) {
-                Log.w(TAG, "No description for " + volume + "; using uuid instead: " + uuid);
-                name = uuid;
-            }
-            volumeNames.put(uuid, name);
-        }
-        if (VERBOSE) {
-            Log.v(TAG, "UUID -> name mapping: " + volumeNames);
-        }
-
-        for (ExternalVolume volume : externalVolumes.values()) {
-            final String volumeName = volumeNames.get(volume.uuid);
-            if (volumeName == null) {
-                Log.w(TAG, "Ignoring entry for invalid UUID: " + volume.uuid);
-                continue;
-            }
-            // First add the pref for the whole volume...
-            final PreferenceCategory category = new PreferenceCategory(context);
-            prefsGroup.addPreference(category);
-            final Set<SwitchPreference> children = new HashSet<>(volume.children.size());
-            category.addPreference(newPreference(context, volumeName, providerUri, volume.uuid,
-                    /* dir= */ null, volume.granted, children));
-
-            // ... then the children prefs
-            volume.children.forEach((pair) -> {
-                final String dir = pair.first;
-                final String name = context.getResources()
-                        .getString(R.string.directory_on_volume, volumeName, dir);
-                final SwitchPreference childPref =
-                        newPreference(context, name, providerUri, volume.uuid, dir, pair.second,
-                                /* children= */ null);
-                category.addPreference(childPref);
-                children.add(childPref);
-            });
-        }
-        return true;
-    }
-
-    private SwitchPreference newPreference(Context context, String title, Uri providerUri,
-            String uuid, String dir, boolean granted, @Nullable Set<SwitchPreference> children) {
-        final SwitchPreference pref = new SwitchPreference(context);
-        pref.setKey(String.format("%s:%s", uuid, dir));
-        pref.setTitle(title);
-        pref.setChecked(granted);
-        pref.setOnPreferenceChangeListener((unused, value) -> {
-            if (!Boolean.class.isInstance(value)) {
-                // Sanity check
-                Log.wtf(TAG, "Invalid value from switch: " + value);
-                return true;
-            }
-            final boolean newValue = ((Boolean) value).booleanValue();
-
-            resetDoNotAskAgain(context, newValue, providerUri, uuid, dir);
-            if (children != null) {
-                // When parent is granted, children should be hidden; and vice versa
-                final boolean newChildValue = !newValue;
-                for (SwitchPreference child : children) {
-                    child.setVisible(newChildValue);
-                }
-            }
-            return true;
-        });
-        return pref;
-    }
-
-    private void resetDoNotAskAgain(Context context, boolean newValue, Uri providerUri,
-            @Nullable String uuid, @Nullable String directory) {
-        if (DEBUG) {
-            Log.d(TAG, "Asking " + providerUri  + " to update " + uuid + "/" + directory + " to "
-                    + newValue);
-        }
-        final ContentValues values = new ContentValues(1);
-        values.put(COL_GRANTED, newValue);
-        final int updated = context.getContentResolver().update(providerUri, values,
-                null, new String[] { mPackageName, uuid, directory });
-        if (DEBUG) {
-            Log.d(TAG, "Updated " + updated + " entries for " + uuid + "/" + directory);
-        }
-    }
-
-    @Override
-    protected AlertDialog createDialog(int id, int errorCode) {
-        return null;
-    }
-
-    @Override
-    public int getMetricsCategory() {
-        return MetricsEvent.APPLICATIONS_DIRECTORY_ACCESS_DETAIL;
-    }
-
-    private static class ExternalVolume {
-        final String uuid;
-        final List<Pair<String, Boolean>> children = new ArrayList<>();
-        boolean granted;
-
-        ExternalVolume(String uuid) {
-            this.uuid = uuid;
-        }
-
-        @Override
-        public String toString() {
-            return "ExternalVolume: [uuid=" + uuid + ", granted=" + granted +
-                    ", children=" + children + "]";
-        }
-    }
-}
diff --git a/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceController.java b/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceController.java
index c861175..5f41ae0 100644
--- a/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceController.java
@@ -90,12 +90,9 @@
     private void setAppLabelAndIcon(PackageInfo pkgInfo, AppEntry appEntry) {
         final Activity activity = mParent.getActivity();
         final boolean isInstantApp = AppUtils.isInstant(pkgInfo.applicationInfo);
-        final CharSequence summary = isInstantApp
-                ? null : mContext.getString(Utils.getInstallationStatus(appEntry.info));
         mEntityHeaderController
                 .setLabel(appEntry)
                 .setIcon(appEntry)
-                .setSummary(summary)
                 .setIsInstantApp(isInstantApp)
                 .done(activity, false /* rebindActions */);
     }
diff --git a/src/com/android/settings/applications/appinfo/TimeSpentInAppPreferenceController.java b/src/com/android/settings/applications/appinfo/TimeSpentInAppPreferenceController.java
index a4cfebf..70ffcb3 100644
--- a/src/com/android/settings/applications/appinfo/TimeSpentInAppPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/TimeSpentInAppPreferenceController.java
@@ -21,6 +21,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.provider.Settings;
 import android.text.TextUtils;
 
 import androidx.annotation.VisibleForTesting;
@@ -34,8 +35,7 @@
 public class TimeSpentInAppPreferenceController extends BasePreferenceController {
 
     @VisibleForTesting
-    static final Intent SEE_TIME_IN_APP_TEMPLATE =
-            new Intent("com.android.settings.action.TIME_SPENT_IN_APP");
+    static final Intent SEE_TIME_IN_APP_TEMPLATE = new Intent(Settings.ACTION_APP_USAGE_SETTINGS);
 
     private final PackageManager mPackageManager;
 
diff --git a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
index 7d1e159..0d2bcab 100644
--- a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
+++ b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
@@ -19,7 +19,6 @@
 import androidx.annotation.IntDef;
 
 import com.android.settings.R;
-import com.android.settings.applications.AppStateDirectoryAccessBridge;
 import com.android.settings.applications.AppStateInstallAppsBridge;
 import com.android.settings.applications.AppStateNotificationBridge;
 import com.android.settings.applications.AppStateOverlayBridge;
@@ -70,7 +69,6 @@
     public static final int FILTER_APPS_WITH_OVERLAY = 11;
     public static final int FILTER_APPS_WRITE_SETTINGS = 12;
     public static final int FILTER_APPS_INSTALL_SOURCES = 13;
-    public static final int FILTER_APP_HAS_DIRECTORY_ACCESS = 14;
     public static final int FILTER_APP_CAN_CHANGE_WIFI_STATE = 15;
     public static final int FILTER_APPS_BLOCKED = 16;
     // Next id: 17
@@ -170,12 +168,6 @@
                 FILTER_APPS_INSTALL_SOURCES,
                 R.string.filter_install_sources_apps);
 
-        // Apps that interacted with directory access permissions (A.K.A. Scoped Directory Access)
-        mFilters[FILTER_APP_HAS_DIRECTORY_ACCESS] = new AppFilterItem(
-                AppStateDirectoryAccessBridge.FILTER_APP_HAS_DIRECTORY_ACCESS,
-                FILTER_APP_HAS_DIRECTORY_ACCESS,
-                R.string.filter_install_sources_apps);
-
         mFilters[FILTER_APP_CAN_CHANGE_WIFI_STATE] = new AppFilterItem(
                 AppStateChangeWifiStateBridge.FILTER_CHANGE_WIFI_STATE,
                 FILTER_APP_CAN_CHANGE_WIFI_STATE,
@@ -208,8 +200,6 @@
                 return FILTER_APPS_WRITE_SETTINGS;
             case ManageApplications.LIST_TYPE_MANAGE_SOURCES:
                 return FILTER_APPS_INSTALL_SOURCES;
-            case ManageApplications.LIST_TYPE_DIRECTORY_ACCESS:
-                return FILTER_APP_HAS_DIRECTORY_ACCESS;
             case ManageApplications.LIST_TYPE_WIFI_ACCESS:
                 return FILTER_APP_CAN_CHANGE_WIFI_STATE;
             case ManageApplications.LIST_TYPE_NOTIFICATION:
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index 44ea575..6b2fb91 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -90,7 +90,6 @@
 import com.android.settings.applications.AppInfoBase;
 import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
 import com.android.settings.applications.AppStateBaseBridge;
-import com.android.settings.applications.AppStateDirectoryAccessBridge;
 import com.android.settings.applications.AppStateInstallAppsBridge;
 import com.android.settings.applications.AppStateNotificationBridge;
 import com.android.settings.applications.AppStateNotificationBridge.NotificationsSentState;
@@ -101,7 +100,6 @@
 import com.android.settings.applications.AppStateWriteSettingsBridge;
 import com.android.settings.applications.AppStorageSettings;
 import com.android.settings.applications.DefaultAppSettings;
-import com.android.settings.applications.DirectoryAccessDetails;
 import com.android.settings.applications.InstalledAppCounter;
 import com.android.settings.applications.UsageAccessDetails;
 import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
@@ -218,7 +216,6 @@
     public static final int LIST_TYPE_GAMES = 9;
     public static final int LIST_TYPE_MOVIES = 10;
     public static final int LIST_TYPE_PHOTOGRAPHY = 11;
-    public static final int LIST_TYPE_DIRECTORY_ACCESS = 12;
     public static final int LIST_TYPE_WIFI_ACCESS = 13;
 
     // List types that should show instant apps.
@@ -293,9 +290,6 @@
             mListType = LIST_TYPE_PHOTOGRAPHY;
             mSortOrder = R.id.sort_order_size;
             mStorageType = args.getInt(EXTRA_STORAGE_TYPE, STORAGE_TYPE_DEFAULT);
-        } else if (className.equals(Settings.DirectoryAccessSettingsActivity.class.getName())) {
-            mListType = LIST_TYPE_DIRECTORY_ACCESS;
-            screenTitle = R.string.directory_access;
         } else if (className.equals(Settings.ChangeWifiStateActivity.class.getName())) {
             mListType = LIST_TYPE_WIFI_ACCESS;
             screenTitle = R.string.change_wifi_state_title;
@@ -479,8 +473,6 @@
                 return MetricsEvent.SYSTEM_ALERT_WINDOW_APPS;
             case LIST_TYPE_MANAGE_SOURCES:
                 return MetricsEvent.MANAGE_EXTERNAL_SOURCES;
-            case LIST_TYPE_DIRECTORY_ACCESS:
-                return MetricsEvent.DIRECTORY_ACCESS;
             case LIST_TYPE_WIFI_ACCESS:
                 return MetricsEvent.CONFIGURE_WIFI;
             default:
@@ -578,9 +570,6 @@
             case LIST_TYPE_PHOTOGRAPHY:
                 startAppInfoFragment(AppStorageSettings.class, R.string.storage_photos_videos);
                 break;
-            case LIST_TYPE_DIRECTORY_ACCESS:
-                startAppInfoFragment(DirectoryAccessDetails.class, R.string.directory_access);
-                break;
             case LIST_TYPE_WIFI_ACCESS:
                 startAppInfoFragment(ChangeWifiStateDetails.class,
                         R.string.change_wifi_state_title);
@@ -916,8 +905,6 @@
                 mExtraInfoBridge = new AppStateWriteSettingsBridge(mContext, mState, this);
             } else if (mManageApplications.mListType == LIST_TYPE_MANAGE_SOURCES) {
                 mExtraInfoBridge = new AppStateInstallAppsBridge(mContext, mState, this);
-            } else if (mManageApplications.mListType == LIST_TYPE_DIRECTORY_ACCESS) {
-                mExtraInfoBridge = new AppStateDirectoryAccessBridge(mState, this);
             } else if (mManageApplications.mListType == LIST_TYPE_WIFI_ACCESS) {
                 mExtraInfoBridge = new AppStateChangeWifiStateBridge(mContext, mState, this);
             } else {
@@ -1360,9 +1347,6 @@
                 case LIST_TYPE_MANAGE_SOURCES:
                     holder.setSummary(ExternalSourcesDetails.getPreferenceSummary(mContext, entry));
                     break;
-                case LIST_TYPE_DIRECTORY_ACCESS:
-                    holder.setSummary(null);
-                    break;
                 case LIST_TYPE_WIFI_ACCESS:
                     holder.setSummary(ChangeWifiStateDetails.getSummary(mContext, entry));
                     break;
diff --git a/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java
index 5c678a9..54842f7 100644
--- a/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java
@@ -74,7 +74,6 @@
         final List<AbstractPreferenceController> controllers = new ArrayList<>();
 
         controllers.add(new BluetoothFilesPreferenceController(context));
-        controllers.add(new BluetoothOnWhileDrivingPreferenceController(context));
 
         final PrintSettingPreferenceController printerController =
                 new PrintSettingPreferenceController(context);
diff --git a/src/com/android/settings/connecteddevice/BluetoothOnWhileDrivingPreferenceController.java b/src/com/android/settings/connecteddevice/BluetoothOnWhileDrivingPreferenceController.java
deleted file mode 100644
index 6d4e8b8..0000000
--- a/src/com/android/settings/connecteddevice/BluetoothOnWhileDrivingPreferenceController.java
+++ /dev/null
@@ -1,59 +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.connecteddevice;
-
-import android.content.Context;
-import android.provider.Settings;
-import android.util.FeatureFlagUtils;
-
-import com.android.settings.core.FeatureFlags;
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settings.core.TogglePreferenceController;
-
-/** Handles a toggle for a setting to turn on Bluetooth while driving. * */
-public class BluetoothOnWhileDrivingPreferenceController extends TogglePreferenceController
-        implements PreferenceControllerMixin {
-    static final String KEY_BLUETOOTH_ON_DRIVING = "bluetooth_on_while_driving";
-
-    public BluetoothOnWhileDrivingPreferenceController(Context context) {
-        super(context, KEY_BLUETOOTH_ON_DRIVING);
-    }
-
-    @Override
-    public int getAvailabilityStatus() {
-        if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.BLUETOOTH_WHILE_DRIVING)) {
-            return AVAILABLE;
-        }
-        return CONDITIONALLY_UNAVAILABLE;
-    }
-
-    @Override
-    public boolean isChecked() {
-        return Settings.Secure.getInt(
-                        mContext.getContentResolver(),
-                        Settings.Secure.BLUETOOTH_ON_WHILE_DRIVING,
-                        0)
-                != 0;
-    }
-
-    @Override
-    public boolean setChecked(boolean isChecked) {
-        final int value = isChecked ? 1 : 0;
-        return Settings.Secure.putInt(
-                mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON_WHILE_DRIVING, value);
-    }
-}
diff --git a/src/com/android/settings/core/FeatureFlags.java b/src/com/android/settings/core/FeatureFlags.java
index 811f7ad..0a26b79 100644
--- a/src/com/android/settings/core/FeatureFlags.java
+++ b/src/com/android/settings/core/FeatureFlags.java
@@ -20,7 +20,6 @@
  * This class keeps track of all feature flags in Settings.
  */
 public class FeatureFlags {
-    public static final String BLUETOOTH_WHILE_DRIVING = "settings_bluetooth_while_driving";
     public static final String AUDIO_SWITCHER_SETTINGS = "settings_audio_switcher";
     public static final String DYNAMIC_HOMEPAGE = "settings_dynamic_homepage";
     public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 4346973..f61cb0c 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -34,7 +34,6 @@
 import com.android.settings.accounts.ManagedProfileSettings;
 import com.android.settings.applications.AppAndNotificationDashboardFragment;
 import com.android.settings.applications.DefaultAppSettings;
-import com.android.settings.applications.DirectoryAccessDetails;
 import com.android.settings.applications.ProcessStatsSummary;
 import com.android.settings.applications.ProcessStatsUi;
 import com.android.settings.applications.UsageAccessDetails;
@@ -258,7 +257,6 @@
             LockscreenDashboardFragment.class.getName(),
             BluetoothDeviceDetailsFragment.class.getName(),
             DataUsageList.class.getName(),
-            DirectoryAccessDetails.class.getName(),
             ToggleBackupSettingFragment.class.getName(),
             PreviouslyConnectedDeviceDashboardFragment.class.getName(),
     };
diff --git a/src/com/android/settings/development/DesktopModePreferenceController.java b/src/com/android/settings/development/DesktopModePreferenceController.java
new file mode 100644
index 0000000..528af8a
--- /dev/null
+++ b/src/com/android/settings/development/DesktopModePreferenceController.java
@@ -0,0 +1,79 @@
+/*
+ * 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.development;
+
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
+
+import android.content.Context;
+import android.os.Build;
+import android.provider.Settings;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+public class DesktopModePreferenceController extends DeveloperOptionsPreferenceController
+        implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+
+    private static final String FORCE_DESKTOP_MODE_KEY = "force_desktop_mode_on_external_displays";
+
+    @VisibleForTesting
+    static final int SETTING_VALUE_OFF = 0;
+    @VisibleForTesting
+    static final int SETTING_VALUE_ON = 1;
+
+    public DesktopModePreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return FORCE_DESKTOP_MODE_KEY;
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        final boolean isEnabled = (Boolean) newValue;
+        Settings.Global.putInt(mContext.getContentResolver(),
+                DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS,
+                isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
+        return true;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        final int mode = Settings.Global.getInt(mContext.getContentResolver(),
+                DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, SETTING_VALUE_OFF);
+        ((SwitchPreference) mPreference).setChecked(mode != SETTING_VALUE_OFF);
+    }
+
+    @Override
+    protected void onDeveloperOptionsSwitchDisabled() {
+        super.onDeveloperOptionsSwitchDisabled();
+        Settings.Global.putInt(mContext.getContentResolver(),
+                DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, SETTING_VALUE_OFF);
+        ((SwitchPreference) mPreference).setChecked(false);
+    }
+
+    @VisibleForTesting
+    String getBuildType() {
+        return Build.TYPE;
+    }
+}
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index dbcb389..5663d1e 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -458,6 +458,8 @@
         controllers.add(new AllowAppsOnExternalPreferenceController(context));
         controllers.add(new ResizableActivityPreferenceController(context));
         controllers.add(new FreeformWindowsPreferenceController(context));
+        controllers.add(new DesktopModePreferenceController(context));
+        controllers.add(new SmsAccessRestrictionPreferenceController(context));
         controllers.add(new ShortcutManagerThrottlingPreferenceController(context));
         controllers.add(new EnableGnssRawMeasFullTrackingPreferenceController(context));
         controllers.add(new CbrsDataSwitchPreferenceController(context));
diff --git a/src/com/android/settings/development/FreeformWindowsPreferenceController.java b/src/com/android/settings/development/FreeformWindowsPreferenceController.java
index 5b19f36..4d38480 100644
--- a/src/com/android/settings/development/FreeformWindowsPreferenceController.java
+++ b/src/com/android/settings/development/FreeformWindowsPreferenceController.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.os.Build;
 import android.provider.Settings;
-import android.text.TextUtils;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.Preference;
@@ -37,19 +36,12 @@
     static final int SETTING_VALUE_OFF = 0;
     @VisibleForTesting
     static final int SETTING_VALUE_ON = 1;
-    @VisibleForTesting
-    static final String USER_BUILD_TYPE = "user";
 
     public FreeformWindowsPreferenceController(Context context) {
         super(context);
     }
 
     @Override
-    public boolean isAvailable() {
-        return !TextUtils.equals(USER_BUILD_TYPE, getBuildType());
-    }
-
-    @Override
     public String getPreferenceKey() {
         return ENABLE_FREEFORM_SUPPORT_KEY;
     }
diff --git a/src/com/android/settings/development/SmsAccessRestrictionPreferenceController.java b/src/com/android/settings/development/SmsAccessRestrictionPreferenceController.java
new file mode 100644
index 0000000..b3f7b23
--- /dev/null
+++ b/src/com/android/settings/development/SmsAccessRestrictionPreferenceController.java
@@ -0,0 +1,69 @@
+/*
+ * 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.development;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+// STOPSHIP b/118694572: remove the kill switch once the feature is tested and stable
+public class SmsAccessRestrictionPreferenceController extends DeveloperOptionsPreferenceController
+        implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+
+    private static final String SMS_ACCESS_RESTRICTION_ENABLED_KEY
+            = "sms_access_restriction_enabled";
+
+    public SmsAccessRestrictionPreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return SMS_ACCESS_RESTRICTION_ENABLED_KEY;
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        writeSetting((boolean) newValue);
+        return true;
+    }
+
+    private void writeSetting(boolean isEnabled) {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED,
+                isEnabled ? 1 : 0);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        final int mode = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, 0);
+        ((SwitchPreference) mPreference).setChecked(mode != 0);
+    }
+
+    @Override
+    protected void onDeveloperOptionsSwitchDisabled() {
+        super.onDeveloperOptionsSwitchDisabled();
+        writeSetting(false);
+        ((SwitchPreference) mPreference).setChecked(false);
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/DeviceModelPreferenceController.java b/src/com/android/settings/deviceinfo/DeviceModelPreferenceController.java
index 25090dc..a9d0e3f 100644
--- a/src/com/android/settings/deviceinfo/DeviceModelPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/DeviceModelPreferenceController.java
@@ -79,12 +79,7 @@
     }
 
     public static String getDeviceModel() {
-        FutureTask<String> msvSuffixTask = new FutureTask<String>(new Callable<String>() {
-            @Override
-            public String call() {
-                return DeviceInfoUtils.getMsvSuffix();
-            }
-        });
+        FutureTask<String> msvSuffixTask = new FutureTask<>(() -> DeviceInfoUtils.getMsvSuffix());
 
         msvSuffixTask.run();
         try {
diff --git a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
index 37f80b7..8c6c5ae 100644
--- a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
+++ b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
@@ -181,25 +181,6 @@
         controller.updateDeviceName(confirm);
     }
 
-    private static class SummaryProvider implements SummaryLoader.SummaryProvider {
-
-        private final SummaryLoader mSummaryLoader;
-
-        public SummaryProvider(SummaryLoader summaryLoader) {
-            mSummaryLoader = summaryLoader;
-        }
-
-        @Override
-        public void setListening(boolean listening) {
-            if (listening) {
-                mSummaryLoader.setSummary(this, DeviceModelPreferenceController.getDeviceModel());
-            }
-        }
-    }
-
-    public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY
-            = (activity, summaryLoader) -> new SummaryProvider(summaryLoader);
-
     /**
      * For Search.
      */
diff --git a/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceController.java b/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceController.java
new file mode 100644
index 0000000..ba28f3a
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceController.java
@@ -0,0 +1,39 @@
+/*
+ * 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.aboutphone;
+
+import android.content.Context;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.deviceinfo.DeviceModelPreferenceController;
+
+public class TopLevelAboutDevicePreferenceController extends BasePreferenceController {
+
+    public TopLevelAboutDevicePreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        return DeviceModelPreferenceController.getDeviceModel();
+    }
+}
diff --git a/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelper.java b/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelper.java
index 5ca8fea..5bdf587 100644
--- a/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelper.java
+++ b/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelper.java
@@ -23,6 +23,8 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.os.Process;
 import android.os.UserHandle;
@@ -109,16 +111,24 @@
         if (admin == null) {
             return;
         }
+        ImageView supportIconView = root.requireViewById(R.id.admin_support_icon);
         if (!RestrictedLockUtilsInternal.isAdminInCurrentUserOrProfile(mActivity, admin)
                 || !RestrictedLockUtils.isCurrentUserOrProfile(mActivity, userId)) {
             admin = null;
+
+            supportIconView.setImageDrawable(
+                    mActivity.getDrawable(com.android.internal.R.drawable.ic_info));
+
+            TypedArray ta = mActivity.obtainStyledAttributes(new int[]{android.R.attr.colorAccent});
+            supportIconView.setImageTintList(ColorStateList.valueOf(ta.getColor(0, 0)));
+            ta.recycle();
         } else {
             final Drawable badgedIcon = Utils.getBadgedIcon(
                     IconDrawableFactory.newInstance(mActivity),
                     mActivity.getPackageManager(),
                     admin.getPackageName(),
                     userId);
-            ((ImageView) root.findViewById(R.id.admin_support_icon)).setImageDrawable(badgedIcon);
+            supportIconView.setImageDrawable(badgedIcon);
         }
 
         setAdminSupportTitle(root, restriction);
diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
index e34e622..ce9cabc 100644
--- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
@@ -235,10 +235,7 @@
             controller.setLabel(mAppEntry);
             controller.setIcon(mAppEntry);
             boolean isInstantApp = AppUtils.isInstant(mAppEntry.info);
-            CharSequence summary = isInstantApp
-                    ? null : getString(Utils.getInstallationStatus(mAppEntry.info));
             controller.setIsInstantApp(AppUtils.isInstant(mAppEntry.info));
-            controller.setSummary(summary);
         }
 
         controller.done(context, true /* rebindActions */);
diff --git a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
index 2d95c31..65181c4 100644
--- a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
@@ -63,7 +63,7 @@
         implements PreferenceControllerMixin, LifecycleObserver, OnPause, OnDestroy {
     @VisibleForTesting
     static final boolean USE_FAKE_DATA = false;
-    private static final int MAX_ITEMS_TO_LIST = USE_FAKE_DATA ? 30 : 10;
+    private static final int MAX_ITEMS_TO_LIST = USE_FAKE_DATA ? 30 : 20;
     private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
     private static final int STATS_TYPE = BatteryStats.STATS_SINCE_CHARGED;
 
diff --git a/src/com/android/settings/gestures/GesturesSettingPreferenceController.java b/src/com/android/settings/gestures/GesturesSettingPreferenceController.java
index 069085b..2e9b5a5 100644
--- a/src/com/android/settings/gestures/GesturesSettingPreferenceController.java
+++ b/src/com/android/settings/gestures/GesturesSettingPreferenceController.java
@@ -20,8 +20,6 @@
 import android.content.Context;
 import android.provider.Settings;
 
-import androidx.annotation.NonNull;
-
 import com.android.internal.hardware.AmbientDisplayConfiguration;
 import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
@@ -31,6 +29,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import androidx.annotation.NonNull;
+
 public class GesturesSettingPreferenceController extends BasePreferenceController {
     private final AssistGestureFeatureProvider mFeatureProvider;
     private List<AbstractPreferenceController> mGestureControllers;
@@ -76,7 +76,7 @@
                 .setConfig(ambientDisplayConfiguration));
         controllers.add(new DoubleTapScreenPreferenceController(context, FAKE_PREF_KEY)
                 .setConfig(ambientDisplayConfiguration));
-        controllers.add(new PreventRingingPreferenceController(context, FAKE_PREF_KEY));
+        controllers.add(new PreventRingingParentPreferenceController(context, FAKE_PREF_KEY));
         return controllers;
     }
 
diff --git a/src/com/android/settings/gestures/PreventRingingGesturePreferenceController.java b/src/com/android/settings/gestures/PreventRingingGesturePreferenceController.java
new file mode 100644
index 0000000..cb9bf4f
--- /dev/null
+++ b/src/com/android/settings/gestures/PreventRingingGesturePreferenceController.java
@@ -0,0 +1,222 @@
+/*
+ * 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.gestures;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.provider.Settings;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.widget.RadioButtonPreference;
+import com.android.settings.widget.VideoPreference;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnCreate;
+import com.android.settingslib.core.lifecycle.events.OnPause;
+import com.android.settingslib.core.lifecycle.events.OnResume;
+import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceScreen;
+
+public class PreventRingingGesturePreferenceController extends AbstractPreferenceController
+        implements RadioButtonPreference.OnClickListener, LifecycleObserver, OnSaveInstanceState,
+        OnResume, OnPause, OnCreate, PreferenceControllerMixin {
+
+    @VisibleForTesting static final String KEY_VIBRATE = "prevent_ringing_option_vibrate";
+    @VisibleForTesting static final String KEY_NONE = "prevent_ringing_option_none";
+    @VisibleForTesting static final String KEY_MUTE = "prevent_ringing_option_mute";
+
+    private final String KEY_VIDEO_PAUSED = "key_video_paused";
+    private final String PREF_KEY_VIDEO = "gesture_prevent_ringing_video";
+    private final String KEY = "gesture_prevent_ringing_category";
+    private final Context mContext;
+
+    private VideoPreference mVideoPreference;
+    private boolean mVideoPaused;
+
+    private PreferenceCategory mPreferenceCategory;
+    @VisibleForTesting RadioButtonPreference mVibratePref;
+    @VisibleForTesting RadioButtonPreference mNonePref;
+    @VisibleForTesting RadioButtonPreference mMutePref;
+
+    private SettingObserver mSettingObserver;
+
+    public PreventRingingGesturePreferenceController(Context context, Lifecycle lifecycle) {
+        super(context);
+        mContext = context;
+
+        if (lifecycle != null) {
+            lifecycle.addObserver(this);
+        }
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        if (isAvailable()) {
+            mPreferenceCategory = (PreferenceCategory) screen.findPreference(getPreferenceKey());
+            mVibratePref = makeRadioPreference(KEY_VIBRATE, R.string.prevent_ringing_option_vibrate);
+            mMutePref = makeRadioPreference(KEY_MUTE, R.string.prevent_ringing_option_mute);
+            mNonePref = makeRadioPreference(KEY_NONE, R.string.prevent_ringing_option_none);
+
+            if (mPreferenceCategory != null) {
+                mSettingObserver = new SettingObserver(mPreferenceCategory);
+            }
+
+            mVideoPreference = (VideoPreference) screen.findPreference(getVideoPrefKey());
+        }
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_volumeHushGestureEnabled);
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY;
+    }
+
+    public String getVideoPrefKey() {
+        return PREF_KEY_VIDEO;
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        outState.putBoolean(KEY_VIDEO_PAUSED, mVideoPaused);
+    }
+
+    @Override
+    public void onRadioButtonClicked(RadioButtonPreference preference) {
+        int preventRingingSetting = keyToSetting(preference.getKey());
+        if (preventRingingSetting != Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.VOLUME_HUSH_GESTURE, Settings.Secure.VOLUME_HUSH_VIBRATE)) {
+            Settings.Secure.putInt(mContext.getContentResolver(),
+                    Settings.Secure.VOLUME_HUSH_GESTURE, preventRingingSetting);
+        }
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        int preventRingingSetting = Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.VOLUME_HUSH_GESTURE, Settings.Secure.VOLUME_HUSH_VIBRATE);
+
+        final boolean isVibrate = preventRingingSetting == Settings.Secure.VOLUME_HUSH_VIBRATE;
+        final boolean isMute = preventRingingSetting == Settings.Secure.VOLUME_HUSH_MUTE;
+        final boolean isOff = preventRingingSetting == Settings.Secure.VOLUME_HUSH_OFF
+                || (!isVibrate && !isMute);
+        if (mVibratePref != null && mVibratePref.isChecked() != isVibrate) {
+            mVibratePref.setChecked(isVibrate);
+        }
+        if (mMutePref != null && mMutePref.isChecked() != isMute) {
+            mMutePref.setChecked(isMute);
+        }
+        if (mNonePref != null && mNonePref.isChecked() != isOff) {
+            mNonePref.setChecked(isOff);
+        }
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        if (savedInstanceState != null) {
+            mVideoPaused = savedInstanceState.getBoolean(KEY_VIDEO_PAUSED, false);
+        }
+    }
+
+    @Override
+    public void onResume() {
+        if (mSettingObserver != null) {
+            mSettingObserver.register(mContext.getContentResolver());
+            mSettingObserver.onChange(false, null);
+        }
+
+        if (mVideoPreference != null) {
+            mVideoPreference.onViewVisible(mVideoPaused);
+        }
+    }
+
+    @Override
+    public void onPause() {
+        if (mSettingObserver != null) {
+            mSettingObserver.unregister(mContext.getContentResolver());
+        }
+
+        if (mVideoPreference != null) {
+            mVideoPaused = mVideoPreference.isVideoPaused();
+            mVideoPreference.onViewInvisible();
+        }
+    }
+
+    private int keyToSetting(String key) {
+        switch (key) {
+            case KEY_NONE:
+                return Settings.Secure.VOLUME_HUSH_OFF;
+            case KEY_MUTE:
+                return Settings.Secure.VOLUME_HUSH_MUTE;
+            case KEY_VIBRATE:
+            default:
+                return Settings.Secure.VOLUME_HUSH_VIBRATE;
+        }
+    }
+
+    private RadioButtonPreference makeRadioPreference(String key, int titleId) {
+        RadioButtonPreference pref = new RadioButtonPreference(mPreferenceCategory.getContext());
+        pref.setKey(key);
+        pref.setTitle(titleId);
+        pref.setOnClickListener(this);
+        mPreferenceCategory.addPreference(pref);
+        return pref;
+    }
+
+    private class SettingObserver extends ContentObserver {
+        private final Uri VOLUME_HUSH_GESTURE = Settings.Secure.getUriFor(
+                Settings.Secure.VOLUME_HUSH_GESTURE);
+
+        private final Preference mPreference;
+
+        public SettingObserver(Preference preference) {
+            super(new Handler());
+            mPreference = preference;
+        }
+
+        public void register(ContentResolver cr) {
+            cr.registerContentObserver(VOLUME_HUSH_GESTURE, false, this);
+        }
+
+        public void unregister(ContentResolver cr) {
+            cr.unregisterContentObserver(this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            super.onChange(selfChange, uri);
+            if (uri == null || VOLUME_HUSH_GESTURE.equals(uri)) {
+                updateState(mPreference);
+            }
+        }
+    }
+}
diff --git a/src/com/android/settings/gestures/PreventRingingGestureSettings.java b/src/com/android/settings/gestures/PreventRingingGestureSettings.java
index 84b4e16..3e8ae85 100644
--- a/src/com/android/settings/gestures/PreventRingingGestureSettings.java
+++ b/src/com/android/settings/gestures/PreventRingingGestureSettings.java
@@ -23,8 +23,11 @@
 import com.android.settings.R;
 import com.android.settings.dashboard.DashboardFragment;
 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 java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
@@ -40,6 +43,18 @@
     }
 
     @Override
+    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+        return buildPreferenceControllers(context, getSettingsLifecycle());
+    }
+
+    private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
+            Lifecycle lifecycle) {
+        List<AbstractPreferenceController> controllers = new ArrayList<>();
+        controllers.add(new PreventRingingGesturePreferenceController(context, lifecycle));
+        return controllers;
+    }
+
+    @Override
     public int getMetricsCategory() {
         return MetricsProto.MetricsEvent.SETTINGS_PREVENT_RINGING;
     }
@@ -68,6 +83,12 @@
                     sir.xmlResId = R.xml.prevent_ringing_gesture_settings;
                     return Arrays.asList(sir);
                 }
+
+                @Override
+                public List<AbstractPreferenceController> createPreferenceControllers(
+                        Context context) {
+                    return buildPreferenceControllers(context, null);
+                }
             };
 
 }
diff --git a/src/com/android/settings/gestures/PreventRingingPreferenceController.java b/src/com/android/settings/gestures/PreventRingingPreferenceController.java
deleted file mode 100644
index 570c1c6..0000000
--- a/src/com/android/settings/gestures/PreventRingingPreferenceController.java
+++ /dev/null
@@ -1,132 +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.gestures;
-
-import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
-import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
-import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.provider.Settings;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.ListPreference;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.widget.VideoPreference;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnCreate;
-import com.android.settingslib.core.lifecycle.events.OnPause;
-import com.android.settingslib.core.lifecycle.events.OnResume;
-import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
-
-public class PreventRingingPreferenceController extends PreventRingingParentPreferenceController
-        implements Preference.OnPreferenceChangeListener,
-        LifecycleObserver, OnResume, OnPause, OnCreate, OnSaveInstanceState {
-
-    private static final String PREF_KEY_VIDEO = "gesture_prevent_ringing_video";
-    @VisibleForTesting
-    static final String KEY_VIDEO_PAUSED = "key_video_paused";
-
-    private VideoPreference mVideoPreference;
-    @VisibleForTesting
-    boolean mVideoPaused;
-
-    public PreventRingingPreferenceController(Context context, String key) {
-        super(context, key);
-    }
-
-    @Override
-    public int getAvailabilityStatus() {
-        final int status = super.getAvailabilityStatus();
-        if (status == AVAILABLE_UNSEARCHABLE) {
-            return AVAILABLE;
-        }
-        return status;
-    }
-
-    @Override
-    public void displayPreference(PreferenceScreen screen) {
-        super.displayPreference(screen);
-        if (isAvailable()) {
-            mVideoPreference = (VideoPreference) screen.findPreference(getVideoPrefKey());
-        }
-    }
-
-    @Override
-    public void updateState(Preference preference) {
-        super.updateState(preference);
-        if (preference != null) {
-            if (preference instanceof ListPreference) {
-                ListPreference pref = (ListPreference) preference;
-                int value = Settings.Secure.getInt(
-                        mContext.getContentResolver(), SECURE_KEY, VOLUME_HUSH_VIBRATE);
-                switch (value) {
-                    case VOLUME_HUSH_VIBRATE:
-                        pref.setValue(String.valueOf(value));
-                        break;
-                    case VOLUME_HUSH_MUTE:
-                        pref.setValue(String.valueOf(value));
-                        break;
-                    default:
-                        pref.setValue(String.valueOf(VOLUME_HUSH_OFF));
-                }
-            }
-        }
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        if (savedInstanceState != null) {
-            mVideoPaused = savedInstanceState.getBoolean(KEY_VIDEO_PAUSED, false);
-        }
-    }
-
-    @Override
-    public void onSaveInstanceState(Bundle outState) {
-        outState.putBoolean(KEY_VIDEO_PAUSED, mVideoPaused);
-    }
-
-    @Override
-    public void onPause() {
-        if (mVideoPreference != null) {
-            mVideoPaused = mVideoPreference.isVideoPaused();
-            mVideoPreference.onViewInvisible();
-        }
-    }
-
-    @Override
-    public void onResume() {
-        if (mVideoPreference != null) {
-            mVideoPreference.onViewVisible(mVideoPaused);
-        }
-    }
-
-    protected String getVideoPrefKey() {
-        return PREF_KEY_VIDEO;
-    }
-
-    @Override
-    public boolean onPreferenceChange(Preference preference, Object newValue) {
-        int value = Integer.parseInt((String) newValue);
-        Settings.Secure.putInt(mContext.getContentResolver(), SECURE_KEY, value);
-        preference.setSummary(getSummary());
-        return true;
-    }
-}
diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java
index c10543d..d3f11a0 100644
--- a/src/com/android/settings/homepage/SettingsHomepageActivity.java
+++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java
@@ -19,6 +19,7 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.util.FeatureFlagUtils;
+import android.widget.ImageView;
 import android.widget.Toolbar;
 
 import androidx.fragment.app.Fragment;
@@ -27,6 +28,7 @@
 
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
+import com.android.settings.accounts.AvatarViewMixin;
 import com.android.settings.core.FeatureFlags;
 import com.android.settings.core.SettingsBaseActivity;
 import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
@@ -51,6 +53,10 @@
         FeatureFactory.getFactory(this).getSearchFeatureProvider()
                 .initSearchToolbar(this, toolbar);
 
+        final ImageView avatarView = findViewById(R.id.account_avatar);
+        final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(this, avatarView);
+        getLifecycle().addObserver(avatarViewMixin);
+
         showFragment(new ContextualCardsFragment(), R.id.contextual_cards_content);
         showFragment(new TopLevelSettings(), R.id.main_content);
     }
diff --git a/src/com/android/settings/homepage/contextualcards/CardDatabaseHelper.java b/src/com/android/settings/homepage/contextualcards/CardDatabaseHelper.java
index 11ab8d8..b5cdf87 100644
--- a/src/com/android/settings/homepage/contextualcards/CardDatabaseHelper.java
+++ b/src/com/android/settings/homepage/contextualcards/CardDatabaseHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.homepage.contextualcards;
 
+import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
@@ -30,7 +31,7 @@
 public class CardDatabaseHelper extends SQLiteOpenHelper {
     private static final String TAG = "CardDatabaseHelper";
     private static final String DATABASE_NAME = "homepage_cards.db";
-    private static final int DATABASE_VERSION = 3;
+    private static final int DATABASE_VERSION = 5;
 
     public static final String CARD_TABLE = "cards";
 
@@ -56,7 +57,7 @@
         String SLICE_URI = "slice_uri";
 
         /**
-         * Category of the card. The value is between 0 to 3.
+         * Category of the card.
          */
         String CATEGORY = "category";
 
@@ -119,6 +120,11 @@
          * Decide the card display full-length width or half-width in screen.
          */
         String SUPPORT_HALF_WIDTH = "support_half_width";
+
+        /**
+         * Decide the card is dismissed or not.
+         */
+        String CARD_DISMISSED = "card_dismissed";
     }
 
     private static final String CREATE_CARD_TABLE =
@@ -133,11 +139,7 @@
                     CardColumns.SLICE_URI +
                     " TEXT, " +
                     CardColumns.CATEGORY +
-                    " INTEGER DEFAULT 0 CHECK (" +
-                    CardColumns.CATEGORY +
-                    " >= 0 AND " +
-                    CardColumns.CATEGORY +
-                    " <= 3), " +
+                    " INTEGER DEFAULT 0, " +
                     CardColumns.LOCALIZED_TO_LOCALE +
                     " TEXT, " +
                     CardColumns.PACKAGE_NAME +
@@ -161,6 +163,8 @@
                     CardColumns.EXPIRE_TIME_MS +
                     " INTEGER, " +
                     CardColumns.SUPPORT_HALF_WIDTH +
+                    " INTEGER DEFAULT 0, " +
+                    CardColumns.CARD_DISMISSED +
                     " INTEGER DEFAULT 0 " +
                     ");";
 
@@ -194,9 +198,27 @@
 
     Cursor getContextualCards() {
         final SQLiteDatabase db = this.getReadableDatabase();
-        Cursor cursor = db.query(CARD_TABLE, null /* columns */, null /* selection */,
+        final String selection = CardColumns.CARD_DISMISSED + "=0";
+        Cursor cursor = db.query(CARD_TABLE, null /* columns */, selection,
                 null /* selectionArgs */, null /* groupBy */, null /* having */,
-                null /* orderBy */);
+                CardColumns.SCORE + " DESC" /* orderBy */);
         return cursor;
     }
+
+    /**
+     * Mark a specific ContextualCard with dismissal flag in the database to indicate that the
+     * card has been dismissed.
+     *
+     * @param cardName the card name of the ContextualCard which is dismissed by user.
+     * @return updated row number
+     */
+    public int markContextualCardAsDismissed(String cardName) {
+        final SQLiteDatabase database = this.getWritableDatabase();
+        final ContentValues values = new ContentValues();
+        values.put(CardColumns.CARD_DISMISSED, 1);
+        final String selection = CardColumns.NAME + "=?";
+        final String[] selectionArgs = {cardName};
+        final int rowsUpdated = database.update(CARD_TABLE, values, selection, selectionArgs);
+        return rowsUpdated;
+    }
 }
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCard.java b/src/com/android/settings/homepage/contextualcards/ContextualCard.java
index 996c2dd..8d43914 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCard.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCard.java
@@ -33,15 +33,16 @@
     /**
      * Flags indicating the type of the ContextualCard.
      */
-    @IntDef({CardType.DEFAULT, CardType.SLICE, CardType.SUGGESTION, CardType.CONDITIONAL})
+    @IntDef({CardType.DEFAULT, CardType.SLICE, CardType.LEGACY_SUGGESTION, CardType.CONDITIONAL})
     @Retention(RetentionPolicy.SOURCE)
     public @interface CardType {
         int DEFAULT = 0;
         int SLICE = 1;
-        int SUGGESTION = 2;
+        int LEGACY_SUGGESTION = 2;
         int CONDITIONAL = 3;
     }
 
+    private final Builder mBuilder;
     private final String mName;
     @CardType
     private final int mCardType;
@@ -142,7 +143,12 @@
         return TextUtils.isEmpty(mSliceUri);
     }
 
+    public Builder mutate() {
+        return mBuilder;
+    }
+
     public ContextualCard(Builder builder) {
+        mBuilder = builder;
         mName = builder.mName;
         mCardType = builder.mCardType;
         mRankingScore = builder.mRankingScore;
@@ -164,28 +170,47 @@
     }
 
     ContextualCard(Cursor c) {
+        mBuilder = new Builder();
         mName = c.getString(c.getColumnIndex(CardDatabaseHelper.CardColumns.NAME));
+        mBuilder.setName(mName);
         mCardType = c.getInt(c.getColumnIndex(CardDatabaseHelper.CardColumns.TYPE));
+        mBuilder.setCardType(mCardType);
         mRankingScore = c.getDouble(c.getColumnIndex(CardDatabaseHelper.CardColumns.SCORE));
+        mBuilder.setRankingScore(mRankingScore);
         mSliceUri = c.getString(c.getColumnIndex(CardDatabaseHelper.CardColumns.SLICE_URI));
+        mBuilder.setSliceUri(Uri.parse(mSliceUri));
         mCategory = c.getInt(c.getColumnIndex(CardDatabaseHelper.CardColumns.CATEGORY));
+        mBuilder.setCategory(mCategory);
         mLocalizedToLocale = c.getString(
                 c.getColumnIndex(CardDatabaseHelper.CardColumns.LOCALIZED_TO_LOCALE));
+        mBuilder.setLocalizedToLocale(mLocalizedToLocale);
         mPackageName = c.getString(c.getColumnIndex(CardDatabaseHelper.CardColumns.PACKAGE_NAME));
+        mBuilder.setPackageName(mPackageName);
         mAppVersion = c.getLong(c.getColumnIndex(CardDatabaseHelper.CardColumns.APP_VERSION));
+        mBuilder.setAppVersion(mAppVersion);
         mTitleResName = c.getString(
                 c.getColumnIndex(CardDatabaseHelper.CardColumns.TITLE_RES_NAME));
+        mBuilder.setTitleResName(mTitleResName);
         mTitleText = c.getString(c.getColumnIndex(CardDatabaseHelper.CardColumns.TITLE_TEXT));
+        mBuilder.setTitleText(mTitleText);
         mSummaryResName = c.getString(
                 c.getColumnIndex(CardDatabaseHelper.CardColumns.SUMMARY_RES_NAME));
+        mBuilder.setSummaryResName(mSummaryResName);
         mSummaryText = c.getString(c.getColumnIndex(CardDatabaseHelper.CardColumns.SUMMARY_TEXT));
+        mBuilder.setSummaryText(mSummaryText);
         mIconResName = c.getString(c.getColumnIndex(CardDatabaseHelper.CardColumns.ICON_RES_NAME));
+        mBuilder.setIconResName(mIconResName);
         mIconResId = c.getInt(c.getColumnIndex(CardDatabaseHelper.CardColumns.ICON_RES_ID));
+        mBuilder.setIconResId(mIconResId);
         mCardAction = c.getInt(c.getColumnIndex(CardDatabaseHelper.CardColumns.CARD_ACTION));
+        mBuilder.setCardAction(mCardAction);
         mExpireTimeMS = c.getLong(c.getColumnIndex(CardDatabaseHelper.CardColumns.EXPIRE_TIME_MS));
+        mBuilder.setExpireTimeMS(mExpireTimeMS);
         mIsHalfWidth = (c.getInt(
                 c.getColumnIndex(CardDatabaseHelper.CardColumns.SUPPORT_HALF_WIDTH)) == 1);
+        mBuilder.setIsHalfWidth(mIsHalfWidth);
         mIconDrawable = null;
+        mBuilder.setIconDrawable(mIconDrawable);
     }
 
     @Override
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTable.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTable.java
index 0268fb0..dabc88c 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTable.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTable.java
@@ -16,43 +16,71 @@
 
 package com.android.settings.homepage.contextualcards;
 
+import android.util.Log;
+
+import androidx.annotation.LayoutRes;
+import androidx.annotation.VisibleForTesting;
+
 import com.android.settings.homepage.contextualcards.ContextualCard.CardType;
 import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardController;
 import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardRenderer;
+import com.android.settings.homepage.contextualcards.legacysuggestion
+        .LegacySuggestionContextualCardController;
+import com.android.settings.homepage.contextualcards.legacysuggestion
+        .LegacySuggestionContextualCardRenderer;
 import com.android.settings.homepage.contextualcards.slices.SliceContextualCardController;
 import com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer;
 
+import java.util.Comparator;
+import java.util.List;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.stream.Collectors;
 
 public class ContextualCardLookupTable {
+    private static final String TAG = "ContextualCardLookup";
 
     static class ControllerRendererMapping implements Comparable<ControllerRendererMapping> {
         @CardType
-        private final int mCardType;
-        private final Class<? extends ContextualCardController> mControllerClass;
-        private final Class<? extends ContextualCardRenderer> mRendererClass;
+        final int mCardType;
+        final int mViewType;
+        final Class<? extends ContextualCardController> mControllerClass;
+        final Class<? extends ContextualCardRenderer> mRendererClass;
 
-        private ControllerRendererMapping(@CardType int cardType,
+        ControllerRendererMapping(@CardType int cardType, @LayoutRes int viewType,
                 Class<? extends ContextualCardController> controllerClass,
                 Class<? extends ContextualCardRenderer> rendererClass) {
             mCardType = cardType;
+            mViewType = viewType;
             mControllerClass = controllerClass;
             mRendererClass = rendererClass;
         }
 
         @Override
         public int compareTo(ControllerRendererMapping other) {
-            return Integer.compare(this.mCardType, other.mCardType);
+            return Comparator.comparingInt((ControllerRendererMapping mapping) -> mapping.mCardType)
+                    .thenComparingInt(mapping -> mapping.mViewType)
+                    .compare(this, other);
         }
     }
 
-    private static final Set<ControllerRendererMapping> LOOKUP_TABLE =
+    @VisibleForTesting
+    static final Set<ControllerRendererMapping> LOOKUP_TABLE =
             new TreeSet<ControllerRendererMapping>() {{
                 add(new ControllerRendererMapping(CardType.CONDITIONAL,
+                        ConditionContextualCardRenderer.HALF_WIDTH_VIEW_TYPE,
                         ConditionContextualCardController.class,
                         ConditionContextualCardRenderer.class));
+                add(new ControllerRendererMapping(CardType.CONDITIONAL,
+                        ConditionContextualCardRenderer.FULL_WIDTH_VIEW_TYPE,
+                        ConditionContextualCardController.class,
+                        ConditionContextualCardRenderer.class));
+                add(new ControllerRendererMapping(CardType.LEGACY_SUGGESTION,
+                        LegacySuggestionContextualCardRenderer.VIEW_TYPE,
+                        LegacySuggestionContextualCardController.class,
+                        LegacySuggestionContextualCardRenderer.class));
                 add(new ControllerRendererMapping(CardType.SLICE,
+                        SliceContextualCardRenderer.VIEW_TYPE,
                         SliceContextualCardController.class,
                         SliceContextualCardRenderer.class));
             }};
@@ -67,14 +95,27 @@
         return null;
     }
 
-    //TODO(b/112578070): Implement multi renderer cases.
-    public static Class<? extends ContextualCardRenderer> getCardRendererClasses(
+    public static Class<? extends ContextualCardRenderer> getCardRendererClassByCardType(
             @CardType int cardType) {
-        for (ControllerRendererMapping mapping : LOOKUP_TABLE) {
-            if (mapping.mCardType == cardType) {
-                return mapping.mRendererClass;
-            }
+        return LOOKUP_TABLE.stream()
+                .filter(m -> m.mCardType == cardType)
+                .findFirst()
+                .map(mapping -> mapping.mRendererClass)
+                .orElse(null);
+    }
+
+    public static Class<? extends ContextualCardRenderer> getCardRendererClassByViewType(
+            int viewType) throws IllegalStateException {
+        List<ControllerRendererMapping> validMappings = LOOKUP_TABLE.stream()
+                .filter(m -> m.mViewType == viewType).collect(Collectors.toList());
+        if (validMappings == null || validMappings.isEmpty()) {
+            Log.w(TAG, "No matching mapping");
+            return null;
         }
-        return null;
+        if (validMappings.size() != 1) {
+            throw new IllegalStateException("Have duplicate VIEW_TYPE in lookup table.");
+        }
+
+        return validMappings.get(0).mRendererClass;
     }
 }
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
index 51bef87..39ceff3 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
@@ -16,7 +16,8 @@
 
 package com.android.settings.homepage.contextualcards;
 
-import static com.android.settings.homepage.contextualcards.ContextualCardLoader.CARD_CONTENT_LOADER_ID;
+import static com.android.settings.homepage.contextualcards.ContextualCardLoader
+        .CARD_CONTENT_LOADER_ID;
 
 import static java.util.stream.Collectors.groupingBy;
 
@@ -57,8 +58,8 @@
 
     private static final String TAG = "ContextualCardManager";
     //The list for Settings Custom Card
-    @ContextualCard.CardType
-    private static final int[] SETTINGS_CARDS = {ContextualCard.CardType.CONDITIONAL};
+    private static final int[] SETTINGS_CARDS =
+            {ContextualCard.CardType.CONDITIONAL, ContextualCard.CardType.LEGACY_SUGGESTION};
 
     private final Context mContext;
     private final ControllerRendererPool mControllerRendererPool;
@@ -68,14 +69,14 @@
 
     private ContextualCardUpdateListener mListener;
 
-    public ContextualCardManager(Context context, @NonNull Lifecycle lifecycle) {
+    public ContextualCardManager(Context context, Lifecycle lifecycle) {
         mContext = context;
         mLifecycle = lifecycle;
         mContextualCards = new ArrayList<>();
         mLifecycleObservers = new ArrayList<>();
         mControllerRendererPool = new ControllerRendererPool();
         //for data provided by Settings
-        for (int cardType : SETTINGS_CARDS) {
+        for (@ContextualCard.CardType int cardType : SETTINGS_CARDS) {
             setupController(cardType);
         }
     }
@@ -84,7 +85,7 @@
         final CardContentLoaderCallbacks cardContentLoaderCallbacks =
                 new CardContentLoaderCallbacks(mContext);
         cardContentLoaderCallbacks.setListener(this);
-        LoaderManager.getInstance(fragment).initLoader(CARD_CONTENT_LOADER_ID, null /* bundle */,
+        LoaderManager.getInstance(fragment).restartLoader(CARD_CONTENT_LOADER_ID, null /* bundle */,
                 cardContentLoaderCallbacks);
     }
 
@@ -94,7 +95,7 @@
         }
     }
 
-    private void setupController(int cardType) {
+    private void setupController(@ContextualCard.CardType int cardType) {
         final ContextualCardController controller = mControllerRendererPool.getController(mContext,
                 cardType);
         if (controller == null) {
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardRenderer.java b/src/com/android/settings/homepage/contextualcards/ContextualCardRenderer.java
index 689b572..283a079 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardRenderer.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardRenderer.java
@@ -18,6 +18,7 @@
 
 import android.view.View;
 
+import androidx.annotation.LayoutRes;
 import androidx.recyclerview.widget.RecyclerView;
 
 /**
@@ -26,9 +27,10 @@
 public interface ContextualCardRenderer {
 
     /**
-     * The layout type of the controller.
+     * The layout type of the renderer.
      */
-    int getViewType();
+    @LayoutRes
+    int getViewType(boolean isHalfWidth);
 
     /**
      * When {@link ContextualCardsAdapter} calls {@link ContextualCardsAdapter#onCreateViewHolder},
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardUpdateListener.java b/src/com/android/settings/homepage/contextualcards/ContextualCardUpdateListener.java
index 725f6da..9b90d41 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardUpdateListener.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardUpdateListener.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.homepage.contextualcards;
 
+import androidx.annotation.MainThread;
+
 import java.util.List;
 import java.util.Map;
 
@@ -31,5 +33,6 @@
      *              null, which means all cards from corresponding {@link
      *              ContextualCard.CardType} are removed.
      */
+    @MainThread
     void onContextualCardUpdated(Map<Integer, List<ContextualCard>> cards);
 }
\ No newline at end of file
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardsAdapter.java b/src/com/android/settings/homepage/contextualcards/ContextualCardsAdapter.java
index 865d242..0a8749d 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardsAdapter.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardsAdapter.java
@@ -61,26 +61,26 @@
 
     @Override
     public int getItemViewType(int position) {
-        return mContextualCards.get(position).getCardType();
+        final ContextualCard card = mContextualCards.get(position);
+        final ContextualCardRenderer renderer = mControllerRendererPool.getRendererByCardType(
+                mContext, mLifecycleOwner, card.getCardType());
+        return renderer.getViewType(card.isHalfWidth());
     }
 
     @Override
-    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int cardType) {
-        final ContextualCardRenderer renderer = mControllerRendererPool.getRenderer(mContext,
-                mLifecycleOwner, cardType);
-        final int viewType = renderer.getViewType();
+    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        final ContextualCardRenderer renderer = mControllerRendererPool.getRendererByViewType(
+                mContext, mLifecycleOwner, viewType);
         final View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
-
         return renderer.createViewHolder(view);
     }
 
     @Override
     public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
-        final int cardType = mContextualCards.get(position).getCardType();
-        final ContextualCardRenderer renderer = mControllerRendererPool.getRenderer(mContext,
-                mLifecycleOwner, cardType);
-
-        renderer.bindView(holder, mContextualCards.get(position));
+        final ContextualCard card = mContextualCards.get(position);
+        final ContextualCardRenderer renderer = mControllerRendererPool.getRendererByCardType(
+                mContext, mLifecycleOwner, card.getCardType());
+        renderer.bindView(holder, card);
     }
 
     @Override
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java b/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java
index d82fdfe..29eea4b 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java
@@ -43,6 +43,11 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mContextualCardManager = new ContextualCardManager(getContext(), getSettingsLifecycle());
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
         mContextualCardManager.loadContextualCards(this);
     }
 
diff --git a/src/com/android/settings/homepage/contextualcards/ControllerRendererPool.java b/src/com/android/settings/homepage/contextualcards/ControllerRendererPool.java
index 212b6be..7d9d5a8 100644
--- a/src/com/android/settings/homepage/contextualcards/ControllerRendererPool.java
+++ b/src/com/android/settings/homepage/contextualcards/ControllerRendererPool.java
@@ -16,14 +16,20 @@
 
 package com.android.settings.homepage.contextualcards;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.util.Log;
 
 import androidx.collection.ArraySet;
 import androidx.lifecycle.LifecycleOwner;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardController;
 import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardRenderer;
+import com.android.settings.homepage.contextualcards.legacysuggestion
+        .LegacySuggestionContextualCardController;
+import com.android.settings.homepage.contextualcards.legacysuggestion
+        .LegacySuggestionContextualCardRenderer;
 import com.android.settings.homepage.contextualcards.slices.SliceContextualCardController;
 import com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer;
 
@@ -63,14 +69,32 @@
         return (T) controller;
     }
 
-    public Set<ContextualCardController> getControllers() {
+    @VisibleForTesting
+    Set<ContextualCardController> getControllers() {
         return mControllers;
     }
 
-    public ContextualCardRenderer getRenderer(Context context, LifecycleOwner lifecycleOwner,
-            @ContextualCard.CardType int cardType) {
+    @VisibleForTesting
+    Set<ContextualCardRenderer> getRenderers() {
+        return mRenderers;
+    }
+
+    public ContextualCardRenderer getRendererByViewType(Context context,
+            LifecycleOwner lifecycleOwner, int viewType) {
         final Class<? extends ContextualCardRenderer> clz =
-                ContextualCardLookupTable.getCardRendererClasses(cardType);
+                ContextualCardLookupTable.getCardRendererClassByViewType(viewType);
+        return getRenderer(context, lifecycleOwner, clz);
+    }
+
+    public ContextualCardRenderer getRendererByCardType(Context context,
+            LifecycleOwner lifecycleOwner, @ContextualCard.CardType int cardType) {
+        final Class<? extends ContextualCardRenderer> clz =
+                ContextualCardLookupTable.getCardRendererClassByCardType(cardType);
+        return getRenderer(context, lifecycleOwner, clz);
+    }
+
+    private ContextualCardRenderer getRenderer(Context context, LifecycleOwner lifecycleOwner,
+            @NonNull Class<? extends ContextualCardRenderer> clz) {
         for (ContextualCardRenderer renderer : mRenderers) {
             if (renderer.getClass() == clz) {
                 Log.d(TAG, "Renderer is already there.");
@@ -91,6 +115,8 @@
             return new ConditionContextualCardController(context);
         } else if (SliceContextualCardController.class == clz) {
             return new SliceContextualCardController();
+        } else if (LegacySuggestionContextualCardController.class == clz) {
+            return new LegacySuggestionContextualCardController(context);
         }
         return null;
     }
@@ -98,9 +124,12 @@
     private ContextualCardRenderer createCardRenderer(Context context,
             LifecycleOwner lifecycleOwner, Class<?> clz) {
         if (ConditionContextualCardRenderer.class == clz) {
-            return new ConditionContextualCardRenderer(context, this /*controllerRendererPool*/);
+            return new ConditionContextualCardRenderer(context, this /* controllerRendererPool */);
         } else if (SliceContextualCardRenderer.class == clz) {
             return new SliceContextualCardRenderer(context, lifecycleOwner);
+        } else if (LegacySuggestionContextualCardRenderer.class == clz) {
+            return new LegacySuggestionContextualCardRenderer(context,
+                    this /* controllerRendererPool */);
         }
         return null;
     }
diff --git a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
index 59c9ba9..c736c4d 100644
--- a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
+++ b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
@@ -26,7 +26,6 @@
 import com.android.settings.intelligence.ContextualCardProto.ContextualCardList;
 import com.android.settings.wifi.WifiSlice;
 
-import com.google.android.settings.intelligence.libs.contextualcards.ContextualCardCategory;
 import com.google.android.settings.intelligence.libs.contextualcards.ContextualCardProvider;
 
 /** Provides dynamic card for SettingsIntelligence. */
@@ -41,19 +40,19 @@
                 ContextualCard.newBuilder()
                         .setSliceUri(WifiSlice.WIFI_URI.toString())
                         .setCardName(KEY_WIFI)
-                        .setCategory(ContextualCardCategory.IMPORTANT)
+                        .setCardCategory(ContextualCard.Category.IMPORTANT)
                         .build();
         final ContextualCard batteryInfoCard =
                 ContextualCard.newBuilder()
                         .setSliceUri(BatterySlice.BATTERY_CARD_URI.toString())
                         .setCardName(BatterySlice.PATH_BATTERY_INFO)
-                        .setCategory(ContextualCardCategory.DEFAULT)
+                        .setCardCategory(ContextualCard.Category.DEFAULT)
                         .build();
         final ContextualCard connectedDeviceCard =
                 ContextualCard.newBuilder()
                         .setSliceUri(ConnectedDeviceSlice.CONNECTED_DEVICE_URI.toString())
                         .setCardName(ConnectedDeviceSlice.PATH_CONNECTED_DEVICE)
-                        .setCategory(ContextualCardCategory.IMPORTANT)
+                        .setCardCategory(ContextualCard.Category.IMPORTANT)
                         .build();
         final ContextualCardList cards = ContextualCardList.newBuilder()
                 .addCard(wifiCard)
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/AirplaneModeConditionController.java b/src/com/android/settings/homepage/contextualcards/conditional/AirplaneModeConditionController.java
index b6bb05a..f33633e 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/AirplaneModeConditionController.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/AirplaneModeConditionController.java
@@ -79,6 +79,7 @@
                 .setTitleText(mAppContext.getText(R.string.condition_airplane_title).toString())
                 .setSummaryText(mAppContext.getText(R.string.condition_airplane_summary).toString())
                 .setIconDrawable(mAppContext.getDrawable(R.drawable.ic_airplanemode_active))
+                .setIsHalfWidth(true)
                 .build();
     }
 
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/BackgroundDataConditionController.java b/src/com/android/settings/homepage/contextualcards/conditional/BackgroundDataConditionController.java
index 8b0ee42..4e40556 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/BackgroundDataConditionController.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/BackgroundDataConditionController.java
@@ -73,6 +73,7 @@
                 .setTitleText(mAppContext.getText(R.string.condition_bg_data_title).toString())
                 .setSummaryText(mAppContext.getText(R.string.condition_bg_data_summary).toString())
                 .setIconDrawable(mAppContext.getDrawable(R.drawable.ic_data_saver))
+                .setIsHalfWidth(true)
                 .build();
     }
 
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/BatterySaverConditionController.java b/src/com/android/settings/homepage/contextualcards/conditional/BatterySaverConditionController.java
index 66901f3..bce7c5d 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/BatterySaverConditionController.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/BatterySaverConditionController.java
@@ -82,6 +82,7 @@
                 .setTitleText(mAppContext.getText(R.string.condition_battery_title).toString())
                 .setSummaryText(mAppContext.getText(R.string.condition_battery_summary).toString())
                 .setIconDrawable(mAppContext.getDrawable(R.drawable.ic_battery_saver_accent_24dp))
+                .setIsHalfWidth(true)
                 .build();
     }
 
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/CellularDataConditionController.java b/src/com/android/settings/homepage/contextualcards/conditional/CellularDataConditionController.java
index b2fbbcb..05199ba 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/CellularDataConditionController.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/CellularDataConditionController.java
@@ -89,6 +89,7 @@
                 .setTitleText(mAppContext.getText(R.string.condition_cellular_title).toString())
                 .setSummaryText(mAppContext.getText(R.string.condition_cellular_summary).toString())
                 .setIconDrawable(mAppContext.getDrawable(R.drawable.ic_cellular_off))
+                .setIsHalfWidth(true)
                 .build();
     }
 
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardController.java b/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardController.java
index eb65819..10881d9 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardController.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardController.java
@@ -85,6 +85,14 @@
     public void onConditionsChanged() {
         final List<ContextualCard> conditionCards = mConditionManager.getDisplayableCards();
 
+        final boolean isOddNumber = conditionCards.size() % 2 == 1;
+        if (isOddNumber) {
+            final int lastIndex = conditionCards.size() - 1;
+            final ConditionalContextualCard card = (ConditionalContextualCard) conditionCards.get(
+                    lastIndex);
+            conditionCards.set(lastIndex, card.mutate().setIsHalfWidth(false).build());
+        }
+
         if (mListener != null) {
             final Map<Integer, List<ContextualCard>> conditionalCards = new ArrayMap<>();
             conditionalCards.put(ContextualCard.CardType.CONDITIONAL, conditionCards);
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardRenderer.java b/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardRenderer.java
index 8a3635b..5e4e749 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardRenderer.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardRenderer.java
@@ -23,6 +23,7 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import androidx.annotation.LayoutRes;
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.internal.logging.nano.MetricsProto;
@@ -37,6 +38,10 @@
  * Card renderer for {@link ConditionalContextualCard}.
  */
 public class ConditionContextualCardRenderer implements ContextualCardRenderer {
+    @LayoutRes
+    public static final int HALF_WIDTH_VIEW_TYPE = R.layout.homepage_condition_half_tile;
+    @LayoutRes
+    public static final int FULL_WIDTH_VIEW_TYPE = R.layout.homepage_condition_full_tile;
 
     private final Context mContext;
     private final ControllerRendererPool mControllerRendererPool;
@@ -48,8 +53,12 @@
     }
 
     @Override
-    public int getViewType() {
-        return R.layout.homepage_condition_tile;
+    public int getViewType(boolean isHalfWidth) {
+        if (isHalfWidth) {
+            return HALF_WIDTH_VIEW_TYPE;
+        } else {
+            return FULL_WIDTH_VIEW_TYPE;
+        }
     }
 
     @Override
@@ -87,15 +96,12 @@
         view.icon.setImageDrawable(card.getIconDrawable());
         view.title.setText(card.getTitleText());
         view.summary.setText(card.getSummaryText());
-
-        setViewVisibility(view.itemView, R.id.divider, false);
     }
 
     private void initializeActionButton(ConditionalCardHolder view, ConditionalContextualCard card,
             MetricsFeatureProvider metricsFeatureProvider) {
         final CharSequence action = card.getActionText();
         final boolean hasButtons = !TextUtils.isEmpty(action);
-        setViewVisibility(view.itemView, R.id.buttonBar, hasButtons);
 
         final Button button = view.itemView.findViewById(R.id.first_action);
         if (hasButtons) {
@@ -114,13 +120,6 @@
         }
     }
 
-    private void setViewVisibility(View containerView, int viewId, boolean visible) {
-        View view = containerView.findViewById(viewId);
-        if (view != null) {
-            view.setVisibility(visible ? View.VISIBLE : View.GONE);
-        }
-    }
-
     public static class ConditionalCardHolder extends RecyclerView.ViewHolder {
 
         public final ImageView icon;
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/DndConditionCardController.java b/src/com/android/settings/homepage/contextualcards/conditional/DndConditionCardController.java
index 21cb6c0..706b50e 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/DndConditionCardController.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/DndConditionCardController.java
@@ -100,6 +100,7 @@
                 .setTitleText(mAppContext.getText(R.string.condition_zen_title).toString())
                 .setSummaryText(getSummary().toString())
                 .setIconDrawable(mAppContext.getDrawable(R.drawable.ic_do_not_disturb_on_24dp))
+                .setIsHalfWidth(true)
                 .build();
     }
 
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/HotspotConditionController.java b/src/com/android/settings/homepage/contextualcards/conditional/HotspotConditionController.java
index eec7e4a..862f828 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/HotspotConditionController.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/HotspotConditionController.java
@@ -99,6 +99,7 @@
                 .setTitleText(mAppContext.getText(R.string.condition_hotspot_title).toString())
                 .setSummaryText(getSummary().toString())
                 .setIconDrawable(mAppContext.getDrawable(R.drawable.ic_hotspot))
+                .setIsHalfWidth(true)
                 .build();
     }
 
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/NightDisplayConditionController.java b/src/com/android/settings/homepage/contextualcards/conditional/NightDisplayConditionController.java
index d8d5f79..249e4a0 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/NightDisplayConditionController.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/NightDisplayConditionController.java
@@ -78,6 +78,7 @@
                 .setSummaryText(
                         mAppContext.getText(R.string.condition_night_display_summary).toString())
                 .setIconDrawable(mAppContext.getDrawable(R.drawable.ic_settings_night_display))
+                .setIsHalfWidth(true)
                 .build();
     }
 
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/RingerMutedConditionController.java b/src/com/android/settings/homepage/contextualcards/conditional/RingerMutedConditionController.java
index 75a72fd..09b75eb 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/RingerMutedConditionController.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/RingerMutedConditionController.java
@@ -72,6 +72,7 @@
                 .setSummaryText(
                         mAppContext.getText(R.string.condition_device_muted_summary).toString())
                 .setIconDrawable(mAppContext.getDrawable(R.drawable.ic_notifications_off_24dp))
+                .setIsHalfWidth(true)
                 .build();
     }
 }
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/RingerVibrateConditionController.java b/src/com/android/settings/homepage/contextualcards/conditional/RingerVibrateConditionController.java
index 4c355a3..d8084b5 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/RingerVibrateConditionController.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/RingerVibrateConditionController.java
@@ -60,6 +60,7 @@
                 .setSummaryText(
                         mAppContext.getText(R.string.condition_device_vibrate_summary).toString())
                 .setIconDrawable(mAppContext.getDrawable(R.drawable.ic_volume_ringer_vibrate))
+                .setIsHalfWidth(true)
                 .build();
     }
 }
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/WorkModeConditionController.java b/src/com/android/settings/homepage/contextualcards/conditional/WorkModeConditionController.java
index c508403f..44b21bf 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/WorkModeConditionController.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/WorkModeConditionController.java
@@ -93,6 +93,7 @@
                 .setTitleText(mAppContext.getText(R.string.condition_work_title).toString())
                 .setSummaryText(mAppContext.getText(R.string.condition_work_summary).toString())
                 .setIconDrawable(mAppContext.getDrawable(R.drawable.ic_signal_workmode_enable))
+                .setIsHalfWidth(true)
                 .build();
     }
 
diff --git a/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCard.java b/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCard.java
new file mode 100644
index 0000000..d11f771
--- /dev/null
+++ b/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCard.java
@@ -0,0 +1,61 @@
+/*
+ * 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.homepage.contextualcards.legacysuggestion;
+
+import android.app.PendingIntent;
+
+import com.android.settings.homepage.contextualcards.ContextualCard;
+
+public class LegacySuggestionContextualCard extends ContextualCard {
+
+    private final PendingIntent mPendingIntent;
+
+    public LegacySuggestionContextualCard(Builder builder) {
+        super(builder);
+        mPendingIntent = builder.mPendingIntent;
+    }
+
+    @Override
+    public int getCardType() {
+        return CardType.LEGACY_SUGGESTION;
+    }
+
+    public PendingIntent getPendingIntent() {
+        return mPendingIntent;
+    }
+
+    public static class Builder extends ContextualCard.Builder {
+
+        private PendingIntent mPendingIntent;
+
+        public Builder setPendingIntent(PendingIntent pendingIntent) {
+            mPendingIntent = pendingIntent;
+            return this;
+        }
+
+        @Override
+        public Builder setCardType(int cardType) {
+            throw new IllegalArgumentException(
+                    "Cannot change card type for " + getClass().getName());
+        }
+
+        public LegacySuggestionContextualCard build() {
+            return new LegacySuggestionContextualCard(this);
+        }
+    }
+
+}
diff --git a/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardController.java b/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardController.java
new file mode 100644
index 0000000..550f845
--- /dev/null
+++ b/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardController.java
@@ -0,0 +1,156 @@
+/*
+ * 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.homepage.contextualcards.legacysuggestion;
+
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.service.settings.suggestions.Suggestion;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.R;
+import com.android.settings.homepage.contextualcards.ContextualCard;
+import com.android.settings.homepage.contextualcards.ContextualCardController;
+import com.android.settings.homepage.contextualcards.ContextualCardUpdateListener;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settingslib.suggestions.SuggestionController;
+import com.android.settingslib.suggestions.SuggestionController.ServiceConnectionListener;
+import com.android.settingslib.utils.ThreadUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class LegacySuggestionContextualCardController implements ContextualCardController,
+        LifecycleObserver, OnStart, OnStop, ServiceConnectionListener {
+
+    private static final String TAG = "LegacySuggestCardCtrl";
+
+    @VisibleForTesting
+    SuggestionController mSuggestionController;
+
+    private ContextualCardUpdateListener mCardUpdateListener;
+    private final Context mContext;
+
+
+    public LegacySuggestionContextualCardController(Context context) {
+        mContext = context;
+        if (!mContext.getResources().getBoolean(R.bool.config_use_legacy_suggestion)) {
+            Log.w(TAG, "Legacy suggestion contextual card disabled, skipping.");
+            return;
+        }
+        final ComponentName suggestionServiceComponent =
+                FeatureFactory.getFactory(mContext).getSuggestionFeatureProvider(mContext)
+                        .getSuggestionServiceComponent();
+        mSuggestionController = new SuggestionController(
+                mContext, suggestionServiceComponent, this /* listener */);
+
+    }
+
+    @Override
+    public int getCardType() {
+        return ContextualCard.CardType.LEGACY_SUGGESTION;
+    }
+
+    @Override
+    public void onPrimaryClick(ContextualCard card) {
+        try {
+            ((LegacySuggestionContextualCard) card).getPendingIntent().send();
+        } catch (PendingIntent.CanceledException e) {
+            Log.w(TAG, "Failed to start suggestion " + card.getTitleText());
+        }
+    }
+
+    @Override
+    public void onActionClick(ContextualCard card) {
+
+    }
+
+    @Override
+    public void setCardUpdateListener(ContextualCardUpdateListener listener) {
+        mCardUpdateListener = listener;
+    }
+
+    @Override
+    public void onStart() {
+        if (mSuggestionController == null) {
+            return;
+        }
+        mSuggestionController.start();
+    }
+
+    @Override
+    public void onStop() {
+        if (mSuggestionController == null) {
+            return;
+        }
+        mSuggestionController.stop();
+    }
+
+    @Override
+    public void onServiceConnected() {
+        loadSuggestions();
+    }
+
+    @Override
+    public void onServiceDisconnected() {
+
+    }
+
+    private void loadSuggestions() {
+        ThreadUtils.postOnBackgroundThread(() -> {
+            if (mSuggestionController == null || mCardUpdateListener == null) {
+                return;
+            }
+            final List<Suggestion> suggestions = mSuggestionController.getSuggestions();
+            Log.d(TAG, "Loaded suggests: "
+                    + suggestions == null ? "null" : String.valueOf(suggestions.size()));
+
+            final List<ContextualCard> cards = new ArrayList<>();
+            if (suggestions != null) {
+                // Convert suggestion to ContextualCard
+                for (Suggestion suggestion : suggestions) {
+                    final LegacySuggestionContextualCard.Builder cardBuilder =
+                            new LegacySuggestionContextualCard.Builder();
+                    if (suggestion.getIcon() != null) {
+                        cardBuilder.setIconDrawable(suggestion.getIcon().loadDrawable(mContext));
+                    }
+                    cardBuilder
+                            .setPendingIntent(suggestion.getPendingIntent())
+                            .setName(suggestion.getId())
+                            .setTitleText(suggestion.getTitle().toString())
+                            .setSummaryText(suggestion.getSummary().toString());
+
+                    cards.add(cardBuilder.build());
+                }
+            }
+
+            // Update adapter
+            final Map<Integer, List<ContextualCard>> suggestionCards = new ArrayMap<>();
+            suggestionCards.put(ContextualCard.CardType.LEGACY_SUGGESTION, cards);
+            ThreadUtils.postOnMainThread(
+                    () -> mCardUpdateListener.onContextualCardUpdated(suggestionCards));
+
+        });
+    }
+}
diff --git a/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardRenderer.java b/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardRenderer.java
new file mode 100644
index 0000000..3ce1883
--- /dev/null
+++ b/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardRenderer.java
@@ -0,0 +1,81 @@
+/*
+ * 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.homepage.contextualcards.legacysuggestion;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.LayoutRes;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.settings.R;
+import com.android.settings.homepage.contextualcards.ContextualCard;
+import com.android.settings.homepage.contextualcards.ContextualCardRenderer;
+import com.android.settings.homepage.contextualcards.ControllerRendererPool;
+
+public class LegacySuggestionContextualCardRenderer implements ContextualCardRenderer {
+
+    @LayoutRes
+    public static final int VIEW_TYPE = R.layout.homepage_suggestion_tile;
+
+    private final Context mContext;
+    private final ControllerRendererPool mControllerRendererPool;
+
+    public LegacySuggestionContextualCardRenderer(Context context,
+            ControllerRendererPool controllerRendererPool) {
+        mContext = context;
+        mControllerRendererPool = controllerRendererPool;
+    }
+
+    @Override
+    public int getViewType(boolean isHalfWidth) {
+        return VIEW_TYPE;
+    }
+
+    @Override
+    public RecyclerView.ViewHolder createViewHolder(View view) {
+        return new LegacySuggestionViewHolder(view);
+    }
+
+    @Override
+    public void bindView(RecyclerView.ViewHolder holder, ContextualCard card) {
+        final LegacySuggestionViewHolder vh = (LegacySuggestionViewHolder) holder;
+        vh.icon.setImageDrawable(card.getIconDrawable());
+        vh.title.setText(card.getTitleText());
+        vh.summary.setText(card.getSummaryText());
+        vh.itemView.setOnClickListener(v ->
+                mControllerRendererPool.getController(mContext,
+                        card.getCardType()).onPrimaryClick(card));
+    }
+
+    private static class LegacySuggestionViewHolder extends RecyclerView.ViewHolder {
+
+        public final ImageView icon;
+        public final TextView title;
+        public final TextView summary;
+
+        public LegacySuggestionViewHolder(View itemView) {
+            super(itemView);
+            icon = itemView.findViewById(android.R.id.icon);
+            title = itemView.findViewById(android.R.id.title);
+            summary = itemView.findViewById(android.R.id.summary);
+        }
+    }
+}
+
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
index c2bf536..5fc4473 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
@@ -45,6 +45,7 @@
  */
 public class SliceContextualCardRenderer implements ContextualCardRenderer,
         SliceView.OnSliceActionListener {
+    public static final int VIEW_TYPE = R.layout.homepage_slice_tile;
 
     private static final String TAG = "SliceCardRenderer";
 
@@ -61,8 +62,8 @@
     }
 
     @Override
-    public int getViewType() {
-        return R.layout.homepage_slice_tile;
+    public int getViewType(boolean isHalfWidth) {
+        return VIEW_TYPE;
     }
 
     @Override
diff --git a/src/com/android/settings/location/LocationPreferenceController.java b/src/com/android/settings/location/LocationPreferenceController.java
deleted file mode 100644
index 0efc2b1..0000000
--- a/src/com/android/settings/location/LocationPreferenceController.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settings.location;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.location.LocationManager;
-import android.provider.Settings.Secure;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.R;
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnPause;
-import com.android.settingslib.core.lifecycle.events.OnResume;
-
-public class LocationPreferenceController extends AbstractPreferenceController
-        implements PreferenceControllerMixin, LifecycleObserver, OnResume, OnPause {
-
-    private static final String KEY_LOCATION = "location";
-    private Context mContext;
-    private Preference mPreference;
-
-    @VisibleForTesting
-    BroadcastReceiver mLocationProvidersChangedReceiver;
-
-    public LocationPreferenceController(Context context, Lifecycle lifecycle) {
-        super(context);
-        mContext = context;
-        mLocationProvidersChangedReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (intent.getAction().equals(LocationManager.PROVIDERS_CHANGED_ACTION)) {
-                    updateSummary();
-                }
-            }
-        };
-        if (lifecycle != null) {
-            lifecycle.addObserver(this);
-        }
-    }
-
-    @Override
-    public void displayPreference(PreferenceScreen screen) {
-        super.displayPreference(screen);
-        mPreference = screen.findPreference(KEY_LOCATION);
-    }
-
-    @Override
-    public void onResume() {
-        if (mLocationProvidersChangedReceiver != null) {
-            mContext.registerReceiver(mLocationProvidersChangedReceiver, new IntentFilter(
-                    LocationManager.PROVIDERS_CHANGED_ACTION));
-        }
-    }
-
-    @Override
-    public void onPause() {
-        if (mLocationProvidersChangedReceiver != null) {
-            mContext.unregisterReceiver(mLocationProvidersChangedReceiver);
-        }
-    }
-
-    @Override
-    public void updateState(Preference preference) {
-        preference.setSummary(getLocationSummary(mContext));
-    }
-
-    @Override
-    public String getPreferenceKey() {
-        return KEY_LOCATION;
-    }
-
-    @Override
-    public boolean isAvailable() {
-        return true;
-    }
-
-    public void updateSummary() {
-        updateState(mPreference);
-    }
-
-    public static String getLocationSummary(Context context) {
-        int mode = Secure.getInt(context.getContentResolver(),
-                Secure.LOCATION_MODE, Secure.LOCATION_MODE_OFF);
-        if (mode != Secure.LOCATION_MODE_OFF) {
-            return context.getString(R.string.location_on_summary);
-        }
-        return context.getString(R.string.location_off_summary);
-    }
-}
diff --git a/src/com/android/settings/location/LocationSettings.java b/src/com/android/settings/location/LocationSettings.java
index 758ca57..53076e8 100644
--- a/src/com/android/settings/location/LocationSettings.java
+++ b/src/com/android/settings/location/LocationSettings.java
@@ -133,34 +133,6 @@
         return controllers;
     }
 
-    private static class SummaryProvider implements SummaryLoader.SummaryProvider {
-
-        private final Context mContext;
-        private final SummaryLoader mSummaryLoader;
-
-        public SummaryProvider(Context context, SummaryLoader summaryLoader) {
-            mContext = context;
-            mSummaryLoader = summaryLoader;
-        }
-
-        @Override
-        public void setListening(boolean listening) {
-            if (listening) {
-                mSummaryLoader.setSummary(
-                    this, LocationPreferenceController.getLocationSummary(mContext));
-            }
-        }
-    }
-
-    public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY
-            = new SummaryLoader.SummaryProviderFactory() {
-        @Override
-        public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity,
-                                                                   SummaryLoader summaryLoader) {
-            return new SummaryProvider(activity, summaryLoader);
-        }
-    };
-
     /**
      * For Search.
      */
diff --git a/src/com/android/settings/network/ApnPreference.java b/src/com/android/settings/network/ApnPreference.java
index 412259b..a7fbb6e 100755
--- a/src/com/android/settings/network/ApnPreference.java
+++ b/src/com/android/settings/network/ApnPreference.java
@@ -25,18 +25,15 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.widget.CompoundButton;
 import android.widget.RadioButton;
-import android.widget.RelativeLayout;
 
 import androidx.preference.Preference;
 import androidx.preference.PreferenceViewHolder;
 
 import com.android.settings.R;
 
-public class ApnPreference extends Preference implements
-        CompoundButton.OnCheckedChangeListener, OnClickListener {
+public class ApnPreference extends Preference implements CompoundButton.OnCheckedChangeListener {
     final static String TAG = "ApnPreference";
 
     private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -82,11 +79,6 @@
                 rb.setVisibility(View.GONE);
             }
         }
-
-        View textLayout = view.findViewById(R.id.text_layout);
-        if ((textLayout != null) && textLayout instanceof RelativeLayout) {
-            textLayout.setOnClickListener(this);
-        }
     }
 
     public boolean isChecked() {
@@ -116,16 +108,16 @@
         }
     }
 
-    public void onClick(android.view.View v) {
-        if ((v != null) && (R.id.text_layout == v.getId())) {
-            Context context = getContext();
-            if (context != null) {
-                int pos = Integer.parseInt(getKey());
-                Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos);
-                Intent editIntent = new Intent(Intent.ACTION_EDIT, url);
-                editIntent.putExtra(ApnSettings.SUB_ID, mSubId);
-                context.startActivity(editIntent);
-            }
+    @Override
+    protected void onClick() {
+        super.onClick();
+        Context context = getContext();
+        if (context != null) {
+            int pos = Integer.parseInt(getKey());
+            Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos);
+            Intent editIntent = new Intent(Intent.ACTION_EDIT, url);
+            editIntent.putExtra(ApnSettings.SUB_ID, mSubId);
+            context.startActivity(editIntent);
         }
     }
 
diff --git a/src/com/android/settings/network/ApnSettings.java b/src/com/android/settings/network/ApnSettings.java
index beeaab3..a71dfaa 100755
--- a/src/com/android/settings/network/ApnSettings.java
+++ b/src/com/android/settings/network/ApnSettings.java
@@ -21,7 +21,6 @@
 import android.app.ProgressDialog;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
-import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
@@ -65,8 +64,7 @@
 
 import java.util.ArrayList;
 
-public class ApnSettings extends RestrictedSettingsFragment implements
-        Preference.OnPreferenceChangeListener {
+public class ApnSettings extends RestrictedSettingsFragment {
     static final String TAG = "ApnSettings";
 
     public static final String EXTRA_POSITION = "position";
@@ -313,7 +311,6 @@
                 pref.setTitle(name);
                 pref.setSummary(apn);
                 pref.setPersistent(false);
-                pref.setOnPreferenceChangeListener(this);
                 pref.setSubId(subId);
 
                 boolean selectable = ((type == null) || !type.equals("mms"));
@@ -405,14 +402,6 @@
         startActivity(intent);
     }
 
-    @Override
-    public boolean onPreferenceTreeClick(Preference preference) {
-        int pos = Integer.parseInt(preference.getKey());
-        Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos);
-        startActivity(new Intent(Intent.ACTION_EDIT, url));
-        return true;
-    }
-
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         Log.d(TAG, "onPreferenceChange(): Preference - " + preference
                 + ", newValue - " + newValue + ", newValue type - "
diff --git a/src/com/android/settings/network/telephony/ApnPreferenceController.java b/src/com/android/settings/network/telephony/ApnPreferenceController.java
index e02d9d4..f5cd140 100644
--- a/src/com/android/settings/network/telephony/ApnPreferenceController.java
+++ b/src/com/android/settings/network/telephony/ApnPreferenceController.java
@@ -62,12 +62,13 @@
     public int getAvailabilityStatus() {
         final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId);
         final boolean isCdmaApn = MobileNetworkUtils.isCdmaOptions(mContext, mSubId)
+                && carrierConfig != null
                 && carrierConfig.getBoolean(CarrierConfigManager.KEY_SHOW_APN_SETTING_CDMA_BOOL);
         final boolean isGsmApn = MobileNetworkUtils.isGsmOptions(mContext, mSubId)
+                && carrierConfig != null
                 && carrierConfig.getBoolean(CarrierConfigManager.KEY_APN_EXPAND_BOOL);
 
-        return carrierConfig != null
-                && (isCdmaApn || isGsmApn)
+        return isCdmaApn || isGsmApn
                 ? AVAILABLE
                 : CONDITIONALLY_UNAVAILABLE;
     }
diff --git a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java
index 46773dc..b323f91 100644
--- a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java
+++ b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java
@@ -45,7 +45,8 @@
     private PersistableBundle mPersistableBundle;
     private int mSubId;
     private boolean mIsGlobalCdma;
-    private boolean mShow4GForLTE;
+    @VisibleForTesting
+    boolean mShow4GForLTE;
 
     public EnabledNetworkModePreferenceController(Context context, String key) {
         super(context, key);
@@ -111,12 +112,10 @@
                 mTelephonyManager.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE;
         mIsGlobalCdma = isLteOnCdma
                 && mPersistableBundle.getBoolean(CarrierConfigManager.KEY_SHOW_CDMA_CHOICES_BOOL);
-        initShow4GForLTE();
-    }
-
-    @VisibleForTesting
-    void initShow4GForLTE() {
-        mShow4GForLTE = MobileNetworkUtils.isShow4GForLTE(mContext);
+        mShow4GForLTE = mPersistableBundle != null
+                ? mPersistableBundle.getBoolean(
+                CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL)
+                : false;
     }
 
     private int getPreferredNetworkMode() {
@@ -181,7 +180,7 @@
                 preference.setEntryValues(
                         R.array.enabled_networks_tdscdma_values);
             } else if (!carrierConfig.getBoolean(CarrierConfigManager.KEY_PREFER_2G_BOOL)
-                    && !resources.getBoolean(R.bool.config_enabled_lte)) {
+                    && !carrierConfig.getBoolean(CarrierConfigManager.KEY_LTE_ENABLED_BOOL)) {
                 preference.setEntries(R.array.enabled_networks_except_gsm_lte_choices);
                 preference.setEntryValues(R.array.enabled_networks_except_gsm_lte_values);
             } else if (!carrierConfig.getBoolean(CarrierConfigManager.KEY_PREFER_2G_BOOL)) {
@@ -191,7 +190,7 @@
                 preference.setEntries(select);
                 preference.setEntryValues(
                         R.array.enabled_networks_except_gsm_values);
-            } else if (!resources.getBoolean(R.bool.config_enabled_lte)) {
+            } else if (!carrierConfig.getBoolean(CarrierConfigManager.KEY_LTE_ENABLED_BOOL)) {
                 preference.setEntries(
                         R.array.enabled_networks_except_lte_choices);
                 preference.setEntryValues(
diff --git a/src/com/android/settings/network/telephony/MobileNetworkUtils.java b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
index e85c917..dc184d3 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkUtils.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
@@ -27,6 +27,7 @@
 import android.os.PersistableBundle;
 import android.os.SystemProperties;
 import android.provider.Settings;
+import android.service.carrier.CarrierMessagingService;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
@@ -329,28 +330,11 @@
      * settings
      */
     public static boolean isWorldMode(Context context, int subId) {
-        final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class)
-                .createForSubscriptionId(subId);
-        boolean worldModeOn = false;
-        final String configString = context.getString(R.string.config_world_mode);
-
-        if (!TextUtils.isEmpty(configString)) {
-            String[] configArray = configString.split(";");
-            // Check if we have World mode configuration set to True only or config is set to True
-            // and SIM GID value is also set and matches to the current SIM GID.
-            if (configArray != null &&
-                    ((configArray.length == 1 && configArray[0].equalsIgnoreCase("true"))
-                            || (configArray.length == 2 && !TextUtils.isEmpty(configArray[1])
-                            && telephonyManager != null
-                            && configArray[1].equalsIgnoreCase(
-                            telephonyManager.getGroupIdLevel1())))) {
-                worldModeOn = true;
-            }
-        }
-
-        Log.d(TAG, "isWorldMode=" + worldModeOn);
-
-        return worldModeOn;
+        final PersistableBundle carrierConfig = context.getSystemService(
+                CarrierConfigManager.class).getConfigForSubId(subId);
+        return carrierConfig == null
+                ? false
+                : carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_MODE_ENABLED_BOOL);
     }
 
     /**
@@ -386,19 +370,6 @@
         return false;
     }
 
-    public static boolean isShow4GForLTE(Context context) {
-        //TODO(b/117882862): move this to framework
-        try {
-            Context con = context.createPackageContext("com.android.systemui", 0);
-            int id = con.getResources().getIdentifier("config_show4GForLTE",
-                    "bool", "com.android.systemui");
-            return con.getResources().getBoolean(id);
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.e(TAG, "NameNotFoundException for show4GFotLTE");
-            return false;
-        }
-    }
-
     /**
      * Return {@code true} if Tdscdma is supported in current subscription
      */
@@ -409,14 +380,21 @@
 
     //TODO(b/117651939): move it to telephony
     private static boolean isTdscdmaSupported(Context context, TelephonyManager telephonyManager) {
-        if (context.getResources().getBoolean(R.bool.config_support_tdscdma)) {
+        final PersistableBundle carrierConfig = context.getSystemService(
+                CarrierConfigManager.class).getConfig();
+
+        if (carrierConfig == null) {
+            return false;
+        }
+
+        if (carrierConfig.getBoolean(CarrierConfigManager.KEY_SUPPORT_TDSCDMA_BOOL)) {
             return true;
         }
 
         String operatorNumeric = telephonyManager.getServiceState().getOperatorNumeric();
-        String[] numericArray = context.getResources().getStringArray(
-                R.array.config_support_tdscdma_roaming_on_networks);
-        if (numericArray.length == 0 || operatorNumeric == null) {
+        String[] numericArray = carrierConfig.getStringArray(
+                CarrierConfigManager.KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY);
+        if (numericArray == null || operatorNumeric == null) {
             return false;
         }
         for (String numeric : numericArray) {
@@ -426,4 +404,4 @@
         }
         return false;
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/notification/ZenAutomaticRuleHeaderPreferenceController.java b/src/com/android/settings/notification/ZenAutomaticRuleHeaderPreferenceController.java
index 18415c7..41eb111 100644
--- a/src/com/android/settings/notification/ZenAutomaticRuleHeaderPreferenceController.java
+++ b/src/com/android/settings/notification/ZenAutomaticRuleHeaderPreferenceController.java
@@ -24,13 +24,10 @@
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
 import android.service.notification.ZenModeConfig;
+import android.text.TextUtils;
 import android.util.Slog;
 import android.view.View;
 
-import androidx.fragment.app.Fragment;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceFragmentCompat;
-
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
 import com.android.settings.applications.LayoutPreference;
@@ -38,6 +35,10 @@
 import com.android.settings.widget.EntityHeaderController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 
+import androidx.fragment.app.Fragment;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragmentCompat;
+
 public class ZenAutomaticRuleHeaderPreferenceController extends AbstractZenModePreferenceController
         implements PreferenceControllerMixin {
 
@@ -128,9 +129,13 @@
 
         @Override
         public void onOk(String ruleName, Fragment parent) {
+            if (TextUtils.equals(ruleName, mRule.getName())) {
+                return;
+            }
             mMetricsFeatureProvider.action(mContext,
                     MetricsProto.MetricsEvent.ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK);
             mRule.setName(ruleName);
+            mRule.setModified(true);
             mBackend.setZenRule(mId, mRule);
         }
     }
diff --git a/src/com/android/settings/print/PrintJobMessagePreferenceController.java b/src/com/android/settings/print/PrintJobMessagePreferenceController.java
new file mode 100644
index 0000000..9573e5d
--- /dev/null
+++ b/src/com/android/settings/print/PrintJobMessagePreferenceController.java
@@ -0,0 +1,47 @@
+/*
+ * 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.content.Context;
+import android.print.PrintJob;
+import android.print.PrintJobInfo;
+import android.text.TextUtils;
+
+public class PrintJobMessagePreferenceController extends PrintJobPreferenceControllerBase {
+
+    public PrintJobMessagePreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    protected void updateUi() {
+        final PrintJob printJob = getPrintJob();
+
+        if (printJob == null) {
+            mFragment.finish();
+            return;
+        }
+
+        if (printJob.isCancelled() || printJob.isCompleted()) {
+            mFragment.finish();
+            return;
+        }
+
+        final PrintJobInfo info = printJob.getInfo();
+        final CharSequence status = info.getStatus(mContext.getPackageManager());
+        mPreference.setVisible(!TextUtils.isEmpty(status));
+        mPreference.setSummary(status);
+    }
+}
diff --git a/src/com/android/settings/print/PrintJobPreferenceController.java b/src/com/android/settings/print/PrintJobPreferenceController.java
new file mode 100644
index 0000000..0eff0d6
--- /dev/null
+++ b/src/com/android/settings/print/PrintJobPreferenceController.java
@@ -0,0 +1,115 @@
+/*
+ * 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.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.print.PrintJob;
+import android.print.PrintJobInfo;
+import android.text.format.DateUtils;
+
+import com.android.settings.R;
+
+import java.text.DateFormat;
+
+public class PrintJobPreferenceController extends PrintJobPreferenceControllerBase {
+
+    public PrintJobPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    protected void updateUi() {
+        final PrintJob printJob = getPrintJob();
+
+        if (printJob == null) {
+            mFragment.finish();
+            return;
+        }
+
+        if (printJob.isCancelled() || printJob.isCompleted()) {
+            mFragment.finish();
+            return;
+        }
+
+        PrintJobInfo info = printJob.getInfo();
+
+        switch (info.getState()) {
+            case PrintJobInfo.STATE_CREATED: {
+                mPreference.setTitle(mContext.getString(
+                        R.string.print_configuring_state_title_template, info.getLabel()));
+            }
+            break;
+            case PrintJobInfo.STATE_QUEUED:
+            case PrintJobInfo.STATE_STARTED: {
+                if (!printJob.getInfo().isCancelling()) {
+                    mPreference.setTitle(mContext.getString(
+                            R.string.print_printing_state_title_template, info.getLabel()));
+                } else {
+                    mPreference.setTitle(mContext.getString(
+                            R.string.print_cancelling_state_title_template, info.getLabel()));
+                }
+            }
+            break;
+
+            case PrintJobInfo.STATE_FAILED: {
+                mPreference.setTitle(mContext.getString(
+                        R.string.print_failed_state_title_template, info.getLabel()));
+            }
+            break;
+
+            case PrintJobInfo.STATE_BLOCKED: {
+                if (!printJob.getInfo().isCancelling()) {
+                    mPreference.setTitle(mContext.getString(
+                            R.string.print_blocked_state_title_template, info.getLabel()));
+                } else {
+                    mPreference.setTitle(mContext.getString(
+                            R.string.print_cancelling_state_title_template, info.getLabel()));
+                }
+            }
+            break;
+        }
+
+        mPreference.setSummary(mContext.getString(R.string.print_job_summary,
+                info.getPrinterName(), DateUtils.formatSameDayTime(
+                        info.getCreationTime(), info.getCreationTime(), DateFormat.SHORT,
+                        DateFormat.SHORT)));
+
+        TypedArray a = mContext.obtainStyledAttributes(new int[]{
+                android.R.attr.colorControlNormal});
+        int tintColor = a.getColor(0, 0);
+        a.recycle();
+
+        switch (info.getState()) {
+            case PrintJobInfo.STATE_QUEUED:
+            case PrintJobInfo.STATE_STARTED: {
+                Drawable icon = mContext.getDrawable(com.android.internal.R.drawable.ic_print);
+                icon.setTint(tintColor);
+                mPreference.setIcon(icon);
+                break;
+            }
+
+            case PrintJobInfo.STATE_FAILED:
+            case PrintJobInfo.STATE_BLOCKED: {
+                Drawable icon = mContext.getDrawable(
+                        com.android.internal.R.drawable.ic_print_error);
+                icon.setTint(tintColor);
+                mPreference.setIcon(icon);
+                break;
+            }
+        }
+    }
+}
diff --git a/src/com/android/settings/print/PrintJobPreferenceControllerBase.java b/src/com/android/settings/print/PrintJobPreferenceControllerBase.java
new file mode 100644
index 0000000..0726a19
--- /dev/null
+++ b/src/com/android/settings/print/PrintJobPreferenceControllerBase.java
@@ -0,0 +1,99 @@
+/*
+ * 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.content.Context;
+import android.print.PrintJob;
+import android.print.PrintJobId;
+import android.print.PrintManager;
+import android.util.Log;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+
+public abstract class PrintJobPreferenceControllerBase extends BasePreferenceController implements
+        LifecycleObserver, OnStart, OnStop, PrintManager.PrintJobStateChangeListener {
+    private static final String TAG = "PrintJobPrefCtrlBase";
+
+    private static final String EXTRA_PRINT_JOB_ID = "EXTRA_PRINT_JOB_ID";
+
+    private final PrintManager mPrintManager;
+    protected Preference mPreference;
+    protected PrintJobSettingsFragment mFragment;
+    protected PrintJobId mPrintJobId;
+
+    public PrintJobPreferenceControllerBase(Context context, String key) {
+        super(context, key);
+        mPrintManager = ((PrintManager) mContext.getSystemService(
+                Context.PRINT_SERVICE)).getGlobalPrintManagerForUser(mContext.getUserId());
+    }
+
+    @Override
+    public void onStart() {
+        mPrintManager.addPrintJobStateChangeListener(this);
+        updateUi();
+    }
+
+    @Override
+    public void onStop() {
+        mPrintManager.removePrintJobStateChangeListener(this);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public void onPrintJobStateChanged(PrintJobId printJobId) {
+        updateUi();
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreference = screen.findPreference(getPreferenceKey());
+    }
+
+    public void init(PrintJobSettingsFragment fragment) {
+        mFragment = fragment;
+        processArguments();
+    }
+
+    protected PrintJob getPrintJob() {
+        return mPrintManager.getPrintJob(mPrintJobId);
+    }
+
+    protected abstract void updateUi();
+
+    private void processArguments() {
+        String printJobId = mFragment.getArguments().getString(EXTRA_PRINT_JOB_ID);
+        if (printJobId == null) {
+            printJobId = mFragment.getActivity().getIntent().getStringExtra(EXTRA_PRINT_JOB_ID);
+
+            if (printJobId == null) {
+                Log.w(TAG, EXTRA_PRINT_JOB_ID + " not set");
+                mFragment.finish();
+                return;
+            }
+        }
+        mPrintJobId = PrintJobId.unflattenFromString(printJobId);
+    }
+}
diff --git a/src/com/android/settings/print/PrintJobSettingsFragment.java b/src/com/android/settings/print/PrintJobSettingsFragment.java
index ba0172b..1d6ff5a 100644
--- a/src/com/android/settings/print/PrintJobSettingsFragment.java
+++ b/src/com/android/settings/print/PrintJobSettingsFragment.java
@@ -17,60 +17,42 @@
 package com.android.settings.print;
 
 import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.print.PrintJob;
-import android.print.PrintJobId;
-import android.print.PrintJobInfo;
-import android.print.PrintManager;
-import android.print.PrintManager.PrintJobStateChangeListener;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
-import android.util.Log;
-import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.preference.Preference;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
-
-import java.text.DateFormat;
+import com.android.settings.dashboard.DashboardFragment;
 
 /**
  * Fragment for management of a print job.
  */
-public class PrintJobSettingsFragment extends SettingsPreferenceFragment {
-    private static final String LOG_TAG = PrintJobSettingsFragment.class.getSimpleName();
+public class PrintJobSettingsFragment extends DashboardFragment {
+    private static final String TAG = "PrintJobSettingsFragment";
 
     private static final int MENU_ITEM_ID_CANCEL = 1;
     private static final int MENU_ITEM_ID_RESTART = 2;
 
-    private static final String EXTRA_PRINT_JOB_ID = "EXTRA_PRINT_JOB_ID";
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.print_job_settings;
+    }
 
-    private static final String PRINT_JOB_PREFERENCE = "print_job_preference";
-    private static final String PRINT_JOB_MESSAGE_PREFERENCE = "print_job_message_preference";
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
 
-    private final PrintJobStateChangeListener mPrintJobStateChangeListener =
-            new PrintJobStateChangeListener() {
-        @Override
-        public void onPrintJobStateChanged(PrintJobId printJobId) {
-            updateUi();
-        }
-    };
-
-    private PrintManager mPrintManager;
-
-    private Preference mPrintJobPreference;
-    private Preference mMessagePreference;
-
-    private PrintJobId mPrintJobId;
+    @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+        use(PrintJobPreferenceController.class).init(this);
+        use(PrintJobMessagePreferenceController.class).init(this);
+    }
 
     @Override
     public int getMetricsCategory() {
@@ -78,53 +60,16 @@
     }
 
     @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        View view = super.onCreateView(inflater, container, savedInstanceState);
-
-        addPreferencesFromResource(R.xml.print_job_settings);
-        mPrintJobPreference = findPreference(PRINT_JOB_PREFERENCE);
-        mMessagePreference = findPreference(PRINT_JOB_MESSAGE_PREFERENCE);
-
-        mPrintManager = ((PrintManager) getActivity().getSystemService(
-                Context.PRINT_SERVICE)).getGlobalPrintManagerForUser(
-                        getActivity().getUserId());
-
-        getActivity().getActionBar().setTitle(R.string.print_print_job);
-
-        processArguments();
-
-        setHasOptionsMenu(true);
-
-        return  view;
-    }
-
-    @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
         getListView().setEnabled(false);
     }
 
     @Override
-    public void onStart() {
-        super.onStart();
-        mPrintManager.addPrintJobStateChangeListener(
-                mPrintJobStateChangeListener);
-        updateUi();
-    }
-
-    @Override
-    public void onStop() {
-        super.onStop();
-        mPrintManager.removePrintJobStateChangeListener(
-                mPrintJobStateChangeListener);
-    }
-
-    @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         super.onCreateOptionsMenu(menu, inflater);
 
-        PrintJob printJob = getPrintJob();
+        final PrintJob printJob = use(PrintJobPreferenceController.class).getPrintJob();
         if (printJob == null) {
             return;
         }
@@ -144,7 +89,7 @@
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-        PrintJob printJob = getPrintJob();
+        final PrintJob printJob = use(PrintJobPreferenceController.class).getPrintJob();
 
         if (printJob != null) {
             switch (item.getItemId()) {
@@ -164,113 +109,4 @@
 
         return super.onOptionsItemSelected(item);
     }
-
-    private void processArguments() {
-        String printJobId = getArguments().getString(EXTRA_PRINT_JOB_ID);
-        if (printJobId == null) {
-            printJobId = getIntent().getStringExtra(EXTRA_PRINT_JOB_ID);
-
-            if (printJobId == null) {
-                Log.w(LOG_TAG, EXTRA_PRINT_JOB_ID + " not set");
-                finish();
-                return;
-            }
-        }
-
-
-        mPrintJobId = PrintJobId.unflattenFromString(printJobId);
-    }
-
-    private PrintJob getPrintJob() {
-        return mPrintManager.getPrintJob(mPrintJobId);
-    }
-
-    private void updateUi() {
-        PrintJob printJob = getPrintJob();
-
-        if (printJob == null) {
-            finish();
-            return;
-        }
-
-        if (printJob.isCancelled() || printJob.isCompleted()) {
-            finish();
-            return;
-        }
-
-        PrintJobInfo info = printJob.getInfo();
-
-        switch (info.getState()) {
-            case PrintJobInfo.STATE_CREATED: {
-                mPrintJobPreference.setTitle(getString(
-                        R.string.print_configuring_state_title_template, info.getLabel()));
-            } break;
-            case PrintJobInfo.STATE_QUEUED:
-            case PrintJobInfo.STATE_STARTED: {
-                if (!printJob.getInfo().isCancelling()) {
-                    mPrintJobPreference.setTitle(getString(
-                            R.string.print_printing_state_title_template, info.getLabel()));
-                } else {
-                    mPrintJobPreference.setTitle(getString(
-                            R.string.print_cancelling_state_title_template, info.getLabel()));
-                }
-            } break;
-
-            case PrintJobInfo.STATE_FAILED: {
-                mPrintJobPreference.setTitle(getString(
-                        R.string.print_failed_state_title_template, info.getLabel()));
-            } break;
-
-            case PrintJobInfo.STATE_BLOCKED: {
-                if (!printJob.getInfo().isCancelling()) {
-                    mPrintJobPreference.setTitle(getString(
-                            R.string.print_blocked_state_title_template, info.getLabel()));
-                } else {
-                    mPrintJobPreference.setTitle(getString(
-                            R.string.print_cancelling_state_title_template, info.getLabel()));
-                }
-            } break;
-        }
-
-        mPrintJobPreference.setSummary(getString(R.string.print_job_summary,
-                info.getPrinterName(), DateUtils.formatSameDayTime(
-                        info.getCreationTime(), info.getCreationTime(), DateFormat.SHORT,
-                        DateFormat.SHORT)));
-
-        TypedArray a = getActivity().obtainStyledAttributes(new int[]{
-                android.R.attr.colorControlNormal});
-        int tintColor = a.getColor(0, 0);
-        a.recycle();
-
-        switch (info.getState()) {
-            case PrintJobInfo.STATE_QUEUED:
-            case PrintJobInfo.STATE_STARTED: {
-                Drawable icon = getActivity().getDrawable(com.android.internal.R.drawable.ic_print);
-                icon.setTint(tintColor);
-                mPrintJobPreference.setIcon(icon);
-                break;
-            }
-
-            case PrintJobInfo.STATE_FAILED:
-            case PrintJobInfo.STATE_BLOCKED: {
-                Drawable icon = getActivity().getDrawable(
-                        com.android.internal.R.drawable.ic_print_error);
-                icon.setTint(tintColor);
-                mPrintJobPreference.setIcon(icon);
-                break;
-            }
-        }
-
-        CharSequence status = info.getStatus(getPackageManager());
-        if (!TextUtils.isEmpty(status)) {
-            if (getPreferenceScreen().findPreference(PRINT_JOB_MESSAGE_PREFERENCE) == null) {
-                getPreferenceScreen().addPreference(mMessagePreference);
-            }
-            mMessagePreference.setSummary(status);
-        } else {
-            getPreferenceScreen().removePreference(mMessagePreference);
-        }
-
-        getActivity().invalidateOptionsMenu();
-    }
 }
diff --git a/src/com/android/settings/search/SearchFeatureProvider.java b/src/com/android/settings/search/SearchFeatureProvider.java
index b2eb8bb..9c1f07c 100644
--- a/src/com/android/settings/search/SearchFeatureProvider.java
+++ b/src/com/android/settings/search/SearchFeatureProvider.java
@@ -25,9 +25,11 @@
 import android.content.Intent;
 import android.provider.Settings;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.Toolbar;
 
 import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.Utils;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.search.SearchIndexableResources;
 
@@ -64,6 +66,13 @@
         if (activity == null || toolbar == null) {
             return;
         }
+        if (!Utils.isPackageEnabled(activity, getSettingsIntelligencePkgName())) {
+            final ViewGroup parent = (ViewGroup)toolbar.getParent();
+            if (parent != null) {
+                parent.setVisibility(View.GONE);
+            }
+            return;
+        }
         // Please forgive me for what I am about to do.
         //
         // Need to make the navigation icon non-clickable so that the entire card is clickable
diff --git a/src/com/android/settings/search/actionbar/SearchMenuController.java b/src/com/android/settings/search/actionbar/SearchMenuController.java
index 81e9e60..0caa308 100644
--- a/src/com/android/settings/search/actionbar/SearchMenuController.java
+++ b/src/com/android/settings/search/actionbar/SearchMenuController.java
@@ -56,9 +56,15 @@
 
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        final Context context = mHost.getContext();
+        final String SettingsIntelligencePkgName = FeatureFactory.getFactory(context)
+                .getSearchFeatureProvider().getSettingsIntelligencePkgName();
         if (!Utils.isDeviceProvisioned(mHost.getContext())) {
             return;
         }
+        if (!Utils.isPackageEnabled(mHost.getContext(), SettingsIntelligencePkgName)) {
+            return;
+        }
         if (menu == null) {
             return;
         }
@@ -72,10 +78,8 @@
         searchItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
 
         searchItem.setOnMenuItemClickListener(target -> {
-            final Context context = mHost.getContext();
             final Intent intent = SearchFeatureProvider.SEARCH_UI_INTENT;
-            intent.setPackage(FeatureFactory.getFactory(mHost.getContext())
-                    .getSearchFeatureProvider().getSettingsIntelligencePkgName());
+            intent.setPackage(SettingsIntelligencePkgName);
             FeatureFactory.getFactory(context).getMetricsFeatureProvider()
                     .action(context, MetricsProto.MetricsEvent.ACTION_SEARCH_RESULTS);
             mHost.startActivityForResult(intent, 0 /* requestCode */);
diff --git a/src/com/android/settings/security/SecuritySettings.java b/src/com/android/settings/security/SecuritySettings.java
index eb0d6f1..e00d387 100644
--- a/src/com/android/settings/security/SecuritySettings.java
+++ b/src/com/android/settings/security/SecuritySettings.java
@@ -29,7 +29,6 @@
 import com.android.settings.biometrics.fingerprint.FingerprintStatusPreferenceController;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.enterprise.EnterprisePrivacyPreferenceController;
-import com.android.settings.location.LocationPreferenceController;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.security.trustagent.ManageTrustAgentsPreferenceController;
 import com.android.settings.security.trustagent.TrustAgentListPreferenceController;
@@ -105,7 +104,6 @@
     private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
             Lifecycle lifecycle, SecuritySettings host) {
         final List<AbstractPreferenceController> controllers = new ArrayList<>();
-        controllers.add(new LocationPreferenceController(context, lifecycle));
         controllers.add(new EnterprisePrivacyPreferenceController(context));
         controllers.add(new ManageTrustAgentsPreferenceController(context));
         controllers.add(new ScreenPinningPreferenceController(context));
diff --git a/src/com/android/settings/slices/CopyableSlice.java b/src/com/android/settings/slices/CopyableSlice.java
new file mode 100644
index 0000000..31fc151
--- /dev/null
+++ b/src/com/android/settings/slices/CopyableSlice.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.slices;
+
+/**
+ * Provide the copy ability for preference controller to copy the data to the clipboard.
+ */
+public interface CopyableSlice {
+    /**
+     * Copy the key slice information to the clipboard.
+     * It is highly recommended to show the toast to notify users when implemented this function.
+     */
+    void copy();
+}
diff --git a/src/com/android/settings/slices/CustomSliceable.java b/src/com/android/settings/slices/CustomSliceable.java
index e09cc73..b538b89 100644
--- a/src/com/android/settings/slices/CustomSliceable.java
+++ b/src/com/android/settings/slices/CustomSliceable.java
@@ -91,11 +91,12 @@
 
     /**
      * Settings Slices which can represent component lists that are updatable by the
-     * {@link SliceBackgroundWorker} returned here.
+     * {@link SliceBackgroundWorker} class returned here.
      *
-     * @return a {@link SliceBackgroundWorker} for fetching the list of results in the background.
+     * @return a {@link SliceBackgroundWorker} class for fetching the list of results in the
+     * background.
      */
-    default SliceBackgroundWorker getBackgroundWorker() {
+    default Class<? extends SliceBackgroundWorker> getBackgroundWorkerClass() {
         return null;
     }
 
diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java
index 3911603..fa669bb 100644
--- a/src/com/android/settings/slices/SettingsSliceProvider.java
+++ b/src/com/android/settings/slices/SettingsSliceProvider.java
@@ -52,7 +52,6 @@
 import com.android.settingslib.SliceBroadcastRelay;
 import com.android.settingslib.utils.ThreadUtils;
 
-import java.io.IOException;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -108,6 +107,12 @@
             "com.android.settings.slice.action.SLIDER_CHANGED";
 
     /**
+     * Action passed for copy data for the Copyable Slices.
+     */
+    public static final String ACTION_COPY =
+            "com.android.settings.slice.action.COPY";
+
+    /**
      * Intent Extra passed for the key identifying the Setting Slice.
      */
     public static final String EXTRA_SLICE_KEY = "com.android.settings.slice.extra.key";
@@ -134,8 +139,7 @@
 
     final Set<Uri> mRegisteredUris = new ArraySet<>();
 
-    final Map<Uri, SliceBackgroundWorker> mWorkerMap = new ArrayMap<>();
-    final Set<SliceBackgroundWorker> mLiveWorkers = new ArraySet<>();
+    final Map<Uri, SliceBackgroundWorker> mPinnedWorkers = new ArrayMap<>();
 
     public SettingsSliceProvider() {
         super(READ_SEARCH_INDEXABLES);
@@ -365,45 +369,37 @@
     }
 
     private void startBackgroundWorker(CustomSliceable sliceable) {
-        final SliceBackgroundWorker worker = sliceable.getBackgroundWorker();
-        if (worker == null) {
+        final Class workerClass = sliceable.getBackgroundWorkerClass();
+        if (workerClass == null) {
             return;
         }
 
         final Uri uri = sliceable.getUri();
-        if (mWorkerMap.containsKey(uri)) {
+        if (mPinnedWorkers.containsKey(uri)) {
             return;
         }
 
         Log.d(TAG, "Starting background worker for: " + uri);
-        mWorkerMap.put(uri, worker);
-        if (!mLiveWorkers.contains(worker)) {
-            mLiveWorkers.add(worker);
-        }
+        final SliceBackgroundWorker worker = SliceBackgroundWorker.getInstance(
+                getContext(), sliceable);
+        mPinnedWorkers.put(uri, worker);
         worker.onSlicePinned();
     }
 
     private void stopBackgroundWorker(Uri uri) {
-        final SliceBackgroundWorker worker = mWorkerMap.get(uri);
+        final SliceBackgroundWorker worker = mPinnedWorkers.get(uri);
         if (worker != null) {
             Log.d(TAG, "Stopping background worker for: " + uri);
             worker.onSliceUnpinned();
-            mWorkerMap.remove(uri);
+            mPinnedWorkers.remove(uri);
         }
     }
 
     @Override
     public void shutdown() {
-        for (SliceBackgroundWorker worker : mLiveWorkers) {
-            ThreadUtils.postOnMainThread(() -> {
-                try {
-                    worker.close();
-                } catch (IOException e) {
-                    Log.w(TAG, "Exception when shutting down worker", e);
-                }
-            });
-        }
-        mLiveWorkers.clear();
+        ThreadUtils.postOnMainThread(() -> {
+            SliceBackgroundWorker.shutdown();
+        });
     }
 
     private List<Uri> buildUrisFromKeys(List<String> keys, String authority) {
@@ -532,4 +528,4 @@
         }
         return new String[0];
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/slices/SliceBackgroundWorker.java b/src/com/android/settings/slices/SliceBackgroundWorker.java
index 422fcc7..a663ece 100644
--- a/src/com/android/settings/slices/SliceBackgroundWorker.java
+++ b/src/com/android/settings/slices/SliceBackgroundWorker.java
@@ -17,36 +17,87 @@
 package com.android.settings.slices;
 
 import android.annotation.MainThread;
-import android.content.ContentResolver;
+import android.content.Context;
 import android.net.Uri;
+import android.util.ArrayMap;
+import android.util.Log;
 
 import java.io.Closeable;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 /**
  * The Slice background worker is used to make Settings Slices be able to work with data that is
  * changing continuously, e.g. available Wi-Fi networks.
  *
- * The background worker will be started at {@link SettingsSliceProvider#onSlicePinned(Uri)}, and be
- * stopped at {@link SettingsSliceProvider#onSliceUnpinned(Uri)}.
+ * The background worker will be started at {@link SettingsSliceProvider#onSlicePinned(Uri)}, be
+ * stopped at {@link SettingsSliceProvider#onSliceUnpinned(Uri)}, and be closed at {@link
+ * SettingsSliceProvider#shutdown()}.
  *
  * {@link SliceBackgroundWorker} caches the results, uses the cache to compare if there is any data
  * changed, and then notifies the Slice {@link Uri} to update.
+ *
+ * It also stores all instances of all workers to ensure each worker is a Singleton.
  */
 public abstract class SliceBackgroundWorker<E> implements Closeable {
 
-    private final ContentResolver mContentResolver;
+    private static final String TAG = "SliceBackgroundWorker";
+
+    private static final Map<Uri, SliceBackgroundWorker> LIVE_WORKERS = new ArrayMap<>();
+
+    private final Context mContext;
     private final Uri mUri;
 
     private List<E> mCachedResults;
 
-    protected SliceBackgroundWorker(ContentResolver cr, Uri uri) {
-        mContentResolver = cr;
+    protected SliceBackgroundWorker(Context context, Uri uri) {
+        mContext = context;
         mUri = uri;
     }
 
     /**
+     * Returns the singleton instance of the {@link SliceBackgroundWorker} for specified {@link
+     * CustomSliceable}
+     */
+    public static SliceBackgroundWorker getInstance(Context context, CustomSliceable sliceable) {
+        final Uri uri = sliceable.getUri();
+        final Class<? extends SliceBackgroundWorker> workerClass =
+                sliceable.getBackgroundWorkerClass();
+        SliceBackgroundWorker worker = LIVE_WORKERS.get(uri);
+        if (worker == null) {
+            worker = createInstance(context, uri, workerClass);
+            LIVE_WORKERS.put(uri, worker);
+        }
+        return worker;
+    }
+
+    private static SliceBackgroundWorker createInstance(Context context, Uri uri,
+            Class<? extends SliceBackgroundWorker> clazz) {
+        Log.d(TAG, "create instance: " + clazz);
+        try {
+            return clazz.getConstructor(Context.class, Uri.class).newInstance(context, uri);
+        } catch (NoSuchMethodException | IllegalAccessException | InstantiationException |
+                InvocationTargetException e) {
+            throw new IllegalStateException(
+                    "Invalid slice background worker: " + clazz, e);
+        }
+    }
+
+    static void shutdown() {
+        for (SliceBackgroundWorker worker : LIVE_WORKERS.values()) {
+            try {
+                worker.close();
+            } catch (IOException e) {
+                Log.w(TAG, "Shutting down worker failed", e);
+            }
+        }
+        LIVE_WORKERS.clear();
+    }
+
+    /**
      * Called when the Slice is pinned. This is the place to register callbacks or initialize scan
      * tasks.
      */
@@ -83,7 +134,7 @@
 
         if (needNotify) {
             mCachedResults = results;
-            mContentResolver.notifyChange(mUri, null);
+            mContext.getContentResolver().notifyChange(mUri, null);
         }
     }
 }
diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java
index e9e9d2c..4b86f33 100644
--- a/src/com/android/settings/slices/SliceBroadcastReceiver.java
+++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java
@@ -24,6 +24,7 @@
 import static com.android.settings.notification.ZenModeSliceBuilder.ACTION_ZEN_MODE_SLICE_CHANGED;
 import static com.android.settings.slices.SettingsSliceProvider.ACTION_SLIDER_CHANGED;
 import static com.android.settings.slices.SettingsSliceProvider.ACTION_TOGGLE_CHANGED;
+import static com.android.settings.slices.SettingsSliceProvider.ACTION_COPY;
 import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_KEY;
 import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_PLATFORM_DEFINED;
 import static com.android.settings.wifi.calling.WifiCallingSliceHelper.ACTION_WIFI_CALLING_CHANGED;
@@ -115,6 +116,9 @@
             case ACTION_FLASHLIGHT_SLICE_CHANGED:
                 FlashlightSliceBuilder.handleUriChange(context, intent);
                 break;
+            case ACTION_COPY:
+                handleCopyAction(context, key, isPlatformSlice);
+                break;
         }
     }
 
@@ -184,6 +188,29 @@
         updateUri(context, key, isPlatformSlice);
     }
 
+    private void handleCopyAction(Context context, String key, boolean isPlatformSlice) {
+        if (TextUtils.isEmpty(key)) {
+            throw new IllegalArgumentException("No key passed to Intent for controller");
+        }
+
+        final BasePreferenceController controller = getPreferenceController(context, key);
+
+        if (!(controller instanceof CopyableSlice)) {
+            throw new IllegalArgumentException(
+                    "Copyable action passed for a non-copyable key:" + key);
+        }
+
+        if (!controller.isAvailable()) {
+            Log.w(TAG, "Can't update " + key + " since the setting is unavailable");
+            if (!controller.hasAsyncUpdate()) {
+                updateUri(context, key, isPlatformSlice);
+            }
+            return;
+        }
+
+        ((CopyableSlice) controller).copy();
+    }
+
     /**
      * Log Slice value update events into MetricsFeatureProvider. The logging schema generally
      * follows the pattern in SharedPreferenceLogger.
diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java
index 2432cc6..f6cc57f 100644
--- a/src/com/android/settings/slices/SliceBuilderUtils.java
+++ b/src/com/android/settings/slices/SliceBuilderUtils.java
@@ -93,6 +93,10 @@
             return buildUnavailableSlice(context, sliceData);
         }
 
+        if (controller instanceof CopyableSlice) {
+            return buildCopyableSlice(context, sliceData, controller);
+        }
+
         switch (sliceData.getSliceType()) {
             case SliceData.SliceType.INTENT:
                 return buildIntentSlice(context, sliceData, controller);
@@ -324,6 +328,28 @@
                 .build();
     }
 
+    private static Slice buildCopyableSlice(Context context, SliceData sliceData,
+            BasePreferenceController controller) {
+        final SliceAction copyableAction = getCopyableAction(context, sliceData);
+        final PendingIntent contentIntent = getContentPendingIntent(context, sliceData);
+        final IconCompat icon = getSafeIcon(context, sliceData);
+        final SliceAction primaryAction = new SliceAction(contentIntent, icon,
+                sliceData.getTitle());
+        final CharSequence subtitleText = getSubtitleText(context, controller, sliceData);
+        @ColorInt final int color = Utils.getColorAccentDefaultColor(context);
+        final Set<String> keywords = buildSliceKeywords(sliceData);
+
+        return new ListBuilder(context, sliceData.getUri(), ListBuilder.INFINITY)
+                .setAccentColor(color)
+                .addRow(new RowBuilder()
+                        .setTitle(sliceData.getTitle())
+                        .setSubtitle(subtitleText)
+                        .setPrimaryAction(primaryAction)
+                        .addEndItem(copyableAction))
+                .setKeywords(keywords)
+                .build();
+    }
+
     private static BasePreferenceController getPreferenceController(Context context,
             String controllerClassName, String controllerKey) {
         try {
@@ -346,6 +372,14 @@
         return getActionIntent(context, SettingsSliceProvider.ACTION_SLIDER_CHANGED, sliceData);
     }
 
+    private static SliceAction getCopyableAction(Context context, SliceData sliceData) {
+        final PendingIntent intent = getActionIntent(context,
+                SettingsSliceProvider.ACTION_COPY, sliceData);
+        final IconCompat icon = IconCompat.createWithResource(context,
+                R.drawable.ic_content_copy_grey600_24dp);
+        return new SliceAction(intent, icon, sliceData.getTitle());
+    }
+
     private static boolean isValidSummary(Context context, CharSequence summary) {
         if (summary == null || TextUtils.isEmpty(summary.toString().trim())) {
             return false;
diff --git a/src/com/android/settings/tts/TextToSpeechSettings.java b/src/com/android/settings/tts/TextToSpeechSettings.java
index 866e5a8..cce871b 100644
--- a/src/com/android/settings/tts/TextToSpeechSettings.java
+++ b/src/com/android/settings/tts/TextToSpeechSettings.java
@@ -251,15 +251,20 @@
         mTts.setOnUtteranceProgressListener(new UtteranceProgressListener() {
             @Override
             public void onStart(String utteranceId) {
+                updateWidgetState(false);
             }
 
             @Override
             public void onDone(String utteranceId) {
+                updateWidgetState(true);
             }
 
             @Override
             public void onError(String utteranceId) {
                 Log.e(TAG, "Error while trying to synthesize sample text");
+                // Re-enable just in case, although there isn't much hope that following synthesis
+                // requests are going to succeed.
+                updateWidgetState(true);
             }
         });
     }
@@ -696,9 +701,11 @@
     }
 
     private void updateWidgetState(boolean enable) {
-        mActionButtons.setButton1Enabled(enable);
-        mDefaultRatePref.setEnabled(enable);
-        mDefaultPitchPref.setEnabled(enable);
+        getActivity().runOnUiThread(() -> {
+            mActionButtons.setButton1Enabled(enable);
+            mDefaultRatePref.setEnabled(enable);
+            mDefaultPitchPref.setEnabled(enable);
+        });
     }
 
     private void displayNetworkAlert() {
diff --git a/src/com/android/settings/users/AppRestrictionsFragment.java b/src/com/android/settings/users/AppRestrictionsFragment.java
index a4e0cff..5f899eb 100644
--- a/src/com/android/settings/users/AppRestrictionsFragment.java
+++ b/src/com/android/settings/users/AppRestrictionsFragment.java
@@ -450,7 +450,7 @@
     private void addLocationAppRestrictionsPreference(AppRestrictionsHelper.SelectableAppInfo app,
             AppRestrictionsPreference p) {
         String packageName = app.packageName;
-        p.setIcon(R.drawable.ic_settings_location);
+        p.setIcon(R.drawable.ic_preference_location);
         p.setKey(getKeyForPackage(packageName));
         ArrayList<RestrictionEntry> restrictions = RestrictionUtils.getRestrictions(
                 getActivity(), mUser);
diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java
index 4b93fc1..70837a6 100644
--- a/src/com/android/settings/wifi/WifiConfigController.java
+++ b/src/com/android/settings/wifi/WifiConfigController.java
@@ -454,6 +454,13 @@
         return false;
     }
 
+    boolean isValidSaePassword(String password) {
+        if (password.length() >= 1 && password.length() <= 63) {
+            return true;
+        }
+        return false;
+    }
+
     boolean isSubmittable() {
         boolean enabled = false;
         boolean passwordInvalid = false;
@@ -461,7 +468,9 @@
                 && ((mAccessPointSecurity == AccessPoint.SECURITY_WEP
                         && mPasswordView.length() == 0)
                     || (mAccessPointSecurity == AccessPoint.SECURITY_PSK
-                           && !isValidPsk(mPasswordView.getText().toString())))) {
+                           && !isValidPsk(mPasswordView.getText().toString()))
+                    || (mAccessPointSecurity == AccessPoint.SECURITY_SAE
+                        && !isValidSaePassword(mPasswordView.getText().toString())))) {
             passwordInvalid = true;
         }
         if ((mSsidView != null && mSsidView.length() == 0)
@@ -475,7 +484,9 @@
         } else {
             enabled = ipAndProxyFieldsAreValid();
         }
-        if (mAccessPointSecurity == AccessPoint.SECURITY_EAP && mEapCaCertSpinner != null
+        if ((mAccessPointSecurity == AccessPoint.SECURITY_EAP ||
+                mAccessPointSecurity == AccessPoint.SECURITY_EAP_SUITE_B)
+                && mEapCaCertSpinner != null
                 && mView.findViewById(R.id.l_ca_cert).getVisibility() != View.GONE) {
             String caCertSelection = (String) mEapCaCertSpinner.getSelectedItem();
             if (caCertSelection.equals(mUnspecifiedCertString)) {
@@ -492,7 +503,9 @@
                 enabled = false;
             }
         }
-        if (mAccessPointSecurity == AccessPoint.SECURITY_EAP && mEapUserCertSpinner != null
+        if ((mAccessPointSecurity == AccessPoint.SECURITY_EAP ||
+                mAccessPointSecurity == AccessPoint.SECURITY_EAP_SUITE_B)
+                && mEapUserCertSpinner != null
                 && mView.findViewById(R.id.l_user_cert).getVisibility() != View.GONE
                 && mEapUserCertSpinner.getSelectedItem().equals(mUnspecifiedCertString)) {
             // Disallow submit if the user has not selected a user certificate for an EAP network
@@ -590,8 +603,18 @@
                 break;
 
             case AccessPoint.SECURITY_EAP:
+            case AccessPoint.SECURITY_EAP_SUITE_B:
                 config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
                 config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
+                if (mAccessPointSecurity == AccessPoint.SECURITY_EAP_SUITE_B) {
+                    config.allowedKeyManagement.set(KeyMgmt.SUITE_B_192);
+                    config.requirePMF = true;
+                    config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
+                    config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
+                    config.allowedGroupMgmtCiphers.set(WifiConfiguration.GroupMgmtCipher
+                            .BIP_GMAC_256);
+                    config.allowedSuiteBCiphers.set(WifiConfiguration.SuiteBCipher.ECDHE_RSA);
+                }
                 config.enterpriseConfig = new WifiEnterpriseConfig();
                 int eapMethod = mEapMethodSpinner.getSelectedItemPosition();
                 int phase2Method = mPhase2Spinner.getSelectedItemPosition();
@@ -700,6 +723,20 @@
                     config.enterpriseConfig.setPassword(mPasswordView.getText().toString());
                 }
                 break;
+            case AccessPoint.SECURITY_SAE:
+                config.allowedKeyManagement.set(KeyMgmt.SAE);
+                config.requirePMF = true;
+                if (mPasswordView.length() != 0) {
+                    String password = mPasswordView.getText().toString();
+                    config.preSharedKey = '"' + password + '"';
+                }
+                break;
+
+            case AccessPoint.SECURITY_OWE:
+                config.allowedKeyManagement.set(KeyMgmt.OWE);
+                config.requirePMF = true;
+                break;
+
             default:
                 return null;
         }
@@ -851,7 +888,8 @@
     }
 
     private void showSecurityFields() {
-        if (mAccessPointSecurity == AccessPoint.SECURITY_NONE) {
+        if (mAccessPointSecurity == AccessPoint.SECURITY_NONE ||
+                  mAccessPointSecurity == AccessPoint.SECURITY_OWE) {
             mView.findViewById(R.id.security_fields).setVisibility(View.GONE);
             return;
         }
@@ -870,7 +908,8 @@
             }
         }
 
-        if (mAccessPointSecurity != AccessPoint.SECURITY_EAP) {
+        if (mAccessPointSecurity != AccessPoint.SECURITY_EAP &&
+                mAccessPointSecurity != AccessPoint.SECURITY_EAP_SUITE_B) {
             mView.findViewById(R.id.eap).setVisibility(View.GONE);
             return;
         }
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index 4837a88..1c9a5e1 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -112,9 +112,9 @@
     private static final String PREF_KEY_EMPTY_WIFI_LIST = "wifi_empty_list";
     private static final String PREF_KEY_CONNECTED_ACCESS_POINTS = "connected_access_point";
     private static final String PREF_KEY_ACCESS_POINTS = "access_points";
-    private static final String PREF_KEY_ADDITIONAL_SETTINGS = "additional_settings";
     private static final String PREF_KEY_CONFIGURE_WIFI_SETTINGS = "configure_settings";
     private static final String PREF_KEY_SAVED_NETWORKS = "saved_networks";
+    private static final String PREF_KEY_STATUS_MESSAGE = "wifi_status_message";
 
     private static boolean isVerboseLoggingEnabled() {
         return WifiTracker.sVerboseLogging || Log.isLoggable(TAG, Log.VERBOSE);
@@ -167,17 +167,19 @@
     private Bundle mAccessPointSavedState;
     private Bundle mWifiNfcDialogSavedState;
 
-    private WifiTracker mWifiTracker;
+    @VisibleForTesting
+    WifiTracker mWifiTracker;
     private String mOpenSsid;
 
     private AccessPointPreference.UserBadgeCache mUserBadgeCache;
 
     private PreferenceCategory mConnectedAccessPointPreferenceCategory;
     private PreferenceCategory mAccessPointsPreferenceCategory;
-    private PreferenceCategory mAdditionalSettingsPreferenceCategory;
     private Preference mAddPreference;
-    private Preference mConfigureWifiSettingsPreference;
-    private Preference mSavedNetworksPreference;
+    @VisibleForTesting
+    Preference mConfigureWifiSettingsPreference;
+    @VisibleForTesting
+    Preference mSavedNetworksPreference;
     private LinkablePreference mStatusMessagePreference;
 
     // For Search
@@ -229,8 +231,6 @@
                 (PreferenceCategory) findPreference(PREF_KEY_CONNECTED_ACCESS_POINTS);
         mAccessPointsPreferenceCategory =
                 (PreferenceCategory) findPreference(PREF_KEY_ACCESS_POINTS);
-        mAdditionalSettingsPreferenceCategory =
-                (PreferenceCategory) findPreference(PREF_KEY_ADDITIONAL_SETTINGS);
         mConfigureWifiSettingsPreference = findPreference(PREF_KEY_CONFIGURE_WIFI_SETTINGS);
         mSavedNetworksPreference = findPreference(PREF_KEY_SAVED_NETWORKS);
 
@@ -238,7 +238,7 @@
         mAddPreference = new Preference(prefContext);
         mAddPreference.setIcon(R.drawable.ic_menu_add);
         mAddPreference.setTitle(R.string.wifi_add_network);
-        mStatusMessagePreference = new LinkablePreference(prefContext);
+        mStatusMessagePreference = (LinkablePreference) findPreference(PREF_KEY_STATUS_MESSAGE);
 
         mUserBadgeCache = new AccessPointPreference.UserBadgeCache(getPackageManager());
     }
@@ -488,7 +488,8 @@
                 menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify);
                 NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity());
                 if (nfcAdapter != null && nfcAdapter.isEnabled() &&
-                        mSelectedAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
+                        (!(mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) ||
+                                (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_OWE))) {
                     // Only allow writing of NFC tags for password-protected networks.
                     menu.add(Menu.NONE, MENU_ID_WRITE_NFC, 0, R.string.wifi_menu_write_to_nfc);
                 }
@@ -506,7 +507,8 @@
                 boolean isSavedNetwork = mSelectedAccessPoint.isSaved();
                 if (isSavedNetwork) {
                     connect(mSelectedAccessPoint.getConfig(), isSavedNetwork);
-                } else if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) {
+                } else if ((mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) ||
+                        (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_OWE)) {
                     /** Bypass dialog for unsecured networks */
                     mSelectedAccessPoint.generateOpenNetworkConfig();
                     connect(mSelectedAccessPoint.getConfig(), isSavedNetwork);
@@ -552,7 +554,8 @@
              * networks, or Passpoint provided networks.
              */
             WifiConfiguration config = mSelectedAccessPoint.getConfig();
-            if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) {
+            if ((mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) ||
+                    (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_OWE)) {
                 mSelectedAccessPoint.generateOpenNetworkConfig();
                 connect(mSelectedAccessPoint.getConfig(), mSelectedAccessPoint.isSaved());
             } else if (mSelectedAccessPoint.isSaved() && config != null
@@ -692,14 +695,14 @@
 
             case WifiManager.WIFI_STATE_ENABLING:
                 removeConnectedAccessPointPreference();
-                mAccessPointsPreferenceCategory.removeAll();
+                removeAccessPointPreference();
                 addMessagePreference(R.string.wifi_starting);
                 setProgressBarVisible(true);
                 break;
 
             case WifiManager.WIFI_STATE_DISABLING:
                 removeConnectedAccessPointPreference();
-                mAccessPointsPreferenceCategory.removeAll();
+                removeAccessPointPreference();
                 addMessagePreference(R.string.wifi_stopping);
                 break;
 
@@ -746,7 +749,10 @@
         }
 
         boolean hasAvailableAccessPoints = false;
-        mAccessPointsPreferenceCategory.removePreference(mStatusMessagePreference);
+        mStatusMessagePreference.setVisible(false);
+        mConnectedAccessPointPreferenceCategory.setVisible(true);
+        mAccessPointsPreferenceCategory.setVisible(true);
+
         cacheRemoveAllPrefs(mAccessPointsPreferenceCategory);
 
         int index =
@@ -769,7 +775,8 @@
                 preference.setKey(key);
                 preference.setOrder(index);
                 if (mOpenSsid != null && mOpenSsid.equals(accessPoint.getSsidStr())
-                        && accessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
+                        && (accessPoint.getSecurity() != AccessPoint.SECURITY_NONE &&
+                        accessPoint.getSecurity() != AccessPoint.SECURITY_OWE)) {
                     if (!accessPoint.isSaved() || isDisabledByWrongPassword(accessPoint)) {
                         onPreferenceTreeClick(preference);
                         mOpenSsid = null;
@@ -960,26 +967,28 @@
         unregisterCaptivePortalNetworkCallback();
     }
 
-    private void setAdditionalSettingsSummaries() {
-        mAdditionalSettingsPreferenceCategory.addPreference(mConfigureWifiSettingsPreference);
+    private void removeAccessPointPreference() {
+        mAccessPointsPreferenceCategory.removeAll();
+        mAccessPointsPreferenceCategory.setVisible(false);
+    }
+
+    @VisibleForTesting
+    void setAdditionalSettingsSummaries() {
         mConfigureWifiSettingsPreference.setSummary(getString(
                 isWifiWakeupEnabled()
                         ? R.string.wifi_configure_settings_preference_summary_wakeup_on
                         : R.string.wifi_configure_settings_preference_summary_wakeup_off));
-        int numSavedNetworks = mWifiTracker.getNumSavedNetworks();
-        if (numSavedNetworks > 0) {
-            mAdditionalSettingsPreferenceCategory.addPreference(mSavedNetworksPreference);
-            mSavedNetworksPreference.setSummary(
-                    getResources().getQuantityString(R.plurals.wifi_saved_access_points_summary,
-                            numSavedNetworks, numSavedNetworks));
-        } else {
-            mAdditionalSettingsPreferenceCategory.removePreference(mSavedNetworksPreference);
-        }
+        final int numSavedNetworks = mWifiTracker.getNumSavedNetworks();
+        mSavedNetworksPreference.setVisible(numSavedNetworks > 0);
+        mSavedNetworksPreference.setSummary(
+                getResources().getQuantityString(R.plurals.wifi_saved_access_points_summary,
+                        numSavedNetworks, numSavedNetworks));
     }
 
     private boolean isWifiWakeupEnabled() {
-        PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
-        ContentResolver contentResolver = getContentResolver();
+        final Context context = getContext();
+        final PowerManager powerManager = context.getSystemService(PowerManager.class);
+        final ContentResolver contentResolver = context.getContentResolver();
         return Settings.Global.getInt(contentResolver,
                 Settings.Global.WIFI_WAKEUP_ENABLED, 0) == 1
                 && Settings.Global.getInt(contentResolver,
@@ -1006,15 +1015,14 @@
                         .launch();
         mStatusMessagePreference.setText(title, description, clickListener);
         removeConnectedAccessPointPreference();
-        mAccessPointsPreferenceCategory.removeAll();
-        mAccessPointsPreferenceCategory.addPreference(mStatusMessagePreference);
+        removeAccessPointPreference();
+        mStatusMessagePreference.setVisible(true);
     }
 
     private void addMessagePreference(int messageId) {
         mStatusMessagePreference.setTitle(messageId);
-        removeConnectedAccessPointPreference();
-        mAccessPointsPreferenceCategory.removeAll();
-        mAccessPointsPreferenceCategory.addPreference(mStatusMessagePreference);
+        mStatusMessagePreference.setVisible(true);
+
     }
 
     protected void setProgressBarVisible(boolean visible) {
diff --git a/src/com/android/settings/wifi/WifiSlice.java b/src/com/android/settings/wifi/WifiSlice.java
index 43f5372..d06d830 100644
--- a/src/com/android/settings/wifi/WifiSlice.java
+++ b/src/com/android/settings/wifi/WifiSlice.java
@@ -121,7 +121,7 @@
             return listBuilder.build();
         }
 
-        List<AccessPoint> results = getBackgroundWorker().getResults();
+        List<AccessPoint> results = SliceBackgroundWorker.getInstance(mContext, this).getResults();
         if (results == null) {
             results = new ArrayList<>();
         }
@@ -264,36 +264,27 @@
     }
 
     @Override
-    public SliceBackgroundWorker getBackgroundWorker() {
-        return WifiScanWorker.getInstance(mContext, WIFI_URI);
+    public Class getBackgroundWorkerClass() {
+        return WifiScanWorker.class;
     }
 
-    private static class WifiScanWorker extends SliceBackgroundWorker<AccessPoint>
+    public static class WifiScanWorker extends SliceBackgroundWorker<AccessPoint>
             implements WifiTracker.WifiListener {
 
-        // TODO: enforce all the SliceBackgroundWorkers being singletons at syntax level
-        private static WifiScanWorker mWifiScanWorker;
-
         private final Context mContext;
 
         private WifiTracker mWifiTracker;
 
-        private WifiScanWorker(Context context, Uri uri) {
-            super(context.getContentResolver(), uri);
+        public WifiScanWorker(Context context, Uri uri) {
+            super(context, uri);
             mContext = context;
         }
 
-        public static WifiScanWorker getInstance(Context context, Uri uri) {
-            if (mWifiScanWorker == null) {
-                mWifiScanWorker = new WifiScanWorker(context, uri);
-            }
-            return mWifiScanWorker;
-        }
-
         @Override
         protected void onSlicePinned() {
             if (mWifiTracker == null) {
-                mWifiTracker = new WifiTracker(mContext, this, true, true);
+                mWifiTracker = new WifiTracker(mContext, this /* wifiListener */,
+                        true /* includeSaved */, true /* includeScans */);
             }
             mWifiTracker.onStart();
             onAccessPointsChanged();
@@ -307,7 +298,6 @@
         @Override
         public void close() {
             mWifiTracker.onDestroy();
-            mWifiScanWorker = null;
         }
 
         @Override
diff --git a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
index 6b368c5..0de5c77 100644
--- a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
+++ b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
@@ -401,6 +401,7 @@
         // Build and return intent
         Intent intent = new Intent();
         intent.setComponent(componentName);
+        intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mSubId);
         return intent;
     }
 
diff --git a/src/com/android/settings/wifi/details/WifiPrivacyPreferenceController.java b/src/com/android/settings/wifi/details/WifiPrivacyPreferenceController.java
index 2afe35b..9f81431 100644
--- a/src/com/android/settings/wifi/details/WifiPrivacyPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiPrivacyPreferenceController.java
@@ -67,7 +67,7 @@
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         if (mWifiConfiguration != null) {
-            //TODO(b/117957974): update MAC randomization level to WifiManager
+            mWifiConfiguration.macRandomizationSetting = Integer.parseInt((String) newValue);
             mWifiManager.updateNetwork(mWifiConfiguration);
         }
         updateSummary((DropDownPreference) preference, Integer.parseInt((String) newValue));
@@ -77,10 +77,9 @@
     @VisibleForTesting
     int getRandomizationValue() {
         if (mWifiConfiguration != null) {
-            //TODO(b/117957974): get real MAC randomization level from WifiManager
-            return 0;
+            return mWifiConfiguration.macRandomizationSetting;
         }
-        return 0;
+        return WifiConfiguration.RANDOMIZATION_PERSISTENT;
     }
 
     private void updateSummary(DropDownPreference preference, int macRandomized) {
diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider
index 6f4deca..f9301a2 100644
--- a/tests/robotests/assets/grandfather_not_implementing_index_provider
+++ b/tests/robotests/assets/grandfather_not_implementing_index_provider
@@ -15,7 +15,6 @@
 com.android.settings.applications.AppLaunchSettings
 com.android.settings.applications.AppStorageSettings
 com.android.settings.applications.ConfirmConvertToFbe
-com.android.settings.applications.DirectoryAccessDetails
 com.android.settings.applications.ProcessStatsDetail
 com.android.settings.applications.ProcessStatsSummary
 com.android.settings.applications.ProcessStatsUi
diff --git a/tests/robotests/res/values-mcc999/config.xml b/tests/robotests/res/values-mcc999/config.xml
index 6347d79..73d2264 100644
--- a/tests/robotests/res/values-mcc999/config.xml
+++ b/tests/robotests/res/values-mcc999/config.xml
@@ -62,6 +62,8 @@
     <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>
+    <bool name="config_use_legacy_suggestion">false</bool>
+    <bool name="config_show_avatar_in_homepage">true</bool>
 
     <!-- Whether or not extra preview panels should be used for screen zoom setting. -->
     <bool name="config_enable_extra_screen_zoom_preview">false</bool>
diff --git a/tests/robotests/src/com/android/settings/SettingsActivityTest.java b/tests/robotests/src/com/android/settings/SettingsActivityTest.java
index af25f48..2c98f70 100644
--- a/tests/robotests/src/com/android/settings/SettingsActivityTest.java
+++ b/tests/robotests/src/com/android/settings/SettingsActivityTest.java
@@ -38,6 +38,7 @@
 
 import com.android.settings.core.OnActivityResultListener;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.ShadowUtils;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -46,6 +47,7 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.Robolectric;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -69,6 +71,7 @@
     }
 
     @Test
+    @Config(shadows = ShadowUtils.class)
     public void onCreate_deviceNotProvisioned_shouldDisableSearch() {
         Global.putInt(mContext.getContentResolver(), Global.DEVICE_PROVISIONED, 0);
         final SettingsActivity activity = Robolectric.buildActivity(SettingsActivity.class)
@@ -80,6 +83,7 @@
     }
 
     @Test
+    @Config(shadows = ShadowUtils.class)
     public void onCreate_deviceProvisioned_shouldEnableSearch() {
         Global.putInt(mContext.getContentResolver(), Global.DEVICE_PROVISIONED, 1);
         final SettingsActivity activity = Robolectric.buildActivity(SettingsActivity.class)
diff --git a/tests/robotests/src/com/android/settings/UtilsTest.java b/tests/robotests/src/com/android/settings/UtilsTest.java
index 5f2abba..77cbae2 100644
--- a/tests/robotests/src/com/android/settings/UtilsTest.java
+++ b/tests/robotests/src/com/android/settings/UtilsTest.java
@@ -93,6 +93,7 @@
         when(mContext.getSystemService(WifiManager.class)).thenReturn(wifiManager);
         when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
                 .thenReturn(connectivityManager);
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
     }
 
     @Test
@@ -200,4 +201,27 @@
         verify(mPackageManager).getApplicationInfoAsUser(eq(PACKAGE_NAME), anyInt(), eq(USER_ID));
         verify(mIconDrawableFactory).getBadgedIcon(mApplicationInfo, USER_ID);
     }
+
+    @Test
+    public void isPackageEnabled_appEnabled_returnTrue()
+            throws PackageManager.NameNotFoundException{
+        mApplicationInfo.enabled = true;
+        when(mPackageManager.getApplicationInfo(PACKAGE_NAME, 0)).thenReturn(mApplicationInfo);
+
+        assertThat(Utils.isPackageEnabled(mContext, PACKAGE_NAME)).isTrue();
+    }
+
+    @Test
+    public void isPackageEnabled_appDisabled_returnTrue()
+            throws PackageManager.NameNotFoundException{
+        mApplicationInfo.enabled = false;
+        when(mPackageManager.getApplicationInfo(PACKAGE_NAME, 0)).thenReturn(mApplicationInfo);
+
+        assertThat(Utils.isPackageEnabled(mContext, PACKAGE_NAME)).isFalse();
+    }
+
+    @Test
+    public void isPackageEnabled_noApp_returnFalse() {
+        assertThat(Utils.isPackageEnabled(mContext, PACKAGE_NAME)).isFalse();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
index a4d1567..2648916 100644
--- a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
@@ -35,8 +35,10 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
 import android.os.Bundle;
 import android.os.UserHandle;
+import android.os.UserManager;
 
 import androidx.fragment.app.FragmentActivity;
 import androidx.preference.Preference;
@@ -44,9 +46,12 @@
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.dashboard.DashboardFeatureProviderImpl;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.ShadowAccountManager;
+import com.android.settings.testutils.shadow.ShadowUserManager;
 import com.android.settingslib.drawer.CategoryKey;
 import com.android.settingslib.drawer.Tile;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -54,10 +59,11 @@
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.Shadows;
 import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowAccountManager;
+import org.robolectric.shadow.api.Shadow;
 import org.robolectric.util.ReflectionHelpers;
 
 @RunWith(SettingsRobolectricTestRunner.class)
+@Config(shadows = {ShadowAccountManager.class, ShadowUserManager.class})
 public class AccountDetailDashboardFragmentTest {
 
     private static final String METADATA_CATEGORY = "com.android.settings.category";
@@ -86,6 +92,11 @@
         when(mFragment.getContext()).thenReturn(mContext);
     }
 
+    @After
+    public void tearDown() {
+        ShadowAccountManager.reset();
+    }
+
     @Test
     public void testCategory_isAccountDetail() {
         assertThat(new AccountDetailDashboardFragment().getCategoryKey())
@@ -152,17 +163,45 @@
     }
 
     @Test
-    @Config(shadows = {ShadowAccountManager.class})
     public void onResume_accountMissing_shouldFinish() {
+        ShadowUserManager userManager = Shadow.extract(
+                mContext.getSystemService(UserManager.class));
+        ShadowAccountManager acctMgr = Shadow.extract(
+                mContext.getSystemService(AccountManager.class));
+
+        userManager.addProfile(new UserInfo(1, null, 0));
+        acctMgr.addAccountForUser(1, new Account("test@test.com", "com.test"));
+
         mFragment.finishIfAccountMissing();
         verify(mFragment).finish();
     }
 
     @Test
-    @Config(shadows = {ShadowAccountManager.class})
-    public void onResume_accountPresent_shouldNotFinish() {
-        AccountManager mgr = mContext.getSystemService(AccountManager.class);
-        Shadows.shadowOf(mgr).addAccount(mFragment.mAccount);
+    public void onResume_accountPresentOneProfile_shouldNotFinish() {
+        ShadowUserManager userManager = Shadow.extract(
+                mContext.getSystemService(UserManager.class));
+        ShadowAccountManager acctMgr = Shadow.extract(
+                mContext.getSystemService(AccountManager.class));
+
+        userManager.addProfile(new UserInfo(1, null, 0));
+        acctMgr.addAccountForUser(1, mFragment.mAccount);
+
+        mFragment.finishIfAccountMissing();
+        verify(mFragment, never()).finish();
+    }
+
+    @Test
+    public void onResume_accountPresentTwoProfiles_shouldNotFinish() {
+        ShadowUserManager userManager = Shadow.extract(
+                mContext.getSystemService(UserManager.class));
+        ShadowAccountManager acctMgr = Shadow.extract(
+                mContext.getSystemService(AccountManager.class));
+
+        userManager.addProfile(new UserInfo(1, null, 0));
+        userManager.addProfile(new UserInfo(2, null, 0));
+        acctMgr.addAccountForUser(1, new Account("test@test.com", "com.test"));
+        acctMgr.addAccountForUser(2, mFragment.mAccount);
+
         mFragment.finishIfAccountMissing();
         verify(mFragment, never()).finish();
     }
diff --git a/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java b/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java
new file mode 100644
index 0000000..039d2e2
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java
@@ -0,0 +1,140 @@
+/*
+ * 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.accounts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.accounts.Account;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.widget.ImageView;
+
+import com.android.settings.homepage.SettingsHomepageActivity;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+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 org.robolectric.shadows.ShadowPackageManager;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class AvatarViewMixinTest {
+    private static final String DUMMY_ACCOUNT = "test@domain.com";
+    private static final String DUMMY_DOMAIN = "domain.com";
+    private static final String DUMMY_AUTHORITY = "authority.domain.com";
+
+    private Context mContext;
+    private ImageView mImageView;
+    private ActivityController mController;
+    private SettingsHomepageActivity mActivity;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mImageView = new ImageView(mContext);
+        mController = Robolectric.buildActivity(SettingsHomepageActivity.class).create();
+        mActivity = (SettingsHomepageActivity) mController.get();
+    }
+
+    @Test
+    public void hasAccount_useDefaultAccountData_returnFalse() {
+        final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(mActivity, mImageView);
+        assertThat(avatarViewMixin.hasAccount()).isFalse();
+    }
+
+    @Test
+    @Config(shadows = ShadowAccountFeatureProviderImpl.class)
+    public void hasAccount_useShadowAccountData_returnTrue() {
+        final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(mActivity, mImageView);
+        assertThat(avatarViewMixin.hasAccount()).isTrue();
+    }
+
+    @Test
+    public void onStart_configDisabled_doNothing() {
+        final AvatarViewMixin mixin = spy(new AvatarViewMixin(mActivity, mImageView));
+        mixin.onStart();
+
+        verify(mixin, never()).hasAccount();
+    }
+
+    @Test
+    @Config(qualifiers = "mcc999")
+    public void onStart_useMockAvatarViewMixin_shouldBeExecuted() {
+        final AvatarViewMixin mockAvatar = spy(new AvatarViewMixin(mActivity, mImageView));
+
+        mActivity.getLifecycle().addObserver(mockAvatar);
+        mController.start();
+
+        verify(mockAvatar).hasAccount();
+    }
+
+    @Test
+    public void queryProviderAuthority_useShadowPackagteManager_returnNull() {
+        final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(mActivity, mImageView);
+
+        assertThat(avatarViewMixin.queryProviderAuthority()).isNull();
+    }
+
+    @Test
+    public void queryProviderAuthority_useNewShadowPackagteManager_returnAuthority() {
+        final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(mActivity, mImageView);
+        ShadowPackageManager shadowPackageManager = Shadow.extract(mContext.getPackageManager());
+        final PackageInfo accountProvider = new PackageInfo();
+        accountProvider.packageName = "test.pkg";
+        accountProvider.applicationInfo = new ApplicationInfo();
+        accountProvider.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+        accountProvider.applicationInfo.packageName = accountProvider.packageName;
+        accountProvider.providers = new ProviderInfo[1];
+        accountProvider.providers[0] = new ProviderInfo();
+        accountProvider.providers[0].authority = DUMMY_AUTHORITY;
+        accountProvider.providers[0].packageName = accountProvider.packageName;
+        accountProvider.providers[0].name = "test.class";
+        accountProvider.providers[0].applicationInfo = accountProvider.applicationInfo;
+
+        final ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.providerInfo = accountProvider.providers[0];
+        shadowPackageManager.addResolveInfoForIntent(AvatarViewMixin.INTENT_GET_ACCOUNT_DATA,
+                resolveInfo);
+        assertThat(avatarViewMixin.queryProviderAuthority()).isEqualTo(DUMMY_AUTHORITY);
+    }
+
+    @Implements(value = AccountFeatureProviderImpl.class)
+    public static class ShadowAccountFeatureProviderImpl {
+
+        @Implementation
+        public Account[] getAccounts(Context context) {
+            Account[] accounts = {new Account(DUMMY_ACCOUNT, DUMMY_DOMAIN)};
+            return accounts;
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accounts/ChooseAccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/ChooseAccountPreferenceControllerTest.java
index 22c2cdb..241765e 100644
--- a/tests/robotests/src/com/android/settings/accounts/ChooseAccountPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/ChooseAccountPreferenceControllerTest.java
@@ -76,7 +76,7 @@
     @After
     public void tearDown() {
         ShadowContentResolver.reset();
-        ShadowAccountManager.resetAuthenticator();
+        ShadowAccountManager.reset();
         ShadowRestrictedLockUtilsInternal.clearDisabledTypes();
     }
 
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceControllerTest.java
index a342e10..d3e00c3 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceControllerTest.java
@@ -106,15 +106,12 @@
 
 
         final TextView title = mHeader.findViewById(R.id.entity_header_title);
-        final TextView summary = mHeader.findViewById(R.id.entity_header_summary);
 
         mController.displayPreference(mScreen);
         mController.refreshUi();
 
         assertThat(title).isNotNull();
         assertThat(title.getText()).isEqualTo(appLabel);
-        assertThat(summary).isNotNull();
-        assertThat(summary.getText()).isEqualTo(mContext.getString(R.string.installed));
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/BluetoothOnWhileDrivingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/BluetoothOnWhileDrivingPreferenceControllerTest.java
deleted file mode 100644
index 83763bb..0000000
--- a/tests/robotests/src/com/android/settings/connecteddevice/BluetoothOnWhileDrivingPreferenceControllerTest.java
+++ /dev/null
@@ -1,67 +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.connecteddevice;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.provider.Settings;
-import android.provider.Settings.Secure;
-import android.util.FeatureFlagUtils;
-
-import com.android.settings.core.BasePreferenceController;
-import com.android.settings.core.FeatureFlags;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-public class BluetoothOnWhileDrivingPreferenceControllerTest {
-
-    private BluetoothOnWhileDrivingPreferenceController mController;
-    private Context mContext;
-
-    @Before
-    public void setUp() {
-        mContext = RuntimeEnvironment.application;
-        mController = new BluetoothOnWhileDrivingPreferenceController(mContext);
-    }
-
-    @Test
-    public void getAvailabilityStatus_onWhenEnabled() {
-        FeatureFlagUtils.setEnabled(mContext, FeatureFlags.BLUETOOTH_WHILE_DRIVING, true);
-
-        assertThat(mController.getAvailabilityStatus())
-            .isEqualTo(BasePreferenceController.AVAILABLE);
-    }
-
-    @Test
-    public void getAvailabilityStatus_offWhenDisabled() {
-        assertThat(mController.getAvailabilityStatus())
-            .isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
-    }
-
-    @Test
-    public void setChecked_togglesSettingSecure() {
-        mController.setChecked(true);
-
-        final String name = Secure.BLUETOOTH_ON_WHILE_DRIVING;
-        assertThat(Settings.Secure.getInt(mContext.getContentResolver(), name, 0)).isEqualTo(1);
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/development/DesktopModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/DesktopModePreferenceControllerTest.java
new file mode 100644
index 0000000..e6e8cb9
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/DesktopModePreferenceControllerTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.development;
+
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
+
+import static com.android.settings.development.DesktopModePreferenceController.SETTING_VALUE_OFF;
+import static com.android.settings.development.DesktopModePreferenceController.SETTING_VALUE_ON;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class DesktopModePreferenceControllerTest {
+
+    private static final String ENG_BUILD_TYPE = "eng";
+    private static final String USER_BUILD_TYPE = "user";
+
+    @Mock
+    private SwitchPreference mPreference;
+    @Mock
+    private PreferenceScreen mScreen;
+
+    private Context mContext;
+    private DesktopModePreferenceController mController;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mController = new DesktopModePreferenceController(mContext);
+        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
+        mController.displayPreference(mScreen);
+    }
+
+    @Test
+    public void isAvailable_engBuild_shouldBeTrue() {
+        mController = spy(mController);
+        doReturn(ENG_BUILD_TYPE).when(mController).getBuildType();
+
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void isAvaiable_userBuild_shouldBeTrue() {
+        mController = spy(mController);
+        doReturn(USER_BUILD_TYPE).when(mController).getBuildType();
+
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void onPreferenceChange_switchEnabled_shouldEnableFreeformWindows() {
+        mController.onPreferenceChange(mPreference, true /* new value */);
+
+        final int mode = Settings.Global.getInt(mContext.getContentResolver(),
+                DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, -1 /* default */);
+        assertThat(mode).isEqualTo(SETTING_VALUE_ON);
+    }
+
+    @Test
+    public void onPreferenceChange_switchDisabled_shouldDisableFreeformWindows() {
+        mController.onPreferenceChange(mPreference, false /* new value */);
+
+        final int mode = Settings.Global.getInt(mContext.getContentResolver(),
+                DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, -1 /* default */);
+        assertThat(mode).isEqualTo(SETTING_VALUE_OFF);
+    }
+
+    @Test
+    public void updateState_settingEnabled_preferenceShouldBeChecked() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, SETTING_VALUE_ON);
+
+        mController.updateState(mPreference);
+
+        verify(mPreference).setChecked(true);
+    }
+
+    @Test
+    public void updateState_settingDisabled_preferenceShouldNotBeChecked() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, SETTING_VALUE_OFF);
+
+        mController.updateState(mPreference);
+
+        verify(mPreference).setChecked(false);
+    }
+
+    @Test
+    public void onDeveloperOptionsSwitchDisabled_shouldDisablePreference() {
+        mController.onDeveloperOptionsSwitchDisabled();
+
+        final int mode = Settings.Global.getInt(mContext.getContentResolver(),
+                DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, -1 /* default */);
+        assertThat(mode).isEqualTo(SETTING_VALUE_OFF);
+        verify(mPreference).setEnabled(false);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java
index b58f756..08fb23e 100644
--- a/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java
@@ -19,7 +19,6 @@
 import static com.android.settings.development.FreeformWindowsPreferenceController
         .SETTING_VALUE_OFF;
 import static com.android.settings.development.FreeformWindowsPreferenceController.SETTING_VALUE_ON;
-import static com.android.settings.development.FreeformWindowsPreferenceController.USER_BUILD_TYPE;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -47,6 +46,7 @@
 public class FreeformWindowsPreferenceControllerTest {
 
     private static final String ENG_BUILD_TYPE = "eng";
+    private static final String USER_BUILD_TYPE = "user";
 
     @Mock
     private SwitchPreference mPreference;
@@ -74,11 +74,11 @@
     }
 
     @Test
-    public void isAvaiable_userBuild_shouldBeFalse() {
+    public void isAvaiable_userBuild_shouldBeTrue() {
         mController = spy(mController);
         doReturn(USER_BUILD_TYPE).when(mController).getBuildType();
 
-        assertThat(mController.isAvailable()).isFalse();
+        assertThat(mController.isAvailable()).isTrue();
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/development/SmsAccessRestrictionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/SmsAccessRestrictionPreferenceControllerTest.java
new file mode 100644
index 0000000..7a0dd68
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/SmsAccessRestrictionPreferenceControllerTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class SmsAccessRestrictionPreferenceControllerTest {
+
+    @Mock
+    private SwitchPreference mPreference;
+    @Mock
+    private PreferenceScreen mPreferenceScreen;
+
+    private Context mContext;
+    private SmsAccessRestrictionPreferenceController mController;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mController = new SmsAccessRestrictionPreferenceController(mContext);
+        when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
+            .thenReturn(mPreference);
+        mController.displayPreference(mPreferenceScreen);
+    }
+
+    @Test
+    public void onPreferenceChange_settingEnabled_enableSmsRestrictionShouldBeOn() {
+        mController.onPreferenceChange(mPreference, true /* new value */);
+
+        final int mode = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, -1 /* default */);
+
+        assertThat(mode).isEqualTo(1);
+    }
+
+    @Test
+    public void onPreferenceChange_settingDisabled_enableSmsRestrictionShouldBeOff() {
+        mController.onPreferenceChange(mPreference, false /* new value */);
+
+        final int mode = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, -1 /* default */);
+
+        assertThat(mode).isEqualTo(0);
+    }
+
+    @Test
+    public void updateState_settingDisabled_preferenceShouldNotBeChecked() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, 0);
+        mController.updateState(mPreference);
+
+        verify(mPreference).setChecked(false);
+    }
+
+    @Test
+    public void updateState_settingEnabled_preferenceShouldBeChecked() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, 1);
+        mController.updateState(mPreference);
+
+        verify(mPreference).setChecked(true);
+    }
+
+    @Test
+    public void onDeveloperOptionsSwitchDisabled_shouldDisablePreference() {
+        mController.onDeveloperOptionsSwitchDisabled();
+
+        final int mode = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, -1 /* default */);
+
+        assertThat(mode).isEqualTo(0);
+        verify(mPreference).setChecked(false);
+        verify(mPreference).setEnabled(false);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/deviceinfo/DeviceNameWarningDialogTest.java b/tests/robotests/src/com/android/settings/deviceinfo/aboutphone/DeviceNameWarningDialogTest.java
similarity index 72%
rename from tests/robotests/src/com/android/settings/deviceinfo/deviceinfo/DeviceNameWarningDialogTest.java
rename to tests/robotests/src/com/android/settings/deviceinfo/aboutphone/DeviceNameWarningDialogTest.java
index 0be0ac2..6ea36a0 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/deviceinfo/DeviceNameWarningDialogTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/aboutphone/DeviceNameWarningDialogTest.java
@@ -1,4 +1,20 @@
-package com.android.settings.deviceinfo.deviceinfo;
+/*
+ * 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.aboutphone;
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
@@ -6,8 +22,6 @@
 
 import android.content.DialogInterface;
 
-import com.android.settings.deviceinfo.aboutphone.DeviceNameWarningDialog;
-import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 
 import org.junit.Test;
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/MyDeviceInfoFragmentTest.java b/tests/robotests/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragmentTest.java
similarity index 97%
rename from tests/robotests/src/com/android/settings/deviceinfo/MyDeviceInfoFragmentTest.java
rename to tests/robotests/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragmentTest.java
index 4a741cf..e304a1e 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/MyDeviceInfoFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragmentTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.deviceinfo;
+package com.android.settings.deviceinfo.aboutphone;
 
 import static com.android.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY;
 
@@ -35,7 +35,7 @@
 import androidx.fragment.app.FragmentActivity;
 import androidx.preference.PreferenceScreen;
 
-import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment;
+import com.android.settings.deviceinfo.BuildNumberPreferenceController;
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.testutils.shadow.SettingsShadowResources;
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceControllerTest.java
new file mode 100644
index 0000000..ae3007c
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceControllerTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.aboutphone;
+
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.Build;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class TopLevelAboutDevicePreferenceControllerTest {
+
+    private Context mContext;
+    private TopLevelAboutDevicePreferenceController mController;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mController = new TopLevelAboutDevicePreferenceController(mContext, "test_key");
+    }
+
+    @Test
+    public void getAvailabilityState_shouldBeAvailable() {
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+    }
+
+    @Test
+    public void getSummary_shouldReturnDeviceModel() {
+        assertThat(mController.getSummary().toString()).isEqualTo(Build.MODEL);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
index b356c49..1a8d58d 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
@@ -258,7 +258,6 @@
         verify(mEntityHeaderController).setIcon(mAppEntry);
         verify(mEntityHeaderController).setLabel(mAppEntry);
         verify(mEntityHeaderController).setIsInstantApp(true);
-        verify(mEntityHeaderController).setSummary((CharSequence) null);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/gestures/PreventRingingGesturePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/PreventRingingGesturePreferenceControllerTest.java
new file mode 100644
index 0000000..6d77d77
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/gestures/PreventRingingGesturePreferenceControllerTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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.gestures;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.preference.PreferenceCategory;
+import android.provider.Settings;
+
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.widget.RadioButtonPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class PreventRingingGesturePreferenceControllerTest {
+
+    private Context mContext;
+    private Resources mResources;
+    private PreventRingingGesturePreferenceController mController;
+
+    @Before
+    public void setUp() {
+        mContext = spy(RuntimeEnvironment.application);
+        mResources = mock(Resources.class);
+        when(mContext.getResources()).thenReturn(mResources);
+        when(mResources.getBoolean(com.android.internal.R.bool.config_volumeHushGestureEnabled))
+                .thenReturn(true);
+        mController = new PreventRingingGesturePreferenceController(mContext, null);
+        mController.mVibratePref = new RadioButtonPreference(mContext);
+        mController.mNonePref = new RadioButtonPreference(mContext);
+        mController.mMutePref = new RadioButtonPreference(mContext);
+    }
+
+    @Test
+    public void testIsAvailable_configIsTrue_shouldReturnTrue() {
+        when(mResources.getBoolean(
+                com.android.internal.R.bool.config_volumeHushGestureEnabled)).thenReturn(true);
+
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void testIsAvailable_configIsFalse_shouldReturnFalse() {
+        when(mResources.getBoolean(
+                com.android.internal.R.bool.config_volumeHushGestureEnabled)).thenReturn(false);
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void testUpdateState_mute() {
+        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
+                Settings.Secure.VOLUME_HUSH_MUTE);
+        mController.updateState(null);
+        assertThat(mController.mVibratePref.isChecked()).isFalse();
+        assertThat(mController.mNonePref.isChecked()).isFalse();
+        assertThat(mController.mMutePref.isChecked()).isTrue();
+    }
+
+    @Test
+    public void testUpdateState_vibrate() {
+        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
+                Settings.Secure.VOLUME_HUSH_VIBRATE);
+        mController.updateState(null);
+        assertThat(mController.mVibratePref.isChecked()).isTrue();
+        assertThat(mController.mNonePref.isChecked()).isFalse();
+        assertThat(mController.mMutePref.isChecked()).isFalse();
+    }
+
+    @Test
+    public void testUpdateState_other() {
+        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
+                7);
+        mController.updateState(null);
+        assertThat(mController.mVibratePref.isChecked()).isFalse();
+        assertThat(mController.mNonePref.isChecked()).isTrue();
+        assertThat(mController.mMutePref.isChecked()).isFalse();
+    }
+
+    @Test
+    public void testRadioButtonClicked_mute() {
+        RadioButtonPreference rbPref = new RadioButtonPreference(mContext);
+        rbPref.setKey(PreventRingingGesturePreferenceController.KEY_MUTE);
+
+        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
+                Settings.Secure.VOLUME_HUSH_OFF);
+        mController.onRadioButtonClicked(rbPref);
+
+        assertThat(Settings.Secure.VOLUME_HUSH_MUTE).isEqualTo(
+                Settings.Secure.getInt(mContext.getContentResolver(),
+                        Settings.Secure.VOLUME_HUSH_GESTURE, Settings.Secure.VOLUME_HUSH_OFF));
+    }
+
+    @Test
+    public void testRadioButtonClicked_vibrate() {
+        RadioButtonPreference rbPref = new RadioButtonPreference(mContext);
+        rbPref.setKey(PreventRingingGesturePreferenceController.KEY_VIBRATE);
+
+        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
+                Settings.Secure.VOLUME_HUSH_OFF);
+        mController.onRadioButtonClicked(rbPref);
+
+        assertThat(Settings.Secure.VOLUME_HUSH_VIBRATE).isEqualTo(
+                Settings.Secure.getInt(mContext.getContentResolver(),
+                        Settings.Secure.VOLUME_HUSH_GESTURE, Settings.Secure.VOLUME_HUSH_OFF));
+    }
+
+    @Test
+    public void testRadioButtonClicked_off() {
+        RadioButtonPreference rbPref = new RadioButtonPreference(mContext);
+        rbPref.setKey(PreventRingingGesturePreferenceController.KEY_NONE);
+
+        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
+                Settings.Secure.VOLUME_HUSH_MUTE);
+
+        mController.onRadioButtonClicked(rbPref);
+
+        assertThat(Settings.Secure.VOLUME_HUSH_OFF).isEqualTo(
+                Settings.Secure.getInt(mContext.getContentResolver(),
+                        Settings.Secure.VOLUME_HUSH_GESTURE, Settings.Secure.VOLUME_HUSH_VIBRATE));
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/gestures/PreventRingingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/PreventRingingPreferenceControllerTest.java
deleted file mode 100644
index 65c3b5d..0000000
--- a/tests/robotests/src/com/android/settings/gestures/PreventRingingPreferenceControllerTest.java
+++ /dev/null
@@ -1,122 +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.gestures;
-
-import static android.provider.Settings.Secure.VOLUME_HUSH_GESTURE;
-import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
-import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static junit.framework.Assert.assertEquals;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.provider.Settings;
-
-import androidx.preference.ListPreference;
-import androidx.preference.Preference;
-
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-
-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;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-public class PreventRingingPreferenceControllerTest {
-
-    private static final String KEY_PICK_UP = "gesture_prevent_ringing";
-
-    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
-    private Context mContext;
-
-    private PreventRingingPreferenceController mController;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mController = new PreventRingingPreferenceController(mContext, KEY_PICK_UP);
-    }
-
-    @Test
-    public void testIsAvailable_configIsTrue_shouldReturnTrue() {
-        when(mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_volumeHushGestureEnabled)).thenReturn(true);
-
-        assertThat(mController.isAvailable()).isTrue();
-    }
-
-    @Test
-    public void testIsAvailable_configIsFalse_shouldReturnFalse() {
-        when(mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_volumeHushGestureEnabled)).thenReturn(false);
-
-        assertThat(mController.isAvailable()).isFalse();
-    }
-
-    @Test
-    public void testUpdateState_mute() {
-        ListPreference pref = mock(ListPreference.class);
-        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
-                Settings.Secure.VOLUME_HUSH_MUTE);
-        mController.updateState(pref);
-        verify(pref).setValue(String.valueOf(Settings.Secure.VOLUME_HUSH_MUTE));
-    }
-
-    @Test
-    public void testUpdateState_vibrate() {
-        ListPreference pref = mock(ListPreference.class);
-        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
-                Settings.Secure.VOLUME_HUSH_VIBRATE);
-        mController.updateState(pref);
-        verify(pref).setValue(String.valueOf(Settings.Secure.VOLUME_HUSH_VIBRATE));
-    }
-
-    @Test
-    public void testUpdateState_other() {
-        ListPreference pref = mock(ListPreference.class);
-        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
-                7);
-        mController.updateState(pref);
-        verify(pref).setValue(String.valueOf(Settings.Secure.VOLUME_HUSH_OFF));
-    }
-
-    @Test
-    public void testUpdateState_parentPage() {
-        Preference pref = mock(Preference.class);
-        // verify no exception
-        mController.updateState(pref);
-    }
-
-    @Test
-    public void testOnPreferenceChange() {
-        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
-                7);
-
-        mController.onPreferenceChange(mock(Preference.class), String.valueOf(VOLUME_HUSH_MUTE));
-
-        assertEquals(VOLUME_HUSH_MUTE, Settings.Secure.getInt(mContext.getContentResolver(),
-                VOLUME_HUSH_GESTURE, VOLUME_HUSH_OFF));
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/CardDatabaseHelperTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/CardDatabaseHelperTest.java
index 4ef982f..ef60f85 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/CardDatabaseHelperTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/CardDatabaseHelperTest.java
@@ -18,10 +18,12 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 
+import com.android.settings.intelligence.ContextualCardProto;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 
 import org.junit.After;
@@ -30,6 +32,9 @@
 import org.junit.runner.RunWith;
 import org.robolectric.RuntimeEnvironment;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @RunWith(SettingsRobolectricTestRunner.class)
 public class CardDatabaseHelperTest {
 
@@ -74,9 +79,44 @@
                 CardDatabaseHelper.CardColumns.CARD_ACTION,
                 CardDatabaseHelper.CardColumns.EXPIRE_TIME_MS,
                 CardDatabaseHelper.CardColumns.SUPPORT_HALF_WIDTH,
+                CardDatabaseHelper.CardColumns.CARD_DISMISSED,
         };
 
         assertThat(columnNames).isEqualTo(expectedNames);
         cursor.close();
     }
+
+    @Test
+    public void getContextualCards_shouldSortByScore() {
+        insertFakeCard(mDatabase, "card1", 1, "uri1");
+        insertFakeCard(mDatabase, "card2", 0, "uri2");
+        insertFakeCard(mDatabase, "card3", 10, "uri3");
+        // Should sort as 3,1,2
+        try (final Cursor cursor = CardDatabaseHelper.getInstance(mContext).getContextualCards()) {
+            assertThat(cursor.getCount()).isEqualTo(3);
+            final List<ContextualCard> cards = new ArrayList<>();
+            for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
+                cards.add(new ContextualCard(cursor));
+            }
+            assertThat(cards.get(0).getName()).isEqualTo("card3");
+            assertThat(cards.get(1).getName()).isEqualTo("card1");
+            assertThat(cards.get(2).getName()).isEqualTo("card2");
+        }
+    }
+
+    private static void insertFakeCard(SQLiteDatabase db, String name, double score, String uri) {
+        final ContentValues value = new ContentValues();
+        value.put(CardDatabaseHelper.CardColumns.NAME, name);
+        value.put(CardDatabaseHelper.CardColumns.SCORE, score);
+        value.put(CardDatabaseHelper.CardColumns.SLICE_URI, uri);
+
+        value.put(CardDatabaseHelper.CardColumns.TYPE, ContextualCard.CardType.SLICE);
+        value.put(CardDatabaseHelper.CardColumns.CATEGORY,
+                ContextualCardProto.ContextualCard.Category.DEFAULT.getNumber());
+        value.put(CardDatabaseHelper.CardColumns.PACKAGE_NAME,
+                RuntimeEnvironment.application.getPackageName());
+        value.put(CardDatabaseHelper.CardColumns.APP_VERSION, 1);
+
+        db.insert(CardDatabaseHelper.CARD_TABLE, null, value);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ConditionalContextualCardTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ConditionalContextualCardTest.java
index 2cff9f2..74e88d7 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ConditionalContextualCardTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ConditionalContextualCardTest.java
@@ -30,7 +30,7 @@
     @Test(expected = IllegalArgumentException.class)
     public void newInstance_changeCardType_shouldCrash() {
         new ConditionalContextualCard.Builder()
-                .setCardType(ContextualCard.CardType.SUGGESTION)
+                .setCardType(ContextualCard.CardType.LEGACY_SUGGESTION)
                 .build();
     }
 
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTableTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTableTest.java
new file mode 100644
index 0000000..4724500
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTableTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.homepage.contextualcards;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.android.settings.homepage.contextualcards.ContextualCardLookupTable
+        .ControllerRendererMapping;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class ContextualCardLookupTableTest {
+
+    private static final int UNSUPPORTED_CARD_TYPE = -99999;
+    private static final int UNSUPPORTED_VIEW_TYPE = -99999;
+
+    private List<ControllerRendererMapping> mOriginalLookupTable;
+
+    @Before
+    public void setUp() {
+        mOriginalLookupTable = new ArrayList<>();
+        ContextualCardLookupTable.LOOKUP_TABLE.stream()
+                .forEach(mapping -> mOriginalLookupTable.add(mapping));
+    }
+
+    @After
+    public void reset() {
+        ContextualCardLookupTable.LOOKUP_TABLE.clear();
+        ContextualCardLookupTable.LOOKUP_TABLE.addAll(mOriginalLookupTable);
+    }
+
+    @Test
+    public void getCardControllerClass_hasSupportedCardType_shouldGetCorrespondingController() {
+        for (ControllerRendererMapping mapping : ContextualCardLookupTable.LOOKUP_TABLE) {
+            assertThat(ContextualCardLookupTable.getCardControllerClass(mapping.mCardType))
+                    .isEqualTo(mapping.mControllerClass);
+        }
+    }
+
+    @Test
+    public void getCardControllerClass_hasUnsupportedCardType_shouldAlwaysGetNull() {
+        assertThat(ContextualCardLookupTable.getCardControllerClass(UNSUPPORTED_CARD_TYPE))
+                .isNull();
+    }
+
+    @Test
+    public void
+    getCardRendererClassByViewType_hasSupportedViewType_shouldGetCorrespondingRenderer() {
+        for (ControllerRendererMapping mapping : ContextualCardLookupTable.LOOKUP_TABLE) {
+            assertThat(ContextualCardLookupTable.getCardRendererClassByViewType(mapping.mViewType))
+                    .isEqualTo(mapping.mRendererClass);
+        }
+    }
+
+    @Test
+    public void getCardRendererClassByViewType_hasUnsupportedViewType_shouldAlwaysGetNull() {
+        assertThat(ContextualCardLookupTable.getCardRendererClassByViewType(
+                UNSUPPORTED_VIEW_TYPE)).isNull();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void
+    getCardRendererClassByViewType_hasDuplicateViewType_shouldThrowsIllegalStateException() {
+        final ControllerRendererMapping mapping1 =
+                new ControllerRendererMapping(
+                        1111 /* cardType */, UNSUPPORTED_VIEW_TYPE /* viewType */,
+                        ContextualCardController.class, ContextualCardRenderer.class
+                );
+        final ControllerRendererMapping mapping2 =
+                new ControllerRendererMapping(
+                        2222 /* cardType */, UNSUPPORTED_VIEW_TYPE /* viewType */,
+                        ContextualCardController.class, ContextualCardRenderer.class
+                );
+        ContextualCardLookupTable.LOOKUP_TABLE.add(mapping1);
+        ContextualCardLookupTable.LOOKUP_TABLE.add(mapping2);
+
+        ContextualCardLookupTable.getCardRendererClassByViewType(UNSUPPORTED_VIEW_TYPE);
+    }
+
+    @Test
+    public void getRendererClassByCardType_hasSupportedCardType_shouldGetCorrespondingRenderer() {
+        for (ControllerRendererMapping mapping : ContextualCardLookupTable.LOOKUP_TABLE) {
+            assertThat(ContextualCardLookupTable.getCardRendererClassByCardType(mapping.mCardType))
+                    .isEqualTo(mapping.mRendererClass);
+        }
+    }
+
+    @Test
+    public void getCardRendererClassByCardType_hasUnsupportedCardType_shouldAlwaysGetNull() {
+        assertThat(ContextualCardLookupTable.getCardRendererClassByCardType(UNSUPPORTED_CARD_TYPE))
+                .isNull();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ControllerRendererPoolTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ControllerRendererPoolTest.java
new file mode 100644
index 0000000..e51169e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ControllerRendererPoolTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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.homepage.contextualcards;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import androidx.lifecycle.LifecycleOwner;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class ControllerRendererPoolTest {
+
+    private static final int UNSUPPORTED_CARD_TYPE = -99999;
+    private static final int UNSUPPORTED_VIEW_TYPE = -99999;
+
+    private ControllerRendererPool mPool;
+    private Context mContext;
+    private Lifecycle mLifecycle;
+    private LifecycleOwner mLifecycleOwner;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mLifecycleOwner = () -> mLifecycle;
+        mLifecycle = new Lifecycle(mLifecycleOwner);
+
+        mPool = new ControllerRendererPool();
+    }
+
+    @Test
+    public void getController_hasSupportedCardType_shouldReturnCorrespondingController() {
+        ContextualCardLookupTable.LOOKUP_TABLE.stream().forEach(mapping -> assertThat(
+                mPool.getController(mContext, mapping.mCardType).getClass()).isEqualTo(
+                mapping.mControllerClass));
+    }
+
+    @Test
+    public void getController_hasSupportedCardType_shouldHaveTwoControllersInPool() {
+        final long count = ContextualCardLookupTable.LOOKUP_TABLE.stream().map(
+                mapping -> mapping.mControllerClass).distinct().count();
+
+        ContextualCardLookupTable.LOOKUP_TABLE.stream().forEach(
+                mapping -> mPool.getController(mContext, mapping.mCardType));
+
+        assertThat(mPool.getControllers()).hasSize((int) count);
+    }
+
+    @Test
+    public void getController_hasUnsupportedCardType_shouldReturnNullAndPoolIsEmpty() {
+        final ContextualCardController controller = mPool.getController(mContext,
+                UNSUPPORTED_CARD_TYPE);
+
+        assertThat(controller).isNull();
+        assertThat(mPool.getControllers()).isEmpty();
+    }
+
+    @Test
+    public void getRenderer_hasSupportedViewType_shouldReturnCorrespondingRenderer() {
+        ContextualCardLookupTable.LOOKUP_TABLE.stream().forEach(mapping -> assertThat(
+                mPool.getRendererByViewType(mContext, mLifecycleOwner,
+                        mapping.mViewType).getClass()).isEqualTo(mapping.mRendererClass));
+    }
+
+    @Test
+    public void getRenderer_hasSupportedViewType_shouldHaveDistinctRenderersInPool() {
+        final long count = ContextualCardLookupTable.LOOKUP_TABLE.stream().map(
+                mapping -> mapping.mRendererClass).distinct().count();
+
+        ContextualCardLookupTable.LOOKUP_TABLE.stream().forEach(
+                mapping -> mPool.getRendererByViewType(mContext, mLifecycleOwner,
+                        mapping.mViewType));
+
+        assertThat(mPool.getRenderers()).hasSize((int) count);
+    }
+
+    @Test
+    public void getRenderer_hasUnsupportedViewType_shouldReturnNullAndPoolIsEmpty() {
+        final ContextualCardRenderer renderer = mPool.getRendererByViewType(mContext,
+                mLifecycleOwner,
+                UNSUPPORTED_VIEW_TYPE);
+
+        assertThat(renderer).isNull();
+        assertThat(mPool.getRenderers()).isEmpty();
+    }
+
+    @Test
+    public void getRenderer_hasSupportedCardTypeAndWidth_shouldReturnCorrespondingRenderer() {
+        ContextualCardLookupTable.LOOKUP_TABLE.stream().forEach(mapping -> assertThat(
+                mPool.getRendererByCardType(mContext, mLifecycleOwner,
+                        mapping.mCardType).getClass()).isEqualTo(mapping.mRendererClass));
+    }
+
+    @Test
+    public void getRenderer_hasSupportedCardTypeAndWidth_shouldHaveDistinctRenderersInPool() {
+        final long count = ContextualCardLookupTable.LOOKUP_TABLE.stream().map(
+                mapping -> mapping.mRendererClass).distinct().count();
+
+        ContextualCardLookupTable.LOOKUP_TABLE.stream().forEach(
+                mapping -> mPool.getRendererByCardType(mContext, mLifecycleOwner,
+                        mapping.mCardType));
+
+        assertThat(mPool.getRenderers()).hasSize((int) count);
+    }
+
+    @Test
+    public void getRenderer_hasUnsupportedCardType_shouldReturnNullAndPoolIsEmpty() {
+        final ContextualCardRenderer renderer = mPool.getRendererByCardType(mContext,
+                mLifecycleOwner,
+                UNSUPPORTED_CARD_TYPE);
+
+        assertThat(renderer).isNull();
+        assertThat(mPool.getRenderers()).isEmpty();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProviderTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProviderTest.java
index 8b541c6..6b1f8b1 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProviderTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProviderTest.java
@@ -19,7 +19,12 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.app.slice.SliceManager;
 import android.content.ContentResolver;
+import android.content.Context;
 import android.net.Uri;
 import android.os.Bundle;
 
@@ -28,30 +33,37 @@
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.wifi.WifiSlice;
 
-import com.google.android.settings.intelligence.libs.contextualcards.ContextualCardCategory;
 import com.google.android.settings.intelligence.libs.contextualcards.ContextualCardProvider;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 import org.robolectric.Robolectric;
 import org.robolectric.RuntimeEnvironment;
 
 @RunWith(SettingsRobolectricTestRunner.class)
 public class SettingsContextualCardProviderTest {
 
+    @Mock
+    private SliceManager mSliceManager;
     private ContentResolver mResolver;
     private Uri mUri;
     private SettingsContextualCardProvider mProvider;
 
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
         mResolver = RuntimeEnvironment.application.getContentResolver();
         mUri = new Uri.Builder()
                 .scheme(ContentResolver.SCHEME_CONTENT)
                 .authority(SettingsContextualCardProvider.CARD_AUTHORITY)
                 .build();
-        mProvider = Robolectric.setupContentProvider(SettingsContextualCardProvider.class);
+        mProvider = spy(Robolectric.setupContentProvider(SettingsContextualCardProvider.class));
+        final Context context = spy(RuntimeEnvironment.application);
+        doReturn(mSliceManager).when(context).getSystemService(SliceManager.class);
+        doReturn(context).when(mProvider).getContext();
     }
 
     @Test
@@ -59,7 +71,7 @@
         final int actualNo = mProvider.getContextualCards().getCardCount();
 
         final Bundle returnValue =
-                mResolver.call(mUri, ContextualCardProvider.METHOD_GET_CARD_LIST, "", null);
+                mProvider.call(ContextualCardProvider.METHOD_GET_CARD_LIST, "", null);
         final ContextualCardList cards =
                 ContextualCardList.parseFrom(
                         returnValue.getByteArray(ContextualCardProvider.BUNDLE_CARD_LIST));
@@ -76,6 +88,6 @@
             }
         }
 
-        assertThat(wifiCard.getCategory()).isEqualTo(ContextualCardCategory.IMPORTANT);
+        assertThat(wifiCard.getCardCategory()).isEqualTo(ContextualCard.Category.IMPORTANT);
     }
 }
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardRendererTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardRendererTest.java
index ccfbbfb..376042d 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardRendererTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardRendererTest.java
@@ -61,7 +61,7 @@
 
     @Test
     public void bindView_shouldSetListener() {
-        final int viewType = mRenderer.getViewType();
+        final int viewType = mRenderer.getViewType(false /* isHalfWidth */);
         final RecyclerView recyclerView = new RecyclerView(mContext);
         recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
         final View view = LayoutInflater.from(mContext).inflate(viewType, recyclerView, false);
@@ -78,7 +78,7 @@
 
     @Test
     public void viewClick_shouldInvokeControllerPrimaryClick() {
-        final int viewType = mRenderer.getViewType();
+        final int viewType = mRenderer.getViewType(false /* isHalfWidth */);
         final RecyclerView recyclerView = new RecyclerView(mContext);
         recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
         final View view = LayoutInflater.from(mContext).inflate(viewType, recyclerView, false);
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardControllerTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardControllerTest.java
new file mode 100644
index 0000000..9d9d84e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardControllerTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.homepage.contextualcards.legacysuggestion;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+
+import com.android.settings.homepage.contextualcards.ContextualCardUpdateListener;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.ShadowThreadUtils;
+import com.android.settingslib.suggestions.SuggestionController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(shadows = ShadowThreadUtils.class)
+public class LegacySuggestionContextualCardControllerTest {
+
+    @Mock
+    private SuggestionController mSuggestionController;
+    @Mock
+    private ContextualCardUpdateListener mCardUpdateListener;
+
+    private Context mContext;
+    private LegacySuggestionContextualCardController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        FakeFeatureFactory.setupForTest();
+        mContext = RuntimeEnvironment.application;
+        mController = new LegacySuggestionContextualCardController(mContext);
+    }
+
+    @Test
+    public void init_configOn_shouldCreateSuggestionController() {
+        final LegacySuggestionContextualCardController controller =
+                new LegacySuggestionContextualCardController(mContext);
+        assertThat(controller.mSuggestionController).isNotNull();
+    }
+
+    @Test
+    @Config(qualifiers = "mcc999")
+    public void init_configOff_shouldNotCreateSuggestionController() {
+        final LegacySuggestionContextualCardController controller =
+                new LegacySuggestionContextualCardController(mContext);
+
+        assertThat(controller.mSuggestionController).isNull();
+    }
+
+    @Test
+    public void goThroughLifecycle_hasSuggestionController_shouldStartStopController() {
+        mController.mSuggestionController = mSuggestionController;
+        mController.onStart();
+        verify(mSuggestionController).start();
+
+        mController.onStop();
+        verify(mSuggestionController).stop();
+    }
+
+    @Test
+    public void onServiceConnected_shouldLoadSuggestion() {
+        mController.mSuggestionController = mSuggestionController;
+        mController.setCardUpdateListener(mCardUpdateListener);
+        mController.onServiceConnected();
+
+        verify(mSuggestionController).getSuggestions();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardRendererTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardRendererTest.java
new file mode 100644
index 0000000..20f1b7b
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardRendererTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.homepage.contextualcards.legacysuggestion;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.settings.R;
+import com.android.settings.homepage.contextualcards.ContextualCard;
+import com.android.settings.homepage.contextualcards.ControllerRendererPool;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class LegacySuggestionContextualCardRendererTest {
+    @Mock
+    private ControllerRendererPool mControllerRendererPool;
+    @Mock
+    private LegacySuggestionContextualCardController mController;
+    private Context mContext;
+    private LegacySuggestionContextualCardRenderer mRenderer;
+
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mRenderer = new LegacySuggestionContextualCardRenderer(mContext, mControllerRendererPool);
+    }
+
+    @Test
+    public void bindView_shouldSetListener() {
+        final int viewType = mRenderer.getViewType(true /* isHalfWidth */);
+        final RecyclerView recyclerView = new RecyclerView(mContext);
+        recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
+        final View card = LayoutInflater.from(mContext).inflate(viewType, recyclerView, false);
+        final RecyclerView.ViewHolder viewHolder = mRenderer.createViewHolder(card);
+
+        when(mControllerRendererPool.getController(mContext,
+                ContextualCard.CardType.LEGACY_SUGGESTION)).thenReturn(mController);
+
+        mRenderer.bindView(viewHolder, buildContextualCard());
+
+        assertThat(card).isNotNull();
+        assertThat(card.hasOnClickListeners()).isTrue();
+    }
+
+    @Test
+    public void viewClick_shouldInvokeControllerPrimaryClick() {
+        final int viewType = mRenderer.getViewType(true /* isHalfWidth */);
+        final RecyclerView recyclerView = new RecyclerView(mContext);
+        recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
+        final View card = LayoutInflater.from(mContext).inflate(viewType, recyclerView, false);
+        final RecyclerView.ViewHolder viewHolder = mRenderer.createViewHolder(card);
+        when(mControllerRendererPool.getController(mContext,
+                ContextualCard.CardType.LEGACY_SUGGESTION)).thenReturn(mController);
+
+        mRenderer.bindView(viewHolder, buildContextualCard());
+
+        assertThat(card).isNotNull();
+        card.performClick();
+
+        verify(mController).onPrimaryClick(any(ContextualCard.class));
+    }
+
+    private ContextualCard buildContextualCard() {
+        return new LegacySuggestionContextualCard.Builder()
+                .setName("test_name")
+                .setTitleText("test_title")
+                .setSummaryText("test_summary")
+                .setIconDrawable(mContext.getDrawable(R.drawable.ic_do_not_disturb_on_24dp))
+                .build();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardTest.java
new file mode 100644
index 0000000..8b9a7a9
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.homepage.contextualcards.legacysuggestion;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+
+import android.app.PendingIntent;
+
+import com.android.settings.homepage.contextualcards.ContextualCard;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class LegacySuggestionContextualCardTest {
+
+    @Test(expected = IllegalArgumentException.class)
+    public void newInstance_changeCardType_shouldCrash() {
+        new LegacySuggestionContextualCard.Builder()
+                .setCardType(ContextualCard.CardType.CONDITIONAL)
+                .build();
+    }
+
+    @Test
+    public void getCardType_shouldAlwaysBeSuggestionType() {
+        assertThat(new LegacySuggestionContextualCard.Builder().build().getCardType())
+                .isEqualTo(ContextualCard.CardType.LEGACY_SUGGESTION);
+    }
+
+    @Test
+    public void build_shouldSetPendingIntent() {
+        assertThat(new LegacySuggestionContextualCard.Builder()
+                .setPendingIntent(mock(PendingIntent.class))
+                .build()
+                .getPendingIntent()).isNotNull();
+    }
+
+}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java
index 025f262..7a07d35 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java
@@ -113,7 +113,7 @@
     }
 
     private RecyclerView.ViewHolder getSliceViewHolder() {
-        final int viewType = mRenderer.getViewType();
+        final int viewType = mRenderer.getViewType(false /* isHalfWidth */);
         final RecyclerView recyclerView = new RecyclerView(mContext);
         recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
         final View view = LayoutInflater.from(mContext).inflate(viewType, recyclerView, false);
diff --git a/tests/robotests/src/com/android/settings/location/LocationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/LocationPreferenceControllerTest.java
deleted file mode 100644
index c12fdc9..0000000
--- a/tests/robotests/src/com/android/settings/location/LocationPreferenceControllerTest.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settings.location;
-
-import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
-import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.nullable;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.location.LocationManager;
-import android.provider.Settings.Secure;
-
-import androidx.lifecycle.LifecycleOwner;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.R;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-
-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;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-public class LocationPreferenceControllerTest {
-    @Mock
-    private Preference mPreference;
-    @Mock
-    private PreferenceScreen mScreen;
-
-    private LifecycleOwner mLifecycleOwner;
-    private Lifecycle mLifecycle;
-    private LocationPreferenceController mController;
-
-    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
-    private Context mContext;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mLifecycleOwner = () -> mLifecycle;
-        mLifecycle = new Lifecycle(mLifecycleOwner);
-        mController = new LocationPreferenceController(mContext, mLifecycle);
-        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
-    }
-
-    @Test
-    public void isAvailable_shouldReturnTrue() {
-        assertThat(mController.isAvailable()).isTrue();
-    }
-
-    @Test
-    public void updateState_shouldSetSummary() {
-        mController.updateState(mPreference);
-
-        verify(mPreference).setSummary(nullable(String.class));
-    }
-
-    @Test
-    public void updateSummary_shouldSetSummary() {
-        mController.displayPreference(mScreen);
-        mController.updateSummary();
-
-        verify(mPreference).setSummary(nullable(String.class));
-    }
-
-    @Test
-    public void getLocationSummary_locationOff_shouldSetSummaryOff() {
-        final ContentResolver contentResolver = mContext.getContentResolver();
-        Secure.putInt(contentResolver, Secure.LOCATION_MODE, Secure.LOCATION_MODE_OFF);
-
-        final String locationSummary = mController.getLocationSummary(mContext);
-        assertThat(locationSummary).isEqualTo(mContext.getString(R.string.location_off_summary));
-    }
-
-    @Test
-    public void getLocationSummary_sensorsOnly_shouldSetSummaryOn() {
-        final ContentResolver contentResolver = mContext.getContentResolver();
-        Secure.putInt(contentResolver, Secure.LOCATION_MODE, Secure.LOCATION_MODE_SENSORS_ONLY);
-
-        final String locationSummary = mController.getLocationSummary(mContext);
-        assertThat(locationSummary).isEqualTo(mContext.getString(R.string.location_on_summary));
-    }
-
-    @Test
-    public void getLocationSummary_highAccuracy_shouldSetSummaryOn() {
-        final ContentResolver contentResolver = mContext.getContentResolver();
-        Secure.putInt(contentResolver, Secure.LOCATION_MODE, Secure.LOCATION_MODE_HIGH_ACCURACY);
-
-        final String locationSummary = mController.getLocationSummary(mContext);
-        assertThat(locationSummary).isEqualTo(mContext.getString(R.string.location_on_summary));
-    }
-
-    @Test
-    public void getLocationSummary_batterySaving_shouldSetSummaryOn() {
-        final ContentResolver contentResolver = mContext.getContentResolver();
-        Secure.putInt(contentResolver, Secure.LOCATION_MODE, Secure.LOCATION_MODE_BATTERY_SAVING);
-
-        final String locationSummary = mController.getLocationSummary(mContext);
-        assertThat(locationSummary).isEqualTo(mContext.getString(R.string.location_on_summary));
-    }
-
-    @Test
-    public void onResume_shouldRegisterObserver() {
-        mLifecycle.handleLifecycleEvent(ON_RESUME);
-        verify(mContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class));
-    }
-
-    @Test
-    public void onPause_shouldUnregisterObserver() {
-        mLifecycle.handleLifecycleEvent(ON_RESUME);
-        mLifecycle.handleLifecycleEvent(ON_PAUSE);
-        verify(mContext).unregisterReceiver(any(BroadcastReceiver.class));
-    }
-
-    @Test
-    public void locationProvidersChangedReceiver_updatesPreferenceSummary() {
-        mController.displayPreference(mScreen);
-        mController.onResume();
-
-        mController.mLocationProvidersChangedReceiver
-                .onReceive(mContext, new Intent(LocationManager.PROVIDERS_CHANGED_ACTION));
-
-        verify(mPreference).setSummary(any());
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/network/telephony/ApnPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/ApnPreferenceControllerTest.java
index dc277d2..9664428 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/ApnPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/ApnPreferenceControllerTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.app.Activity;
 import android.content.Context;
@@ -115,6 +116,14 @@
     }
 
     @Test
+    public void getAvailabilityStatus_carrierConfigNull_returnUnavailable() {
+        doReturn(PhoneConstants.PHONE_TYPE_GSM).when(mTelephonyManager).getPhoneType();
+        when(mCarrierConfigManager.getConfigForSubId(SUB_ID)).thenReturn(null);
+
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+    }
+
+    @Test
     public void handPreferenceTreeClick_fireIntent() {
         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
 
diff --git a/tests/robotests/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java
index 71df401..02710fb 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java
@@ -23,7 +23,6 @@
 
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 
@@ -80,8 +79,7 @@
         mPreference = new ListPreference(mContext);
         mPreference.setEntries(R.array.enabled_networks_choices);
         mPreference.setEntryValues(R.array.enabled_networks_values);
-        mController = spy(new EnabledNetworkModePreferenceController(mContext, "enabled_network"));
-        doNothing().when(mController).initShow4GForLTE();
+        mController = new EnabledNetworkModePreferenceController(mContext, "enabled_network");
         mController.init(SUB_ID);
         mPreference.setKey(mController.getPreferenceKey());
     }
@@ -104,6 +102,16 @@
     }
 
     @Test
+    public void init_initShow4GForLTE() {
+        mPersistableBundle.putBoolean(CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL,
+                true);
+
+        mController.init(SUB_ID);
+
+        assertThat(mController.mShow4GForLTE).isTrue();
+    }
+
+    @Test
     public void updateState_updateByNetworkMode() {
         Settings.Global.putInt(mContext.getContentResolver(),
                 Settings.Global.PREFERRED_NETWORK_MODE + SUB_ID,
diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java
index 676c9f4..8a57a0c 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java
@@ -165,7 +165,8 @@
     @Test
     public void isCdmaOptions_worldModeWithGsmWcdma_returnTrue() {
         when(mTelephonyManager.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM);
-        when(mContext.getString(R.string.config_world_mode)).thenReturn("true");
+        mCarrierConfig.putBoolean(CarrierConfigManager.KEY_WORLD_MODE_ENABLED_BOOL, true);
+
         Settings.Global.putInt(mContext.getContentResolver(),
                 android.provider.Settings.Global.PREFERRED_NETWORK_MODE + SUB_ID_1,
                 TelephonyManager.NETWORK_MODE_LTE_GSM_WCDMA);
diff --git a/tests/robotests/src/com/android/settings/print/PrintJobMessagePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/print/PrintJobMessagePreferenceControllerTest.java
new file mode 100644
index 0000000..50dd38b
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/print/PrintJobMessagePreferenceControllerTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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 static androidx.lifecycle.Lifecycle.Event.ON_START;
+import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.print.PrintJob;
+import android.print.PrintJobInfo;
+import android.print.PrintManager;
+
+import androidx.lifecycle.LifecycleOwner;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class PrintJobMessagePreferenceControllerTest {
+    private static final String PREF_KEY = "print_job_message_preference";
+
+    @Mock
+    private PrintManager mPrintManager;
+    @Mock
+    private PrintJob mPrintJob;
+    @Mock
+    private PrintJobInfo mPrintJobInfo;
+    @Mock
+    private PreferenceScreen mScreen;
+
+    private Context mContext;
+    private PrintJobMessagePreferenceController mController;
+    private Preference mPreference;
+    private LifecycleOwner mLifecycleOwner;
+    private Lifecycle mLifecycle;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        mPreference = new Preference(mContext);
+        when(mContext.getSystemService(Context.PRINT_SERVICE)).thenReturn(mPrintManager);
+        when(mPrintManager.getGlobalPrintManagerForUser(anyInt())).thenReturn(mPrintManager);
+        when(mPrintManager.getPrintJob(anyObject())).thenReturn(mPrintJob);
+        when(mPrintJob.getInfo()).thenReturn(mPrintJobInfo);
+        mController = new PrintJobMessagePreferenceController(mContext, PREF_KEY);
+        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
+        mController.displayPreference(mScreen);
+        mLifecycleOwner = () -> mLifecycle;
+        mLifecycle = new Lifecycle(mLifecycleOwner);
+        mLifecycle.addObserver(mController);
+    }
+
+    @Test
+    public void onStartStop_shouldRegisterPrintStateListener() {
+        mLifecycle.handleLifecycleEvent(ON_START);
+        mLifecycle.handleLifecycleEvent(ON_STOP);
+
+        verify(mPrintManager).addPrintJobStateChangeListener(mController);
+        verify(mPrintManager).removePrintJobStateChangeListener(mController);
+    }
+
+    @Test
+    public void updateUi_visiblePreference() {
+        when(mPrintJobInfo.getStatus(anyObject())).thenReturn("TestPrint");
+        mLifecycle.handleLifecycleEvent(ON_START);
+
+        assertThat(mPreference.isVisible()).isTrue();
+
+        mLifecycle.handleLifecycleEvent(ON_STOP);
+    }
+
+    @Test
+    public void updateUi_invisiblePreference() {
+        when(mPrintJobInfo.getStatus(anyObject())).thenReturn(null);
+        mLifecycle.handleLifecycleEvent(ON_START);
+
+        assertThat(mPreference.isVisible()).isFalse();
+
+        mLifecycle.handleLifecycleEvent(ON_STOP);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/print/PrintJobPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/print/PrintJobPreferenceControllerTest.java
new file mode 100644
index 0000000..fc92eb3
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/print/PrintJobPreferenceControllerTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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 static androidx.lifecycle.Lifecycle.Event.ON_START;
+import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.print.PrintJob;
+import android.print.PrintJobInfo;
+import android.print.PrintManager;
+
+import androidx.lifecycle.LifecycleOwner;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class PrintJobPreferenceControllerTest {
+    private static final String PREF_KEY = "print_job_preference";
+
+    @Mock
+    private PrintManager mPrintManager;
+    @Mock
+    private PrintJob mPrintJob;
+    @Mock
+    private PrintJobInfo mPrintJobInfo;
+    @Mock
+    private PreferenceScreen mScreen;
+
+    private Context mContext;
+    private LifecycleOwner mLifecycleOwner;
+    private Lifecycle mLifecycle;
+    private PrintJobPreferenceController mController;
+    private Preference mPreference;
+    private String mTestLabel;
+
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        mPreference = new Preference(mContext);
+        mTestLabel = "PrintTest";
+        when(mContext.getSystemService(Context.PRINT_SERVICE)).thenReturn(mPrintManager);
+        when(mPrintManager.getGlobalPrintManagerForUser(anyInt())).thenReturn(mPrintManager);
+        when(mPrintManager.getPrintJob(anyObject())).thenReturn(mPrintJob);
+        when(mPrintJob.getInfo()).thenReturn(mPrintJobInfo);
+        mController = new PrintJobPreferenceController(mContext, PREF_KEY);
+        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
+        when(mPrintJobInfo.getLabel()).thenReturn(mTestLabel);
+        mController.displayPreference(mScreen);
+        mLifecycleOwner = () -> mLifecycle;
+        mLifecycle = new Lifecycle(mLifecycleOwner);
+        mLifecycle.addObserver(mController);
+    }
+
+    @Test
+    public void onStartStop_shouldRegisterPrintStateListener() {
+        mLifecycle.handleLifecycleEvent(ON_START);
+        mLifecycle.handleLifecycleEvent(ON_STOP);
+
+        verify(mPrintManager).addPrintJobStateChangeListener(mController);
+        verify(mPrintManager).removePrintJobStateChangeListener(mController);
+    }
+
+    @Test
+    public void updateUi_jobState_STATE_CREATED() {
+        when(mPrintJobInfo.getState()).thenReturn(PrintJobInfo.STATE_CREATED);
+
+        mController.onStart();
+        String title = mContext.getString(
+                R.string.print_configuring_state_title_template, mTestLabel);
+
+        assertThat(mPreference.getTitle()).isEqualTo(title);
+    }
+
+    @Test
+    public void updateUi_jobState_STATE_QUEUED() {
+        when(mPrintJobInfo.getState()).thenReturn(PrintJobInfo.STATE_QUEUED);
+
+        mController.onStart();
+        String title = mContext.getString(
+                R.string.print_printing_state_title_template, mTestLabel);
+
+        assertThat(mPreference.getTitle()).isEqualTo(title);
+    }
+
+    @Test
+    public void updateUi_jobState_STATE_STARTED() {
+        when(mPrintJobInfo.getState()).thenReturn(PrintJobInfo.STATE_STARTED);
+
+        mController.onStart();
+        String title = mContext.getString(
+                R.string.print_printing_state_title_template, mTestLabel);
+
+        assertThat(mPreference.getTitle()).isEqualTo(title);
+    }
+
+    @Test
+    public void updateUi_jobState_STATE_QUEUED_and_jobInfo_CANCELLING() {
+        when(mPrintJobInfo.getState()).thenReturn(PrintJobInfo.STATE_QUEUED);
+        when(mPrintJobInfo.isCancelling()).thenReturn(true);
+
+        mController.onStart();
+        String title = mContext.getString(
+                R.string.print_cancelling_state_title_template, mTestLabel);
+
+        assertThat(mPreference.getTitle()).isEqualTo(title);
+    }
+
+    @Test
+    public void updateUi_jobState_STATE_STARTED_and_jobInfo_CANCELLING() {
+        when(mPrintJobInfo.getState()).thenReturn(PrintJobInfo.STATE_STARTED);
+        when(mPrintJobInfo.isCancelling()).thenReturn(true);
+
+        mController.onStart();
+        String title = mContext.getString(
+                R.string.print_cancelling_state_title_template, mTestLabel);
+
+        assertThat(mPreference.getTitle()).isEqualTo(title);
+    }
+
+    @Test
+    public void updateUi_jobState_STATE_FAILED() {
+        when(mPrintJobInfo.getState()).thenReturn(PrintJobInfo.STATE_FAILED);
+
+        mController.onStart();
+        String title = mContext.getString(
+                R.string.print_failed_state_title_template, mTestLabel);
+
+        assertThat(mPreference.getTitle()).isEqualTo(title);
+    }
+
+    @Test
+    public void updateUi_jobState_STATE_BLOCKED() {
+        when(mPrintJobInfo.getState()).thenReturn(PrintJobInfo.STATE_BLOCKED);
+
+        mController.onStart();
+        String title = mContext.getString(
+                R.string.print_blocked_state_title_template, mTestLabel);
+
+        assertThat(mPreference.getTitle()).isEqualTo(title);
+    }
+
+    @Test
+    public void updateUi_jobState_STATE_BLOCKED_and_jobInfo_CANCELLING() {
+        when(mPrintJobInfo.getState()).thenReturn(PrintJobInfo.STATE_BLOCKED);
+        when(mPrintJobInfo.isCancelling()).thenReturn(true);
+
+        mController.onStart();
+        String title = mContext.getString(
+                R.string.print_cancelling_state_title_template, mTestLabel);
+
+        assertThat(mPreference.getTitle()).isEqualTo(title);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/search/SearchFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/search/SearchFeatureProviderImplTest.java
index ba29ea1..d0546b6 100644
--- a/tests/robotests/src/com/android/settings/search/SearchFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/search/SearchFeatureProviderImplTest.java
@@ -29,12 +29,14 @@
 
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.ShadowUtils;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.Robolectric;
 import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
 
 @RunWith(SettingsRobolectricTestRunner.class)
 public class SearchFeatureProviderImplTest {
@@ -50,6 +52,7 @@
     }
 
     @Test
+    @Config(shadows = ShadowUtils.class)
     public void initSearchToolbar_shouldInitWithOnClickListener() {
         mProvider.initSearchToolbar(mActivity, null);
         // Should not crash.
diff --git a/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java b/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java
index 3ab4ab4..b4076b5 100644
--- a/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java
+++ b/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java
@@ -30,6 +30,7 @@
 
 import com.android.settings.R;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.ShadowUtils;
 import com.android.settingslib.core.lifecycle.ObservableFragment;
 import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment;
 
@@ -39,8 +40,10 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(SettingsRobolectricTestRunner.class)
+@Config(shadows = ShadowUtils.class)
 public class SearchMenuControllerTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
index a0fd21b..3c2cbdb 100644
--- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
@@ -25,6 +25,7 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -60,6 +61,7 @@
 import com.android.settings.testutils.shadow.ShadowUserManager;
 import com.android.settings.testutils.shadow.ShadowUtils;
 import com.android.settings.wifi.WifiSlice;
+import com.android.settingslib.wifi.WifiTracker;
 
 import org.junit.After;
 import org.junit.Before;
@@ -75,7 +77,6 @@
 import org.robolectric.shadow.api.Shadow;
 import org.robolectric.shadows.ShadowAccessibilityManager;
 
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -91,7 +92,8 @@
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(shadows = {ShadowUserManager.class, ShadowThreadUtils.class, ShadowUtils.class,
         SlicesDatabaseAccessorTest.ShadowApplicationPackageManager.class,
-        ShadowBluetoothAdapter.class, ShadowLockPatternUtils.class})
+        ShadowBluetoothAdapter.class, ShadowLockPatternUtils.class,
+        SettingsSliceProviderTest.ShadowWifiScanWorker.class})
 public class SettingsSliceProviderTest {
 
     private static final String KEY = "KEY";
@@ -135,7 +137,7 @@
         mProvider.mSliceWeakDataCache = new HashMap<>();
         mProvider.mSliceDataCache = new HashMap<>();
         mProvider.mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(mContext);
-        mProvider.mCustomSliceManager = spy(new CustomSliceManager(mContext));
+        mProvider.mCustomSliceManager = new CustomSliceManager(mContext);
         when(mProvider.getContext()).thenReturn(mContext);
 
         SlicesDatabaseHelper.getInstance(mContext).setIndexedState();
@@ -497,57 +499,52 @@
         mProvider.onSlicePinned(uri);
     }
 
-    private SliceBackgroundWorker initBackgroundWorker(Uri uri) {
-        final SliceBackgroundWorker worker = spy(new SliceBackgroundWorker(
-                mContext.getContentResolver(), uri) {
-            @Override
-            protected void onSlicePinned() {
-            }
+    @Implements(WifiSlice.WifiScanWorker.class)
+    public static class ShadowWifiScanWorker {
+        private static WifiTracker mWifiTracker;
 
-            @Override
-            protected void onSliceUnpinned() {
-            }
+        @Implementation
+        protected void onSlicePinned() {
+            mWifiTracker = mock(WifiTracker.class);
+            mWifiTracker.onStart();
+        }
 
-            @Override
-            public void close() {
-            }
-        });
-        final WifiSlice wifiSlice = spy(new WifiSlice(mContext));
-        when(wifiSlice.getBackgroundWorker()).thenReturn(worker);
-        when(mProvider.mCustomSliceManager.getSliceableFromUri(uri)).thenReturn(wifiSlice);
-        return worker;
+        @Implementation
+        protected void onSliceUnpinned() {
+            mWifiTracker.onStop();
+        }
+
+        @Implementation
+        public void close() {
+            mWifiTracker.onDestroy();
+        }
+
+        static WifiTracker getWifiTracker() {
+            return mWifiTracker;
+        }
     }
 
     @Test
     public void onSlicePinned_backgroundWorker_started() {
-        final Uri uri = WifiSlice.WIFI_URI;
-        final SliceBackgroundWorker worker = initBackgroundWorker(uri);
+        mProvider.onSlicePinned(WifiSlice.WIFI_URI);
 
-        mProvider.onSlicePinned(uri);
-
-        verify(worker).onSlicePinned();
+        verify(ShadowWifiScanWorker.getWifiTracker()).onStart();
     }
 
     @Test
     public void onSlicePinned_backgroundWorker_stopped() {
-        final Uri uri = WifiSlice.WIFI_URI;
-        final SliceBackgroundWorker worker = initBackgroundWorker(uri);
+        mProvider.onSlicePinned(WifiSlice.WIFI_URI);
+        mProvider.onSliceUnpinned(WifiSlice.WIFI_URI);
 
-        mProvider.onSlicePinned(uri);
-        mProvider.onSliceUnpinned(uri);
-
-        verify(worker).onSliceUnpinned();
+        verify(ShadowWifiScanWorker.getWifiTracker()).onStop();
     }
 
     @Test
-    public void shutdown_backgroundWorker_closed() throws IOException {
-        final Uri uri = WifiSlice.WIFI_URI;
-        final SliceBackgroundWorker worker = initBackgroundWorker(uri);
-
-        mProvider.onSlicePinned(uri);
+    public void shutdown_backgroundWorker_closed() {
+        mProvider.onSlicePinned(WifiSlice.WIFI_URI);
         mProvider.shutdown();
 
-        verify(worker).close();
+        verify(ShadowWifiScanWorker.getWifiTracker()).onDestroy();
     }
 
     @Test
@@ -630,4 +627,4 @@
             return sSetThreadPolicyCount != 0;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
index 1055667..4371278 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
@@ -41,6 +41,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
+import com.android.settings.testutils.FakeCopyableController;
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.testutils.FakeSliderController;
 import com.android.settings.testutils.FakeToggleController;
@@ -67,6 +68,7 @@
     private final Uri URI = Uri.parse("content://com.android.settings.slices/test");
     private final Class TOGGLE_CONTROLLER = FakeToggleController.class;
     private final Class SLIDER_CONTROLLER = FakeSliderController.class;
+    private final Class COPYABLE_CONTROLLER = FakeCopyableController.class;
     private final Class CONTEXT_CONTROLLER = FakeContextOnlyPreferenceController.class;
     private final boolean IS_DYNAMIC_SUMMARY_ALLOWED = false;
 
@@ -116,7 +118,6 @@
     public void buildSliderSlice_returnsMatchingSlice() {
         final SliceData data = getDummyData(SLIDER_CONTROLLER, SliceData.SliceType.SLIDER);
 
-
         final Slice slice = SliceBuilderUtils.buildSlice(mContext, data);
         verify(mFeatureFactory.metricsFeatureProvider)
                 .action(eq(mContext), eq(MetricsEvent.ACTION_SETTINGS_SLICE_REQUESTED),
@@ -131,6 +132,23 @@
     }
 
     @Test
+    public void buildCopyableSlice_returnsMatchingSlice() {
+        final SliceData dummyData = getDummyData(COPYABLE_CONTROLLER, -1);
+
+        final Slice slice = SliceBuilderUtils.buildSlice(mContext, dummyData);
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(eq(mContext), eq(MetricsEvent.ACTION_SETTINGS_SLICE_REQUESTED),
+                        mLoggingArgumentCatpor.capture());
+        final Pair<Integer, Object> capturedLoggingPair = mLoggingArgumentCatpor.getValue();
+
+        assertThat(capturedLoggingPair.first)
+                .isEqualTo(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME);
+        assertThat(capturedLoggingPair.second)
+                .isEqualTo(dummyData.getKey());
+        SliceTester.testSettingsCopyableSlice(mContext, slice, dummyData);
+    }
+
+    @Test
     public void testUriBuilder_oemAuthority_intentPath_returnsValidSliceUri() {
         final Uri expectedUri = new Uri.Builder()
                 .scheme(ContentResolver.SCHEME_CONTENT)
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeCopyableController.java b/tests/robotests/src/com/android/settings/testutils/FakeCopyableController.java
new file mode 100644
index 0000000..a02377c
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/FakeCopyableController.java
@@ -0,0 +1,44 @@
+/*
+ * 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.testutils;
+
+import android.content.Context;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.slices.CopyableSlice;
+
+public class FakeCopyableController extends BasePreferenceController implements
+        CopyableSlice {
+
+    public FakeCopyableController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public boolean isSliceable() {
+        return true;
+    }
+
+    @Override
+    public void copy() {
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/SliceTester.java b/tests/robotests/src/com/android/settings/testutils/SliceTester.java
index 892f948..be4199d 100644
--- a/tests/robotests/src/com/android/settings/testutils/SliceTester.java
+++ b/tests/robotests/src/com/android/settings/testutils/SliceTester.java
@@ -169,6 +169,43 @@
     }
 
     /**
+     * Test the copyable slice, including:
+     * - No intent
+     * - Correct title
+     * - Correct intent
+     * - Correct keywords
+     * - TTL
+     * - Color
+     */
+    public static void testSettingsCopyableSlice(Context context, Slice slice,
+            SliceData sliceData) {
+        final SliceMetadata metadata = SliceMetadata.from(context, slice);
+
+        final SliceItem colorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
+        final int color = colorItem.getInt();
+        assertThat(color).isEqualTo(Utils.getColorAccentDefaultColor(context));
+
+        final SliceAction primaryAction = metadata.getPrimaryAction();
+
+        final IconCompat expectedIcon = IconCompat.createWithResource(context,
+                sliceData.getIconResource());
+        assertThat(expectedIcon.toString()).isEqualTo(primaryAction.getIcon().toString());
+
+        final long sliceTTL = metadata.getExpiry();
+        assertThat(sliceTTL).isEqualTo(ListBuilder.INFINITY);
+
+        // Check primary intent
+        final PendingIntent primaryPendingIntent = primaryAction.getAction();
+        assertThat(primaryPendingIntent).isEqualTo(
+                SliceBuilderUtils.getContentPendingIntent(context, sliceData));
+
+        final List<SliceItem> sliceItems = slice.getItems();
+        assertTitle(sliceItems, sliceData.getTitle());
+
+        assertKeywords(metadata, sliceData);
+    }
+
+    /**
      * Test the contents of an unavailable slice, including:
      * - No toggles
      * - Correct title
@@ -229,4 +266,4 @@
         expectedKeywords.add(data.getScreenTitle().toString());
         assertThat(keywords).containsExactlyElementsIn(expectedKeywords);
     }
-}
\ No newline at end of file
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccountManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccountManager.java
index 03aabb5..4401926 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccountManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccountManager.java
@@ -16,19 +16,24 @@
 
 package com.android.settings.testutils.shadow;
 
+import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.AuthenticatorDescription;
+import android.annotation.NonNull;
 
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 @Implements(AccountManager.class)
 public class ShadowAccountManager{
 
     private static final Map<String, AuthenticatorDescription> sAuthenticators = new HashMap<>();
+    private static final Map<Integer, List<Account>> sAccountsByUserId = new HashMap<>();
 
     @Implementation
     public AuthenticatorDescription[] getAuthenticatorTypesAsUser(int userId) {
@@ -39,7 +44,24 @@
         sAuthenticators.put(authenticator.type, authenticator);
     }
 
-    public static void resetAuthenticator() {
+    public static void reset() {
         sAuthenticators.clear();
+        sAccountsByUserId.clear();
+    }
+
+    @Implementation @NonNull
+    public Account[] getAccountsAsUser(int userId) {
+        if (sAccountsByUserId.containsKey(userId)) {
+            return sAccountsByUserId.get(userId).toArray(new Account[0]);
+        } else {
+            return new Account[0];
+        }
+    }
+
+    public static void addAccountForUser(int userId, Account account) {
+        if (!sAccountsByUserId.containsKey(userId)) {
+            sAccountsByUserId.put(userId, new ArrayList<>());
+        }
+        sAccountsByUserId.get(userId).add(account);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java
index b09bc74..0927956 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java
@@ -21,9 +21,13 @@
 import android.hardware.fingerprint.FingerprintManager;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.Log;
 
 import com.android.settings.Utils;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.search.SearchFeatureProviderImpl;
 
+import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
 
@@ -102,6 +106,11 @@
         return null;
     }
 
+    @Implementation
+    public static boolean isPackageEnabled(Context context, String packageName) {
+        return true;
+    }
+
     public static void setApplicationLabel(String packageName, String appLabel) {
         if (sAppNameMap == null) {
             sAppNameMap = new HashMap<>();
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/WifiSettingsTest.java
index e9daec3..c9e6c1e 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiSettingsTest.java
@@ -20,20 +20,31 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.app.Activity;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.os.PowerManager;
+import android.provider.Settings;
 
+import androidx.preference.Preference;
+
+import com.android.settings.R;
 import com.android.settings.search.SearchIndexableRaw;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.wifi.WifiTracker;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 
@@ -42,18 +53,33 @@
 @RunWith(SettingsRobolectricTestRunner.class)
 public class WifiSettingsTest {
 
+    private static final int NUM_NETWORKS = 4;
+
+    @Mock
+    private WifiTracker mWifiTracker;
+    @Mock
+    private PowerManager mPowerManager;
     private Context mContext;
+    private WifiSettings mWifiSettings;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = spy(RuntimeEnvironment.application);
+
+        mWifiSettings = spy(new WifiSettings());
+        doReturn(mContext).when(mWifiSettings).getContext();
+        doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
+        mWifiSettings.mSavedNetworksPreference = new Preference(mContext);
+        mWifiSettings.mConfigureWifiSettingsPreference = new Preference(mContext);
+        mWifiSettings.mWifiTracker = mWifiTracker;
     }
 
     @Test
     public void testSearchIndexProvider_shouldIndexFragmentTitle() {
         final List<SearchIndexableRaw> indexRes =
-            WifiSettings.SEARCH_INDEX_DATA_PROVIDER.getRawDataToIndex(mContext, true /* enabled */);
+                WifiSettings.SEARCH_INDEX_DATA_PROVIDER.getRawDataToIndex(mContext,
+                        true /* enabled */);
 
         assertThat(indexRes).isNotNull();
         assertThat(indexRes.get(0).key).isEqualTo(WifiSettings.DATA_KEY_REFERENCE);
@@ -63,7 +89,8 @@
     @Config(qualifiers = "mcc999")
     public void testSearchIndexProvider_ifWifiSettingsNotVisible_shouldNotIndexFragmentTitle() {
         final List<SearchIndexableRaw> indexRes =
-            WifiSettings.SEARCH_INDEX_DATA_PROVIDER.getRawDataToIndex(mContext, true /* enabled */);
+                WifiSettings.SEARCH_INDEX_DATA_PROVIDER.getRawDataToIndex(mContext,
+                        true /* enabled */);
 
         assertThat(indexRes).isEmpty();
     }
@@ -78,4 +105,51 @@
 
         verify(wifiSettings).handleAddNetworkRequest(anyInt(), any(Intent.class));
     }
+
+    @Test
+    public void setAdditionalSettingsSummaries_hasSavedNetwork_preferenceVisible() {
+        when(mWifiTracker.getNumSavedNetworks()).thenReturn(NUM_NETWORKS);
+
+        mWifiSettings.setAdditionalSettingsSummaries();
+
+        assertThat(mWifiSettings.mSavedNetworksPreference.isVisible()).isTrue();
+        assertThat(mWifiSettings.mSavedNetworksPreference.getSummary()).isEqualTo(
+                mContext.getResources().getQuantityString(
+                        R.plurals.wifi_saved_access_points_summary,
+                        NUM_NETWORKS, NUM_NETWORKS));
+    }
+
+    @Test
+    public void setAdditionalSettingsSummaries_noSavedNetwork_preferenceInvisible() {
+        when(mWifiTracker.getNumSavedNetworks()).thenReturn(0);
+
+        mWifiSettings.setAdditionalSettingsSummaries();
+
+        assertThat(mWifiSettings.mSavedNetworksPreference.isVisible()).isFalse();
+    }
+
+    @Test
+    public void setAdditionalSettingsSummaries_wifiWakeupEnabled_displayOn() {
+        final ContentResolver contentResolver = mContext.getContentResolver();
+        Settings.Global.putInt(contentResolver, Settings.Global.WIFI_WAKEUP_ENABLED, 1);
+        Settings.Global.putInt(contentResolver, Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 1);
+        Settings.Global.putInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, 0);
+        when(mPowerManager.isPowerSaveMode()).thenReturn(false);
+
+        mWifiSettings.setAdditionalSettingsSummaries();
+
+        assertThat(mWifiSettings.mConfigureWifiSettingsPreference.getSummary()).isEqualTo(
+                mContext.getString(R.string.wifi_configure_settings_preference_summary_wakeup_on));
+    }
+
+    @Test
+    public void setAdditionalSettingsSummaries_wifiWakeupDisabled_displayOff() {
+        final ContentResolver contentResolver = mContext.getContentResolver();
+        Settings.Global.putInt(contentResolver, Settings.Global.WIFI_WAKEUP_ENABLED, 0);
+
+        mWifiSettings.setAdditionalSettingsSummaries();
+
+        assertThat(mWifiSettings.mConfigureWifiSettingsPreference.getSummary()).isEqualTo(
+                mContext.getString(R.string.wifi_configure_settings_preference_summary_wakeup_off));
+    }
 }
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java
index f813185..e8d13df 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java
@@ -66,7 +66,7 @@
     public void onPreferenceChange_securityValueUpdated() {
         mController.onPreferenceChange(mPreference, WPA2_PSK);
         assertThat(mController.getSecurityType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
-        assertThat(mPreference.getSummary()).isEqualTo("WPA2 PSK");
+        assertThat(mPreference.getSummary()).isEqualTo("WPA2-Personal");
 
         mController.onPreferenceChange(mPreference, NONE);
         assertThat(mController.getSecurityType()).isEqualTo(WifiConfiguration.KeyMgmt.NONE);
@@ -75,11 +75,11 @@
 
     @Test
     public void updateDisplay_preferenceUpdated() {
-        // test defaulting to WPA2 PSK on new config
+        // test defaulting to WPA2-Personal on new config
         when(mWifiManager.getWifiApConfiguration()).thenReturn(null);
         mController.updateDisplay();
         assertThat(mController.getSecurityType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
-        assertThat(mPreference.getSummary()).isEqualTo("WPA2 PSK");
+        assertThat(mPreference.getSummary()).isEqualTo("WPA2-Personal");
 
         // test open tether network
         when(mWifiManager.getWifiApConfiguration()).thenReturn(mConfig);
@@ -89,11 +89,11 @@
         assertThat(mController.getSecurityType()).isEqualTo(WifiConfiguration.KeyMgmt.NONE);
         assertThat(mPreference.getSummary()).isEqualTo("None");
 
-        // test WPA2 PSK tether network
+        // test WPA2-Personal tether network
         mConfig.allowedKeyManagement.clear();
         mConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA2_PSK);
         mController.updateDisplay();
         assertThat(mController.getSecurityType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
-        assertThat(mPreference.getSummary()).isEqualTo("WPA2 PSK");
+        assertThat(mPreference.getSummary()).isEqualTo("WPA2-Personal");
     }
 }
diff --git a/tests/uitests/assets/search_results_list b/tests/uitests/assets/search_results_list
index a0cc894..6f7c513 100644
--- a/tests/uitests/assets/search_results_list
+++ b/tests/uitests/assets/search_results_list
@@ -166,7 +166,6 @@
 Device security;security_category
 Device theme;theme
 Dial pad tones;dial_pad_tones
-Directory access;special_app_directory_access
 Disable Bluetooth A2DP hardware offload;bluetooth_disable_a2dp_hw_offload
 Disable HW overlays;disable_overlays
 Disable USB audio routing;usb_audio
@@ -236,6 +235,7 @@
 Force RTL layout direction;force_rtl_layout_all_locales
 Force activities to be resizable;force_resizable_activities
 Force allow apps on external;force_allow_on_external
+Force desktop mode;force_desktop_mode_on_external_displays
 Force full GNSS measurements;enable_gnss_raw_meas_full_tracking
 Free up space;storage_settings_free_space
 Games;pref_games
@@ -620,4 +620,4 @@
  ;auto_brightness_video
  ;battery_header
  ;battery_tip
- ;feature_flag_category
\ No newline at end of file
+ ;feature_flag_category