Merge "Show "Done" button to prevent user from getting stuck"
diff --git a/color-check-baseline.xml b/color-check-baseline.xml
index 787c559..fd0fc6c 100644
--- a/color-check-baseline.xml
+++ b/color-check-baseline.xml
@@ -2,18 +2,6 @@
 <issues format="4">
 
     <issue
-        id="LintError"
-        severity="Error"
-        message="No `.class` files were found in project &quot;.&quot;, so none of the classfile based checks could be run. Does the project need to be built first?"
-        category="Lint"
-        priority="10"
-        summary="Lint Failure"
-        explanation="This issue type represents a problem running lint itself. Examples include failure to find bytecode for source files (which means certain detectors could not be run), parsing errors in lint configuration files, etc.&#xA;These errors are not errors in your own code, but they are shown to make it clear that some checks were not completed.">
-        <location
-            file="."/>
-    </issue>
-
-    <issue
         id="HardCodedColor"
         severity="Error"
         message="Avoid using hardcoded color"
@@ -1301,6 +1289,54 @@
         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;qr_corner_line_color&quot;>#ffdadce0&lt;/color>"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/values/colors.xml"
+            line="133"
+            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;qr_focused_corner_line_color&quot;>#ff1a73e8&lt;/color>"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/values/colors.xml"
+            line="134"
+            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;qr_background_color&quot;>#b3ffffff&lt;/color> &lt;!-- 70% white transparency -->"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/values/colors.xml"
+            line="135"
+            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="                android:background=&quot;@color/lock_pattern_background&quot; />"
         errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
@@ -2441,7 +2477,7 @@
         errorLine2="                                   ~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/strings.xml"
-            line="5805"
+            line="5883"
             column="36"/>
     </issue>
 
@@ -2473,7 +2509,7 @@
         errorLine2="                                           ^">
         <location
             file="res/values/styles.xml"
-            line="425"
+            line="415"
             column="44"/>
     </issue>
 
@@ -2489,7 +2525,7 @@
         errorLine2="                                           ^">
         <location
             file="res/values/styles.xml"
-            line="431"
+            line="421"
             column="44"/>
     </issue>
 
@@ -2505,7 +2541,7 @@
         errorLine2="                                           ^">
         <location
             file="res/values/styles.xml"
-            line="432"
+            line="422"
             column="44"/>
     </issue>
 
@@ -2521,23 +2557,7 @@
         errorLine2="                                 ^">
         <location
             file="res/values/styles.xml"
-            line="467"
-            column="34"/>
-    </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;item name=&quot;strokeColor&quot;>@color/homepage_card_stroke_color&lt;/item>"
-        errorLine2="                                 ^">
-        <location
-            file="res/values/styles.xml"
-            line="474"
+            line="457"
             column="34"/>
     </issue>
 
@@ -2553,7 +2573,7 @@
         errorLine2="                                      ^">
         <location
             file="res/values/themes.xml"
-            line="54"
+            line="57"
             column="39"/>
     </issue>
 
@@ -2569,7 +2589,7 @@
         errorLine2="                                       ^">
         <location
             file="res/values/themes.xml"
-            line="55"
+            line="58"
             column="40"/>
     </issue>
 
@@ -2585,7 +2605,7 @@
         errorLine2="                                     ^">
         <location
             file="res/values/themes.xml"
-            line="56"
+            line="59"
             column="38"/>
     </issue>
 
@@ -2601,7 +2621,7 @@
         errorLine2="                                              ^">
         <location
             file="res/values/themes.xml"
-            line="90"
+            line="97"
             column="47"/>
     </issue>
 
@@ -2617,7 +2637,7 @@
         errorLine2="                                              ^">
         <location
             file="res/values/themes.xml"
-            line="90"
+            line="97"
             column="47"/>
     </issue>
 
@@ -2633,7 +2653,7 @@
         errorLine2="                                       ^">
         <location
             file="res/values/themes.xml"
-            line="96"
+            line="103"
             column="40"/>
     </issue>
 
@@ -2649,7 +2669,7 @@
         errorLine2="                                       ^">
         <location
             file="res/values/themes.xml"
-            line="96"
+            line="103"
             column="40"/>
     </issue>
 
@@ -2665,7 +2685,7 @@
         errorLine2="                                            ^">
         <location
             file="res/values/themes.xml"
-            line="159"
+            line="166"
             column="45"/>
     </issue>
 
@@ -2681,7 +2701,7 @@
         errorLine2="                                                ^">
         <location
             file="res/values/themes.xml"
-            line="160"
+            line="167"
             column="49"/>
     </issue>
 
@@ -2697,7 +2717,7 @@
         errorLine2="                                            ^">
         <location
             file="res/values/themes.xml"
-            line="168"
+            line="175"
             column="45"/>
     </issue>
 
@@ -2713,7 +2733,7 @@
         errorLine2="                                                ^">
         <location
             file="res/values/themes.xml"
-            line="169"
+            line="176"
             column="49"/>
     </issue>
 
@@ -2729,7 +2749,7 @@
         errorLine2="                                      ^">
         <location
             file="res/values/themes.xml"
-            line="185"
+            line="192"
             column="39"/>
     </issue>
 
@@ -2745,7 +2765,7 @@
         errorLine2="                                       ^">
         <location
             file="res/values/themes.xml"
-            line="186"
+            line="193"
             column="40"/>
     </issue>
 
@@ -2761,7 +2781,7 @@
         errorLine2="                                     ^">
         <location
             file="res/values/themes.xml"
-            line="187"
+            line="194"
             column="38"/>
     </issue>
 
diff --git a/res/layout-land/choose_lock_pattern.xml b/res/layout-land/choose_lock_pattern.xml
index 25230cb..d2d436f 100644
--- a/res/layout-land/choose_lock_pattern.xml
+++ b/res/layout-land/choose_lock_pattern.xml
@@ -21,7 +21,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:icon="@drawable/ic_lock"
-    android:layout="@layout/suw_glif_blank_template"
+    android:layout="@layout/sud_glif_blank_template"
     settings:suwHeaderText="@string/lock_settings_picker_title">
 
     <com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
diff --git a/res/layout-land/confirm_lock_password.xml b/res/layout-land/confirm_lock_password.xml
index a6a85d3..d140bad 100644
--- a/res/layout-land/confirm_lock_password.xml
+++ b/res/layout-land/confirm_lock_password.xml
@@ -28,7 +28,7 @@
         android:layout_height="match_parent">
 
         <TextView
-            style="@android:style/TextAppearance.Material.Title"
+            style="@*android:style/TextAppearance.DeviceDefault.Title"
             android:id="@+id/headerText"
             android:layout_marginStart="24dp"
             android:layout_marginEnd="24dp"
@@ -38,7 +38,7 @@
             android:textColor="?android:attr/colorAccent"/>
 
         <TextView
-            style="@android:style/TextAppearance.Material.Body1"
+            style="@*android:style/TextAppearance.DeviceDefault.Body1"
             android:id="@+id/detailsText"
             android:layout_marginStart="24dp"
             android:layout_marginEnd="24dp"
@@ -78,7 +78,7 @@
                     android:gravity="center"
                     style="@style/TextAppearance.PasswordEntry"/>
 
-                <TextView style="@style/TextAppearance.ConfirmDeviceCredentialsErrorText"
+                <TextView style="@style/TextAppearance.ErrorText"
                     android:accessibilityLiveRegion="polite"
                     android:id="@+id/errorText"
                     android:layout_width="wrap_content"
diff --git a/res/layout-land/confirm_lock_pattern.xml b/res/layout-land/confirm_lock_pattern.xml
index b0a0a96..bcfd907 100644
--- a/res/layout-land/confirm_lock_pattern.xml
+++ b/res/layout-land/confirm_lock_pattern.xml
@@ -37,7 +37,7 @@
             android:orientation="vertical">
 
             <TextView
-                style="@android:style/TextAppearance.Material.Headline"
+                style="@*android:style/TextAppearance.DeviceDefault.Headline"
                 android:id="@+id/headerText"
                 android:layout_marginStart="32dp"
                 android:layout_marginEnd="32dp"
@@ -46,7 +46,7 @@
                 android:textColor="?android:attr/colorAccent"/>
 
             <TextView
-                style="@android:style/TextAppearance.Material.Body1"
+                style="@*android:style/TextAppearance.DeviceDefault.Body1"
                 android:id="@+id/detailsText"
                 android:layout_marginStart="32dp"
                 android:layout_marginEnd="32dp"
@@ -94,7 +94,7 @@
                     android:layout_gravity="center_vertical"/>
 
                 <TextView
-                    style="@style/TextAppearance.ConfirmDeviceCredentialsErrorText"
+                    style="@style/TextAppearance.ErrorText"
                     android:accessibilityLiveRegion="polite"
                     android:id="@+id/errorText"
                     android:layout_width="wrap_content"
@@ -111,4 +111,4 @@
         </LinearLayout>
 
     </com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
-</FrameLayout>
\ No newline at end of file
+</FrameLayout>
diff --git a/res/layout-land/confirm_lock_pattern_normal.xml b/res/layout-land/confirm_lock_pattern_normal.xml
index 23e5d66..993a84e 100644
--- a/res/layout-land/confirm_lock_pattern_normal.xml
+++ b/res/layout-land/confirm_lock_pattern_normal.xml
@@ -19,7 +19,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:icon="@drawable/ic_lock"
-    android:layout="@layout/suw_glif_blank_template">
+    android:layout="@layout/sud_glif_blank_template">
 
     <com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
         android:id="@+id/topLayout"
@@ -76,7 +76,7 @@
                     android:layout_weight="1" />
 
                 <TextView
-                    style="@style/TextAppearance.ConfirmDeviceCredentialsErrorText"
+                    style="@style/TextAppearance.ErrorText"
                     android:accessibilityLiveRegion="polite"
                     android:id="@+id/errorText"
                     android:layout_width="wrap_content"
diff --git a/res/layout-land/fingerprint_enroll_enrolling.xml b/res/layout-land/fingerprint_enroll_enrolling.xml
index eb32602..e71725e 100644
--- a/res/layout-land/fingerprint_enroll_enrolling.xml
+++ b/res/layout-land/fingerprint_enroll_enrolling.xml
@@ -20,7 +20,7 @@
     android:id="@+id/setup_wizard_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:layout="@layout/suw_glif_blank_template"
+    android:layout="@layout/sud_glif_blank_template"
     style="?attr/fingerprint_layout_theme">
 
     <ScrollView
@@ -123,7 +123,7 @@
                 </com.google.android.setupdesign.view.FillContentLayout>
 
                 <TextView
-                    style="@style/TextAppearance.FingerprintErrorText"
+                    style="@style/TextAppearance.ErrorText"
                     android:id="@+id/error_text"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
diff --git a/res/layout-land/fingerprint_enroll_find_sensor.xml b/res/layout-land/fingerprint_enroll_find_sensor.xml
index e6a2e66..0decbf2 100644
--- a/res/layout-land/fingerprint_enroll_find_sensor.xml
+++ b/res/layout-land/fingerprint_enroll_find_sensor.xml
@@ -20,7 +20,7 @@
     android:id="@+id/setup_wizard_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:layout="@layout/suw_glif_blank_template"
+    android:layout="@layout/sud_glif_blank_template"
     style="?attr/fingerprint_layout_theme">
 
     <LinearLayout
diff --git a/res/layout-land/fingerprint_enroll_finish.xml b/res/layout-land/fingerprint_enroll_finish.xml
index 97a4de2..53e430e 100644
--- a/res/layout-land/fingerprint_enroll_finish.xml
+++ b/res/layout-land/fingerprint_enroll_finish.xml
@@ -20,7 +20,7 @@
     android:id="@+id/setup_wizard_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:layout="@layout/suw_glif_blank_template"
+    android:layout="@layout/sud_glif_blank_template"
     style="?attr/fingerprint_layout_theme">
 
     <ScrollView
diff --git a/res/layout-land/storage_summary_donut.xml b/res/layout-land/storage_summary_donut.xml
index 5fe4cc8..f43737a 100644
--- a/res/layout-land/storage_summary_donut.xml
+++ b/res/layout-land/storage_summary_donut.xml
@@ -42,7 +42,7 @@
             android:fontFamily="@*android:string/config_headlineFontFamily"
             android:singleLine="true"
             android:textAlignment="viewStart"
-            android:textAppearance="@android:style/TextAppearance.Material.Display1"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Display1"
             android:textSize="36sp" />
 
         <TextView
@@ -54,7 +54,7 @@
             android:maxLines="10"
             android:paddingBottom="20dp"
             android:textAlignment="viewStart"
-            android:textAppearance="@android:style/TextAppearance.Material.Body1" />
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1" />
 
         <Button
             android:id="@+id/deletion_helper_button"
diff --git a/res/layout-land/wifi_dpp_qrcode_scanner_fragment.xml b/res/layout-land/wifi_dpp_qrcode_scanner_fragment.xml
index 4217867..21df686 100644
--- a/res/layout-land/wifi_dpp_qrcode_scanner_fragment.xml
+++ b/res/layout-land/wifi_dpp_qrcode_scanner_fragment.xml
@@ -25,8 +25,8 @@
     <include layout="@layout/wifi_dpp_fragment_header"/>
 
     <com.android.settings.wifi.qrcode.QrPreviewLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_width="@dimen/qrcode_preview_size"
+        android:layout_height="@dimen/qrcode_preview_size"
         android:layout_gravity="center">
         <TextureView
             android:id="@+id/preview_view"
diff --git a/res/layout-sw300dp-land/font_size_activity.xml b/res/layout-sw300dp-land/font_size_activity.xml
index 69abac1..6664704 100644
--- a/res/layout-sw300dp-land/font_size_activity.xml
+++ b/res/layout-sw300dp-land/font_size_activity.xml
@@ -56,7 +56,7 @@
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_horizontal"
                 android:padding="6dp"
-                android:textAppearance="@android:style/TextAppearance.Material.Widget.TextView"
+                android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.TextView"
                 android:elevation="2dp" />
 
             <com.android.settings.widget.LabeledSeekBar
@@ -102,7 +102,7 @@
                 android:layout_height="wrap_content"
                 android:text="@string/font_size_summary"
                 android:layout_marginBottom="16dp"
-                android:textAppearance="@android:style/TextAppearance.Material.Subhead" />
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead" />
         </LinearLayout>
     </ScrollView>
 </LinearLayout>
diff --git a/res/layout-sw300dp-land/screen_zoom_activity.xml b/res/layout-sw300dp-land/screen_zoom_activity.xml
index 8d6e735..cd7c67c 100644
--- a/res/layout-sw300dp-land/screen_zoom_activity.xml
+++ b/res/layout-sw300dp-land/screen_zoom_activity.xml
@@ -56,7 +56,7 @@
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_horizontal"
                 android:padding="6dp"
-                android:textAppearance="@android:style/TextAppearance.Material.Widget.TextView"
+                android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.TextView"
                 android:elevation="2dp" />
 
             <com.android.settings.widget.LabeledSeekBar
@@ -102,7 +102,7 @@
                 android:layout_height="wrap_content"
                 android:text="@string/screen_zoom_summary"
                 android:layout_marginBottom="16dp"
-                android:textAppearance="@android:style/TextAppearance.Material.Subhead" />
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead" />
         </LinearLayout>
     </ScrollView>
 </LinearLayout>
diff --git a/res/layout-sw360dp/homepage_condition_full_tile.xml b/res/layout-sw360dp/homepage_condition_full_tile.xml
new file mode 100644
index 0000000..4a8ad0a
--- /dev/null
+++ b/res/layout-sw360dp/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.
+-->
+
+<com.google.android.material.card.MaterialCardView
+    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"
+                android:textAppearance="@style/TextAppearance.ConditionCardTitle"/>
+
+            <TextView
+                android:id="@android:id/summary"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textAppearance="@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>
+
+</com.google.android.material.card.MaterialCardView>
diff --git a/res/layout-sw360dp/storage_summary_donut.xml b/res/layout-sw360dp/storage_summary_donut.xml
index 5fe4cc8..f43737a 100644
--- a/res/layout-sw360dp/storage_summary_donut.xml
+++ b/res/layout-sw360dp/storage_summary_donut.xml
@@ -42,7 +42,7 @@
             android:fontFamily="@*android:string/config_headlineFontFamily"
             android:singleLine="true"
             android:textAlignment="viewStart"
-            android:textAppearance="@android:style/TextAppearance.Material.Display1"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Display1"
             android:textSize="36sp" />
 
         <TextView
@@ -54,7 +54,7 @@
             android:maxLines="10"
             android:paddingBottom="20dp"
             android:textAlignment="viewStart"
-            android:textAppearance="@android:style/TextAppearance.Material.Body1" />
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1" />
 
         <Button
             android:id="@+id/deletion_helper_button"
diff --git a/res/layout/admin_support_details_dialog.xml b/res/layout/admin_support_details_dialog.xml
index 922451f..66eaf0d 100644
--- a/res/layout/admin_support_details_dialog.xml
+++ b/res/layout/admin_support_details_dialog.xml
@@ -34,7 +34,7 @@
                 android:layout_height="wrap_content"
                 android:paddingStart="@dimen/admin_details_dialog_padding"
                 android:text="@string/disabled_by_policy_title"
-                android:textAppearance="@android:style/TextAppearance.Material.Title" />
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Title" />
     </LinearLayout>
 
     <ScrollView
@@ -48,7 +48,7 @@
             <TextView android:id="@+id/admin_support_msg"
                       android:layout_width="match_parent"
                       android:layout_height="wrap_content"
-                      android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                      android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
                       android:text="@string/default_admin_support_msg"
                       android:maxLength="200"
                       android:autoLink="email|phone|web"
diff --git a/res/layout/battery_header.xml b/res/layout/battery_header.xml
index 9f5bde9..d6ecafa 100644
--- a/res/layout/battery_header.xml
+++ b/res/layout/battery_header.xml
@@ -40,7 +40,7 @@
             android:layout_height="wrap_content"
             android:layout_marginTop="12dp"
             android:fontFamily="@*android:string/config_headlineFontFamily"
-            android:textAppearance="@android:style/TextAppearance.Material.Display1"/>
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Display1"/>
 
         <TextView
             android:id="@+id/summary1"
@@ -48,13 +48,13 @@
             android:layout_height="wrap_content"
             android:layout_marginTop="8dp"
             android:minLines="2"
-            android:textAppearance="@android:style/TextAppearance.Material.Small"/>
+            android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"/>
 
         <TextView
             android:id="@+id/summary2"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:textAppearance="@android:style/TextAppearance.Material.Small"/>
+            android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"/>
 
     </LinearLayout>
 
diff --git a/res/layout/bluetooth_pin_confirm.xml b/res/layout/bluetooth_pin_confirm.xml
index 33140d9..c55c9ff 100644
--- a/res/layout/bluetooth_pin_confirm.xml
+++ b/res/layout/bluetooth_pin_confirm.xml
@@ -40,7 +40,7 @@
             android:gravity="center_vertical"
             android:text="@string/bluetooth_pairing_key_msg"
             android:visibility="gone"
-            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
             android:textColor="@color/bluetooth_dialog_text_color"  />
 
         <TextView
@@ -52,7 +52,7 @@
             android:layout_marginBottom="@dimen/bluetooth_dialog_padding"
             android:gravity="center_vertical"
             android:visibility="gone"
-            android:textAppearance="@android:style/TextAppearance.Material.Headline" />
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Headline" />
 
         <TextView
             android:id="@+id/pairing_code_message"
@@ -63,7 +63,7 @@
             android:layout_marginBottom="@dimen/bluetooth_dialog_padding"
             android:gravity="center_vertical"
             android:text="@string/bluetooth_enter_passkey_msg"
-            android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
             android:textColor="@color/bluetooth_dialog_text_color"
             android:visibility="gone" />
 
@@ -73,7 +73,7 @@
             android:layout_height="wrap_content"
             android:layout_marginStart="@dimen/bluetooth_dialog_padding"
             android:layout_marginEnd="@dimen/bluetooth_dialog_padding"
-            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
             android:textColor="@color/bluetooth_dialog_text_color"  />
 
     </LinearLayout>
diff --git a/res/layout/bluetooth_pin_entry.xml b/res/layout/bluetooth_pin_entry.xml
index c309a24..0c6861c 100644
--- a/res/layout/bluetooth_pin_entry.xml
+++ b/res/layout/bluetooth_pin_entry.xml
@@ -60,7 +60,7 @@
             android:layout_marginBottom="16dp"
             android:gravity="center"
             android:paddingStart="@dimen/bluetooth_checkbox_padding"
-            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
             android:textColor="?android:attr/textColorSecondary"/>
 
         <TextView
@@ -71,7 +71,7 @@
             android:layout_marginEnd="@dimen/bluetooth_pairing_padding"
             android:layout_marginBottom="12dp"
             android:gravity="center_vertical"
-            android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
             android:textColor="?android:attr/textColorSecondary"/>
 
         <CheckBox
@@ -84,7 +84,7 @@
             android:gravity="center_vertical"
             android:paddingStart="@dimen/bluetooth_checkbox_padding"
             android:text="@string/bluetooth_pairing_shares_phonebook"
-            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
             android:textColor="?android:attr/textColorSecondary"/>
 
     </LinearLayout>
diff --git a/res/layout/choose_lock_dialog_item.xml b/res/layout/choose_lock_dialog_item.xml
index 46ad539..f87b7c4 100644
--- a/res/layout/choose_lock_dialog_item.xml
+++ b/res/layout/choose_lock_dialog_item.xml
@@ -26,5 +26,5 @@
     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
     android:paddingStart="?android:attr/listPreferredItemPaddingStart"
     android:textAlignment="viewStart"
-    android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+    android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
     android:textColor="?android:attr/textColorAlertDialogListItem" />
diff --git a/res/layout/choose_lock_pattern_common.xml b/res/layout/choose_lock_pattern_common.xml
index df7fd8c..6d64b88 100644
--- a/res/layout/choose_lock_pattern_common.xml
+++ b/res/layout/choose_lock_pattern_common.xml
@@ -22,7 +22,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:icon="@drawable/ic_lock"
-    android:layout="@layout/suw_glif_blank_template"
+    android:layout="@layout/sud_glif_blank_template"
     settings:sucFooter="@layout/choose_lock_pattern_common_footer"
     settings:suwHeaderText="@string/lockpassword_choose_your_screen_lock_header">
 
diff --git a/res/layout/confirm_lock_password_base.xml b/res/layout/confirm_lock_password_base.xml
index 1e42fbe..22934ba 100644
--- a/res/layout/confirm_lock_password_base.xml
+++ b/res/layout/confirm_lock_password_base.xml
@@ -31,7 +31,7 @@
         android:paddingTop="@dimen/confirm_credentials_top_padding">
 
         <TextView
-            style="@android:style/TextAppearance.Material.Headline"
+            style="@*android:style/TextAppearance.DeviceDefault.Headline"
             android:id="@+id/headerText"
             android:layout_marginStart="?attr/confirmDeviceCredentialsSideMargin"
             android:layout_marginEnd="?attr/confirmDeviceCredentialsSideMargin"
@@ -41,7 +41,7 @@
             android:textColor="?android:attr/colorAccent"/>
 
         <TextView
-            style="@android:style/TextAppearance.Material.Body1"
+            style="@*android:style/TextAppearance.DeviceDefault.Body1"
             android:id="@+id/detailsText"
             android:layout_marginStart="?attr/confirmDeviceCredentialsSideMargin"
             android:layout_marginEnd="?attr/confirmDeviceCredentialsSideMargin"
@@ -79,7 +79,7 @@
                 style="@style/TextAppearance.PasswordEntry"/>
 
             <TextView
-                style="@style/TextAppearance.ConfirmDeviceCredentialsErrorText"
+                style="@style/TextAppearance.ErrorText"
                 android:accessibilityLiveRegion="polite"
                 android:id="@+id/errorText"
                 android:layout_width="wrap_content"
diff --git a/res/layout/confirm_lock_password_normal.xml b/res/layout/confirm_lock_password_normal.xml
index 4b92a4a..44d96e0 100644
--- a/res/layout/confirm_lock_password_normal.xml
+++ b/res/layout/confirm_lock_password_normal.xml
@@ -58,7 +58,7 @@
 
             <TextView
                 android:id="@+id/errorText"
-                style="@style/TextAppearance.ConfirmDeviceCredentialsErrorText"
+                style="@style/TextAppearance.ErrorText"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:accessibilityLiveRegion="polite"/>
diff --git a/res/layout/confirm_lock_pattern_base.xml b/res/layout/confirm_lock_pattern_base.xml
index f841391..25fa08f 100644
--- a/res/layout/confirm_lock_pattern_base.xml
+++ b/res/layout/confirm_lock_pattern_base.xml
@@ -40,7 +40,7 @@
                 android:orientation="vertical">
 
                 <TextView
-                    style="@android:style/TextAppearance.Material.Headline"
+                    style="@*android:style/TextAppearance.DeviceDefault.Headline"
                     android:id="@+id/headerText"
                     android:layout_marginStart="?attr/confirmDeviceCredentialsSideMargin"
                     android:layout_marginEnd="?attr/confirmDeviceCredentialsSideMargin"
@@ -50,7 +50,7 @@
                     android:textColor="?android:attr/colorAccent"/>
 
                 <TextView
-                    style="@android:style/TextAppearance.Material.Body1"
+                    style="@*android:style/TextAppearance.DeviceDefault.Body1"
                     android:id="@+id/detailsText"
                     android:layout_marginStart="?attr/confirmDeviceCredentialsSideMargin"
                     android:layout_marginEnd="?attr/confirmDeviceCredentialsSideMargin"
@@ -85,7 +85,7 @@
             android:orientation="vertical">
 
             <TextView
-                style="@style/TextAppearance.ConfirmDeviceCredentialsErrorText"
+                style="@style/TextAppearance.ErrorText"
                 android:accessibilityLiveRegion="polite"
                 android:id="@+id/errorText"
                 android:layout_width="wrap_content"
diff --git a/res/layout/confirm_lock_pattern_normal_base.xml b/res/layout/confirm_lock_pattern_normal_base.xml
index 14798df..8cf8f87 100644
--- a/res/layout/confirm_lock_pattern_normal_base.xml
+++ b/res/layout/confirm_lock_pattern_normal_base.xml
@@ -19,7 +19,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:icon="@drawable/ic_lock"
-    android:layout="@layout/suw_glif_blank_template">
+    android:layout="@layout/sud_glif_blank_template">
 
     <com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
         android:id="@+id/topLayout"
@@ -80,7 +80,7 @@
             </com.google.android.setupdesign.view.FillContentLayout>
 
             <TextView
-                style="@style/TextAppearance.ConfirmDeviceCredentialsErrorText"
+                style="@style/TextAppearance.ErrorText"
                 android:accessibilityLiveRegion="polite"
                 android:id="@+id/errorText"
                 android:layout_width="wrap_content"
diff --git a/res/layout/data_usage_detail.xml b/res/layout/data_usage_detail.xml
index 5113139..8079fe1 100644
--- a/res/layout/data_usage_detail.xml
+++ b/res/layout/data_usage_detail.xml
@@ -64,14 +64,14 @@
                     android:singleLine="true"
                     android:ellipsize="marquee"
                     android:text="@string/data_usage_label_foreground"
-                    android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                    android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
                     android:textColor="?android:attr/textColorSecondary"
                     android:textAlignment="viewStart" />
                 <TextView
                     android:id="@+id/app_foreground"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                    android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
                     android:textColor="?android:attr/textColorSecondary"
                     android:textAlignment="viewEnd" />
             </LinearLayout>
@@ -87,14 +87,14 @@
                     android:singleLine="true"
                     android:ellipsize="marquee"
                     android:text="@string/data_usage_label_background"
-                    android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                    android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
                     android:textColor="?android:attr/textColorSecondary"
                     android:textAlignment="viewStart" />
                 <TextView
                     android:id="@+id/app_background"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                    android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
                     android:textColor="?android:attr/textColorSecondary"
                     android:textAlignment="viewEnd" />
             </LinearLayout>
diff --git a/res/layout/encryption_interstitial.xml b/res/layout/encryption_interstitial.xml
index ff56a7c..5acc7b1 100644
--- a/res/layout/encryption_interstitial.xml
+++ b/res/layout/encryption_interstitial.xml
@@ -20,8 +20,7 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:icon="@drawable/ic_lock"
-    app:sucFooter="@layout/encryption_interstitial_footer">
+    android:icon="@drawable/ic_lock">
 
     <LinearLayout
         style="@style/SuwContentFrame"
diff --git a/res/layout/encryption_interstitial_footer.xml b/res/layout/encryption_interstitial_footer.xml
deleted file mode 100644
index 2f876f3..0000000
--- a/res/layout/encryption_interstitial_footer.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-    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.
--->
-
-<!-- TODO: Use aapt:attr when it is fixed (b/36809755) -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/SuwGlifButtonBar"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content">
-
-    <Button
-        android:id="@+id/encrypt_dont_require_password"
-        style="@style/SuwGlifButton.Secondary"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/encryption_interstitial_no" />
-
-    <Space
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="1" />
-
-    <Button
-        android:id="@+id/encrypt_require_password"
-        style="@style/SuwGlifButton.Primary"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/encryption_interstitial_yes" />
-
-</LinearLayout>
diff --git a/res/layout/face_enroll_enrolling.xml b/res/layout/face_enroll_enrolling.xml
index 7aef9b6..38a26a2 100644
--- a/res/layout/face_enroll_enrolling.xml
+++ b/res/layout/face_enroll_enrolling.xml
@@ -57,7 +57,7 @@
             </com.android.settings.biometrics.face.FaceSquareFrameLayout>
 
             <TextView
-                style="@style/TextAppearance.FaceErrorText"
+                style="@style/TextAppearance.ErrorText"
                 android:id="@+id/error_text"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
diff --git a/res/layout/filter_spinner_item.xml b/res/layout/filter_spinner_item.xml
deleted file mode 100644
index ffdd623..0000000
--- a/res/layout/filter_spinner_item.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 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.
--->
-
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@android:id/text1"
-    style="?android:attr/spinnerItemStyle"
-    android:maxLines="1"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:ellipsize="marquee"
-    android:textColor="?android:attr/colorForegroundInverse"
-    android:textAppearance="@style/TextAppearance.Switch"
-    android:textAlignment="inherit" />
diff --git a/res/layout/fingerprint_enroll_enrolling_base.xml b/res/layout/fingerprint_enroll_enrolling_base.xml
index 6ca3fdc..4439b08 100644
--- a/res/layout/fingerprint_enroll_enrolling_base.xml
+++ b/res/layout/fingerprint_enroll_enrolling_base.xml
@@ -77,7 +77,7 @@
             </com.google.android.setupdesign.view.FillContentLayout>
 
             <TextView
-                style="@style/TextAppearance.FingerprintErrorText"
+                style="@style/TextAppearance.ErrorText"
                 android:id="@+id/error_text"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
diff --git a/res/layout/fingerprint_enroll_finish_base.xml b/res/layout/fingerprint_enroll_finish_base.xml
index 7120d90..1849f51 100644
--- a/res/layout/fingerprint_enroll_finish_base.xml
+++ b/res/layout/fingerprint_enroll_finish_base.xml
@@ -67,7 +67,7 @@
 
             <!-- Added to align elements with fingerprint_enroll_enrolling_base -->
             <TextView
-                style="@style/TextAppearance.FingerprintErrorText"
+                style="@style/TextAppearance.ErrorText"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_horizontal|bottom"
diff --git a/res/layout/font_size_activity.xml b/res/layout/font_size_activity.xml
index aa3930c..3e84336 100644
--- a/res/layout/font_size_activity.xml
+++ b/res/layout/font_size_activity.xml
@@ -48,7 +48,7 @@
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_horizontal"
                 android:padding="6dp"
-                android:textAppearance="@android:style/TextAppearance.Material.Widget.TextView"
+                android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.TextView"
                 android:elevation="2dp" />
 
             <LinearLayout
@@ -94,7 +94,7 @@
                 android:layout_height="wrap_content"
                 android:text="@string/font_size_summary"
                 android:layout_marginBottom="16dp"
-                android:textAppearance="@android:style/TextAppearance.Material.Subhead" />
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead" />
         </LinearLayout>
     </LinearLayout>
 </ScrollView>
diff --git a/res/layout/font_size_preview.xml b/res/layout/font_size_preview.xml
index d84bb39..669ece0 100644
--- a/res/layout/font_size_preview.xml
+++ b/res/layout/font_size_preview.xml
@@ -36,25 +36,25 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:text="@string/font_size_preview_text_headline"
-                android:textAppearance="@android:style/TextAppearance.Material.Headline"/>
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Headline"/>
 
             <TextView
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:text="@string/font_size_preview_text_title"
-                android:textAppearance="@android:style/TextAppearance.Material.Title"/>
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Title"/>
 
             <TextView
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:text="@string/font_size_preview_text_subtitle"
-                android:textAppearance="@android:style/TextAppearance.Material.Subhead"/>
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"/>
 
             <TextView
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:text="@string/font_size_preview_text_body"
-                android:textAppearance="@android:style/TextAppearance.Material.Body1"/>
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"/>
         </LinearLayout>
     </view>
 </ScrollView>
diff --git a/res/layout/homepage_condition_full_tile.xml b/res/layout/homepage_condition_full_tile.xml
index 4b12625..2de1464 100644
--- a/res/layout/homepage_condition_full_tile.xml
+++ b/res/layout/homepage_condition_full_tile.xml
@@ -25,49 +25,50 @@
         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"/>
+        android:paddingTop="@dimen/homepage_condition_half_card_padding_top"
+        android:orientation="vertical">
 
         <LinearLayout
-            android:layout_width="0dp"
+            android:layout_width="match_parent"
             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:paddingStart="@dimen/homepage_card_padding_start"
+            android:paddingEnd="@dimen/homepage_card_padding_end"
             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="wrap_content"
+                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"/>
+                android:textAppearance="@style/TextAppearance.ConditionCardTitle"/>
 
             <TextView
                 android:id="@android:id/summary"
-                android:layout_width="wrap_content"
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                style="@style/TextAppearance.ConditionCardSummary"/>
+                android:maxLines="1"
+                android:ellipsize="end"
+                android:layout_marginBottom="@dimen/homepage_condition_half_card_summary_margin_bottom"
+                android:textAppearance="@style/TextAppearance.ConditionCardSummary"/>
+
+            <include layout="@layout/horizontal_divider"/>
 
         </LinearLayout>
-
-        <include layout="@layout/vertical_divider"/>
-
         <Button
             android:id="@+id/first_action"
-            android:layout_width="wrap_content"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            style="@style/ConditionFullCardBorderlessButton"/>
+            android:scrollbars="none"
+            style="@style/ConditionHalfCardBorderlessButton"/>
 
     </LinearLayout>
 
diff --git a/res/layout/homepage_condition_half_tile.xml b/res/layout/homepage_condition_half_tile.xml
index 895183f..8f5af02 100644
--- a/res/layout/homepage_condition_half_tile.xml
+++ b/res/layout/homepage_condition_half_tile.xml
@@ -18,7 +18,7 @@
 <com.google.android.material.card.MaterialCardView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="@dimen/homepage_condition_half_card_height"
+    android:layout_height="wrap_content"
     style="@style/ContextualCardStyle">
 
     <LinearLayout
@@ -49,7 +49,7 @@
                 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"/>
+                android:textAppearance="@style/TextAppearance.ConditionCardTitle"/>
 
             <TextView
                 android:id="@android:id/summary"
@@ -58,7 +58,7 @@
                 android:maxLines="1"
                 android:ellipsize="end"
                 android:layout_marginBottom="@dimen/homepage_condition_half_card_summary_margin_bottom"
-                style="@style/TextAppearance.ConditionCardSummary"/>
+                android:textAppearance="@style/TextAppearance.ConditionCardSummary"/>
 
             <include layout="@layout/horizontal_divider"/>
 
diff --git a/res/layout/preference.xml b/res/layout/preference.xml
index cf85e5d..195671b 100644
--- a/res/layout/preference.xml
+++ b/res/layout/preference.xml
@@ -35,7 +35,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:singleLine="true"
-            android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
             android:textColor="?android:attr/textColorPrimary"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal" />
@@ -48,7 +48,7 @@
             android:layout_alignStart="@android:id/title"
             android:visibility="gone"
             android:textAlignment="viewStart"
-            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
             android:textColor="?android:attr/textColorSecondary"
             android:maxLines="10" />
 
diff --git a/res/layout/preference_multiline_title.xml b/res/layout/preference_multiline_title.xml
index 16c25d5..ae93ead 100644
--- a/res/layout/preference_multiline_title.xml
+++ b/res/layout/preference_multiline_title.xml
@@ -34,7 +34,7 @@
             android:id="@android:id/title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
             android:textColor="?android:attr/textColorPrimary"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal" />
@@ -47,7 +47,7 @@
             android:layout_alignStart="@android:id/title"
             android:visibility="gone"
             android:textAlignment="viewStart"
-            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
             android:textColor="?android:attr/textColorSecondary"
             android:maxLines="10" />
 
diff --git a/res/layout/preference_progress_category.xml b/res/layout/preference_progress_category.xml
index 2ac3dc1..91a0312 100644
--- a/res/layout/preference_progress_category.xml
+++ b/res/layout/preference_progress_category.xml
@@ -46,7 +46,7 @@
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:layout_gravity="start|center"
-        android:textAppearance="@android:style/TextAppearance.Material.Body2"
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"
         android:textColor="?android:attr/colorAccent"/>
 
     <ProgressBar
diff --git a/res/layout/preference_volume_slider.xml b/res/layout/preference_volume_slider.xml
index da3a028..34c732d 100644
--- a/res/layout/preference_volume_slider.xml
+++ b/res/layout/preference_volume_slider.xml
@@ -58,7 +58,7 @@
                 android:layout_weight="1"
                 android:paddingStart="12dp"
                 android:singleLine="true"
-                android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
                 android:textColor="?android:attr/textColorPrimary"
                 android:ellipsize="marquee"
                 android:fadingEdge="horizontal"/>
@@ -94,7 +94,7 @@
                 android:singleLine="true"
                 android:ellipsize="end"
                 android:visibility="gone"
-                android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
                 android:textColor="?android:attr/textColorSecondary"/>
 
         </LinearLayout>
diff --git a/res/layout/preference_widget_seekbar_settings.xml b/res/layout/preference_widget_seekbar_settings.xml
index fb1e9c8..9893a1b 100644
--- a/res/layout/preference_widget_seekbar_settings.xml
+++ b/res/layout/preference_widget_seekbar_settings.xml
@@ -35,7 +35,7 @@
         android:paddingStart="56dp"
         android:paddingEnd="8dp"
         android:singleLine="true"
-        android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
         android:textColor="?android:attr/textColorPrimary" />
 
     <TextView
diff --git a/res/layout/preset_picker_item.xml b/res/layout/preset_picker_item.xml
index 405b735..47887e1 100644
--- a/res/layout/preset_picker_item.xml
+++ b/res/layout/preset_picker_item.xml
@@ -44,6 +44,6 @@
         android:maxLines="2"
         android:minLines="2"
         android:gravity="top|center_horizontal"
-        android:textAppearance="@android:style/TextAppearance.Material.Body1" />
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1" />
 
 </LinearLayout>
diff --git a/res/layout/preview_seek_bar_view_pager.xml b/res/layout/preview_seek_bar_view_pager.xml
index 264991a..12f2611 100644
--- a/res/layout/preview_seek_bar_view_pager.xml
+++ b/res/layout/preview_seek_bar_view_pager.xml
@@ -36,7 +36,7 @@
         android:paddingStart="32dp"
         android:gravity="start|center"
         android:text="@string/screen_zoom_preview_title"
-        android:textAppearance="@android:style/TextAppearance.Material.Widget.ActionBar.Title"
+        android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"
         android:importantForAccessibility="no" />
 </LinearLayout>
 
diff --git a/res/layout/redaction_interstitial.xml b/res/layout/redaction_interstitial.xml
index 929ac07..ab7e0b3 100644
--- a/res/layout/redaction_interstitial.xml
+++ b/res/layout/redaction_interstitial.xml
@@ -22,7 +22,6 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:icon="@drawable/ic_suggested_notifications"
-    settings:sucFooter="@layout/redaction_interstitial_footer"
     settings:suwHeaderText="@string/lock_screen_notifications_interstitial_title">
 
     <LinearLayout
diff --git a/res/layout/redaction_interstitial_footer.xml b/res/layout/redaction_interstitial_footer.xml
deleted file mode 100644
index 1d8758b..0000000
--- a/res/layout/redaction_interstitial_footer.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-    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
--->
-
-<!-- TODO: Use aapt:attr when it is fixed (b/36809755) -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/SuwGlifButtonBar"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content">
-
-    <Button
-        android:id="@+id/redaction_done_button"
-        style="@style/SuwGlifButton.Primary"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="end"
-        android:text="@string/app_notifications_dialog_done" />
-
-</FrameLayout>
diff --git a/res/layout/running_processes_header.xml b/res/layout/running_processes_header.xml
index a696b38..b2db025 100644
--- a/res/layout/running_processes_header.xml
+++ b/res/layout/running_processes_header.xml
@@ -30,7 +30,7 @@
         android:layout_height="48dp"
         android:singleLine="true"
         android:ellipsize="marquee"
-        android:textAppearance="@android:style/TextAppearance.Material.Body2"
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"
         android:textColor="?android:attr/textColorPrimary"
         android:textAlignment="viewStart"
         android:gravity="left|center_vertical"
@@ -63,7 +63,7 @@
             <TextView
                 android:id="@+id/systemSizePrefix"
                 android:text="@string/running_processes_header_system_prefix"
-                android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
                 android:textColor="?android:attr/textColorSecondary"
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
@@ -81,7 +81,7 @@
                 android:contentDescription="@null" />
             <TextView
                 android:id="@+id/systemSize"
-                android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
                 android:textColor="?android:attr/textColorSecondary"
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
@@ -108,7 +108,7 @@
             <TextView
                 android:id="@+id/appsSizePrefix"
                 android:text="@string/running_processes_header_apps_prefix"
-                android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
                 android:textColor="?android:attr/textColorSecondary"
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
@@ -126,7 +126,7 @@
                 android:contentDescription="@null" />
             <TextView
                 android:id="@+id/appsSize"
-                android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
                 android:textColor="?android:attr/textColorSecondary"
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
@@ -153,7 +153,7 @@
             <TextView
                 android:id="@+id/freeSizePrefix"
                 android:text="@string/running_processes_header_free_prefix"
-                android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
                 android:textColor="?android:attr/textColorSecondary"
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
@@ -171,7 +171,7 @@
                 android:contentDescription="@null" />
             <TextView
                 android:id="@+id/freeSize"
-                android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
                 android:textColor="?android:attr/textColorSecondary"
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
@@ -186,7 +186,7 @@
         android:layout_marginTop="8dp"
         android:singleLine="true"
         android:ellipsize="marquee"
-        android:textAppearance="@android:style/TextAppearance.Material.Body2"
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"
         android:textColor="?android:attr/textColorPrimary"
         android:textAlignment="viewStart"
         android:gravity="left|center_vertical"
diff --git a/res/layout/running_processes_item.xml b/res/layout/running_processes_item.xml
index 036a90e..45121eb 100644
--- a/res/layout/running_processes_item.xml
+++ b/res/layout/running_processes_item.xml
@@ -48,7 +48,7 @@
             android:layout_weight="1"
             android:singleLine="true"
             android:ellipsize="marquee"
-            android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
             android:textAlignment="viewStart" />
 
         <TextView
@@ -56,7 +56,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginStart="8dip"
-            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
             android:textColor="?android:attr/textColorSecondary" />
 
     </LinearLayout>
@@ -70,7 +70,7 @@
             android:layout_width="0dip"
             android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
             android:textColor="?android:attr/textColorSecondary"
             android:textAlignment="viewStart" />
 
@@ -79,7 +79,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginStart="8dip"
-            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
             android:textColor="?android:attr/textColorSecondary" />
 
     </LinearLayout>
diff --git a/res/layout/screen_zoom_activity.xml b/res/layout/screen_zoom_activity.xml
index 0141019..4cfa7b6 100644
--- a/res/layout/screen_zoom_activity.xml
+++ b/res/layout/screen_zoom_activity.xml
@@ -48,7 +48,7 @@
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_horizontal"
                 android:padding="6dp"
-                android:textAppearance="@android:style/TextAppearance.Material.Widget.TextView"
+                android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.TextView"
                 android:elevation="2dp" />
 
             <LinearLayout
@@ -93,7 +93,7 @@
                 android:layout_height="wrap_content"
                 android:text="@string/screen_zoom_summary"
                 android:layout_marginBottom="16dp"
-                android:textAppearance="@android:style/TextAppearance.Material.Subhead" />
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead" />
         </LinearLayout>
     </LinearLayout>
 </ScrollView>
diff --git a/res/layout/screen_zoom_preview_app_icon.xml b/res/layout/screen_zoom_preview_app_icon.xml
index 087afb8..1d56410 100644
--- a/res/layout/screen_zoom_preview_app_icon.xml
+++ b/res/layout/screen_zoom_preview_app_icon.xml
@@ -37,5 +37,5 @@
         android:ellipsize="end"
         android:gravity="center_horizontal|top"
         android:singleLine="true"
-        android:textAppearance="@android:style/TextAppearance.Material.Caption" />
-</LinearLayout>
\ No newline at end of file
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Caption" />
+</LinearLayout>
diff --git a/res/layout/screen_zoom_preview_settings.xml b/res/layout/screen_zoom_preview_settings.xml
index 9a0cc59..3401fcf 100644
--- a/res/layout/screen_zoom_preview_settings.xml
+++ b/res/layout/screen_zoom_preview_settings.xml
@@ -57,7 +57,7 @@
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:text="@string/wifi_settings"
-                        android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
                         android:textColor="?android:attr/textColorPrimary" />
 
 
@@ -65,7 +65,7 @@
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:text="@string/wifi_display_status_not_available"
-                        android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
                         android:textColor="?android:attr/textColorSecondary" />
                 </LinearLayout>
             </LinearLayout>
@@ -96,14 +96,14 @@
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:text="@string/data_usage_summary_title"
-                        android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
                         android:textColor="?android:attr/textColorPrimary" />
 
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:text="@string/no_data_usage"
-                        android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
                         android:textColor="?android:attr/textColorSecondary" />
                 </LinearLayout>
             </LinearLayout>
@@ -134,14 +134,14 @@
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:text="@string/display_settings_title"
-                        android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
                         android:textColor="?android:attr/textColorPrimary" />
 
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:text="@string/display_summary_example"
-                        android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
                         android:textColor="?android:attr/textColorSecondary" />
                 </LinearLayout>
             </LinearLayout>
@@ -172,14 +172,14 @@
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:text="@string/sound_settings"
-                        android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
                         android:textColor="?android:attr/textColorPrimary" />
 
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:text="@string/sound_settings_example_summary"
-                        android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
                         android:textColor="?android:attr/textColorSecondary" />
                 </LinearLayout>
             </LinearLayout>
@@ -210,14 +210,14 @@
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:text="@string/applications_settings"
-                        android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
                         android:textColor="?android:attr/textColorPrimary" />
 
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:text="@string/apps_summary_example"
-                        android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
                         android:textColor="?android:attr/textColorSecondary" />
                 </LinearLayout>
             </LinearLayout>
diff --git a/res/layout/settings_summary_preference.xml b/res/layout/settings_summary_preference.xml
index ae3b70d..e76190f 100644
--- a/res/layout/settings_summary_preference.xml
+++ b/res/layout/settings_summary_preference.xml
@@ -31,7 +31,7 @@
         android:fontFamily="@*android:string/config_headlineFontFamily"
         android:paddingTop="0dp"
         android:textColor="?android:attr/colorAccent"
-        android:textAppearance="@android:style/TextAppearance.Material.Display1"
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Display1"
         />
 
     <TextView android:id="@android:id/summary"
diff --git a/res/layout/storage_internal_forget.xml b/res/layout/storage_internal_forget.xml
index cb47d3b..5ff232a 100644
--- a/res/layout/storage_internal_forget.xml
+++ b/res/layout/storage_internal_forget.xml
@@ -33,7 +33,7 @@
             android:paddingStart="@dimen/suw_layout_margin_sides"
             android:paddingEnd="@dimen/suw_layout_margin_sides"
             android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
-            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
             android:textColor="?android:attr/textColorPrimary" />
     </ScrollView>
 
diff --git a/res/layout/storage_internal_format.xml b/res/layout/storage_internal_format.xml
index 8aec28f..500592f 100644
--- a/res/layout/storage_internal_format.xml
+++ b/res/layout/storage_internal_format.xml
@@ -33,7 +33,7 @@
             android:paddingStart="@dimen/suw_layout_margin_sides"
             android:paddingEnd="@dimen/suw_layout_margin_sides"
             android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
-            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
             android:textColor="?android:attr/textColorPrimary" />
     </ScrollView>
 
diff --git a/res/layout/storage_internal_unmount.xml b/res/layout/storage_internal_unmount.xml
index 7e728c8..2e394df 100644
--- a/res/layout/storage_internal_unmount.xml
+++ b/res/layout/storage_internal_unmount.xml
@@ -33,7 +33,7 @@
             android:paddingStart="@dimen/suw_layout_margin_sides"
             android:paddingEnd="@dimen/suw_layout_margin_sides"
             android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
-            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
             android:textColor="?android:attr/textColorPrimary" />
     </ScrollView>
 
diff --git a/res/layout/storage_item.xml b/res/layout/storage_item.xml
index aa2b4f8..cefb399 100644
--- a/res/layout/storage_item.xml
+++ b/res/layout/storage_item.xml
@@ -61,7 +61,7 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:singleLine="true"
-                android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
                 android:textAlignment="viewStart"
                 android:ellipsize="marquee"
                 android:fadingEdge="horizontal" />
@@ -71,7 +71,7 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textAlignment="viewStart"
-                android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
                 android:textColor="?android:attr/textColorSecondary"
                 android:maxLines="10"
                 android:layout_alignParentEnd="true"/>
diff --git a/res/layout/storage_summary.xml b/res/layout/storage_summary.xml
index d48d62d..ce03b54 100644
--- a/res/layout/storage_summary.xml
+++ b/res/layout/storage_summary.xml
@@ -35,7 +35,7 @@
         android:fontFamily="@*android:string/config_headlineFontFamily"
         android:singleLine="true"
         android:textAlignment="viewStart"
-        android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
         android:textColor="?android:attr/colorAccent"
         android:textSize="36sp"/>
 
@@ -44,7 +44,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:textAlignment="viewStart"
-        android:textAppearance="@android:style/TextAppearance.Material.Body1"
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
         android:maxLines="10" />
 
     <ProgressBar
diff --git a/res/layout/storage_summary_donut.xml b/res/layout/storage_summary_donut.xml
index 7a10fe7..1637189 100644
--- a/res/layout/storage_summary_donut.xml
+++ b/res/layout/storage_summary_donut.xml
@@ -32,7 +32,7 @@
         android:fontFamily="@*android:string/config_headlineFontFamily"
         android:singleLine="true"
         android:textAlignment="center"
-        android:textAppearance="@android:style/TextAppearance.Material.Display1"
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Display1"
         android:textSize="36sp" />
 
     <TextView
@@ -43,7 +43,7 @@
         android:layout_marginEnd="4dp"
         android:maxLines="10"
         android:textAlignment="center"
-        android:textAppearance="@android:style/TextAppearance.Material.Body1" />
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1" />
 
     <com.android.settings.widget.DonutView
         android:id="@+id/donut"
diff --git a/res/layout/storage_wizard_init.xml b/res/layout/storage_wizard_init.xml
index 73af8da..bca2676 100644
--- a/res/layout/storage_wizard_init.xml
+++ b/res/layout/storage_wizard_init.xml
@@ -48,7 +48,7 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginBottom="@dimen/suw_description_margin_bottom"
-                    android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                    android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
                     android:text="@string/storage_wizard_init_v2_internal_title" />
                 <TextView
                     android:layout_width="match_parent"
@@ -115,7 +115,7 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginBottom="@dimen/suw_description_margin_bottom"
-                    android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                    android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
                     android:text="@string/storage_wizard_init_v2_external_title" />
                 <TextView
                     android:layout_width="match_parent"
diff --git a/res/layout/tall_preference_category.xml b/res/layout/tall_preference_category.xml
index f0630f8..7eefdab 100644
--- a/res/layout/tall_preference_category.xml
+++ b/res/layout/tall_preference_category.xml
@@ -21,7 +21,7 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_marginBottom="16dip"
-    android:textAppearance="@android:style/TextAppearance.Material.Body2"
+    android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"
     android:textColor="?android:attr/colorAccent"
     android:paddingStart="?android:attr/listPreferredItemPaddingStart"
     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
diff --git a/res/layout/text_description_preference.xml b/res/layout/text_description_preference.xml
index 6b8594b..70385aa 100644
--- a/res/layout/text_description_preference.xml
+++ b/res/layout/text_description_preference.xml
@@ -18,5 +18,5 @@
     android:id="@android:id/summary"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:textAppearance="@android:style/TextAppearance.Material.Body1"
+    android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
     android:padding="16dip" />
diff --git a/res/layout/widget_text_views.xml b/res/layout/widget_text_views.xml
index d95599d..9f0506e 100644
--- a/res/layout/widget_text_views.xml
+++ b/res/layout/widget_text_views.xml
@@ -26,7 +26,7 @@
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:layout_gravity="fill_horizontal|top"
-        android:textAppearance="@android:style/TextAppearance.Material.Body1"
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
         android:textColor="?android:attr/textColorSecondary"
         android:textAlignment="viewStart"
         android:singleLine="true"
@@ -40,7 +40,7 @@
         android:layout_weight="1"
         android:layout_marginStart="8dip"
         android:layout_gravity="fill_horizontal|top"
-        android:textAppearance="@android:style/TextAppearance.Material.Body1"
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
         android:textColor="?android:attr/textColorSecondary"
         android:textAlignment="viewEnd"
         android:singleLine="true"
diff --git a/res/layout/wifi_dpp_activity.xml b/res/layout/wifi_dpp_activity.xml
index cb82f66..48f2b65 100644
--- a/res/layout/wifi_dpp_activity.xml
+++ b/res/layout/wifi_dpp_activity.xml
@@ -15,7 +15,7 @@
      limitations under the License.
 -->
 
-<LinearLayout
+<ScrollView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/root"
     android:layout_width="match_parent"
@@ -27,4 +27,4 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"/>
 
-</LinearLayout>
+</ScrollView>
diff --git a/res/layout/wifi_dpp_fragment_header.xml b/res/layout/wifi_dpp_fragment_header.xml
index 266a3e8..20bcd7d 100644
--- a/res/layout/wifi_dpp_fragment_header.xml
+++ b/res/layout/wifi_dpp_fragment_header.xml
@@ -27,13 +27,13 @@
     android:paddingEnd="16dp">
 
     <ImageView
-        android:id="@+id/header_icon"
+        android:id="@android:id/icon"
         android:layout_width="48dp"
         android:layout_height="48dp"
         android:scaleType="fitCenter"/>
 
     <TextView
-        android:id="@+id/title"
+        android:id="@android:id/title"
         style="@style/TextAppearance.EntityHeaderTitle"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -44,7 +44,7 @@
         android:paddingEnd="32dp"/>
 
     <TextView
-        android:id="@+id/description"
+        android:id="@android:id/summary"
         style="@style/TextAppearance.EntityHeaderSummary"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
diff --git a/res/layout/wifi_dpp_qrcode_generator_fragment.xml b/res/layout/wifi_dpp_qrcode_generator_fragment.xml
index 789b3a3..c7c258b 100644
--- a/res/layout/wifi_dpp_qrcode_generator_fragment.xml
+++ b/res/layout/wifi_dpp_qrcode_generator_fragment.xml
@@ -25,9 +25,10 @@
     <include layout="@layout/wifi_dpp_fragment_header"/>
 
     <ImageView
-        android:id="@+id/barcode_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:id="@+id/qrcode_view"
+        android:layout_width="@dimen/qrcode_size"
+        android:layout_height="@dimen/qrcode_size"
+        android:src="@android:color/transparent"
         android:layout_gravity="center"/>
 
 </LinearLayout>
diff --git a/res/layout/wifi_dpp_qrcode_scanner_fragment.xml b/res/layout/wifi_dpp_qrcode_scanner_fragment.xml
index 913998f..f09fc69 100644
--- a/res/layout/wifi_dpp_qrcode_scanner_fragment.xml
+++ b/res/layout/wifi_dpp_qrcode_scanner_fragment.xml
@@ -39,10 +39,15 @@
             android:layout_gravity="center"/>
     </com.android.settings.wifi.qrcode.QrPreviewLayout>
 
-    <TextView android:id="@+id/error_message"
+    <TextView
+        android:id="@+id/error_message"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center"/>
+        android:layout_gravity="center"
+        android:layout_marginTop="8dp"
+        android:text="@string/wifi_dpp_could_not_detect_valid_qr_code"
+        android:visibility="invisible"
+        android:textColor="?android:attr/colorError"/>
 
 </LinearLayout>
 
diff --git a/res/layout/zen_custom_settings_dialog.xml b/res/layout/zen_custom_settings_dialog.xml
new file mode 100644
index 0000000..f44b2f7
--- /dev/null
+++ b/res/layout/zen_custom_settings_dialog.xml
@@ -0,0 +1,171 @@
+<?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.
+-->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:fadeScrollbars="false"
+            android:scrollIndicators="top|bottom">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:paddingStart="24dp">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:layout_marginTop="14dp">
+            <TextView
+                android:id="@+id/zen_custom_settings_dialog_calls"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/zen_mode_calls" />
+
+            <TextView
+                android:id="@+id/zen_custom_settings_dialog_calls_allow"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAppearance="?android:attr/textAppearanceListItem" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:layout_marginTop="14dp">
+            <TextView
+                android:id="@+id/zen_custom_settings_dialog_messages"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/zen_mode_messages" />
+
+            <TextView
+                android:id="@+id/zen_custom_settings_dialog_messages_allow"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAppearance="?android:attr/textAppearanceListItem" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:layout_marginTop="14dp">
+            <TextView
+                android:id="@+id/zen_custom_settings_dialog_alarms"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/zen_mode_alarms" />
+
+            <TextView
+                android:id="@+id/zen_custom_settings_dialog_alarms_allow"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAppearance="?android:attr/textAppearanceListItem" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:layout_marginTop="14dp">
+            <TextView
+                android:id="@+id/zen_custom_settings_dialog_media"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/zen_mode_media" />
+
+            <TextView
+                android:id="@+id/zen_custom_settings_dialog_media_allow"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAppearance="?android:attr/textAppearanceListItem" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:layout_marginTop="14dp">
+            <TextView
+                android:id="@+id/zen_custom_settings_dialog_system"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/zen_mode_system" />
+
+            <TextView
+                android:id="@+id/zen_custom_settings_dialog_system_allow"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAppearance="?android:attr/textAppearanceListItem" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:layout_marginTop="14dp">
+            <TextView
+                android:id="@+id/zen_custom_settings_dialog_reminders"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/zen_mode_reminders"/>
+
+            <TextView
+                android:id="@+id/zen_custom_settings_dialog_reminders_allow"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAppearance="?android:attr/textAppearanceListItem" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:layout_marginTop="14dp">
+            <TextView
+                android:id="@+id/zen_custom_settings_dialog_events"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/zen_mode_events"/>
+
+            <TextView
+                android:id="@+id/zen_custom_settings_dialog_events_allow"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAppearance="?android:attr/textAppearanceListItem" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:layout_marginTop="14dp">
+            <TextView
+                android:id="@+id/zen_custom_settings_dialog_notifications"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/zen_custom_settings_notifications_header" />
+
+            <TextView
+                android:id="@+id/zen_custom_settings_dialog_show_notifications"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAppearance="?android:attr/textAppearanceListItem" />
+        </LinearLayout>
+    </LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/res/layout/zen_onboarding.xml b/res/layout/zen_onboarding.xml
index 35b992d..27922c6 100644
--- a/res/layout/zen_onboarding.xml
+++ b/res/layout/zen_onboarding.xml
@@ -32,7 +32,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/zen_onboarding_dnd_visual_disturbances_header"
-            android:textAppearance="@android:style/TextAppearance.Material.DialogWindowTitle" />
+            android:textAppearance="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle" />
 
         <LinearLayout
             android:id="@+id/zen_onboarding_new_setting"
diff --git a/res/layout/zen_rule_type.xml b/res/layout/zen_rule_type.xml
index dea39ed..bd50273 100644
--- a/res/layout/zen_rule_type.xml
+++ b/res/layout/zen_rule_type.xml
@@ -42,7 +42,7 @@
                   android:singleLine="true"
                   android:textSize="16sp"
                   android:ellipsize="marquee"
-                  android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                  android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
                   android:fadingEdge="horizontal" />
 
         <TextView android:id="@+id/subtitle"
@@ -52,7 +52,7 @@
                   android:layout_alignStart="@id/title"
                   android:textSize="14sp"
                   android:textColor="?android:attr/textColorSecondary"
-                  android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                  android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
                   android:maxLines="2"
                   android:visibility="gone" />
 
diff --git a/res/layout/zen_rule_widget.xml b/res/layout/zen_rule_widget.xml
index c6214e7..3d75469 100644
--- a/res/layout/zen_rule_widget.xml
+++ b/res/layout/zen_rule_widget.xml
@@ -19,14 +19,7 @@
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:orientation="horizontal">
-    <ImageView
-            android:id="@+id/zen_automatic_rule_widget"
-            android:layout_width="wrap_content"
-            android:layout_height="fill_parent"
-            android:paddingStart="16dip"
-            android:paddingEnd="16dip"
-            android:src="@drawable/ic_settings"
-            android:contentDescription="zen_mode_rule_settings"
-            android:layout_gravity="center"
-            android:background="?android:attr/selectableItemBackground" />
+
+    <include layout="@layout/preference_widget_gear"
+             android:id="@+id/zen_automatic_rule_widget" />
 </LinearLayout>
diff --git a/res/values/aliases.xml b/res/values/aliases.xml
index 060ba1d..881d3ca 100644
--- a/res/values/aliases.xml
+++ b/res/values/aliases.xml
@@ -15,7 +15,6 @@
 -->
 
 <resources>
-     <item name="notification_app_section" type="layout">@*android:layout/preference_category_material</item>
      <item name="confirm_lock_pattern" type="layout">@layout/confirm_lock_pattern_base</item>
      <item name="confirm_lock_pattern_normal" type="layout">@layout/confirm_lock_pattern_normal_base</item>
      <item name="confirm_lock_password" type="layout">@layout/confirm_lock_password_base</item>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index eb5b99a..6f336eb 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1081,14 +1081,14 @@
         <item>@string/zen_mode_from_anyone</item>
         <item>@string/zen_mode_from_contacts</item>
         <item>@string/zen_mode_from_starred</item>
-        <item>@string/zen_mode_from_none_calls</item>
+        <item>@string/zen_mode_from_none_messages</item>
     </string-array>
 
     <string-array name="zen_mode_contacts_calls_entries" translatable="false">
         <item>@string/zen_mode_from_anyone</item>
         <item>@string/zen_mode_from_contacts</item>
         <item>@string/zen_mode_from_starred</item>
-        <item>@string/zen_mode_from_none_messages</item>
+        <item>@string/zen_mode_from_none_calls</item>
     </string-array>
 
     <string-array name="zen_mode_contacts_values" translatable="false">
@@ -1105,8 +1105,8 @@
     </string-array>
 
     <string-array name="wifi_privacy_entries">
-        <item>Default (use randomized MAC)</item>
-        <item>Trusted</item>
+        <item>Use device MAC</item>
+        <item>Use randomized MAC (default)</item>
     </string-array>
 
     <string-array name="wifi_hidden_entries">
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 587184b..2103649 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -128,5 +128,10 @@
 
     <!-- launcher icon color -->
     <color name="icon_launcher_setting_color">@*android:color/accent_device_default_light</color>
-</resources>
 
+    <!-- QR code scanner colors -->
+    <color name="qr_corner_line_color">#ffdadce0</color>
+    <color name="qr_focused_corner_line_color">#ff1a73e8</color>
+    <color name="qr_background_color">#b3ffffff</color> <!-- 70% white transparency -->
+    <!-- End of QR code scanner colors -->
+</resources>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a109d57..383f564 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -346,7 +346,6 @@
 
     <!-- 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>
@@ -366,4 +365,8 @@
     <dimen name="homepage_condition_header_icon_width_height">24dp</dimen>
     <dimen name="homepage_condition_header_icon_margin_end">24dp</dimen>
 
+    <!-- QR code picture size -->
+    <dimen name="qrcode_size">264dp</dimen>
+    <dimen name="qrcode_preview_size">360dp</dimen>
+
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 126a835..a45be06 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2090,6 +2090,8 @@
     <string name="wifi_dpp_share_wifi">Share Wi\u2011Fi</string>
     <!-- Hint for the user to use another device to scan QR code on screen to join Wi-Fi [CHAR LIMIT=NONE] -->
     <string name="wifi_dpp_scan_qr_code_with_another_device">Scan this QR code with another device to join \u201c<xliff:g id="ssid" example="OfficeWifi">%1$s</xliff:g>\u201d</string>
+    <!-- Hint for QR code detection [CHAR LIMIT=NONE]  -->
+    <string name="wifi_dpp_could_not_detect_valid_qr_code">Could not detect valid QR code</string>
     <!-- Label for the check box to share a network with other users on the same device -->
     <string name="wifi_shared">Share with other device users</string>
     <!-- Hint for unchanged fields -->
@@ -7336,8 +7338,8 @@
     <!-- [CHAR LIMIT=110] Zen mode settings footer: Footer showing length of DND -->
     <string name="zen_mode_settings_dnd_manual_indefinite">Do Not Disturb will stay on until you turn it off</string>
 
-    <!-- [CHAR LIMIT=110] Zen mode settings footer: Footer showing how DND was triggered by an automatic DND rule -->
-    <string name="zen_mode_settings_dnd_automatic_rule">Do Not Disturb was automatically turned on by a rule (<xliff:g id="rule_name" example="Weeknights">%s</xliff:g>)</string>
+    <!-- [CHAR LIMIT=110] Zen mode settings footer: Footer showing how DND was triggered by an automatic DND schedule -->
+    <string name="zen_mode_settings_dnd_automatic_rule">Do Not Disturb was automatically turned on by a schedule (<xliff:g id="rule_name" example="Weeknights">%s</xliff:g>)</string>
 
     <!-- [CHAR LIMIT=110] Zen mode settings footer: Footer how DND was triggered by an app -->
     <string name="zen_mode_settings_dnd_automatic_rule_app">Do Not Disturb was automatically turned on by an app (<xliff:g id="app_name" example="Android Services">%s</xliff:g>)</string>
@@ -7345,6 +7347,9 @@
     <!-- [CHAR LIMIT=120] Zen mode settings footer: Footer informing user DND has custom settings. -->
     <string name="zen_mode_settings_dnd_custom_settings_footer">Do Not Disturb is on for <xliff:g id="rule_names" example="Sleeping and Work">%s</xliff:g> with custom settings.</string>
 
+    <!-- [CHAR LIMIT=120] Zen mode settings footer: Link following zen_mode_settings_dnd_custom_settings_footer to see the currently applied custom dnd settings. -->
+    <string name="zen_mode_settings_dnd_custom_settings_footer_link"><annotation id="link"> View custom settings</annotation></string>
+
     <!--[CHAR LIMIT=40] Zen Interruption level: Priority.  -->
     <string name="zen_interruption_level_priority">Priority only</string>
 
@@ -7408,6 +7413,17 @@
     <!-- Do not disturb settings, sound and vibrations summary [CHAR LIMIT=100]-->
     <string name="zen_sound_three_allowed">Muted, but allow <xliff:g id="sound_type" example="alarms">%1$s</xliff:g>, <xliff:g id="sound_type" example="alarms">%2$s</xliff:g>, and <xliff:g id="sound_type" example="media">%3$s</xliff:g></string>
 
+    <!-- Do not disturb custom settings dialog title [CHAR LIMIT=40]-->
+    <string name="zen_custom_settings_dialog_title">Custom settings</string>
+    <!-- Do not disturb custom settings dialog button label [CHAR LIMIT=40]-->
+    <string name="zen_custom_settings_dialog_review_schedule">Review schedule</string>
+    <!-- Do not disturb custom settings dialog button label [CHAR LIMIT=40]-->
+    <string name="zen_custom_settings_dialog_ok">Got it</string>
+    <!-- Do not disturb custom settings notifications header [CHAR LIMIT=40]-->
+    <string name="zen_custom_settings_notifications_header">Notifications</string>
+    <!-- Do not disturb custom settings duration header [CHAR LIMIT=40]-->
+    <string name="zen_custom_settings_duration_header">Duration</string>
+
     <!-- Do not disturb settings, messages, events and reminders title [CHAR LIMIT=100]-->
     <string name="zen_msg_event_reminder_title">Messages, events &amp; reminders</string>
     <!-- Do not disturb settings, messages, events and reminders footer [CHAR LIMIT=NONE]-->
@@ -7949,6 +7965,9 @@
     <!-- [CHAR LIMIT=120] Zen mode settings: Summay text indicating the currenty dnd schedule is using custom behavior -->
     <string name="zen_mode_custom_behavior_summary">Create custom settings for this schedule</string>
 
+    <!-- [CHAR LIMIT=100] Zen mode settings: Category text indicating the schedule this custom behavior will be configured for-->
+    <string name="zen_mode_custom_behavior_category_title">For \u2018<xliff:g id="schedule_name" example="Schedule 1">%1$s</xliff:g>\u2019</string>
+
     <!-- [CHAR LIMIT=40] General divider text when concatenating multiple items in a text summary -->
     <string name="summary_divider_text">,\u0020</string>
 
@@ -7964,9 +7983,12 @@
     <!-- [CHAR LIMIT=40] Zen mode settings: Allow calls toggle title -->
     <string name="zen_mode_calls_title">Calls</string>
 
-    <!-- [CHAR LIMIT=20] Zen mode settings: Calls screen footer -->
+    <!-- [CHAR LIMIT=NONE] Zen mode settings: Calls screen footer -->
     <string name="zen_mode_calls_footer">When Do Not Disturb is on, incoming calls are blocked. You can adjust settings to allow your friends, family, or other contacts to reach you.</string>
 
+    <!-- [CHAR LIMIT=NONE] Zen mode custom rule settings: Calls screen footer -->
+    <string name="zen_mode_custom_calls_footer">For \u2018<xliff:g id="schedule_name" example="Schedule 1">%1$s</xliff:g>\u2019 incoming calls are blocked. You can adjust settings to allow your friends, family, or other contacts to reach you.</string>
+
     <!-- [CHAR LIMIT=50] Zen mode settings: Starred contacts preference title -->
     <string name="zen_mode_starred_contacts_title">Starred contacts</string>
 
@@ -7982,6 +8004,9 @@
     <!-- Do not disturb settings, messages, events and reminders footer [CHAR LIMIT=NONE]-->
     <string name="zen_mode_messages_footer">When Do Not Disturb is on, incoming text messages are blocked. You can adjust settings to allow your friends, family, or other contacts to reach you.</string>
 
+    <!-- [CHAR LIMIT=NONE] Zen mode custom rule settings: Messages screen footer -->
+    <string name="zen_mode_custom_messages_footer">For \u2018<xliff:g id="schedule_name" example="Schedule 1">%1$s</xliff:g>\u2019 incoming text messages are blocked. You can adjust settings to allow your friends, family, or other contacts to reach you.</string>
+
     <!-- [CHAR LIMIT=40] Zen mode settings: Allow messages to bypass DND title -->
     <string name="zen_mode_messages_title">Text messages</string>
 
@@ -8045,11 +8070,11 @@
     <!-- [CHAR LIMIT=100] Zen mode settings: Allow apps to bypass DND title-->
     <string name="zen_mode_bypassing_apps_title">App exceptions</string>
 
-    <!-- [CHAR LIMIT=80] Zen mode settings: Allow apps to bypass DND -->
+    <!-- [CHAR LIMIT=120] Zen mode settings: Allow apps to bypass DND -->
     <plurals name="zen_mode_bypassing_apps_subtext">
         <item quantity="zero">No apps can override Do Not Disturb</item>
-        <item quantity="one">1 app can override Do Not Disturb</item>
-        <item quantity="other"><xliff:g id="number" example="2">%1$d</xliff:g> apps can override Do Not Disturb</item>
+        <item quantity="one">Notifications from 1 app can override Do Not Disturb</item>
+        <item quantity="other">Notifications from <xliff:g id="number" example="2">%1$d</xliff:g> apps can override Do Not Disturb</item>
     </plurals>
 
     <!-- [CHAR LIMIT=50] Zen mode settings: Events (ie: calendar events) -->
@@ -8269,8 +8294,6 @@
     <!-- Summary describing external storage for applications [CHAR LIMIT=25] -->
     <string name="storage_type_external">External storage</string>
 
-    <!-- Title for data usage screen when entered from app info [CHAR LIMIT=30] -->
-    <string name="app_data_usage">App data usage</string>
     <!-- Summary for data usage preference [CHAR LIMIT=15] -->
     <string name="data_summary_format"><xliff:g id="size" example="30.00MB">%1$s</xliff:g> used since <xliff:g id="date" example="Jan 12">%2$s</xliff:g></string>
 
@@ -10317,9 +10340,9 @@
     <string name="see_less">See less</string>
 
     <!-- Title for Network connection request Dialog [CHAR LIMIT=30] -->
-    <string name="network_connection_request_dialog_title">Choose device</string>
+    <string name="network_connection_request_dialog_title">Choose a device</string>
     <!-- Message for Network connection timeout Dialog [CHAR LIMIT=NONE] -->
-    <string name="network_connection_timeout_dialog_message">No devices found. Make sure the device is turned on and available to connect.</string>
+    <string name="network_connection_timeout_dialog_message">No devices found. Make sure devices are turned on and available to connect.</string>
     <!-- OK button for Network connection timeout Dialog [CHAR LIMIT=30] -->
     <string name="network_connection_timeout_dialog_ok">Try again</string>
     <!-- Message for Network connection error state Dialog [CHAR LIMIT=NONE] -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 15ec46d..98b6283 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -121,7 +121,7 @@
         <item name="android:paddingStart">8dip</item>
         <item name="android:textSize">14sp</item>
         <item name="android:textAlignment">viewStart</item>
-        <item name="android:textAppearance">@android:style/TextAppearance.Material.Body1</item>
+        <item name="android:textAppearance">@*android:style/TextAppearance.DeviceDefault.Body1</item>
         <item name="android:textColor">?android:attr/textColorSecondary</item>
     </style>
 
@@ -129,13 +129,13 @@
         <item name="android:paddingStart">8dip</item>
         <item name="android:textSize">12sp</item>
         <item name="android:textAlignment">viewStart</item>
-        <item name="android:textAppearance">@android:style/TextAppearance.Material.Body1</item>
+        <item name="android:textAppearance">@*android:style/TextAppearance.DeviceDefault.Body1</item>
         <item name="android:textColor">?android:attr/colorError</item>
     </style>
 
     <style name="wifi_item_content">
         <item name="android:textAlignment">viewStart</item>
-        <item name="android:textAppearance">@android:style/TextAppearance.Material.Subhead</item>
+        <item name="android:textAppearance">@*android:style/TextAppearance.DeviceDefault.Subhead</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
         <item name="android:minHeight">@dimen/min_tap_target_size</item>
     </style>
@@ -174,23 +174,6 @@
         <item name="android:background">#ff000000</item>
     </style>
 
-    <style name="SecurityPreferenceButtonContainer"
-           parent="@android:style/Widget.Material.Light.SegmentedButton">
-        <item name="android:layout_width">match_parent</item>
-        <item name="android:layout_height">wrap_content</item>
-        <item name="android:weightSum">2</item>
-        <item name="android:dividerPadding">8dip</item>
-    </style>
-
-    <style name="SecurityPreferenceButton"
-           parent="@android:style/Widget.Material.Light.Button.Borderless">
-        <item name="android:layout_width">0dip</item>
-        <item name="android:layout_weight">1</item>
-        <item name="android:layout_height">wrap_content</item>
-        <item name="android:ellipsize">marquee</item>
-        <item name="android:singleLine">true</item>
-    </style>
-
     <style name="SetupWizardButton.Negative" parent="@style/SuwGlifButton.Secondary">
         <!-- Negative margin to offset for padding of the button itself. We want the label to be
              aligned with the text above it -->
@@ -206,13 +189,13 @@
     <style name="vpn_label">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
-        <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
+        <item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Small</item>
     </style>
 
     <style name="vpn_value">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
-        <item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
+        <item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item>
         <item name="android:singleLine">true</item>
         <item name="android:textAlignment">viewStart</item>
         <item name="android:minHeight">@dimen/min_tap_target_size</item>
@@ -222,10 +205,10 @@
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
         <item name="android:paddingStart">8dip</item>
-        <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
+        <item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Small</item>
     </style>
 
-    <style name="TextAppearance" parent="android:TextAppearance.Material"/>
+    <style name="TextAppearance" parent="android:TextAppearance.DeviceDefault"/>
 
     <style name="TextAppearance.info_label">
         <item name="android:textSize">14sp</item>
@@ -242,14 +225,14 @@
         <item name="android:textStyle">normal</item>
     </style>
 
-    <style name="TextAppearance.PasswordEntry" parent="android:TextAppearance.Material">
+    <style name="TextAppearance.PasswordEntry" parent="android:TextAppearance.DeviceDefault">
         <item name="android:gravity">center</item>
         <item name="android:singleLine">true</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
         <item name="android:textSize">24sp</item>
     </style>
 
-    <style name="TextAppearance.CryptKeeper_PasswordEntry" parent="android:TextAppearance.Material">
+    <style name="TextAppearance.CryptKeeper_PasswordEntry" parent="android:TextAppearance.DeviceDefault">
         <item name="android:gravity">center_horizontal</item>
         <item name="android:background">@null</item>
         <item name="android:textCursorDrawable">@null</item>
@@ -257,22 +240,22 @@
         <item name="android:imeOptions">flagForceAscii|actionDone</item>
     </style>
 
-    <style name="TextAppearance.Medium" parent="@android:style/TextAppearance.Material.Medium"/>
-    <style name="TextAppearance.Small" parent="@android:style/TextAppearance.Material.Small"/>
+    <style name="TextAppearance.Medium" parent="@android:style/TextAppearance.DeviceDefault.Medium"/>
+    <style name="TextAppearance.Small" parent="@android:style/TextAppearance.DeviceDefault.Small"/>
     <style name="TextAppearance.Switch"
            parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
         <item name="android:textSize">16sp</item>
     </style>
 
     <style name="TextAppearance.CategoryTitle"
-           parent="@android:style/TextAppearance.Material.Body2">
+           parent="@*android:style/TextAppearance.DeviceDefault.Body2">
         <item name="android:textColor">?android:attr/textColorSecondary</item>
     </style>
 
-    <style name="TextAppearance.TileTitle" parent="@android:style/TextAppearance.Material.Subhead"/>
+    <style name="TextAppearance.TileTitle" parent="@*android:style/TextAppearance.DeviceDefault.Subhead"/>
 
     <style name="TextAppearance.SuggestionTitle"
-           parent="@android:style/TextAppearance.Material.Subhead">
+           parent="@*android:style/TextAppearance.DeviceDefault.Subhead">
         <item name="android:textSize">16sp</item>
     </style>
 
@@ -280,18 +263,8 @@
         <item name="android:textColor">?android:attr/textColorSecondary</item>
     </style>
 
-    <style name="TextAppearance.FingerprintErrorText"
-           parent="android:TextAppearance.Material.Body1">
-        <item name="android:textColor">?android:attr/colorError</item>
-    </style>
-
-    <style name="TextAppearance.FaceErrorText"
-           parent="android:TextAppearance.Material.Body1">
-        <item name="android:textColor">?android:attr/colorError</item>
-    </style>
-
-    <style name="TextAppearance.ConfirmDeviceCredentialsErrorText"
-           parent="android:TextAppearance.Material.Body1">
+    <style name="TextAppearance.ErrorText"
+           parent="@*android:TextAppearance.DeviceDefault.Body1">
         <item name="android:textColor">?android:attr/colorError</item>
     </style>
 
@@ -301,29 +274,29 @@
     </style>
 
     <style name="TextAppearance.RemoveDialogContent"
-           parent="@android:style/TextAppearance.Material">
+           parent="@android:style/TextAppearance.DeviceDefault">
         <item name="android:textSize">16sp</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
     </style>
 
     <style name="TextAppearance.SearchBar"
-           parent="@android:style/TextAppearance.Material.Widget.Toolbar.Subtitle">
+           parent="@*android:style/TextAppearance.DeviceDefault.Widget.Toolbar.Subtitle">
         <item name="android:textSize">@dimen/search_bar_text_size</item>
     </style>
 
     <style name="TextAppearance.SuggestionHeader"
-           parent="@android:style/TextAppearance.Material.Subhead">
+           parent="@*android:style/TextAppearance.DeviceDefault.Subhead">
         <item name="android:textSize">14sp</item>
         <item name="android:textColor">?android:attr/colorAccent</item>
     </style>
 
     <style name="TextAppearance.ConditionCardTitle"
-           parent="@android:style/TextAppearance.Material.Body2">
+           parent="@*android:style/TextAppearance.DeviceDefault.Body2">
         <item name="android:textSize">16sp</item>
     </style>
 
     <style name="TextAppearance.ConditionCardSummary"
-           parent="@android:style/TextAppearance.Material.Body1">
+           parent="@*android:style/TextAppearance.DeviceDefault.Body1">
         <item name="android:textColor">?android:attr/textColorSecondary</item>
     </style>
 
@@ -338,7 +311,7 @@
     </style>
 
     <style name="TextAppearance.ContextualCardDismissalText"
-           parent="@android:style/TextAppearance.Material.Body1">
+           parent="@*android:style/TextAppearance.DeviceDefault.Body1">
         <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
         <item name="android:textSize">16sp</item>
     </style>
@@ -377,13 +350,13 @@
         <item name="android:gravity">center_vertical</item>
     </style>
 
-    <style name="FingerprintHeaderStyle" parent="android:style/TextAppearance.Material.Subhead">
+    <style name="FingerprintHeaderStyle" parent="@*android:style/TextAppearance.DeviceDefault.Subhead">
         <item name="android:paddingTop">16dp</item>
         <item name="android:textColor">@color/primary_dark_material_light</item>
         <item name="android:lineSpacingMultiplier">1.2</item>
     </style>
 
-    <style name="FaceHeaderStyle" parent="android:style/TextAppearance.Material.Subhead">
+    <style name="FaceHeaderStyle" parent="@*android:style/TextAppearance.DeviceDefault.Subhead">
         <item name="android:paddingTop">16dp</item>
         <item name="android:textColor">@color/primary_dark_material_light</item>
         <item name="android:lineSpacingMultiplier">1.2</item>
@@ -438,13 +411,13 @@
 
     <style name="device_info_dialog_label">
         <item name="android:textAlignment">viewStart</item>
-        <item name="android:textAppearance">@android:style/TextAppearance.Material.Body1</item>
+        <item name="android:textAppearance">@*android:style/TextAppearance.DeviceDefault.Body1</item>
         <item name="android:textColor">?android:attr/textColorSecondary</item>
     </style>
 
     <style name="device_info_dialog_value">
         <item name="android:textAlignment">viewStart</item>
-        <item name="android:textAppearance">@android:style/TextAppearance.Material.Body2</item>
+        <item name="android:textAppearance">@*android:style/TextAppearance.DeviceDefault.Body2</item>
         <item name="android:paddingBottom">24dp</item>
     </style>
 
diff --git a/res/values/themes.xml b/res/values/themes.xml
index 6b05a7c..6041ef8 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -180,7 +180,7 @@
         <item name="android:windowNoTitle">true</item>
     </style>
 
-    <style name="Theme.Settings.HomeBase" parent="Theme.AppCompat.DayNight.NoActionBar">
+    <style name="Theme.Settings.HomeBase" parent="Theme.Settings.NoActionBar">
         <item name="colorPrimary">@*android:color/primary_device_default_settings_light</item>
         <item name="colorAccent">@*android:color/accent_device_default_light</item>
         <item name="preferenceTheme">@style/PreferenceTheme</item>
diff --git a/res/xml/zen_mode_custom_rule_configuration.xml b/res/xml/zen_mode_custom_rule_configuration.xml
new file mode 100644
index 0000000..c1732a3
--- /dev/null
+++ b/res/xml/zen_mode_custom_rule_configuration.xml
@@ -0,0 +1,66 @@
+<?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.
+-->
+
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:key="zen_custom_rule_configuration_page"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:title="@string/zen_mode_settings_title">
+
+    <PreferenceCategory
+        android:key="zen_custom_rule_configuration_category">
+        <!-- Calls -->
+        <Preference
+            android:key="zen_rule_calls_settings"
+            android:title="@string/zen_mode_calls" />
+
+        <!-- Messages -->
+        <Preference
+            android:key="zen_rule_messages_settings"
+            android:title="@string/zen_mode_messages" />
+
+        <!-- Alarms -->
+        <SwitchPreference
+            android:key="zen_rule_alarms"
+            android:title="@string/zen_mode_alarms"/>
+
+        <!-- Media -->
+        <SwitchPreference
+            android:key="zen_rule_media"
+            android:title="@string/zen_mode_media"/>
+
+        <!-- System -->
+        <SwitchPreference
+            android:key="zen_rule_system"
+            android:title="@string/zen_mode_system"/>
+
+        <!-- Reminders -->
+        <SwitchPreference
+            android:key="zen_rule_reminders"
+            android:title="@string/zen_mode_reminders"/>
+
+        <!-- Events -->
+        <SwitchPreference
+            android:key="zen_rule_events"
+            android:title="@string/zen_mode_events"/>
+    </PreferenceCategory>
+
+    <Preference
+        android:key="zen_rule_notifications"
+        android:title="@string/zen_mode_restrict_notifications_title"
+        settings:allowDividerAbove="true"/>
+</PreferenceScreen>
diff --git a/res/xml/zen_mode_custom_rule_settings.xml b/res/xml/zen_mode_custom_rule_settings.xml
new file mode 100644
index 0000000..7aedd2c
--- /dev/null
+++ b/res/xml/zen_mode_custom_rule_settings.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:key="zen_custom_rule_settings_page"
+    android:title="@string/zen_mode_custom_behavior_title">
+
+    <PreferenceCategory
+        android:key="zen_custom_rule_category">
+        <com.android.settings.notification.ZenCustomRadioButtonPreference
+            android:key="zen_custom_rule_setting_default"
+            android:title="@string/zen_mode_custom_behavior_summary_default"/>
+
+        <com.android.settings.notification.ZenCustomRadioButtonPreference
+            android:key="zen_custom_rule_setting"
+            android:title="@string/zen_mode_custom_behavior_summary" />
+    </PreferenceCategory>
+
+</PreferenceScreen>
diff --git a/res/xml/zen_mode_event_rule_settings.xml b/res/xml/zen_mode_event_rule_settings.xml
index a70b46c..841fc06 100644
--- a/res/xml/zen_mode_event_rule_settings.xml
+++ b/res/xml/zen_mode_event_rule_settings.xml
@@ -45,4 +45,10 @@
         android:title="@string/zen_mode_event_rule_reply"
         android:summary="%s" />
 
+    <!-- Custom Do Not Disturb Setting-->
+    <Preference
+        android:key="zen_custom_setting"
+        android:title="@string/zen_mode_custom_behavior_title"
+        android:order="100" />
+
 </PreferenceScreen>
diff --git a/res/xml/zen_mode_schedule_rule_settings.xml b/res/xml/zen_mode_schedule_rule_settings.xml
index 7de10b3..8484854 100644
--- a/res/xml/zen_mode_schedule_rule_settings.xml
+++ b/res/xml/zen_mode_schedule_rule_settings.xml
@@ -50,7 +50,7 @@
 
     <!-- Custom Do Not Disturb Setting-->
     <Preference
-        android:key="zen_schedule_custom_setting"
+        android:key="zen_custom_setting"
         android:title="@string/zen_mode_custom_behavior_title"
         android:order="100" />
 
diff --git a/src/com/android/settings/EncryptionInterstitial.java b/src/com/android/settings/EncryptionInterstitial.java
index 8cae26b..656b18c 100644
--- a/src/com/android/settings/EncryptionInterstitial.java
+++ b/src/com/android/settings/EncryptionInterstitial.java
@@ -40,6 +40,8 @@
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
 import com.android.settings.password.ChooseLockSettingsHelper;
 
+import com.google.android.setupcompat.item.FooterButton;
+import com.google.android.setupcompat.template.ButtonFooterMixin;
 import com.google.android.setupdesign.GlifLayout;
 
 import java.util.List;
@@ -86,11 +88,8 @@
         layout.setFitsSystemWindows(false);
     }
 
-    public static class EncryptionInterstitialFragment extends InstrumentedFragment
-            implements View.OnClickListener {
+    public static class EncryptionInterstitialFragment extends InstrumentedFragment {
 
-        private View mRequirePasswordToDecrypt;
-        private View mDontRequirePasswordToDecrypt;
         private boolean mPasswordRequired;
         private Intent mUnlockMethodIntent;
         private int mRequestedPasswordQuality;
@@ -110,8 +109,6 @@
         public void onViewCreated(View view, Bundle savedInstanceState) {
             super.onViewCreated(view, savedInstanceState);
 
-            mRequirePasswordToDecrypt = view.findViewById(R.id.encrypt_require_password);
-            mDontRequirePasswordToDecrypt = view.findViewById(R.id.encrypt_dont_require_password);
             final boolean forFingerprint = getActivity().getIntent().getBooleanExtra(
                     ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
             final boolean forFace = getActivity().getIntent()
@@ -147,14 +144,30 @@
             TextView message = (TextView) getActivity().findViewById(R.id.encryption_message);
             message.setText(msgId);
 
-            mRequirePasswordToDecrypt.setOnClickListener(this);
-            mDontRequirePasswordToDecrypt.setOnClickListener(this);
-
             setRequirePasswordState(getActivity().getIntent().getBooleanExtra(
                     EXTRA_REQUIRE_PASSWORD, true));
 
             GlifLayout layout = (GlifLayout) view;
             layout.setHeaderText(getActivity().getTitle());
+
+            final ButtonFooterMixin buttonFooterMixin = layout.getMixin(ButtonFooterMixin.class);
+            buttonFooterMixin.setSecondaryButton(
+                    new FooterButton.Builder(getContext())
+                            .setText(R.string.encryption_interstitial_no)
+                            .setListener(this::onNoButtonClicked)
+                            .setButtonType(FooterButton.ButtonType.SKIP)
+                            .setTheme(R.style.SuwGlifButton_Secondary)
+                            .build()
+            );
+
+            buttonFooterMixin.setPrimaryButton(
+                    new FooterButton.Builder(getContext())
+                            .setText(R.string.encryption_interstitial_yes)
+                            .setListener(this::onYesButtonClicked)
+                            .setButtonType(FooterButton.ButtonType.NEXT)
+                            .setTheme(R.style.SuwGlifButton_Primary)
+                            .build()
+            );
         }
 
         protected void startLockIntent() {
@@ -176,26 +189,25 @@
             }
         }
 
-        @Override
-        public void onClick(View view) {
-            if (view == mRequirePasswordToDecrypt) {
-                final boolean accEn = AccessibilityManager.getInstance(getActivity()).isEnabled();
-                if (accEn && !mPasswordRequired) {
-                    setRequirePasswordState(false); // clear the UI state
-                    AccessibilityWarningDialogFragment.newInstance(mRequestedPasswordQuality)
-                            .show(
-                                    getChildFragmentManager(),
-                                    AccessibilityWarningDialogFragment.TAG);
-                } else {
-                    setRequirePasswordState(true);
-                    startLockIntent();
-                }
+        private void onYesButtonClicked(View view) {
+            final boolean accEn = AccessibilityManager.getInstance(getActivity()).isEnabled();
+            if (accEn && !mPasswordRequired) {
+                setRequirePasswordState(false); // clear the UI state
+                AccessibilityWarningDialogFragment.newInstance(mRequestedPasswordQuality)
+                        .show(
+                                getChildFragmentManager(),
+                                AccessibilityWarningDialogFragment.TAG);
             } else {
-                setRequirePasswordState(false);
+                setRequirePasswordState(true);
                 startLockIntent();
             }
         }
 
+        private void onNoButtonClicked(View view) {
+            setRequirePasswordState(false);
+            startLockIntent();
+        }
+
         private void setRequirePasswordState(boolean required) {
             mPasswordRequired = required;
         }
diff --git a/src/com/android/settings/MasterClear.java b/src/com/android/settings/MasterClear.java
index 61a247d..e4ce6443 100644
--- a/src/com/android/settings/MasterClear.java
+++ b/src/com/android/settings/MasterClear.java
@@ -419,12 +419,12 @@
         final TemplateLayout layout = mContentView.findViewById(R.id.setup_wizard_layout);
         final ButtonFooterMixin buttonFooterMixin = layout.getMixin(ButtonFooterMixin.class);
         buttonFooterMixin.setPrimaryButton(
-                new FooterButton(
-                        getActivity(),
-                        R.string.master_clear_button_text,
-                        mInitiateListener,
-                        ButtonType.OTHER,
-                        R.style.SuwGlifButton_Primary)
+                new FooterButton.Builder(getActivity())
+                        .setText(R.string.master_clear_button_text)
+                        .setListener(mInitiateListener)
+                        .setButtonType(ButtonType.OTHER)
+                        .setTheme(R.style.SuwGlifButton_Primary)
+                        .build()
         );
         mInitiateButton = buttonFooterMixin.getPrimaryButton();
     }
diff --git a/src/com/android/settings/MasterClearConfirm.java b/src/com/android/settings/MasterClearConfirm.java
index b2bf838..0750cb1 100644
--- a/src/com/android/settings/MasterClearConfirm.java
+++ b/src/com/android/settings/MasterClearConfirm.java
@@ -156,12 +156,12 @@
 
         final ButtonFooterMixin buttonFooterMixin = layout.getMixin(ButtonFooterMixin.class);
         buttonFooterMixin.setPrimaryButton(
-                new FooterButton(
-                        getActivity(),
-                        R.string.master_clear_button_text,
-                        mFinalClickListener,
-                        ButtonType.OTHER,
-                        R.style.SuwGlifButton_Primary)
+                new FooterButton.Builder(getActivity())
+                        .setText(R.string.master_clear_button_text)
+                        .setListener(mFinalClickListener)
+                        .setButtonType(ButtonType.OTHER)
+                        .setTheme(R.style.SuwGlifButton_Primary)
+                        .build()
         );
     }
 
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java b/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
index 8cc7133..ec75266 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
@@ -93,12 +93,12 @@
 
         mButtonFooterMixin = getLayout().getMixin(ButtonFooterMixin.class);
         mButtonFooterMixin.setSecondaryButton(
-                new FooterButton(
-                        this,
-                        R.string.security_settings_face_enroll_enrolling_skip,
-                        this::onSkipButtonClick,
-                        FooterButton.ButtonType.SKIP,
-                        R.style.SuwGlifButton_Secondary)
+                new FooterButton.Builder(this)
+                        .setText(R.string.security_settings_face_enroll_enrolling_skip)
+                        .setListener(this::onSkipButtonClick)
+                        .setButtonType(FooterButton.ButtonType.SKIP)
+                        .setTheme(R.style.SuwGlifButton_Secondary)
+                        .build()
         );
 
         if (!getIntent().getBooleanExtra(BiometricEnrollBase.EXTRA_KEY_REQUIRE_DIVERSITY, true)) {
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollFinish.java b/src/com/android/settings/biometrics/face/FaceEnrollFinish.java
index f0ff523..afd6f55 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollFinish.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollFinish.java
@@ -39,12 +39,12 @@
 
         mButtonFooterMixin = getLayout().getMixin(ButtonFooterMixin.class);
         mButtonFooterMixin.setPrimaryButton(
-                new FooterButton(
-                        this,
-                        R.string.security_settings_face_enroll_done,
-                        this::onNextButtonClick,
-                        FooterButton.ButtonType.NEXT,
-                        R.style.SuwGlifButton_Primary)
+                new FooterButton.Builder(this)
+                        .setText(R.string.security_settings_face_enroll_done)
+                        .setListener(this::onNextButtonClick)
+                        .setButtonType(FooterButton.ButtonType.NEXT)
+                        .setTheme(R.style.SuwGlifButton_Primary)
+                        .build()
         );
     }
 
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
index a90cf5d..9311810 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
@@ -62,21 +62,21 @@
 
         mButtonFooterMixin = getLayout().getMixin(ButtonFooterMixin.class);
         mButtonFooterMixin.setSecondaryButton(
-                new FooterButton(
-                        this,
-                        R.string.security_settings_face_enroll_introduction_cancel,
-                        this::onCancelButtonClick,
-                        FooterButton.ButtonType.SKIP,
-                        R.style.SuwGlifButton_Secondary)
+                new FooterButton.Builder(this)
+                        .setText(R.string.security_settings_face_enroll_introduction_cancel)
+                        .setListener(this::onCancelButtonClick)
+                        .setButtonType(FooterButton.ButtonType.SKIP)
+                        .setTheme(R.style.SuwGlifButton_Secondary)
+                        .build()
         );
 
         mButtonFooterMixin.setPrimaryButton(
-                new FooterButton(
-                        this,
-                        R.string.wizard_next,
-                        this::onNextButtonClick,
-                        FooterButton.ButtonType.NEXT,
-                        R.style.SuwGlifButton_Primary)
+                new FooterButton.Builder(this)
+                        .setText(R.string.wizard_next)
+                        .setListener(this::onNextButtonClick)
+                        .setButtonType(FooterButton.ButtonType.NEXT)
+                        .setTheme(R.style.SuwGlifButton_Primary)
+                        .build()
         );
     }
 
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
index 5953c10..88e1c6a 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@@ -139,12 +139,12 @@
 
         mButtonFooterMixin = getLayout().getMixin(ButtonFooterMixin.class);
         mButtonFooterMixin.setSecondaryButton(
-                new FooterButton(
-                        this,
-                        R.string.security_settings_fingerprint_enroll_enrolling_skip,
-                        this::onSkipButtonClick,
-                        FooterButton.ButtonType.SKIP,
-                        R.style.SuwGlifButton_Secondary)
+                new FooterButton.Builder(this)
+                        .setText(R.string.security_settings_fingerprint_enroll_enrolling_skip)
+                        .setListener(this::onSkipButtonClick)
+                        .setButtonType(FooterButton.ButtonType.SKIP)
+                        .setTheme(R.style.SuwGlifButton_Secondary)
+                        .build()
         );
 
         final LayerDrawable fingerprintDrawable = (LayerDrawable) mProgressBar.getBackground();
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
index b8a0f40..1b97d19 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
@@ -49,12 +49,12 @@
         setContentView(getContentView());
         mButtonFooterMixin = getLayout().getMixin(ButtonFooterMixin.class);
         mButtonFooterMixin.setSecondaryButton(
-                new FooterButton(
-                        this,
-                        R.string.skip_label,
-                        this::onSkipButtonClick,
-                        FooterButton.ButtonType.SKIP,
-                        R.style.SuwGlifButton_Secondary)
+                new FooterButton.Builder(this)
+                        .setText(R.string.skip_label)
+                        .setListener(this::onSkipButtonClick)
+                        .setButtonType(FooterButton.ButtonType.SKIP)
+                        .setTheme(R.style.SuwGlifButton_Secondary)
+                        .build()
         );
 
         setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title);
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java
index 76f1d1f..db7d92e 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java
@@ -44,21 +44,20 @@
 
         mButtonFooterMixin = getLayout().getMixin(ButtonFooterMixin.class);
         mButtonFooterMixin.setSecondaryButton(
-                new FooterButton(
-                        this,
-                        R.string.fingerprint_enroll_button_add,
-                        null,
-                        FooterButton.ButtonType.SKIP,
-                        R.style.SuwGlifButton_Secondary)
+                new FooterButton.Builder(this)
+                        .setText(R.string.fingerprint_enroll_button_add)
+                        .setButtonType(FooterButton.ButtonType.SKIP)
+                        .setTheme(R.style.SuwGlifButton_Secondary)
+                        .build()
         );
 
         mButtonFooterMixin.setPrimaryButton(
-                new FooterButton(
-                        this,
-                        R.string.security_settings_fingerprint_enroll_done,
-                        this::onNextButtonClick,
-                        FooterButton.ButtonType.NEXT,
-                        R.style.SuwGlifButton_Primary)
+                new FooterButton.Builder(this)
+                        .setText(R.string.security_settings_fingerprint_enroll_done)
+                        .setListener(this::onNextButtonClick)
+                        .setButtonType(FooterButton.ButtonType.NEXT)
+                        .setTheme(R.style.SuwGlifButton_Primary)
+                        .build()
         );
     }
 
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
index 4eca87d..1ad11e3 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
@@ -49,21 +49,21 @@
 
         mButtonFooterMixin = getLayout().getMixin(ButtonFooterMixin.class);
         mButtonFooterMixin.setSecondaryButton(
-                new FooterButton(
-                        this,
-                        R.string.security_settings_face_enroll_introduction_cancel,
-                        this::onCancelButtonClick,
-                        FooterButton.ButtonType.SKIP,
-                        R.style.SuwGlifButton_Secondary)
+                new FooterButton.Builder(this)
+                        .setText(R.string.security_settings_face_enroll_introduction_cancel)
+                        .setListener(this::onCancelButtonClick)
+                        .setButtonType(FooterButton.ButtonType.SKIP)
+                        .setTheme(R.style.SuwGlifButton_Secondary)
+                        .build()
         );
 
         mButtonFooterMixin.setPrimaryButton(
-                new FooterButton(
-                        this,
-                        R.string.wizard_next,
-                        this::onNextButtonClick,
-                        FooterButton.ButtonType.NEXT,
-                        R.style.SuwGlifButton_Primary)
+                new FooterButton.Builder(this)
+                        .setText(R.string.wizard_next)
+                        .setListener(this::onNextButtonClick)
+                        .setButtonType(FooterButton.ButtonType.NEXT)
+                        .setTheme(R.style.SuwGlifButton_Primary)
+                        .build()
         );
     }
 
diff --git a/src/com/android/settings/datausage/AppDataUsageActivity.java b/src/com/android/settings/datausage/AppDataUsageActivity.java
index 2b8e42d..82a3a45 100644
--- a/src/com/android/settings/datausage/AppDataUsageActivity.java
+++ b/src/com/android/settings/datausage/AppDataUsageActivity.java
@@ -62,7 +62,7 @@
         args.putParcelable(AppDataUsage.ARG_APP_ITEM, appItem);
         intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
         intent.putExtra(EXTRA_SHOW_FRAGMENT, AppDataUsage.class.getName());
-        intent.putExtra(EXTRA_SHOW_FRAGMENT_TITLE_RESID, R.string.app_data_usage);
+        intent.putExtra(EXTRA_SHOW_FRAGMENT_TITLE_RESID, R.string.data_usage_app_summary_title);
 
         super.onCreate(savedInstanceState);
     }
diff --git a/src/com/android/settings/datausage/DataUsageList.java b/src/com/android/settings/datausage/DataUsageList.java
index 326b0d4..3369e5e 100644
--- a/src/com/android/settings/datausage/DataUsageList.java
+++ b/src/com/android/settings/datausage/DataUsageList.java
@@ -419,7 +419,7 @@
 
         new SubSettingLauncher(getContext())
                 .setDestination(AppDataUsage.class.getName())
-                .setTitleRes(R.string.app_data_usage)
+                .setTitleRes(R.string.data_usage_app_summary_title)
                 .setArguments(args)
                 .setSourceMetricsCategory(getMetricsCategory())
                 .launch();
diff --git a/src/com/android/settings/datausage/UnrestrictedDataAccessPreference.java b/src/com/android/settings/datausage/UnrestrictedDataAccessPreference.java
index 824c102..97ed5ac 100644
--- a/src/com/android/settings/datausage/UnrestrictedDataAccessPreference.java
+++ b/src/com/android/settings/datausage/UnrestrictedDataAccessPreference.java
@@ -82,7 +82,7 @@
         if (mDataUsageState.isDataSaverBlacklisted) {
             // app is blacklisted, launch App Data Usage screen
             AppInfoDashboardFragment.startAppInfoFragment(AppDataUsage.class,
-                    R.string.app_data_usage,
+                    R.string.data_usage_app_summary_title,
                     null /* arguments */,
                     mParentFragment,
                     mEntry);
diff --git a/src/com/android/settings/deviceinfo/StorageWizardBase.java b/src/com/android/settings/deviceinfo/StorageWizardBase.java
index 9950d3f..4d6ded1 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardBase.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardBase.java
@@ -96,20 +96,20 @@
 
         mButtonFooterMixin = getGlifLayout().getMixin(ButtonFooterMixin.class);
         mButtonFooterMixin.setSecondaryButton(
-                new FooterButton(
-                        this,
-                        R.string.wizard_back,
-                        this::onNavigateBack,
-                        FooterButton.ButtonType.OTHER,
-                        R.style.SuwGlifButton_Secondary)
+                new FooterButton.Builder(this)
+                        .setText(R.string.wizard_back)
+                        .setListener(this::onNavigateBack)
+                        .setButtonType(FooterButton.ButtonType.OTHER)
+                        .setTheme(R.style.SuwGlifButton_Secondary)
+                        .build()
         );
         mButtonFooterMixin.setPrimaryButton(
-                new FooterButton(
-                        this,
-                        R.string.wizard_next,
-                        this::onNavigateNext,
-                        FooterButton.ButtonType.NEXT,
-                        R.style.SuwGlifButton_Primary)
+                new FooterButton.Builder(this)
+                        .setText(R.string.wizard_next)
+                        .setListener(this::onNavigateNext)
+                        .setButtonType(FooterButton.ButtonType.NEXT)
+                        .setTheme(R.style.SuwGlifButton_Primary)
+                        .build()
         );
         mBack = mButtonFooterMixin.getSecondaryButton();
         mNext = mButtonFooterMixin.getPrimaryButton();
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionPreferenceController.java b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionPreferenceController.java
index 7d12d43..b7b67b7 100644
--- a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionPreferenceController.java
@@ -23,9 +23,12 @@
 import androidx.fragment.app.Fragment;
 import androidx.preference.Preference;
 
+import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
+import com.android.settings.slices.Copyable;
 
-public class FirmwareVersionPreferenceController extends BasePreferenceController {
+public class FirmwareVersionPreferenceController extends BasePreferenceController implements
+        Copyable {
 
     private Fragment mFragment;
 
@@ -61,4 +64,10 @@
     public boolean isSliceable() {
         return true;
     }
+
+    @Override
+    public void copy() {
+        Copyable.setCopyContent(mContext, getSummary(),
+                mContext.getText(R.string.firmware_version));
+    }
 }
diff --git a/src/com/android/settings/gestures/WakeLockScreenGesturePreferenceController.java b/src/com/android/settings/gestures/WakeLockScreenGesturePreferenceController.java
index 1f1630e..2b61ec8 100644
--- a/src/com/android/settings/gestures/WakeLockScreenGesturePreferenceController.java
+++ b/src/com/android/settings/gestures/WakeLockScreenGesturePreferenceController.java
@@ -53,7 +53,7 @@
     @Override
     public int getAvailabilityStatus() {
         // No hardware support for this Gesture
-        if (!getAmbientConfig().wakeLockScreenGestureAvailable()) {
+        if (!getAmbientConfig().wakeScreenGestureAvailable()) {
             return UNSUPPORTED_ON_DEVICE;
         }
 
diff --git a/src/com/android/settings/location/TopLevelLocationPreferenceController.java b/src/com/android/settings/location/TopLevelLocationPreferenceController.java
index d0bd9a9..455af21 100644
--- a/src/com/android/settings/location/TopLevelLocationPreferenceController.java
+++ b/src/com/android/settings/location/TopLevelLocationPreferenceController.java
@@ -1,6 +1,5 @@
 package com.android.settings.location;
 
-import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
 import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
 
@@ -11,6 +10,7 @@
 import android.location.LocationManager;
 import android.permission.RuntimePermissionPresenter;
 
+import androidx.annotation.VisibleForTesting;
 import androidx.preference.Preference;
 
 import com.android.settings.R;
@@ -20,7 +20,6 @@
 import com.android.settingslib.core.lifecycle.events.OnStop;
 
 import java.util.Arrays;
-import java.util.Collections;
 
 public class TopLevelLocationPreferenceController extends BasePreferenceController implements
         LifecycleObserver, OnStart, OnStop {
@@ -56,6 +55,12 @@
         }
     }
 
+    @VisibleForTesting
+    void setLocationAppCount(int numApps) {
+        mNumTotal = numApps;
+        refreshSummary(mPreference);
+    }
+
     @Override
     public void updateState(Preference preference) {
         super.updateState(preference);
@@ -68,8 +73,7 @@
         RuntimePermissionPresenter.getInstance(mContext).countPermissionApps(
                 Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION), false, false,
                 (numApps) -> {
-                    mNumTotal = numApps;
-                    refreshSummary(preference);
+                    setLocationAppCount(numApps);
                 }, null);
     }
 
diff --git a/src/com/android/settings/network/ApnSettings.java b/src/com/android/settings/network/ApnSettings.java
index 2b47c70..ac3b1f6 100755
--- a/src/com/android/settings/network/ApnSettings.java
+++ b/src/com/android/settings/network/ApnSettings.java
@@ -61,7 +61,8 @@
 
 import java.util.ArrayList;
 
-public class ApnSettings extends RestrictedSettingsFragment {
+public class ApnSettings extends RestrictedSettingsFragment
+        implements Preference.OnPreferenceChangeListener {
     static final String TAG = "ApnSettings";
 
     public static final String EXTRA_POSITION = "position";
@@ -313,6 +314,7 @@
                 pref.setKey(key);
                 pref.setTitle(name);
                 pref.setPersistent(false);
+                pref.setOnPreferenceChangeListener(this);
                 pref.setSubId(subId);
                 if (mHidePresetApnDetails && edited == Telephony.Carriers.UNEDITED) {
                     pref.setHideDetails();
@@ -386,6 +388,7 @@
         startActivity(intent);
     }
 
+    @Override
     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/EnabledNetworkModePreferenceController.java b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java
index b323f91..d2ec162 100644
--- a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java
+++ b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java
@@ -126,7 +126,6 @@
 
     private void updatePreferenceEntries(ListPreference preference) {
         final int phoneType = mTelephonyManager.getPhoneType();
-        final Resources resources = mContext.getResources();
         final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId);
         if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
             final int lteForced = android.provider.Settings.Global.getInt(
@@ -216,6 +215,7 @@
     }
 
     private void updatePreferenceValueAndSummary(ListPreference preference, int networkMode) {
+        preference.setValue(Integer.toString(networkMode));
         switch (networkMode) {
             case TelephonyManager.NETWORK_MODE_TDSCDMA_WCDMA:
             case TelephonyManager.NETWORK_MODE_TDSCDMA_GSM_WCDMA:
diff --git a/src/com/android/settings/notification/AbstractZenCustomRulePreferenceController.java b/src/com/android/settings/notification/AbstractZenCustomRulePreferenceController.java
new file mode 100644
index 0000000..409eec6
--- /dev/null
+++ b/src/com/android/settings/notification/AbstractZenCustomRulePreferenceController.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.notification;
+
+import android.app.AutomaticZenRule;
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.preference.Preference;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+abstract class AbstractZenCustomRulePreferenceController extends
+        AbstractZenModePreferenceController implements PreferenceControllerMixin {
+
+    String mId;
+    AutomaticZenRule mRule;
+
+    AbstractZenCustomRulePreferenceController(Context context, String key,
+            Lifecycle lifecycle) {
+        super(context, key, lifecycle);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        if (mId != null) {
+            mRule = mBackend.getAutomaticZenRule(mId);
+        }
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return mRule != null;
+    }
+
+    public void onResume(AutomaticZenRule rule, String id) {
+        mId = id;
+        mRule = rule;
+    }
+
+    Bundle createBundle() {
+        Bundle bundle = new Bundle();
+        bundle.putString(ZenCustomRuleSettings.RULE_ID, mId);
+        return bundle;
+    }
+}
diff --git a/src/com/android/settings/notification/AbstractZenModePreferenceController.java b/src/com/android/settings/notification/AbstractZenModePreferenceController.java
index 383934a..0e45e58 100644
--- a/src/com/android/settings/notification/AbstractZenModePreferenceController.java
+++ b/src/com/android/settings/notification/AbstractZenModePreferenceController.java
@@ -50,7 +50,7 @@
     @VisibleForTesting
     protected SettingObserver mSettingObserver;
 
-    private final String KEY;
+    final String KEY;
     final private NotificationManager mNotificationManager;
     protected static ZenModeConfigWrapper mZenModeConfigWrapper;
     protected MetricsFeatureProvider mMetricsFeatureProvider;
diff --git a/src/com/android/settings/notification/RedactionInterstitial.java b/src/com/android/settings/notification/RedactionInterstitial.java
index 32dc52d..b2f2d25 100644
--- a/src/com/android/settings/notification/RedactionInterstitial.java
+++ b/src/com/android/settings/notification/RedactionInterstitial.java
@@ -32,7 +32,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.Button;
 import android.widget.LinearLayout;
 import android.widget.RadioButton;
 import android.widget.RadioGroup;
@@ -46,9 +45,12 @@
 import com.android.settings.SetupRedactionInterstitial;
 import com.android.settings.SetupWizardUtils;
 import com.android.settings.Utils;
-import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 
+import com.google.android.setupcompat.item.FooterButton;
+import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupdesign.GlifLayout;
+
 public class RedactionInterstitial extends SettingsActivity {
 
     @Override
@@ -91,7 +93,7 @@
     }
 
     public static class RedactionInterstitialFragment extends SettingsPreferenceFragment
-            implements RadioGroup.OnCheckedChangeListener, View.OnClickListener {
+            implements RadioGroup.OnCheckedChangeListener {
 
         private RadioGroup mRadioGroup;
         private RestrictedRadioButton mShowAllButton;
@@ -130,19 +132,24 @@
                 ((RadioButton) view.findViewById(R.id.hide_all)).setVisibility(View.GONE);
             }
 
-            final Button button = (Button) view.findViewById(R.id.redaction_done_button);
-            button.setOnClickListener(this);
+            final GlifLayout layout = view.findViewById(R.id.setup_wizard_layout);
+            final ButtonFooterMixin buttonFooterMixin = layout.getMixin(ButtonFooterMixin.class);
+            buttonFooterMixin.setPrimaryButton(
+                    new FooterButton.Builder(getContext())
+                            .setText(R.string.app_notifications_dialog_done)
+                            .setListener(this::onDoneButtonClicked)
+                            .setButtonType(FooterButton.ButtonType.NEXT)
+                            .setTheme(R.style.SuwGlifButton_Primary)
+                            .build()
+            );
         }
 
-        @Override
-        public void onClick(View v) {
-            if (v.getId() == R.id.redaction_done_button) {
-                SetupRedactionInterstitial.setEnabled(getContext(), false);
-                final RedactionInterstitial activity = (RedactionInterstitial) getActivity();
-                if (activity != null) {
-                    activity.setResult(RESULT_OK, null);
-                    finish();
-                }
+        private void onDoneButtonClicked(View view) {
+            SetupRedactionInterstitial.setEnabled(getContext(), false);
+            final RedactionInterstitial activity = (RedactionInterstitial) getActivity();
+            if (activity != null) {
+                activity.setResult(RESULT_OK, null);
+                finish();
             }
         }
 
diff --git a/src/com/android/settings/notification/ZenCustomRuleBlockedEffectsSettings.java b/src/com/android/settings/notification/ZenCustomRuleBlockedEffectsSettings.java
new file mode 100644
index 0000000..3f75a20
--- /dev/null
+++ b/src/com/android/settings/notification/ZenCustomRuleBlockedEffectsSettings.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.notification;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.service.notification.ZenPolicy;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ZenCustomRuleBlockedEffectsSettings extends ZenCustomRuleSettingsBase {
+
+    @Override
+    public void onCreate(Bundle bundle) {
+        super.onCreate(bundle);
+        mFooterPreferenceMixin.createFooterPreference().setTitle(
+                R.string.zen_mode_blocked_effects_footer);
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.zen_mode_block_settings;
+    }
+
+    @Override
+    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+        mControllers = new ArrayList<>();
+        mControllers.add(new ZenRuleVisEffectPreferenceController(context, getSettingsLifecycle(),
+                "zen_effect_intent", ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT,
+                MetricsEvent.ACTION_ZEN_BLOCK_FULL_SCREEN_INTENTS, null));
+        mControllers.add(new ZenRuleVisEffectPreferenceController(context, getSettingsLifecycle(),
+                "zen_effect_light", ZenPolicy.VISUAL_EFFECT_LIGHTS,
+                MetricsEvent.ACTION_ZEN_BLOCK_LIGHT, null));
+        mControllers.add(new ZenRuleVisEffectPreferenceController(context, getSettingsLifecycle(),
+                "zen_effect_peek", ZenPolicy.VISUAL_EFFECT_PEEK,
+                MetricsEvent.ACTION_ZEN_BLOCK_PEEK, null));
+        mControllers.add(new ZenRuleVisEffectPreferenceController(context, getSettingsLifecycle(),
+                "zen_effect_status", ZenPolicy.VISUAL_EFFECT_STATUS_BAR,
+                MetricsEvent.ACTION_ZEN_BLOCK_STATUS,
+                new int[] {ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST}));
+        mControllers.add(new ZenRuleVisEffectPreferenceController(context, getSettingsLifecycle(),
+                "zen_effect_badge", ZenPolicy.VISUAL_EFFECT_BADGE,
+                MetricsEvent.ACTION_ZEN_BLOCK_BADGE, null));
+        mControllers.add(new ZenRuleVisEffectPreferenceController(context, getSettingsLifecycle(),
+                "zen_effect_ambient", ZenPolicy.VISUAL_EFFECT_AMBIENT,
+                MetricsEvent.ACTION_ZEN_BLOCK_AMBIENT, null));
+        mControllers.add(new ZenRuleVisEffectPreferenceController(context, getSettingsLifecycle(),
+                "zen_effect_list", ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST,
+                MetricsEvent.ACTION_ZEN_BLOCK_NOTIFICATION_LIST, null));
+        return mControllers;
+    }
+
+    @Override
+    String getPreferenceCategoryKey() {
+        return null;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsEvent.ZEN_CUSTOM_RULE_VIS_EFFECTS;
+    }
+}
diff --git a/src/com/android/settings/notification/ZenCustomRuleCallsSettings.java b/src/com/android/settings/notification/ZenCustomRuleCallsSettings.java
new file mode 100644
index 0000000..808264e
--- /dev/null
+++ b/src/com/android/settings/notification/ZenCustomRuleCallsSettings.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.notification;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.service.notification.ZenPolicy;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.widget.FooterPreference;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ZenCustomRuleCallsSettings extends ZenCustomRuleSettingsBase {
+    private static final String CALLS_KEY = "zen_mode_calls";
+    private static final String REPEAT_CALLERS_KEY = "zen_mode_repeat_callers";
+    private static final String STARRED_CONTACTS_KEY = "zen_mode_starred_contacts_callers";
+    private static final String PREFERENCE_CATEGORY_KEY = "zen_mode_settings_category_calls";
+
+    @Override
+    public void onCreate(Bundle bundle) {
+        super.onCreate(bundle);
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return com.android.settings.R.xml.zen_mode_calls_settings;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsProto.MetricsEvent.ZEN_CUSTOM_RULE_CALLS;
+    }
+
+    @Override
+    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+        mControllers = new ArrayList<>();
+        mControllers.add(new ZenRuleCallsPreferenceController(context, CALLS_KEY,
+                getSettingsLifecycle()));
+        mControllers.add(new ZenRuleRepeatCallersPreferenceController(context,
+                REPEAT_CALLERS_KEY, getSettingsLifecycle(), context.getResources()
+                .getInteger(com.android.internal.R.integer.config_zen_repeat_callers_threshold)));
+        mControllers.add(new ZenRuleStarredContactsPreferenceController(context,
+                getSettingsLifecycle(), ZenPolicy.PRIORITY_CATEGORY_CALLS, STARRED_CONTACTS_KEY));
+        return mControllers;
+    }
+
+    @Override
+    String getPreferenceCategoryKey() {
+        return PREFERENCE_CATEGORY_KEY;
+    }
+
+    @Override
+    public void updatePreferences() {
+        super.updatePreferences();
+        PreferenceScreen screen = getPreferenceScreen();
+        Preference footerPreference = screen.findPreference(FooterPreference.KEY_FOOTER);
+        footerPreference.setTitle(mContext.getResources().getString(
+                R.string.zen_mode_custom_calls_footer, mRule.getName()));
+    }
+}
diff --git a/src/com/android/settings/notification/ZenCustomRuleConfigSettings.java b/src/com/android/settings/notification/ZenCustomRuleConfigSettings.java
new file mode 100644
index 0000000..fd8ce2b
--- /dev/null
+++ b/src/com/android/settings/notification/ZenCustomRuleConfigSettings.java
@@ -0,0 +1,160 @@
+/*
+ * 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.notification;
+
+import android.app.NotificationManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.service.notification.ZenPolicy;
+
+import androidx.preference.Preference;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ZenCustomRuleConfigSettings extends ZenCustomRuleSettingsBase {
+    private static final String CALLS_KEY = "zen_rule_calls_settings";
+    private static final String MESSAGES_KEY = "zen_rule_messages_settings";
+    private static final String ALARMS_KEY = "zen_rule_alarms";
+    private static final String MEDIA_KEY = "zen_rule_media";
+    private static final String SYSTEM_KEY = "zen_rule_system";
+    private static final String REMINDERS_KEY = "zen_rule_reminders";
+    private static final String EVENTS_KEY = "zen_rule_events";
+    private static final String NOTIFICATIONS_KEY = "zen_rule_notifications";
+    private static final String PREFERENCE_CATEGORY_KEY = "zen_custom_rule_configuration_category";
+
+    private Preference mCallsPreference;
+    private Preference mMessagesPreference;
+    private Preference mNotificationsPreference;
+    private ZenModeSettings.SummaryBuilder mSummaryBuilder;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        mSummaryBuilder = new ZenModeSettings.SummaryBuilder(mContext);
+
+        mCallsPreference = getPreferenceScreen().findPreference(CALLS_KEY);
+        mCallsPreference.setOnPreferenceClickListener(
+                new Preference.OnPreferenceClickListener() {
+                    @Override
+                    public boolean onPreferenceClick(Preference preference) {
+                        new SubSettingLauncher(mContext)
+                                .setDestination(ZenCustomRuleCallsSettings.class.getName())
+                                .setArguments(createZenRuleBundle())
+                                .setSourceMetricsCategory(MetricsEvent.ZEN_CUSTOM_RULE_CALLS)
+                                .launch();
+                        return true;
+                    }
+                });
+
+        mMessagesPreference = getPreferenceScreen().findPreference(MESSAGES_KEY);
+        mMessagesPreference.setOnPreferenceClickListener(
+                new Preference.OnPreferenceClickListener() {
+                    @Override
+                    public boolean onPreferenceClick(Preference preference) {
+                        new SubSettingLauncher(mContext)
+                                .setDestination(ZenCustomRuleMessagesSettings.class.getName())
+                                .setArguments(createZenRuleBundle())
+                                .setSourceMetricsCategory(MetricsEvent.ZEN_CUSTOM_RULE_MESSAGES)
+                                .launch();
+                        return true;
+                    }
+                });
+
+        mNotificationsPreference = getPreferenceScreen().findPreference(NOTIFICATIONS_KEY);
+        mNotificationsPreference.setOnPreferenceClickListener(
+                new Preference.OnPreferenceClickListener() {
+                    @Override
+                    public boolean onPreferenceClick(Preference preference) {
+                        new SubSettingLauncher(mContext)
+                                .setDestination(ZenCustomRuleNotificationsSettings.class.getName())
+                                .setArguments(createZenRuleBundle())
+                                .setSourceMetricsCategory
+                                        (MetricsEvent.ZEN_CUSTOM_RULE_NOTIFICATION_RESTRICTIONS)
+                                .launch();
+                        return true;
+                    }
+                });
+
+        updateSummaries();
+    }
+
+    @Override
+    public void onZenModeConfigChanged() {
+        super.onZenModeConfigChanged();
+        updateSummaries();
+    }
+
+    /**
+     * Updates summaries of preferences without preference controllers
+     */
+    private void updateSummaries() {
+        NotificationManager.Policy noManPolicy = mBackend.toNotificationPolicy(
+                mRule.getZenPolicy());
+
+        mCallsPreference.setSummary(mSummaryBuilder.getCallsSettingSummary(noManPolicy));
+        mMessagesPreference.setSummary(mSummaryBuilder.getMessagesSettingSummary(noManPolicy));
+        mNotificationsPreference.setSummary(mSummaryBuilder.getBlockedEffectsSummary(noManPolicy));
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.zen_mode_custom_rule_configuration;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsEvent.ZEN_CUSTOM_RULE_SOUND_SETTINGS;
+    }
+
+    @Override
+    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+        mControllers = new ArrayList<>();
+        mControllers.add(new ZenRuleCustomSwitchPreferenceController(context,
+                getSettingsLifecycle(), ALARMS_KEY, ZenPolicy.PRIORITY_CATEGORY_ALARMS,
+                MetricsEvent.ACTION_ZEN_ALLOW_ALARMS));
+        mControllers.add(new ZenRuleCustomSwitchPreferenceController(context,
+                getSettingsLifecycle(), MEDIA_KEY, ZenPolicy.PRIORITY_CATEGORY_MEDIA,
+                MetricsEvent.ACTION_ZEN_ALLOW_MEDIA));
+        mControllers.add(new ZenRuleCustomSwitchPreferenceController(context,
+                getSettingsLifecycle(), SYSTEM_KEY, ZenPolicy.PRIORITY_CATEGORY_SYSTEM,
+                MetricsEvent.ACTION_ZEN_ALLOW_SYSTEM));
+        mControllers.add(new ZenRuleCustomSwitchPreferenceController(context,
+                getSettingsLifecycle(), REMINDERS_KEY, ZenPolicy.PRIORITY_CATEGORY_REMINDERS,
+                MetricsEvent.ACTION_ZEN_ALLOW_REMINDERS));
+        mControllers.add(new ZenRuleCustomSwitchPreferenceController(context,
+                getSettingsLifecycle(), EVENTS_KEY, ZenPolicy.PRIORITY_CATEGORY_EVENTS,
+                MetricsEvent.ACTION_ZEN_ALLOW_EVENTS));
+        return mControllers;
+    }
+
+    @Override
+    String getPreferenceCategoryKey() {
+        return PREFERENCE_CATEGORY_KEY;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        updateSummaries();
+    }
+}
diff --git a/src/com/android/settings/notification/ZenCustomRuleMessagesSettings.java b/src/com/android/settings/notification/ZenCustomRuleMessagesSettings.java
new file mode 100644
index 0000000..8db2824
--- /dev/null
+++ b/src/com/android/settings/notification/ZenCustomRuleMessagesSettings.java
@@ -0,0 +1,72 @@
+/*
+ * 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.notification;
+
+import android.content.Context;
+import android.service.notification.ZenPolicy;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.widget.FooterPreference;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ZenCustomRuleMessagesSettings extends ZenCustomRuleSettingsBase {
+    private static final String MESSAGES_KEY = "zen_mode_messages";
+    private static final String STARRED_CONTACTS_KEY = "zen_mode_starred_contacts_messages";
+    private static final String PREFERENCE_CATEGORY_KEY = "zen_mode_settings_category_messages";
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return com.android.settings.R.xml.zen_mode_messages_settings;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsProto.MetricsEvent.ZEN_CUSTOM_RULE_MESSAGES;
+    }
+
+    @Override
+    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+        mControllers = new ArrayList<>();
+        mControllers.add(new ZenRuleMessagesPreferenceController(context, MESSAGES_KEY,
+                getSettingsLifecycle()));
+        mControllers.add(new ZenRuleStarredContactsPreferenceController(context,
+                getSettingsLifecycle(), ZenPolicy.PRIORITY_CATEGORY_MESSAGES,
+                STARRED_CONTACTS_KEY));
+        return mControllers;
+    }
+
+    @Override
+    String getPreferenceCategoryKey() {
+        return PREFERENCE_CATEGORY_KEY;
+    }
+
+    @Override
+    public void updatePreferences() {
+        super.updatePreferences();
+        PreferenceScreen screen = getPreferenceScreen();
+        Preference footerPreference = screen.findPreference(FooterPreference.KEY_FOOTER);
+        footerPreference.setTitle(mContext.getResources().getString(
+                R.string.zen_mode_custom_messages_footer, mRule.getName()));
+    }
+}
diff --git a/src/com/android/settings/notification/ZenCustomRuleNotificationsSettings.java b/src/com/android/settings/notification/ZenCustomRuleNotificationsSettings.java
new file mode 100644
index 0000000..a23bc6d
--- /dev/null
+++ b/src/com/android/settings/notification/ZenCustomRuleNotificationsSettings.java
@@ -0,0 +1,63 @@
+/*
+ * 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.notification;
+
+import android.content.Context;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.widget.FooterPreference;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ZenCustomRuleNotificationsSettings extends ZenCustomRuleSettingsBase {
+    private static final String VIS_EFFECTS_ALL_KEY = "zen_mute_notifications";
+    private static final String VIS_EFFECTS_NONE_KEY = "zen_hide_notifications";
+    private static final String VIS_EFFECTS_CUSTOM_KEY = "zen_custom";
+    private static final String PREFERENCE_CATEGORY_KEY = "restrict_category";
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.zen_mode_restrict_notifications_settings;
+    }
+
+    @Override
+    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+        mControllers = new ArrayList<>();
+        mControllers.add(new ZenRuleVisEffectsAllPreferenceController(
+                context, getSettingsLifecycle(), VIS_EFFECTS_ALL_KEY));
+        mControllers.add(new ZenRuleVisEffectsNonePreferenceController(
+                context, getSettingsLifecycle(), VIS_EFFECTS_NONE_KEY));
+        mControllers.add(new ZenRuleVisEffectsCustomPreferenceController(
+                context, getSettingsLifecycle(), VIS_EFFECTS_CUSTOM_KEY));
+        mControllers.add(new ZenRuleNotifFooterPreferenceController(context, getSettingsLifecycle(),
+                FooterPreference.KEY_FOOTER));
+        return mControllers;
+    }
+
+    @Override
+    String getPreferenceCategoryKey() {
+        return PREFERENCE_CATEGORY_KEY;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsProto.MetricsEvent.ZEN_CUSTOM_RULE_NOTIFICATION_RESTRICTIONS;
+    }
+}
diff --git a/src/com/android/settings/notification/ZenCustomRuleSettings.java b/src/com/android/settings/notification/ZenCustomRuleSettings.java
new file mode 100644
index 0000000..ebd6306
--- /dev/null
+++ b/src/com/android/settings/notification/ZenCustomRuleSettings.java
@@ -0,0 +1,57 @@
+/*
+ * 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.notification;
+
+import android.content.Context;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ZenCustomRuleSettings extends ZenCustomRuleSettingsBase {
+    private static final String RULE_DEFAULT_POLICY_KEY = "zen_custom_rule_setting_default";
+    private static final String CUSTOM_RULE_POLICY_KEY = "zen_custom_rule_setting";
+    private static final String PREFERENCE_CATEGORY_KEY = "zen_custom_rule_category";
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.zen_mode_custom_rule_settings;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsProto.MetricsEvent.ZEN_CUSTOM_RULE_SETTINGS;
+    }
+
+    @Override
+    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+        mControllers = new ArrayList<>();
+        mControllers.add(new ZenRuleDefaultPolicyPreferenceController(
+                context, getSettingsLifecycle(), RULE_DEFAULT_POLICY_KEY));
+        mControllers.add(new ZenRuleCustomPolicyPreferenceController(
+                context, getSettingsLifecycle(), CUSTOM_RULE_POLICY_KEY));
+        return mControllers;
+    }
+
+    @Override
+    String getPreferenceCategoryKey() {
+        return PREFERENCE_CATEGORY_KEY;
+    }
+}
diff --git a/src/com/android/settings/notification/ZenCustomRuleSettingsBase.java b/src/com/android/settings/notification/ZenCustomRuleSettingsBase.java
new file mode 100644
index 0000000..94b0b7b
--- /dev/null
+++ b/src/com/android/settings/notification/ZenCustomRuleSettingsBase.java
@@ -0,0 +1,103 @@
+/*
+ * 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.notification;
+
+import android.app.AutomaticZenRule;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+abstract class ZenCustomRuleSettingsBase extends ZenModeSettingsBase {
+    static final String TAG = "ZenCustomRuleSettings";
+    static final String RULE_ID = "RULE_ID";
+
+    String mId;
+    AutomaticZenRule mRule;
+    List<AbstractPreferenceController> mControllers = new ArrayList<>();
+
+    /**
+     * @return null if no preference category exists
+      */
+    abstract String getPreferenceCategoryKey();
+
+    @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+        Bundle bundle = getArguments();
+        if (bundle != null && bundle.containsKey(RULE_ID)) {
+            mId = bundle.getString(RULE_ID);
+            mRule = mBackend.getAutomaticZenRule(mId);
+        } else {
+            Log.d(TAG, "Rule id required to set custom dnd rule config settings");
+            this.finish();
+        }
+    }
+
+    @Override
+    public void onZenModeConfigChanged() {
+        super.onZenModeConfigChanged();
+        updatePreferences();
+    }
+
+    public void updatePreferences() {
+        mRule = mBackend.getAutomaticZenRule(mId);
+        final PreferenceScreen screen = getPreferenceScreen();
+        String categoryKey = getPreferenceCategoryKey();
+        if (categoryKey != null) {
+            Preference prefCategory = screen.findPreference(categoryKey);
+            if (prefCategory != null) {
+                prefCategory.setTitle(mContext.getResources().getString(
+                        com.android.settings.R.string.zen_mode_custom_behavior_category_title,
+                        mRule.getName()));
+            }
+        }
+
+        for (AbstractPreferenceController controller : mControllers) {
+            AbstractZenCustomRulePreferenceController zenRuleController =
+                    (AbstractZenCustomRulePreferenceController) controller;
+            zenRuleController.onResume(mRule, mId);
+            zenRuleController.displayPreference(screen);
+            updatePreference(zenRuleController);
+        }
+    }
+
+    @Override
+    public int getHelpResource() {
+        return R.string.help_uri_interruptions;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        updatePreferences();
+    }
+
+    Bundle createZenRuleBundle() {
+        Bundle bundle = new Bundle();
+        bundle.putString(RULE_ID, mId);
+        return bundle;
+    }
+}
diff --git a/src/com/android/settings/notification/ZenModeBackend.java b/src/com/android/settings/notification/ZenModeBackend.java
index a75f51c..4c9cebe 100644
--- a/src/com/android/settings/notification/ZenModeBackend.java
+++ b/src/com/android/settings/notification/ZenModeBackend.java
@@ -23,15 +23,20 @@
 import android.app.AutomaticZenRule;
 import android.app.NotificationManager;
 import android.content.Context;
+import android.database.Cursor;
+import android.icu.text.ListFormatter;
 import android.net.Uri;
+import android.provider.ContactsContract;
 import android.provider.Settings;
 import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenPolicy;
 import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 
 import com.android.settings.R;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.List;
@@ -116,7 +121,7 @@
         return (mPolicy.priorityCategories & categoryType) != 0;
     }
 
-    protected int getNewPriorityCategories(boolean allow, int categoryType) {
+    protected int getNewDefaultPriorityCategories(boolean allow, int categoryType) {
         int priorityCategories = mPolicy.priorityCategories;
         if (allow) {
             priorityCategories |= categoryType;
@@ -135,7 +140,8 @@
     }
 
     protected int getPriorityMessageSenders() {
-        if (isPriorityCategoryEnabled(NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES)) {
+        if (isPriorityCategoryEnabled(
+                NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES)) {
             return mPolicy.priorityMessageSenders;
         }
         return SOURCE_NONE;
@@ -151,7 +157,7 @@
     }
 
     protected void saveSoundPolicy(int category, boolean allow) {
-        int priorityCategories = getNewPriorityCategories(allow, category);
+        int priorityCategories = getNewDefaultPriorityCategories(allow, category);
         savePolicy(priorityCategories, mPolicy.priorityCallSenders,
                 mPolicy.priorityMessageSenders, mPolicy.suppressedVisualEffects);
     }
@@ -163,6 +169,7 @@
         mNotificationManager.setNotificationPolicy(mPolicy);
     }
 
+
     private int getNewSuppressedEffects(boolean suppress, int effectType) {
         int effects = mPolicy.suppressedVisualEffects;
 
@@ -202,7 +209,7 @@
             priorityMessagesSenders = allowSendersFrom;
         }
 
-        savePolicy(getNewPriorityCategories(allowSenders, category),
+        savePolicy(getNewDefaultPriorityCategories(allowSenders, category),
             priorityCallSenders, priorityMessagesSenders, mPolicy.suppressedVisualEffects);
 
         if (ZenModeSettingsBase.DEBUG) Log.d(TAG, "onPrefChange allow" +
@@ -236,6 +243,20 @@
         return categorySenders;
     }
 
+    protected static String getKeyFromZenPolicySetting(int contactType) {
+        switch (contactType) {
+            case ZenPolicy.PEOPLE_TYPE_ANYONE:
+                return ZEN_MODE_FROM_ANYONE;
+            case  ZenPolicy.PEOPLE_TYPE_CONTACTS:
+                return ZEN_MODE_FROM_CONTACTS;
+            case ZenPolicy.PEOPLE_TYPE_STARRED:
+                return ZEN_MODE_FROM_STARRED;
+            case ZenPolicy.PEOPLE_TYPE_NONE:
+            default:
+                return ZEN_MODE_FROM_NONE;
+        }
+    }
+
     protected static String getKeyFromSetting(int contactType) {
         switch (contactType) {
             case NotificationManager.Policy.PRIORITY_SENDERS_ANY:
@@ -288,6 +309,50 @@
         }
     }
 
+    protected int getContactsCallsSummary(ZenPolicy policy) {
+        int peopleType = policy.getPriorityCallSenders();
+        switch (peopleType) {
+            case ZenPolicy.PEOPLE_TYPE_ANYONE:
+                return R.string.zen_mode_from_anyone;
+            case ZenPolicy.PEOPLE_TYPE_CONTACTS:
+                return R.string.zen_mode_from_contacts;
+            case ZenPolicy.PEOPLE_TYPE_STARRED:
+                return R.string.zen_mode_from_starred;
+            case ZenPolicy.PEOPLE_TYPE_NONE:
+            default:
+                return R.string.zen_mode_from_none_calls;
+        }
+    }
+
+    protected int getContactsMessagesSummary(ZenPolicy policy) {
+        int peopleType = policy.getPriorityMessageSenders();
+        switch (peopleType) {
+            case ZenPolicy.PEOPLE_TYPE_ANYONE:
+                return R.string.zen_mode_from_anyone;
+            case ZenPolicy.PEOPLE_TYPE_CONTACTS:
+                return R.string.zen_mode_from_contacts;
+            case ZenPolicy.PEOPLE_TYPE_STARRED:
+                return R.string.zen_mode_from_starred;
+            case ZenPolicy.PEOPLE_TYPE_NONE:
+            default:
+                return R.string.zen_mode_from_none_messages;
+        }
+    }
+
+    protected static int getZenPolicySettingFromPrefKey(String key) {
+        switch (key) {
+            case ZEN_MODE_FROM_ANYONE:
+                return ZenPolicy.PEOPLE_TYPE_ANYONE;
+            case ZEN_MODE_FROM_CONTACTS:
+                return ZenPolicy.PEOPLE_TYPE_CONTACTS;
+            case ZEN_MODE_FROM_STARRED:
+                return ZenPolicy.PEOPLE_TYPE_STARRED;
+            case ZEN_MODE_FROM_NONE:
+            default:
+                return ZenPolicy.PEOPLE_TYPE_NONE;
+        }
+    }
+
     protected static int getSettingFromPrefKey(String key) {
         switch (key) {
             case ZEN_MODE_FROM_ANYONE:
@@ -318,6 +383,40 @@
         }
     }
 
+    ZenPolicy setDefaultZenPolicy(ZenPolicy zenPolicy) {
+        int calls;
+        if (mPolicy.allowCalls()) {
+            calls = ZenModeConfig.getZenPolicySenders(mPolicy.allowCallsFrom());
+        } else {
+            calls = ZenPolicy.PEOPLE_TYPE_NONE;
+        }
+
+        int messages;
+        if (mPolicy.allowMessages()) {
+            messages = ZenModeConfig.getZenPolicySenders(mPolicy.allowMessagesFrom());
+        } else {
+            messages = ZenPolicy.PEOPLE_TYPE_NONE;
+        }
+
+        return new ZenPolicy.Builder(zenPolicy)
+                .allowAlarms(mPolicy.allowAlarms())
+                .allowCalls(calls)
+                .allowEvents(mPolicy.allowEvents())
+                .allowMedia(mPolicy.allowMedia())
+                .allowMessages(messages)
+                .allowReminders(mPolicy.allowReminders())
+                .allowRepeatCallers(mPolicy.allowRepeatCallers())
+                .allowSystem(mPolicy.allowSystem())
+                .showFullScreenIntent(mPolicy.showFullScreenIntents())
+                .showLights(mPolicy.showLights())
+                .showInAmbientDisplay(mPolicy.showAmbient())
+                .showInNotificationList(mPolicy.showInNotificationList())
+                .showBadges(mPolicy.showBadges())
+                .showPeeking(mPolicy.showPeeking())
+                .showStatusBarIcons(mPolicy.showStatusBarIcons())
+                .build();
+    }
+
     protected Map.Entry<String, AutomaticZenRule>[] getAutomaticZenRules() {
         Map<String, AutomaticZenRule> ruleMap =
                 NotificationManager.from(mContext).getAutomaticZenRules();
@@ -338,6 +437,70 @@
         return mDefaultRuleIds;
     }
 
+    NotificationManager.Policy toNotificationPolicy(ZenPolicy policy) {
+        ZenModeConfig config = new ZenModeConfig();
+        return config.toNotificationPolicy(policy);
+    }
+
+    @VisibleForTesting
+    List<String> getStarredContacts(Cursor cursor) {
+        List<String> starredContacts = new ArrayList<>();
+        if (cursor != null && cursor.moveToFirst()) {
+            do {
+                String contact = cursor.getString(0);
+                if (contact != null) {
+                    starredContacts.add(contact);
+                }
+            } while (cursor.moveToNext());
+        }
+        return starredContacts;
+    }
+
+    private List<String> getStarredContacts() {
+        Cursor cursor = null;
+        try {
+            cursor = queryData();
+            return getStarredContacts(cursor);
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+    }
+
+    public String getStarredContactsSummary() {
+        List<String> starredContacts = getStarredContacts();
+        int numStarredContacts = starredContacts.size();
+
+        List<String> displayContacts = new ArrayList<>();
+
+        if (numStarredContacts == 0) {
+            displayContacts.add(mContext.getString(R.string.zen_mode_from_none));
+        } else {
+            for (int i = 0; i < 2 && i < numStarredContacts; i++) {
+                displayContacts.add(starredContacts.get(i));
+            }
+
+            if (numStarredContacts == 3) {
+                displayContacts.add(starredContacts.get(2));
+            } else if (numStarredContacts > 2) {
+                displayContacts.add(mContext.getResources().getQuantityString(
+                        R.plurals.zen_mode_starred_contacts_summary_additional_contacts,
+                        numStarredContacts - 2, numStarredContacts - 2));
+            }
+        }
+
+        // values in displayContacts must not be null
+        return ListFormatter.getInstance().format(displayContacts);
+    }
+
+    private Cursor queryData() {
+        return mContext.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,
+                new String[]{ContactsContract.Contacts.DISPLAY_NAME_PRIMARY},
+                ContactsContract.Data.STARRED + "=1", null,
+                ContactsContract.Data.TIMES_CONTACTED);
+    }
+
     @VisibleForTesting
     public static final Comparator<Map.Entry<String, AutomaticZenRule>> RULE_COMPARATOR =
             new Comparator<Map.Entry<String, AutomaticZenRule>>() {
diff --git a/src/com/android/settings/notification/ZenModeRuleSettingsBase.java b/src/com/android/settings/notification/ZenModeRuleSettingsBase.java
index e573884..46162a8 100644
--- a/src/com/android/settings/notification/ZenModeRuleSettingsBase.java
+++ b/src/com/android/settings/notification/ZenModeRuleSettingsBase.java
@@ -30,13 +30,15 @@
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.R;
-import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settings.core.SubSettingLauncher;
 
 public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase {
 
     protected static final String TAG = ZenModeSettingsBase.TAG;
     protected static final boolean DEBUG = ZenModeSettingsBase.DEBUG;
 
+    private final String CUSTOM_BEHAVIOR_KEY = "zen_custom_setting";
+
     protected Context mContext;
     protected boolean mDisableListeners;
     protected AutomaticZenRule mRule;
@@ -45,6 +47,7 @@
     protected ZenAutomaticRuleHeaderPreferenceController mHeader;
     protected ZenRuleButtonsPreferenceController mActionButtons;
     protected ZenAutomaticRuleSwitchPreferenceController mSwitch;
+    protected Preference mCustomBehaviorPreference;
 
     abstract protected void onCreateInternal();
     abstract protected boolean setRule(AutomaticZenRule rule);
@@ -75,6 +78,21 @@
         }
 
         super.onCreate(icicle);
+        mCustomBehaviorPreference = getPreferenceScreen().findPreference(CUSTOM_BEHAVIOR_KEY);
+        mCustomBehaviorPreference.setOnPreferenceClickListener(
+                new Preference.OnPreferenceClickListener() {
+                    @Override
+                    public boolean onPreferenceClick(Preference preference) {
+                        Bundle bundle = new Bundle();
+                        bundle.putString(ZenCustomRuleSettings.RULE_ID, mId);
+                        new SubSettingLauncher(mContext)
+                                .setDestination(ZenCustomRuleSettings.class.getName())
+                                .setArguments(bundle)
+                                .setSourceMetricsCategory(0) // TODO
+                                .launch();
+                        return true;
+                    }
+                });
         onCreateInternal();
     }
 
@@ -84,7 +102,9 @@
         if (isUiRestricted()) {
             return;
         }
-        updateControls();
+        if (!refreshRuleOrFinish()) {
+            updateControls();
+        }
     }
 
     @Override
@@ -111,22 +131,6 @@
         updatePreference(mActionButtons);
     }
 
-    private void updatePreference(AbstractPreferenceController controller) {
-        final PreferenceScreen screen = getPreferenceScreen();
-        if (!controller.isAvailable()) {
-            return;
-        }
-        final String key = controller.getPreferenceKey();
-
-        final Preference preference = screen.findPreference(key);
-        if (preference == null) {
-            Log.d(TAG, String.format("Cannot find preference with key %s in Controller %s",
-                    key, controller.getClass().getSimpleName()));
-            return;
-        }
-        controller.updateState(preference);
-    }
-
     protected void updateRule(Uri newConditionId) {
         mRule.setConditionId(newConditionId);
         mBackend.updateZenRule(mId, mRule);
@@ -165,6 +169,11 @@
         mDisableListeners = true;
         updateControlsInternal();
         updateHeader();
+        if (mRule.getZenPolicy() == null) {
+            mCustomBehaviorPreference.setSummary(R.string.zen_mode_custom_behavior_summary_default);
+        } else {
+            mCustomBehaviorPreference.setSummary(R.string.zen_mode_custom_behavior_summary);
+        }
         mDisableListeners = false;
     }
 }
diff --git a/src/com/android/settings/notification/ZenModeSettings.java b/src/com/android/settings/notification/ZenModeSettings.java
index a3f59c6..bdf80a6 100644
--- a/src/com/android/settings/notification/ZenModeSettings.java
+++ b/src/com/android/settings/notification/ZenModeSettings.java
@@ -90,7 +90,8 @@
         controllers.add(new ZenModeDurationPreferenceController(context, lifecycle));
         controllers.add(new ZenModeAutomationPreferenceController(context));
         controllers.add(new ZenModeButtonPreferenceController(context, lifecycle, fragmentManager));
-        controllers.add(new ZenModeSettingsFooterPreferenceController(context, lifecycle));
+        controllers.add(new ZenModeSettingsFooterPreferenceController(context, lifecycle,
+                fragmentManager));
         return controllers;
     }
 
diff --git a/src/com/android/settings/notification/ZenModeSettingsBase.java b/src/com/android/settings/notification/ZenModeSettingsBase.java
index b9a14ee..3f53879 100644
--- a/src/com/android/settings/notification/ZenModeSettingsBase.java
+++ b/src/com/android/settings/notification/ZenModeSettingsBase.java
@@ -26,7 +26,11 @@
 import android.provider.Settings.Global;
 import android.util.Log;
 
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
 import com.android.settings.dashboard.RestrictedDashboardFragment;
+import com.android.settingslib.core.AbstractPreferenceController;
 
 abstract public class ZenModeSettingsBase extends RestrictedDashboardFragment {
     protected static final String TAG = "ZenModeSettings";
@@ -121,4 +125,20 @@
             }
         }
     }
+
+    void updatePreference(AbstractPreferenceController controller) {
+        final PreferenceScreen screen = getPreferenceScreen();
+        if (!controller.isAvailable()) {
+            return;
+        }
+        final String key = controller.getPreferenceKey();
+
+        final Preference preference = screen.findPreference(key);
+        if (preference == null) {
+            Log.d(TAG, String.format("Cannot find preference with key %s in Controller %s",
+                    key, controller.getClass().getSimpleName()));
+            return;
+        }
+        controller.updateState(preference);
+    }
 }
diff --git a/src/com/android/settings/notification/ZenModeSettingsFooterPreferenceController.java b/src/com/android/settings/notification/ZenModeSettingsFooterPreferenceController.java
index f69eac7..7c2464c 100644
--- a/src/com/android/settings/notification/ZenModeSettingsFooterPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeSettingsFooterPreferenceController.java
@@ -16,17 +16,29 @@
 
 package com.android.settings.notification;
 
+import android.app.Dialog;
 import android.app.NotificationManager;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.icu.text.ListFormatter;
 import android.net.Uri;
+import android.os.Bundle;
 import android.provider.Settings;
 import android.service.notification.ZenModeConfig;
-import android.util.Log;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
 
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.FragmentManager;
 import androidx.preference.Preference;
 
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settings.utils.AnnotationSpan;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 
 import java.util.ArrayList;
@@ -34,11 +46,13 @@
 import java.util.Objects;
 
 public class ZenModeSettingsFooterPreferenceController extends AbstractZenModePreferenceController {
+    static final String KEY = "footer_preference";
+    private FragmentManager mFragment;
 
-    protected static final String KEY = "footer_preference";
-
-    public ZenModeSettingsFooterPreferenceController(Context context, Lifecycle lifecycle) {
+    public ZenModeSettingsFooterPreferenceController(Context context, Lifecycle lifecycle,
+            FragmentManager fragment) {
         super(context, KEY, lifecycle);
+        mFragment = fragment;
     }
 
     @Override
@@ -70,7 +84,7 @@
         }
     }
 
-    protected String getFooterText() {
+    protected CharSequence getFooterText() {
         ZenModeConfig config = getZenModeConfig();
 
         NotificationManager.Policy appliedPolicy = mBackend.getConsolidatedPolicy();
@@ -88,15 +102,25 @@
             if (rulesNames.size() > 0) {
                 String rules = ListFormatter.getInstance().format(rulesNames);
                 if (!rules.isEmpty()) {
-                    return mContext.getString(R.string.zen_mode_settings_dnd_custom_settings_footer,
-                            rules);
+                    final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo(
+                            AnnotationSpan.LinkInfo.DEFAULT_ANNOTATION, new View.OnClickListener() {
+                                @Override
+                                public void onClick(View v) {
+                                    showCustomSettingsDialog();
+                                }
+                            });
+                    return TextUtils.concat(mContext.getResources().getString(
+                            R.string.zen_mode_settings_dnd_custom_settings_footer, rules),
+                            AnnotationSpan.linkify(mContext.getResources().getText(
+                            R.string.zen_mode_settings_dnd_custom_settings_footer_link),
+                            linkInfo));
                 }
             }
         }
-        return getFooterUsingDefaultPolicy(config);
+        return getDefaultPolicyFooter(config);
     }
 
-    private String getFooterUsingDefaultPolicy(ZenModeConfig config) {
+    private String getDefaultPolicyFooter(ZenModeConfig config) {
         String footerText = "";
         long latestEndTime = -1;
 
@@ -162,4 +186,101 @@
         }
         return zenRules;
     }
+
+    private void showCustomSettingsDialog() {
+        ZenCustomSettingsDialog dialog = new ZenCustomSettingsDialog();
+        dialog.setNotificationPolicy(mBackend.getConsolidatedPolicy());
+        dialog.show(mFragment, ZenCustomSettingsDialog.class.getName());
+    }
+
+    public static class ZenCustomSettingsDialog extends InstrumentedDialogFragment {
+        private String KEY_POLICY = "policy";
+        private NotificationManager.Policy mPolicy;
+        private ZenModeSettings.SummaryBuilder mSummaryBuilder;
+
+        public void setNotificationPolicy(NotificationManager.Policy policy) {
+            mPolicy = policy;
+        }
+
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            Context context  = getActivity();
+            if (savedInstanceState != null) {
+                NotificationManager.Policy policy = savedInstanceState.getParcelable(KEY_POLICY);
+                if (policy != null) {
+                    mPolicy = policy;
+                }
+            }
+
+            mSummaryBuilder = new ZenModeSettings.SummaryBuilder(context);
+
+            AlertDialog customSettingsDialog = new AlertDialog.Builder(context)
+                    .setTitle(R.string.zen_custom_settings_dialog_title)
+                    .setNeutralButton(R.string.zen_custom_settings_dialog_review_schedule,
+                            new DialogInterface.OnClickListener() {
+                                @Override
+                                public void onClick(DialogInterface dialog,
+                                        int which) {
+                                    new SubSettingLauncher(context)
+                                            .setDestination(
+                                                    ZenModeAutomationSettings.class.getName())
+                                            .setSourceMetricsCategory(
+                                                    MetricsEvent.NOTIFICATION_ZEN_MODE_AUTOMATION)
+                                            .launch();
+                                }
+                            })
+                    .setPositiveButton(R.string.zen_custom_settings_dialog_ok, null)
+                    .setView(LayoutInflater.from(context).inflate(context.getResources().getLayout(
+                            R.layout.zen_custom_settings_dialog), null, false))
+                    .create();
+
+            customSettingsDialog.setOnShowListener(new DialogInterface.OnShowListener() {
+                @Override
+                public void onShow(DialogInterface dialog) {
+                    TextView allowCallsText = customSettingsDialog.findViewById(
+                            R.id.zen_custom_settings_dialog_calls_allow);
+                    TextView allowMessagesText = customSettingsDialog.findViewById(
+                            R.id.zen_custom_settings_dialog_messages_allow);
+                    TextView allowAlarmsText = customSettingsDialog.findViewById(
+                            R.id.zen_custom_settings_dialog_alarms_allow);
+                    TextView allowMediaText = customSettingsDialog.findViewById(
+                            R.id.zen_custom_settings_dialog_media_allow);
+                    TextView allowSystemText = customSettingsDialog.findViewById(
+                            R.id.zen_custom_settings_dialog_system_allow);
+                    TextView allowRemindersText = customSettingsDialog.findViewById(
+                            R.id.zen_custom_settings_dialog_reminders_allow);
+                    TextView allowEventsText = customSettingsDialog.findViewById(
+                            R.id.zen_custom_settings_dialog_events_allow);
+                    TextView notificationsText = customSettingsDialog.findViewById(
+                            R.id.zen_custom_settings_dialog_show_notifications);
+
+                    allowCallsText.setText(mSummaryBuilder.getCallsSettingSummary(mPolicy));
+                    allowMessagesText.setText(mSummaryBuilder.getMessagesSettingSummary(mPolicy));
+                    allowAlarmsText.setText(getAllowRes(mPolicy.allowAlarms()));
+                    allowMediaText.setText(getAllowRes(mPolicy.allowMedia()));
+                    allowSystemText.setText(getAllowRes(mPolicy.allowSystem()));
+                    allowRemindersText.setText(getAllowRes(mPolicy.allowReminders()));
+                    allowEventsText.setText(getAllowRes(mPolicy.allowEvents()));
+                    notificationsText.setText(mSummaryBuilder.getBlockedEffectsSummary(mPolicy));
+                }
+            });
+
+            return customSettingsDialog;
+        }
+
+        @Override
+        public int getMetricsCategory() {
+            return MetricsEvent.ZEN_CUSTOM_SETTINGS_DIALOG;
+        }
+
+        private int getAllowRes(boolean allow) {
+            return allow ? R.string.zen_mode_sound_summary_on : R.string.zen_mode_sound_summary_off;
+        }
+
+        @Override
+        public void onSaveInstanceState(Bundle outState) {
+            super.onSaveInstanceState(outState);
+            outState.putParcelable(KEY_POLICY, mPolicy);
+        }
+    }
 }
diff --git a/src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java b/src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java
index 66c2ddd..e5982eb 100644
--- a/src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java
@@ -23,25 +23,15 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.database.Cursor;
-import android.icu.text.ListFormatter;
 import android.provider.Contacts;
-import android.provider.ContactsContract;
 
-import com.android.settings.R;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import androidx.annotation.VisibleForTesting;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
 public class ZenModeStarredContactsPreferenceController extends
         AbstractZenModePreferenceController implements Preference.OnPreferenceClickListener {
-
-    protected static String KEY;
     private Preference mPreference;
     private final int mPriorityCategory;
     private final PackageManager mPackageManager;
@@ -52,8 +42,6 @@
     public ZenModeStarredContactsPreferenceController(Context context, Lifecycle lifecycle, int
             priorityCategory, String key) {
         super(context, key, lifecycle);
-        KEY = key;
-
         mPriorityCategory = priorityCategory;
         mPackageManager = mContext.getPackageManager();
 
@@ -96,29 +84,7 @@
 
     @Override
     public CharSequence getSummary() {
-        List<String> starredContacts = getStarredContacts();
-        int numStarredContacts = starredContacts.size();
-
-        List<String> displayContacts = new ArrayList<>();
-
-        if (numStarredContacts == 0) {
-            displayContacts.add(mContext.getString(R.string.zen_mode_from_none));
-        } else {
-            for (int i = 0; i < 2 && i < numStarredContacts; i++) {
-                displayContacts.add(starredContacts.get(i));
-            }
-
-            if (numStarredContacts == 3) {
-                displayContacts.add(starredContacts.get(2));
-            } else if (numStarredContacts > 2) {
-                displayContacts.add(mContext.getResources().getQuantityString(
-                        R.plurals.zen_mode_starred_contacts_summary_additional_contacts,
-                        numStarredContacts - 2, numStarredContacts - 2));
-            }
-        }
-
-        // values in displayContacts must not be null
-        return ListFormatter.getInstance().format(displayContacts);
+        return mBackend.getStarredContactsSummary();
     }
 
     @Override
@@ -131,39 +97,6 @@
         return true;
     }
 
-    @VisibleForTesting
-    List<String> getStarredContacts(Cursor cursor) {
-        List<String> starredContacts = new ArrayList<>();
-        if (cursor.moveToFirst()) {
-            do {
-                String contact = cursor.getString(0);
-                if (contact != null) {
-                    starredContacts.add(contact);
-                }
-            } while (cursor.moveToNext());
-        }
-        return starredContacts;
-    }
-
-    private List<String> getStarredContacts() {
-        Cursor cursor = null;
-        try {
-            cursor = queryData();
-            return getStarredContacts(cursor);
-        } finally {
-            if (cursor != null) {
-                cursor.close();
-            }
-        }
-    }
-
-    private Cursor queryData() {
-        return mContext.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,
-                new String[]{ContactsContract.Contacts.DISPLAY_NAME_PRIMARY},
-                ContactsContract.Data.STARRED + "=1", null,
-                ContactsContract.Data.TIMES_CONTACTED);
-    }
-
     private boolean isIntentValid() {
         return mStarredContactsIntent.resolveActivity(mPackageManager) != null
                 || mFallbackIntent.resolveActivity(mPackageManager) != null;
diff --git a/src/com/android/settings/notification/ZenRuleCallsPreferenceController.java b/src/com/android/settings/notification/ZenRuleCallsPreferenceController.java
new file mode 100644
index 0000000..b27c5fe
--- /dev/null
+++ b/src/com/android/settings/notification/ZenRuleCallsPreferenceController.java
@@ -0,0 +1,86 @@
+/*
+ * 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.notification;
+
+import android.content.Context;
+import android.service.notification.ZenPolicy;
+import android.text.TextUtils;
+import android.util.Pair;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+public class ZenRuleCallsPreferenceController extends AbstractZenCustomRulePreferenceController
+        implements Preference.OnPreferenceChangeListener {
+
+    private final String[] mListValues;
+
+    public ZenRuleCallsPreferenceController(Context context, String key, Lifecycle lifecycle) {
+        super(context, key, lifecycle);
+        mListValues = context.getResources().getStringArray(
+                com.android.settings.R.array.zen_mode_contacts_values);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        updateFromContactsValue(preference);
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object selectedContactsFrom) {
+        int allowCalls = ZenModeBackend.getZenPolicySettingFromPrefKey(
+                selectedContactsFrom.toString());
+        mMetricsFeatureProvider.action(mContext, MetricsProto.MetricsEvent.ACTION_ZEN_ALLOW_CALLS,
+                Pair.create(MetricsProto.MetricsEvent.FIELD_ZEN_TOGGLE_EXCEPTION, allowCalls),
+                Pair.create(MetricsProto.MetricsEvent.FIELD_ZEN_RULE_ID, mId));
+        mRule.setZenPolicy(new ZenPolicy.Builder(mRule.getZenPolicy())
+                .allowCalls(allowCalls)
+                .build());
+        mBackend.updateZenRule(mId, mRule);
+        updateFromContactsValue(preference);
+        return true;
+    }
+
+    private void updateFromContactsValue(Preference preference) {
+        if (mRule == null || mRule.getZenPolicy() == null) {
+            return;
+        }
+        ListPreference listPreference = (ListPreference) preference;
+        listPreference.setSummary(mBackend.getContactsCallsSummary(mRule.getZenPolicy()));
+        final String currentVal = ZenModeBackend.getKeyFromZenPolicySetting(
+                mRule.getZenPolicy().getPriorityCallSenders());
+        listPreference.setValue(mListValues[getIndexOfSendersValue(currentVal)]);
+
+    }
+
+    @VisibleForTesting
+    protected int getIndexOfSendersValue(String currentVal) {
+        int index = 3; // defaults to "none" based on R.array.zen_mode_contacts_values
+        for (int i = 0; i < mListValues.length; i++) {
+            if (TextUtils.equals(currentVal, mListValues[i])) {
+                return i;
+            }
+        }
+
+        return index;
+    }
+}
diff --git a/src/com/android/settings/notification/ZenRuleCustomPolicyPreferenceController.java b/src/com/android/settings/notification/ZenRuleCustomPolicyPreferenceController.java
new file mode 100644
index 0000000..39de0eb
--- /dev/null
+++ b/src/com/android/settings/notification/ZenRuleCustomPolicyPreferenceController.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.notification;
+
+import android.content.Context;
+import android.service.notification.ZenPolicy;
+import android.util.Log;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+public class ZenRuleCustomPolicyPreferenceController extends
+        AbstractZenCustomRulePreferenceController {
+
+    private ZenCustomRadioButtonPreference mPreference;
+
+    public ZenRuleCustomPolicyPreferenceController(Context context, Lifecycle lifecycle,
+            String key) {
+        super(context, key, lifecycle);
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreference = (ZenCustomRadioButtonPreference) screen.findPreference(getPreferenceKey());
+
+        mPreference.setOnGearClickListener(p -> {
+            setCustomPolicy();
+            launchCustomSettings();
+
+        });
+
+        mPreference.setOnRadioButtonClickListener(p -> {
+            setCustomPolicy();
+            launchCustomSettings();
+        });
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        if (mId == null || mRule == null) {
+            return;
+        }
+
+        mPreference.setChecked(mRule.getZenPolicy() != null);
+    }
+
+    private void setCustomPolicy() {
+        if (mRule.getZenPolicy() == null) {
+            mRule.setZenPolicy(mBackend.setDefaultZenPolicy(new ZenPolicy()));
+            mBackend.updateZenRule(mId, mRule);
+        }
+    }
+
+    private void launchCustomSettings() {
+        new SubSettingLauncher(mContext)
+                .setDestination(ZenCustomRuleConfigSettings.class.getName())
+                .setArguments(createBundle())
+                .setSourceMetricsCategory(MetricsProto.MetricsEvent.ZEN_CUSTOM_RULE_SOUND_SETTINGS)
+                .launch();
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/notification/ZenRuleCustomSwitchPreferenceController.java b/src/com/android/settings/notification/ZenRuleCustomSwitchPreferenceController.java
new file mode 100644
index 0000000..804469e
--- /dev/null
+++ b/src/com/android/settings/notification/ZenRuleCustomSwitchPreferenceController.java
@@ -0,0 +1,70 @@
+/*
+ * 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.notification;
+
+import android.content.Context;
+import android.service.notification.ZenPolicy;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+public class ZenRuleCustomSwitchPreferenceController extends
+        AbstractZenCustomRulePreferenceController implements Preference.OnPreferenceChangeListener {
+
+    private @ZenPolicy.PriorityCategory int mCategory;
+    private int mMetricsCategory;
+
+    public ZenRuleCustomSwitchPreferenceController(Context context, Lifecycle lifecycle,
+            String key, @ZenPolicy.PriorityCategory int category, int metricsCategory) {
+        super(context, key, lifecycle);
+        mCategory = category;
+        mMetricsCategory = metricsCategory;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        if (mRule == null || mRule.getZenPolicy() == null) {
+            return;
+        }
+
+        SwitchPreference pref = (SwitchPreference) preference;
+        pref.setChecked(mRule.getZenPolicy().isCategoryAllowed(mCategory, false));
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        final boolean allow = (Boolean) newValue;
+        if (ZenModeSettingsBase.DEBUG) {
+            Log.d(TAG, KEY + " onPrefChange mRule=" + mRule + " mCategory=" + mCategory
+                    + " allow=" + allow);
+        }
+        mMetricsFeatureProvider.action(mContext, mMetricsCategory,
+                Pair.create(MetricsProto.MetricsEvent.FIELD_ZEN_TOGGLE_EXCEPTION, allow ? 1 : 0),
+                Pair.create(MetricsProto.MetricsEvent.FIELD_ZEN_RULE_ID, mId));
+        mRule.setZenPolicy(new ZenPolicy.Builder(mRule.getZenPolicy())
+                .allowCategory(mCategory, allow)
+                .build());
+        mBackend.updateZenRule(mId, mRule);
+        return true;
+    }
+}
diff --git a/src/com/android/settings/notification/ZenRuleDefaultPolicyPreferenceController.java b/src/com/android/settings/notification/ZenRuleDefaultPolicyPreferenceController.java
new file mode 100644
index 0000000..857d853
--- /dev/null
+++ b/src/com/android/settings/notification/ZenRuleDefaultPolicyPreferenceController.java
@@ -0,0 +1,60 @@
+/*
+ * 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.notification;
+
+import android.content.Context;
+import android.util.Pair;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+public class ZenRuleDefaultPolicyPreferenceController extends
+        AbstractZenCustomRulePreferenceController implements PreferenceControllerMixin {
+
+    private ZenCustomRadioButtonPreference mPreference;
+
+    public ZenRuleDefaultPolicyPreferenceController(Context context, Lifecycle lifecycle,
+            String key) {
+        super(context, key, lifecycle);
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreference = (ZenCustomRadioButtonPreference) screen.findPreference(getPreferenceKey());
+
+        mPreference.setOnRadioButtonClickListener(p -> {
+            mRule.setZenPolicy(null);
+            mBackend.updateZenRule(mId, mRule);
+        });
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        if (mId == null || mRule == null) {
+            return;
+        }
+        mMetricsFeatureProvider.action(mContext, MetricsEvent.ZEN_CUSTOM_RULE_DEFAULT_SETTINGS,
+                Pair.create(MetricsEvent.FIELD_ZEN_RULE_ID, mId));
+        mPreference.setChecked(mRule.getZenPolicy() == null);
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/notification/ZenRuleMessagesPreferenceController.java b/src/com/android/settings/notification/ZenRuleMessagesPreferenceController.java
new file mode 100644
index 0000000..010e152
--- /dev/null
+++ b/src/com/android/settings/notification/ZenRuleMessagesPreferenceController.java
@@ -0,0 +1,87 @@
+/*
+ * 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.notification;
+
+import android.content.Context;
+import android.service.notification.ZenPolicy;
+import android.text.TextUtils;
+import android.util.Pair;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+public class ZenRuleMessagesPreferenceController extends AbstractZenCustomRulePreferenceController
+        implements Preference.OnPreferenceChangeListener {
+
+    private final String[] mListValues;
+
+    public ZenRuleMessagesPreferenceController(Context context, String key, Lifecycle lifecycle) {
+        super(context, key, lifecycle);
+        mListValues = context.getResources().getStringArray(
+                com.android.settings.R.array.zen_mode_contacts_values);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        updateFromContactsValue(preference);
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object selectedContactsFrom) {
+        int allowMessages = ZenModeBackend.getZenPolicySettingFromPrefKey(
+                selectedContactsFrom.toString());
+        mMetricsFeatureProvider.action(mContext,
+                MetricsProto.MetricsEvent.ACTION_ZEN_ALLOW_MESSAGES,
+                Pair.create(MetricsProto.MetricsEvent.FIELD_ZEN_TOGGLE_EXCEPTION, allowMessages),
+                Pair.create(MetricsProto.MetricsEvent.FIELD_ZEN_RULE_ID, mId));
+        mRule.setZenPolicy(new ZenPolicy.Builder(mRule.getZenPolicy())
+                .allowMessages(allowMessages)
+                .build());
+        mBackend.updateZenRule(mId, mRule);
+        updateFromContactsValue(preference);
+        return true;
+    }
+
+    private void updateFromContactsValue(Preference preference) {
+        if (mRule == null || mRule.getZenPolicy() == null) {
+            return;
+        }
+        ListPreference listPreference = (ListPreference) preference;
+        listPreference.setSummary(mBackend.getContactsMessagesSummary(mRule.getZenPolicy()));
+        final String currentVal = ZenModeBackend.getKeyFromZenPolicySetting(
+                mRule.getZenPolicy().getPriorityMessageSenders());
+        listPreference.setValue(mListValues[getIndexOfSendersValue(currentVal)]);
+
+    }
+
+    @VisibleForTesting
+    protected int getIndexOfSendersValue(String currentVal) {
+        int index = 3; // defaults to "none" based on R.array.zen_mode_contacts_values
+        for (int i = 0; i < mListValues.length; i++) {
+            if (TextUtils.equals(currentVal, mListValues[i])) {
+                return i;
+            }
+        }
+
+        return index;
+    }
+}
diff --git a/src/com/android/settings/notification/ZenRuleNotifFooterPreferenceController.java b/src/com/android/settings/notification/ZenRuleNotifFooterPreferenceController.java
new file mode 100644
index 0000000..678bf90
--- /dev/null
+++ b/src/com/android/settings/notification/ZenRuleNotifFooterPreferenceController.java
@@ -0,0 +1,60 @@
+/*
+ * 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.notification;
+
+import android.content.Context;
+
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+public class ZenRuleNotifFooterPreferenceController extends
+        AbstractZenCustomRulePreferenceController {
+
+    public ZenRuleNotifFooterPreferenceController(Context context, Lifecycle lifecycle,
+            String key) {
+        super(context, key, lifecycle);
+    }
+
+    @Override
+    public boolean isAvailable() {
+        if (!super.isAvailable() || mRule.getZenPolicy() == null) {
+            return false;
+        }
+
+
+        return mRule.getZenPolicy().shouldHideAllVisualEffects()
+                || mRule.getZenPolicy().shouldShowAllVisualEffects();
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        if (mRule == null || mRule.getZenPolicy() == null) {
+            return;
+        }
+
+        if (mRule.getZenPolicy().shouldShowAllVisualEffects()) {
+            preference.setTitle(R.string.zen_mode_restrict_notifications_mute_footer);
+        } else if (mRule.getZenPolicy().shouldHideAllVisualEffects()) {
+            preference.setTitle(R.string.zen_mode_restrict_notifications_hide_footer);
+        } else {
+            preference.setTitle(null);
+        }
+    }
+}
diff --git a/src/com/android/settings/notification/ZenRuleRepeatCallersPreferenceController.java b/src/com/android/settings/notification/ZenRuleRepeatCallersPreferenceController.java
new file mode 100644
index 0000000..1161bec
--- /dev/null
+++ b/src/com/android/settings/notification/ZenRuleRepeatCallersPreferenceController.java
@@ -0,0 +1,91 @@
+/*
+ * 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.notification;
+
+import android.content.Context;
+import android.service.notification.ZenPolicy;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+public class ZenRuleRepeatCallersPreferenceController extends
+        AbstractZenCustomRulePreferenceController implements Preference.OnPreferenceChangeListener {
+
+    private final int mRepeatCallersThreshold;
+
+    public ZenRuleRepeatCallersPreferenceController(Context context,
+            String key, Lifecycle lifecycle, int repeatCallersThreshold) {
+        super(context, key, lifecycle);
+        mRepeatCallersThreshold = repeatCallersThreshold;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        setRepeatCallerSummary(screen.findPreference(KEY));
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        if (mRule == null || mRule.getZenPolicy() == null) {
+            return;
+        }
+
+        SwitchPreference pref = (SwitchPreference) preference;
+        boolean anyCallersCanBypassDnd = mRule.getZenPolicy().getPriorityCallSenders()
+                == ZenPolicy.PEOPLE_TYPE_ANYONE;
+
+        // if any caller can bypass dnd then repeat callers preference is disabled
+        if (anyCallersCanBypassDnd) {
+            pref.setEnabled(false);
+            pref.setChecked(true);
+        } else {
+            pref.setEnabled(true);
+            pref.setChecked(mRule.getZenPolicy().getPriorityCategoryRepeatCallers()
+                    == ZenPolicy.STATE_ALLOW);
+        }
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        final boolean allow = (Boolean) newValue;
+        if (ZenModeSettingsBase.DEBUG) {
+            Log.d(TAG, KEY + " onPrefChange mRule=" + mRule + " mCategory="
+                    + ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS + " allow=" + allow);
+        }
+        mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_ZEN_ALLOW_REPEAT_CALLS,
+                Pair.create(MetricsEvent.FIELD_ZEN_TOGGLE_EXCEPTION, allow ? 1 : 0),
+                Pair.create(MetricsEvent.FIELD_ZEN_RULE_ID, mId));
+        mRule.setZenPolicy(new ZenPolicy.Builder(mRule.getZenPolicy())
+                .allowRepeatCallers(allow)
+                .build());
+        mBackend.updateZenRule(mId, mRule);
+        return true;
+    }
+
+    private void setRepeatCallerSummary(Preference preference) {
+        preference.setSummary(mContext.getString(
+                com.android.settings.R.string.zen_mode_repeat_callers_summary,
+                mRepeatCallersThreshold));
+    }
+}
diff --git a/src/com/android/settings/notification/ZenRuleStarredContactsPreferenceController.java b/src/com/android/settings/notification/ZenRuleStarredContactsPreferenceController.java
new file mode 100644
index 0000000..8a227a1
--- /dev/null
+++ b/src/com/android/settings/notification/ZenRuleStarredContactsPreferenceController.java
@@ -0,0 +1,103 @@
+/*
+ * 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.notification;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.provider.Contacts;
+import android.service.notification.ZenPolicy;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+public class ZenRuleStarredContactsPreferenceController extends
+        AbstractZenCustomRulePreferenceController implements Preference.OnPreferenceClickListener {
+
+    private Preference mPreference;
+    private final @ZenPolicy.PriorityCategory int mPriorityCategory;
+    private final PackageManager mPackageManager;
+
+    private Intent mStarredContactsIntent;
+    private Intent mFallbackIntent;
+
+    public ZenRuleStarredContactsPreferenceController(Context context, Lifecycle lifecycle,
+            @ZenPolicy.PriorityCategory int priorityCategory, String key) {
+        super(context, key, lifecycle);
+        mPriorityCategory = priorityCategory;
+        mPackageManager = mContext.getPackageManager();
+
+        mStarredContactsIntent = new Intent(Contacts.Intents.UI.LIST_STARRED_ACTION);
+
+        mFallbackIntent =  new Intent(Intent.ACTION_MAIN);
+        mFallbackIntent.addCategory(Intent.CATEGORY_APP_CONTACTS);
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreference = screen.findPreference(KEY);
+
+        if (mPreference != null) {
+            mPreference.setOnPreferenceClickListener(this);
+        }
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        if (!super.isAvailable() || mRule.getZenPolicy() == null || !isIntentValid()) {
+            return false;
+        }
+
+        if (mPriorityCategory == ZenPolicy.PRIORITY_CATEGORY_CALLS) {
+            return mRule.getZenPolicy().getPriorityCallSenders() == ZenPolicy.PEOPLE_TYPE_STARRED;
+        } else if (mPriorityCategory == ZenPolicy.PRIORITY_CATEGORY_MESSAGES) {
+            return mRule.getZenPolicy().getPriorityMessageSenders()
+                    == ZenPolicy.PEOPLE_TYPE_STARRED;
+        } else {
+            // invalid category
+            return false;
+        }
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        return mBackend.getStarredContactsSummary();
+    }
+
+    @Override
+    public boolean onPreferenceClick(Preference preference) {
+        if (mStarredContactsIntent.resolveActivity(mPackageManager) != null) {
+            mContext.startActivity(mStarredContactsIntent);
+        } else {
+            mContext.startActivity(mFallbackIntent);
+        }
+        return true;
+    }
+
+    private boolean isIntentValid() {
+        return mStarredContactsIntent.resolveActivity(mPackageManager) != null
+                || mFallbackIntent.resolveActivity(mPackageManager) != null;
+    }
+}
diff --git a/src/com/android/settings/notification/ZenRuleVisEffectPreferenceController.java b/src/com/android/settings/notification/ZenRuleVisEffectPreferenceController.java
new file mode 100644
index 0000000..94b8234
--- /dev/null
+++ b/src/com/android/settings/notification/ZenRuleVisEffectPreferenceController.java
@@ -0,0 +1,104 @@
+/*
+ * 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.notification;
+
+import android.content.Context;
+import android.service.notification.ZenPolicy;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.CheckBoxPreference;
+import androidx.preference.Preference;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.widget.DisabledCheckBoxPreference;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+public class ZenRuleVisEffectPreferenceController extends AbstractZenCustomRulePreferenceController
+        implements Preference.OnPreferenceChangeListener {
+
+    private final int mMetricsCategory;
+
+    @VisibleForTesting protected @ZenPolicy.VisualEffect int mEffect;
+
+    // if any of these effects are suppressed, this effect must be too
+    @VisibleForTesting protected @ZenPolicy.VisualEffect int[] mParentSuppressedEffects;
+
+    public ZenRuleVisEffectPreferenceController(Context context, Lifecycle lifecycle, String key,
+            @ZenPolicy.VisualEffect int visualEffect, int metricsCategory,
+            @ZenPolicy.VisualEffect int[] parentSuppressedEffects) {
+        super(context, key, lifecycle);
+        mEffect = visualEffect;
+        mMetricsCategory = metricsCategory;
+        mParentSuppressedEffects = parentSuppressedEffects;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        if (!super.isAvailable()) {
+            return false;
+        }
+
+        if (mEffect == ZenPolicy.VISUAL_EFFECT_LIGHTS) {
+            return mContext.getResources()
+                    .getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed);
+        }
+        return true;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        if (mRule == null || mRule.getZenPolicy() == null) {
+            return;
+        }
+
+        boolean suppressed = !mRule.getZenPolicy().isVisualEffectAllowed(mEffect, false);
+        boolean parentSuppressed = false;
+        if (mParentSuppressedEffects != null) {
+            for (@ZenPolicy.VisualEffect int parentEffect : mParentSuppressedEffects) {
+                if (!mRule.getZenPolicy().isVisualEffectAllowed(parentEffect, true)) {
+                    parentSuppressed = true;
+                }
+            }
+        }
+        if (parentSuppressed) {
+            ((CheckBoxPreference) preference).setChecked(parentSuppressed);
+            onPreferenceChange(preference, parentSuppressed);
+            ((DisabledCheckBoxPreference) preference).enableCheckbox(false);
+        } else {
+            ((DisabledCheckBoxPreference) preference).enableCheckbox(true);
+            ((CheckBoxPreference) preference).setChecked(suppressed);
+        }
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        final boolean suppressEffect = (Boolean) newValue;
+        mMetricsFeatureProvider.action(mContext, mMetricsCategory,
+                Pair.create(MetricsProto.MetricsEvent.FIELD_ZEN_TOGGLE_EXCEPTION,
+                        suppressEffect ? 1 : 0),
+                Pair.create(MetricsProto.MetricsEvent.FIELD_ZEN_RULE_ID, mId));
+
+        mRule.setZenPolicy(new ZenPolicy.Builder(mRule.getZenPolicy())
+                .showVisualEffect(mEffect, !suppressEffect)
+                .build());
+        mBackend.updateZenRule(mId, mRule);
+        return true;
+    }
+}
diff --git a/src/com/android/settings/notification/ZenRuleVisEffectsAllPreferenceController.java b/src/com/android/settings/notification/ZenRuleVisEffectsAllPreferenceController.java
new file mode 100644
index 0000000..9ddd624
--- /dev/null
+++ b/src/com/android/settings/notification/ZenRuleVisEffectsAllPreferenceController.java
@@ -0,0 +1,64 @@
+/*
+ * 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.notification;
+
+import android.content.Context;
+import android.service.notification.ZenPolicy;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+public class ZenRuleVisEffectsAllPreferenceController extends
+        AbstractZenCustomRulePreferenceController implements PreferenceControllerMixin {
+
+    private ZenCustomRadioButtonPreference mPreference;
+
+    public ZenRuleVisEffectsAllPreferenceController(Context context, Lifecycle lifecycle,
+            String key) {
+        super(context, key, lifecycle);
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreference = (ZenCustomRadioButtonPreference) screen.findPreference(getPreferenceKey());
+
+        mPreference.setOnRadioButtonClickListener(p -> {
+            mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_ZEN_SOUND_ONLY,
+                    Pair.create(MetricsEvent.FIELD_ZEN_RULE_ID, mId));
+            mRule.setZenPolicy(new ZenPolicy.Builder(mRule.getZenPolicy())
+                    .showAllVisualEffects()
+                    .build());
+            mBackend.updateZenRule(mId, mRule);
+        });
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        if (mId == null || mRule == null || mRule.getZenPolicy() == null) {
+            return;
+        }
+        mPreference.setChecked(mRule.getZenPolicy().shouldShowAllVisualEffects());
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/notification/ZenRuleVisEffectsCustomPreferenceController.java b/src/com/android/settings/notification/ZenRuleVisEffectsCustomPreferenceController.java
new file mode 100644
index 0000000..64dd71c
--- /dev/null
+++ b/src/com/android/settings/notification/ZenRuleVisEffectsCustomPreferenceController.java
@@ -0,0 +1,75 @@
+/*
+ * 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.notification;
+
+import android.content.Context;
+import android.util.Pair;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+public class ZenRuleVisEffectsCustomPreferenceController extends
+        AbstractZenCustomRulePreferenceController implements PreferenceControllerMixin {
+
+    private ZenCustomRadioButtonPreference mPreference;
+
+    public ZenRuleVisEffectsCustomPreferenceController(Context context, Lifecycle lifecycle,
+            String key) {
+        super(context, key, lifecycle);
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreference = (ZenCustomRadioButtonPreference) screen.findPreference(getPreferenceKey());
+
+        mPreference.setOnGearClickListener(p -> {
+            launchCustomSettings();
+
+        });
+
+        mPreference.setOnRadioButtonClickListener(p -> {
+            launchCustomSettings();
+        });
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        if (mId == null || mRule == null || mRule.getZenPolicy() == null) {
+            return;
+        }
+
+        mPreference.setChecked(!mRule.getZenPolicy().shouldHideAllVisualEffects()
+                && !mRule.getZenPolicy().shouldShowAllVisualEffects());
+    }
+
+    private void launchCustomSettings() {
+        mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_ZEN_SHOW_CUSTOM,
+                Pair.create(MetricsEvent.FIELD_ZEN_RULE_ID, mId));
+        new SubSettingLauncher(mContext)
+                .setDestination(ZenCustomRuleBlockedEffectsSettings.class.getName())
+                .setArguments(createBundle())
+                .setSourceMetricsCategory(MetricsEvent.ZEN_CUSTOM_RULE_VIS_EFFECTS)
+                .launch();
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/notification/ZenRuleVisEffectsNonePreferenceController.java b/src/com/android/settings/notification/ZenRuleVisEffectsNonePreferenceController.java
new file mode 100644
index 0000000..4f98924
--- /dev/null
+++ b/src/com/android/settings/notification/ZenRuleVisEffectsNonePreferenceController.java
@@ -0,0 +1,65 @@
+/*
+ * 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.notification;
+
+import android.content.Context;
+import android.service.notification.ZenPolicy;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+public class ZenRuleVisEffectsNonePreferenceController extends
+        AbstractZenCustomRulePreferenceController implements PreferenceControllerMixin {
+
+    private ZenCustomRadioButtonPreference mPreference;
+
+    public ZenRuleVisEffectsNonePreferenceController(Context context, Lifecycle lifecycle,
+            String key) {
+        super(context, key, lifecycle);
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreference = (ZenCustomRadioButtonPreference) screen.findPreference(getPreferenceKey());
+
+        mPreference.setOnRadioButtonClickListener(p -> {
+            mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_ZEN_SOUND_AND_VIS_EFFECTS,
+                    Pair.create(MetricsEvent.FIELD_ZEN_RULE_ID, mId));
+            mRule.setZenPolicy(new ZenPolicy.Builder(mRule.getZenPolicy())
+                    .hideAllVisualEffects()
+                    .build());
+            mBackend.updateZenRule(mId, mRule);
+        });
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        if (mId == null || mRule == null || mRule.getZenPolicy() == null) {
+            return;
+        }
+
+        mPreference.setChecked(mRule.getZenPolicy().shouldHideAllVisualEffects());
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/slices/Copyable.java b/src/com/android/settings/slices/Copyable.java
index 12159d1..a480063 100644
--- a/src/com/android/settings/slices/Copyable.java
+++ b/src/com/android/settings/slices/Copyable.java
@@ -16,6 +16,15 @@
 
 package com.android.settings.slices;
 
+import static android.content.Context.CLIPBOARD_SERVICE;
+
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.widget.Toast;
+
+import com.android.settings.R;
+
 /**
  * Provide the copy ability for preference controller to copy the data to the clipboard.
  */
@@ -25,4 +34,18 @@
      * It is highly recommended to show the toast to notify users when implemented this function.
      */
     void copy();
+
+    /**
+     * Set the copy content to the clipboard and show the toast.
+     */
+    static void setCopyContent(Context context, CharSequence copyContent,
+            CharSequence messageTitle) {
+        final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(
+                CLIPBOARD_SERVICE);
+        final ClipData clip = ClipData.newPlainText("text", copyContent);
+        clipboard.setPrimaryClip(clip);
+
+        final String toast = context.getString(R.string.copyable_slice_toast, messageTitle);
+        Toast.makeText(context, toast, Toast.LENGTH_SHORT).show();
+    }
 }
diff --git a/src/com/android/settings/wifi/NetworkRequestDialogFragment.java b/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
index 30c2cd9..7a1bdb4 100644
--- a/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
+++ b/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.wifi;
 
+import android.app.Activity;
 import android.app.Dialog;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -328,8 +329,12 @@
 
     @Override
     public void onUserSelectionConnectSuccess(WifiConfiguration wificonfiguration) {
-        // Dismisses current dialog, since connection is success.
+        // Dismisses current dialog and finishes Activity, since connection is success.
         dismiss();
+        final Activity activity = getActivity();
+        if (activity != null) {
+            activity.finish();
+        }
     }
 
     @Override
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
index f3e8fc1..fe71991 100644
--- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -549,8 +549,8 @@
      * Show QR code to share the network represented by this preference.
      */
     public void launchQRCodeGenerator() {
-        Intent intent = WifiDppUtils.getConfiguratorQrCodeGeneratorIntent(mAccessPoint.getSsidStr(),
-                mAccessPoint.getSecurityString(/* concise */ false));
+        Intent intent = WifiDppUtils.getConfiguratorQrCodeGeneratorIntent(mContext, mWifiManager,
+                mAccessPoint);
         mContext.startActivity(intent);
     }
 
diff --git a/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java b/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java
index 8d6aa68..90fb850 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java
@@ -17,6 +17,13 @@
 package com.android.settings.wifi.dpp;
 
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
@@ -26,10 +33,11 @@
  * to the Wi-Fi network.
  */
 public class WifiDppAddDeviceFragment extends WifiDppQrCodeBaseFragment {
-    @Override
-    protected int getLayout() {
-        return R.layout.wifi_dpp_add_device_fragment;
-    }
+    private ProgressBar mProgressBar;
+    private ImageView mWifiApPictureView;
+    private TextView mChooseDifferentNetwork;
+    private Button mButtonLeft;
+    private Button mButtonRight;
 
     @Override
     public int getMetricsCategory() {
@@ -37,7 +45,20 @@
     }
 
     @Override
-    public void onActivityCreated (Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
+    public final View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.wifi_dpp_add_device_fragment, container,
+                /* attachToRoot */ false);
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+
+        mProgressBar = view.findViewById(R.id.progress_bar);
+        mWifiApPictureView = view.findViewById(R.id.wifi_ap_picture_view);
+        mChooseDifferentNetwork = view.findViewById(R.id.choose_different_network);
+        mButtonLeft = view.findViewById(R.id.button_left);
+        mButtonRight = view.findViewById(R.id.button_right);
     }
 }
diff --git a/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java b/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java
index 66bc349..a3e6db3 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java
@@ -17,6 +17,11 @@
 package com.android.settings.wifi.dpp;
 
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ListView;
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
@@ -26,10 +31,9 @@
  * {@code WifiDppConfiguratorActivity} to start with this fragment to choose a saved Wi-Fi network.
  */
 public class WifiDppChooseSavedWifiNetworkFragment extends WifiDppQrCodeBaseFragment {
-    @Override
-    protected int getLayout() {
-        return R.layout.wifi_dpp_choose_saved_wifi_network_fragment;
-    }
+    private ListView mSavedWifiNetworkList;
+    private Button mButtonLeft;
+    private Button mButtonRight;
 
     @Override
     public int getMetricsCategory() {
@@ -37,7 +41,18 @@
     }
 
     @Override
-    public void onActivityCreated (Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
+    public final View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.wifi_dpp_choose_saved_wifi_network_fragment, container,
+                /* attachToRoot */ false);
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+
+        mSavedWifiNetworkList = view.findViewById(R.id.saved_wifi_network_list);
+        mButtonLeft = view.findViewById(R.id.button_left);
+        mButtonRight = view.findViewById(R.id.button_right);
     }
 }
diff --git a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
index 6c95f09..e89ebaa 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
@@ -49,7 +49,9 @@
  */
 public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
         WifiNetworkConfig.Retriever,
-        WifiDppQrCodeGeneratorFragment.OnQrCodeGeneratorFragmentAddButtonClickedListener {
+        WifiDppQrCodeGeneratorFragment.OnQrCodeGeneratorFragmentAddButtonClickedListener,
+        WifiDppQrCodeScannerFragment.OnScanWifiDppSuccessListener,
+        WifiDppQrCodeScannerFragment.OnScanZxingWifiFormatSuccessListener {
     private static final String TAG = "WifiDppConfiguratorActivity";
 
     public static final String ACTION_CONFIGURATOR_QR_CODE_SCANNER =
@@ -64,6 +66,12 @@
     /** The Wi-Fi network which will be configured */
     private WifiNetworkConfig mWifiNetworkConfig;
 
+    /** The public key from Wi-Fi DPP QR code */
+    private String mPublicKey;
+
+    /** The information from Wi-Fi DPP QR code */
+    private String mInformation;
+
     @Override
     public int getMetricsCategory() {
         return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_CONFIGURATOR;
@@ -127,8 +135,8 @@
             return;
         }
 
-        WifiDppQrCodeScannerFragment fragment = new WifiDppQrCodeScannerFragment();
-        FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
+        final WifiDppQrCodeScannerFragment fragment = new WifiDppQrCodeScannerFragment();
+        final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
 
         fragmentTransaction.replace(R.id.fragment_container, fragment,
                 WifiDppUtils.TAG_FRAGMENT_QR_CODE_SCANNER);
@@ -145,8 +153,8 @@
             return;
         }
 
-        WifiDppQrCodeGeneratorFragment fragment = new WifiDppQrCodeGeneratorFragment();
-        FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
+        final WifiDppQrCodeGeneratorFragment fragment = new WifiDppQrCodeGeneratorFragment();
+        final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
 
         fragmentTransaction.replace(R.id.fragment_container, fragment,
                 WifiDppUtils.TAG_FRAGMENT_QR_CODE_GENERATOR);
@@ -160,9 +168,9 @@
             return;
         }
 
-        WifiDppChooseSavedWifiNetworkFragment fragment =
+        final WifiDppChooseSavedWifiNetworkFragment fragment =
                 new WifiDppChooseSavedWifiNetworkFragment();
-        FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
+        final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
 
         fragmentTransaction.replace(R.id.fragment_container, fragment,
                 WifiDppUtils.TAG_FRAGMENT_CHOOSE_SAVED_WIFI_NETWORK);
@@ -172,11 +180,38 @@
         fragmentTransaction.commit();
     }
 
+    private void showAddDeviceFragment(boolean addToBackStack) {
+        // Avoid to replace the same fragment during configuration change
+        if (mFragmentManager.findFragmentByTag(
+                WifiDppUtils.TAG_FRAGMENT_ADD_DEVICE) != null) {
+            return;
+        }
+
+        final WifiDppAddDeviceFragment fragment =
+                new WifiDppAddDeviceFragment();
+        final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
+
+        fragmentTransaction.replace(R.id.fragment_container, fragment,
+                WifiDppUtils.TAG_FRAGMENT_ADD_DEVICE);
+        if (addToBackStack) {
+            fragmentTransaction.addToBackStack(/* name */ null);
+        }
+        fragmentTransaction.commit();
+    }
+
     @Override
     public WifiNetworkConfig getWifiNetworkConfig() {
         return mWifiNetworkConfig;
     }
 
+    public String getPublicKey() {
+        return mPublicKey;
+    }
+
+    public String getInformation() {
+        return mInformation;
+    }
+
     @Override
     public boolean setWifiNetworkConfig(WifiNetworkConfig config) {
         if(!WifiNetworkConfig.isValidConfig(config)) {
@@ -201,7 +236,26 @@
         return false;
     }
 
-    @Override public void onQrCodeGeneratorFragmentAddButtonClicked() {
+    @Override
+    public void onQrCodeGeneratorFragmentAddButtonClicked() {
         showQrCodeScannerFragment(/* addToBackStack */ true);
     }
+
+    @Override
+    public void onScanWifiDppSuccess(String publicKey, String information) {
+        mPublicKey = publicKey;
+        mInformation = information;
+        mWifiNetworkConfig = null;
+
+        showAddDeviceFragment(/* addToBackStack */ true);
+    }
+
+    @Override
+    public void onScanZxingWifiFormatSuccess(WifiNetworkConfig wifiNetworkConfig) {
+        mPublicKey = null;
+        mInformation = null;
+        mWifiNetworkConfig = new WifiNetworkConfig(wifiNetworkConfig);
+
+        showAddDeviceFragment(/* addToBackStack */ true);
+    }
 }
diff --git a/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivity.java b/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivity.java
index 920e736..584a819 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivity.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivity.java
@@ -16,9 +16,11 @@
 
 package com.android.settings.wifi.dpp;
 
+import android.provider.Settings;
 import android.app.ActionBar;
 import android.app.Activity;
 import android.content.Intent;
+import android.net.wifi.WifiManager;
 import android.os.Bundle;
 import android.util.Log;
 
@@ -36,7 +38,10 @@
  * To use intent action {@code ACTION_ENROLLEE_QR_CODE_SCANNER}, specify the SSID string of the
  * Wi-Fi network to be provisioned in {@code WifiDppUtils.EXTRA_WIFI_SSID}.
  */
-public class WifiDppEnrolleeActivity extends InstrumentedActivity {
+public class WifiDppEnrolleeActivity extends InstrumentedActivity implements
+        WifiManager.ActionListener,
+        WifiDppQrCodeScannerFragment.OnScanWifiDppSuccessListener,
+        WifiDppQrCodeScannerFragment.OnScanZxingWifiFormatSuccessListener {
     private static final String TAG = "WifiDppEnrolleeActivity";
 
     public static final String ACTION_ENROLLEE_QR_CODE_SCANNER =
@@ -101,4 +106,31 @@
         finish();
         return true;
     }
+
+    @Override
+    public void onScanWifiDppSuccess(String publicKey, String information) {
+        // TODO(b/1023597): starts DPP enrollee handshake here
+    }
+
+    @Override
+    public void onScanZxingWifiFormatSuccess(WifiNetworkConfig wifiNetworkConfig) {
+        wifiNetworkConfig.connect(/* context */ this, /* listener */ this);
+    }
+
+    @Override
+    public void onSuccess() {
+        startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
+        setResult(Activity.RESULT_OK);
+        finish();
+    }
+
+    @Override
+    public void onFailure(int reason) {
+        Log.d(TAG, "Wi-Fi connect onFailure reason - " + reason);
+
+        final Fragment fragment = mFragmentManager.findFragmentById(R.id.fragment_container);
+        if (fragment instanceof WifiDppQrCodeScannerFragment) {
+            ((WifiDppQrCodeScannerFragment)fragment).showErrorMessage(true);
+        }
+    }
 }
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java
index 6792dee..4ac5850 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java
@@ -17,25 +17,16 @@
 package com.android.settings.wifi.dpp;
 
 import android.os.Bundle;
-import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
 import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.ProgressBar;
 import android.widget.TextView;
 
 import com.android.settings.core.InstrumentedFragment;
 import com.android.settings.R;
 
 /**
- * TODO: b/120645817 should refine code to only initiate UI component in each child fragment.
- */
-
-/**
  * There are below 4 fragments for Wi-Fi DPP UI flow, to reduce redundant code of UI components,
- * this parent fragment instantiates all UI components and provides setting APIs for them.
+ * this parent fragment instantiates common UI components
  *
  * {@code WifiDppQrCodeScannerFragment}
  * {@code WifiDppQrCodeGeneratorFragment}
@@ -43,128 +34,16 @@
  * {@code WifiDppAddDeviceFragment}
  */
 public abstract class WifiDppQrCodeBaseFragment extends InstrumentedFragment {
-    private ImageView mHeaderIcon;
-    private TextView mTitle;
-    private TextView mDescription;
-
-    private TextView mErrorMessage;         //optional, for WifiDppQrCodeScannerFragment
-    private ListView mSavedWifiNetworkList; //optional, for WifiDppChooseSavedWifiNetworkFragment
-    private ProgressBar mProgressBar;       //optional, for WifiDppAddDeviceFragment
-    private ImageView mWifiApPictureView;   //optional, for WifiDppAddDeviceFragment
-    private TextView mChooseDifferentNetwork;//optional, for WifiDppAddDeviceFragment
-
-    private Button mButtonLeft;             //optional, for WifiDppChooseSavedWifiNetworkFragment,
-                                            //              WifiDppAddDeviceFragment
-    private Button mButtonRight;            //optional, for WifiDppChooseSavedWifiNetworkFragment,
-                                            //              WifiDppAddDeviceFragment
-
-    abstract protected int getLayout();
+    protected ImageView mHeaderIcon;
+    protected TextView mTitle;
+    protected TextView mSummary;
 
     @Override
-    public final void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-    }
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
 
-    @Override
-    public final View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        View view = inflater.inflate(getLayout(), container, false);
-        initView(view);
-        return view;
-    }
-
-    private void initView(View view) {
-        mHeaderIcon = view.findViewById(R.id.header_icon);
-        mTitle = view.findViewById(R.id.title);
-        mDescription = view.findViewById(R.id.description);
-        mErrorMessage = view.findViewById(R.id.error_message);
-
-        mSavedWifiNetworkList = view.findViewById(R.id.saved_wifi_network_list);
-
-        mProgressBar = view.findViewById(R.id.progress_bar);
-        mWifiApPictureView = view.findViewById(R.id.wifi_ap_picture_view);
-        mChooseDifferentNetwork = view.findViewById(R.id.choose_different_network);
-
-        mButtonLeft = view.findViewById(R.id.button_left);
-        mButtonRight = view.findViewById(R.id.button_right);
-    }
-
-    protected void setHeaderIconImageResource(int resId) {
-        mHeaderIcon.setImageResource(resId);
-    }
-
-    protected void setTitle(String title) {
-        mTitle.setText(title);
-    }
-
-    protected void setDescription(String description) {
-        mDescription.setText(description);
-    }
-
-    /** optional, for WifiDppQrCodeScannerFragment */
-    protected void setErrorMessage(String errorMessage) {
-        if (mErrorMessage != null) {
-            mErrorMessage.setText(errorMessage);
-        }
-    }
-
-    /**
-     * optional, for WifiDppChooseSavedWifiNetworkFragment,
-     *               WifiDppAddDeviceFragment
-     */
-    protected void setLeftButtonText(String text) {
-        if (mButtonLeft != null) {
-            mButtonLeft.setText(text);
-        }
-    }
-
-    /**
-     * optional, for WifiDppChooseSavedWifiNetworkFragment,
-     *               WifiDppAddDeviceFragment
-     */
-    protected void setRightButtonText(String text) {
-        if (mButtonRight != null) {
-            mButtonRight.setText(text);
-        }
-    }
-
-    /**
-     * optional, for WifiDppChooseSavedWifiNetworkFragment,
-     *               WifiDppAddDeviceFragment
-     */
-    protected void hideLeftButton() {
-        if (mButtonLeft != null) {
-            mButtonLeft.setVisibility(View.INVISIBLE);
-        }
-    }
-
-    /**
-     * optional, for WifiDppChooseSavedWifiNetworkFragment,
-     *               WifiDppAddDeviceFragment
-     */
-    protected void hideRightButton() {
-        if (mButtonRight != null) {
-            mButtonRight.setVisibility(View.INVISIBLE);
-        }
-    }
-
-    /**
-     * optional, for WifiDppChooseSavedWifiNetworkFragment,
-     *               WifiDppAddDeviceFragment
-     */
-    protected void setLeftButtonOnClickListener(View.OnClickListener listener) {
-        if (mButtonLeft != null) {
-            mButtonLeft.setOnClickListener(listener);
-        }
-    }
-
-    /**
-     * optional, for WifiDppChooseSavedWifiNetworkFragment,
-     *               WifiDppAddDeviceFragment
-     */
-    protected void setRightButtonOnClickListener(View.OnClickListener listener) {
-        if (mButtonRight != null) {
-            mButtonRight.setOnClickListener(listener);
-        }
+        mHeaderIcon = view.findViewById(android.R.id.icon);
+        mTitle = view.findViewById(android.R.id.title);
+        mSummary = view.findViewById(android.R.id.summary);
     }
 }
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java
index 81def9b..f4bbcc1 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java
@@ -18,23 +18,32 @@
 
 import android.app.ActionBar;
 import android.content.Context;
+import android.graphics.Bitmap;
 import android.os.Bundle;
+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 android.widget.ImageView;
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
+import com.android.settings.wifi.qrcode.QrCodeGenerator;
+
+import com.google.zxing.WriterException;
 
 /**
  * After sharing a saved Wi-Fi network, {@code WifiDppConfiguratorActivity} start with this fragment
  * to generate a Wi-Fi DPP QR code for other device to initiate as an enrollee.
  */
 public class WifiDppQrCodeGeneratorFragment extends WifiDppQrCodeBaseFragment {
-    @Override
-    protected int getLayout() {
-        return R.layout.wifi_dpp_qrcode_generator_fragment;
-    }
+    private static final String TAG = "WifiDppQrCodeGeneratorFragment";
+
+    private ImageView mQrCodeView;
+    private String mQrCode;
 
     @Override
     public int getMetricsCategory() {
@@ -51,18 +60,8 @@
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
 
-        setHeaderIconImageResource(R.drawable.ic_qrcode_24dp);
-        WifiNetworkConfig wifiNetworkConfig = ((WifiNetworkConfig.Retriever) getActivity())
-                .getWifiNetworkConfig();
-        if (!WifiNetworkConfig.isValidConfig(wifiNetworkConfig)) {
-            throw new IllegalArgumentException("Invalid Wi-Fi network for configuring");
-        }
-        setTitle(getString(R.string.wifi_dpp_share_wifi));
-        setDescription(getString(R.string.wifi_dpp_scan_qr_code_with_another_device,
-                wifiNetworkConfig.getSsid()));
-
         setHasOptionsMenu(true);
-        ActionBar actionBar = getActivity().getActionBar();
+        final ActionBar actionBar = getActivity().getActionBar();
         if (actionBar != null) {
             actionBar.setDisplayHomeAsUpEnabled(true);
             actionBar.show();
@@ -102,4 +101,42 @@
                 return super.onOptionsItemSelected(menuItem);
         }
     }
+
+    @Override
+    public final View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.wifi_dpp_qrcode_generator_fragment, container,
+                /* attachToRoot */ false);
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+
+        mQrCodeView = view.findViewById(R.id.qrcode_view);
+
+        mHeaderIcon.setImageResource(R.drawable.ic_qrcode_24dp);
+        WifiNetworkConfig wifiNetworkConfig = ((WifiNetworkConfig.Retriever) getActivity())
+                .getWifiNetworkConfig();
+        if (!WifiNetworkConfig.isValidConfig(wifiNetworkConfig)) {
+            throw new IllegalStateException("Invalid Wi-Fi network for configuring");
+        }
+        mTitle.setText(R.string.wifi_dpp_share_wifi);
+        mSummary.setText(getString(R.string.wifi_dpp_scan_qr_code_with_another_device,
+                wifiNetworkConfig.getSsid()));
+
+        mQrCode = wifiNetworkConfig.getQrCode();
+        setQrCode();
+    }
+
+    private void setQrCode() {
+        try {
+            final int qrcodeSize = getContext().getResources().getDimensionPixelSize(
+                    R.dimen.qrcode_size);
+            final Bitmap bmp = QrCodeGenerator.encodeQrCode(mQrCode, qrcodeSize);
+            mQrCodeView.setImageBitmap(bmp);
+        } catch (WriterException e) {
+            Log.e(TAG, "Error generatting QR code bitmap " + e);
+        }
+    }
 }
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
index 8cd3c562..c7c1461 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
@@ -16,7 +16,6 @@
 
 package com.android.settings.wifi.dpp;
 
-import android.annotation.Nullable;
 import android.app.ActionBar;
 import android.app.Activity;
 import android.content.Context;
@@ -25,13 +24,18 @@
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
 import android.text.TextUtils;
 import android.util.Size;
+import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.TextureView;
 import android.view.TextureView.SurfaceTextureListener;
 import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
@@ -41,37 +45,69 @@
 public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment implements
         SurfaceTextureListener,
         QrCamera.ScannerCallback {
+    private static final String TAG = "WifiDppQrCodeScannerFragment";
+
+    /** Message sent to hide error message */
+    private static final int MESSAGE_HIDE_ERROR_MESSAGE = 1;
+
+    /** Message sent to show error message */
+    private static final int MESSAGE_SHOW_ERROR_MESSAGE = 2;
+
+    /** Message sent to manipulate Wi-Fi DPP QR code */
+    private static final int MESSAGE_SCAN_WIFI_DPP_SUCCESS = 3;
+
+    /** Message sent to manipulate ZXing Wi-Fi QR code */
+    private static final int MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS = 4;
+
+    private static final long SHOW_ERROR_MESSAGE_INTERVAL = 2000;
+    private static final long SHOW_SUCCESS_SQUARE_INTERVAL = 1000;
+
+    // Keys for Bundle usage
+    private static final String KEY_PUBLIC_KEY = "key_public_key";
+    private static final String KEY_INFORMATION = "key_information";
+
     private QrCamera mCamera;
     private TextureView mTextureView;
     private QrDecorateView mDecorateView;
+    private TextView mErrorMessage;
 
     /** true if the fragment working for configurator, false enrollee*/
-    private final boolean mConfiguratorMode;
+    private final boolean mIsConfiguratorMode;
 
     /** The SSID of the Wi-Fi network which the user specify to enroll */
     private String mSsid;
 
-    @Override
-    protected int getLayout() {
-        return R.layout.wifi_dpp_qrcode_scanner_fragment;
-    }
+    /** QR code data scanned by camera */
+    private WifiQrCode mWifiQrCode;
 
     @Override
     public int getMetricsCategory() {
-        if (mConfiguratorMode) {
+        if (mIsConfiguratorMode) {
             return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_CONFIGURATOR;
         } else {
             return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_ENROLLEE;
         }
     }
 
+    // Container Activity must implement this interface
+    public interface OnScanWifiDppSuccessListener {
+        public void onScanWifiDppSuccess(String publicKey, String information);
+    }
+    OnScanWifiDppSuccessListener mScanWifiDppSuccessListener;
+
+    // Container Activity must implement this interface
+    public interface OnScanZxingWifiFormatSuccessListener {
+        public void onScanZxingWifiFormatSuccess(WifiNetworkConfig wifiNetworkConfig);
+    }
+    OnScanZxingWifiFormatSuccessListener mScanScanZxingWifiFormatSuccessListener;
+
     /**
      * Configurator container activity of the fragment should create instance with this constructor.
      */
     public WifiDppQrCodeScannerFragment() {
         super();
 
-        mConfiguratorMode = true;
+        mIsConfiguratorMode = true;
     }
 
     /**
@@ -81,7 +117,7 @@
     public WifiDppQrCodeScannerFragment(String ssid) {
         super();
 
-        mConfiguratorMode = false;
+        mIsConfiguratorMode = false;
         mSsid = ssid;
     }
 
@@ -89,30 +125,7 @@
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
 
-        setHeaderIconImageResource(R.drawable.ic_scan_24dp);
-
-        if (mConfiguratorMode) {
-            setTitle(getString(R.string.wifi_dpp_add_device_to_network));
-
-            WifiNetworkConfig wifiNetworkConfig = ((WifiNetworkConfig.Retriever) getActivity())
-                .getWifiNetworkConfig();
-            if (!WifiNetworkConfig.isValidConfig(wifiNetworkConfig)) {
-                throw new IllegalArgumentException("Invalid Wi-Fi network for configuring");
-            }
-            setDescription(getString(R.string.wifi_dpp_center_qr_code, wifiNetworkConfig.getSsid()));
-        } else {
-            setTitle(getString(R.string.wifi_dpp_scan_qr_code));
-
-            String description;
-            if (TextUtils.isEmpty(mSsid)) {
-                description = getString(R.string.wifi_dpp_scan_qr_code_join_unknown_network, mSsid);
-            } else {
-                description = getString(R.string.wifi_dpp_scan_qr_code_join_network, mSsid);
-            }
-            setDescription(description);
-        }
-
-        ActionBar actionBar = getActivity().getActionBar();
+        final ActionBar actionBar = getActivity().getActionBar();
         if (actionBar != null) {
             actionBar.setDisplayHomeAsUpEnabled(true);
             actionBar.show();
@@ -120,13 +133,61 @@
     }
 
     @Override
-    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+    public void onAttach(Context context) {
+        super.onAttach(context);
+
+        mScanWifiDppSuccessListener = (OnScanWifiDppSuccessListener) context;
+        mScanScanZxingWifiFormatSuccessListener = (OnScanZxingWifiFormatSuccessListener) context;
+    }
+
+    @Override
+    public void onDetach() {
+        mScanWifiDppSuccessListener = null;
+        mScanScanZxingWifiFormatSuccessListener = null;
+
+        super.onDetach();
+    }
+
+    @Override
+    public final View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.wifi_dpp_qrcode_scanner_fragment, container,
+                /* attachToRoot */ false);
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
 
         mTextureView = (TextureView) view.findViewById(R.id.preview_view);
         mTextureView.setSurfaceTextureListener(this);
 
         mDecorateView = (QrDecorateView) view.findViewById(R.id.decorate_view);
+
+        mHeaderIcon.setImageResource(R.drawable.ic_scan_24dp);
+        if (mIsConfiguratorMode) {
+            mTitle.setText(R.string.wifi_dpp_add_device_to_network);
+
+            WifiNetworkConfig wifiNetworkConfig = ((WifiNetworkConfig.Retriever) getActivity())
+                .getWifiNetworkConfig();
+            if (!WifiNetworkConfig.isValidConfig(wifiNetworkConfig)) {
+                throw new IllegalStateException("Invalid Wi-Fi network for configuring");
+            }
+            mSummary.setText(getString(R.string.wifi_dpp_center_qr_code,
+                    wifiNetworkConfig.getSsid()));
+        } else {
+            mTitle.setText(R.string.wifi_dpp_scan_qr_code);
+
+            String description;
+            if (TextUtils.isEmpty(mSsid)) {
+                description = getString(R.string.wifi_dpp_scan_qr_code_join_unknown_network, mSsid);
+            } else {
+                description = getString(R.string.wifi_dpp_scan_qr_code_join_network, mSsid);
+            }
+            mSummary.setText(description);
+        }
+
+        mErrorMessage = view.findViewById(R.id.error_message);
     }
 
     @Override
@@ -173,10 +234,75 @@
     }
 
     @Override
+    public boolean isValid(String qrCode) {
+        try {
+            mWifiQrCode = new WifiQrCode(qrCode);
+        } catch (IllegalArgumentException e) {
+            mHandler.sendEmptyMessage(MESSAGE_SHOW_ERROR_MESSAGE);
+            return false;
+        }
+
+        final String scheme = mWifiQrCode.getScheme();
+
+        // When SSID is specified for enrollee, avoid to connect to the Wi-Fi of different SSID
+        if (!mIsConfiguratorMode && WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG.equals(scheme)) {
+            final String ssidQrCode = mWifiQrCode.getWifiNetworkConfig().getSsid();
+            if (!TextUtils.isEmpty(mSsid) && !mSsid.equals(ssidQrCode)) {
+                mHandler.sendEmptyMessage(MESSAGE_SHOW_ERROR_MESSAGE);
+                return false;
+            }
+        }
+
+        // It's impossible to provision other device with ZXing Wi-Fi Network config format
+        if (mIsConfiguratorMode && WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG.equals(scheme)) {
+            mHandler.sendEmptyMessage(MESSAGE_SHOW_ERROR_MESSAGE);
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * This method is only called when QrCamera.ScannerCallback.isValid returns true; 
+     */
+    @Override
     public void handleSuccessfulResult(String qrCode) {
+        switch (mWifiQrCode.getScheme()) {
+            case WifiQrCode.SCHEME_DPP:
+                handleWifiDpp(mWifiQrCode.getPublicKey(), mWifiQrCode.getInformation());
+                break;
+
+            case WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG:
+                handleZxingWifiFormat(mWifiQrCode.getWifiNetworkConfig());
+                break;
+
+            default:
+                // continue below
+        }
+    }
+
+    private void handleWifiDpp(String publicKey, String information) {
         destroyCamera();
         mDecorateView.setFocused(true);
-        // TODO(b/120243131): Add a network by Wi-Fi Network config shared via QR code.
+
+        final Bundle bundle = new Bundle();
+        bundle.putString(KEY_PUBLIC_KEY, publicKey);
+        bundle.putString(KEY_INFORMATION, information);
+
+        Message message = mHandler.obtainMessage(MESSAGE_SCAN_WIFI_DPP_SUCCESS);
+        message.setData(bundle);
+
+        mHandler.sendMessageDelayed(message, SHOW_SUCCESS_SQUARE_INTERVAL);
+    }
+
+    private void handleZxingWifiFormat(WifiNetworkConfig wifiNetworkConfig) {
+        destroyCamera();
+        mDecorateView.setFocused(true);
+
+        Message message = mHandler.obtainMessage(MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS);
+        message.obj = wifiNetworkConfig;
+
+        mHandler.sendMessageDelayed(message, SHOW_SUCCESS_SQUARE_INTERVAL);
     }
 
     @Override
@@ -198,4 +324,51 @@
             mCamera = null;
         }
     }
+
+    public void showErrorMessage(boolean show) {
+        mErrorMessage.setVisibility(show ? View.VISIBLE : View.INVISIBLE);
+
+        if (show) {
+            mHandler.removeMessages(MESSAGE_HIDE_ERROR_MESSAGE);
+            mHandler.sendEmptyMessageDelayed(MESSAGE_HIDE_ERROR_MESSAGE,
+                    SHOW_ERROR_MESSAGE_INTERVAL);
+        }
+    }
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MESSAGE_HIDE_ERROR_MESSAGE:
+                    showErrorMessage(false);
+                    break;
+
+                case MESSAGE_SHOW_ERROR_MESSAGE:
+                    showErrorMessage(true);
+                    break;
+
+                case MESSAGE_SCAN_WIFI_DPP_SUCCESS:
+                    if (mScanWifiDppSuccessListener == null) {
+                        return;
+                    }
+                    final Bundle bundle = msg.getData();
+                    final String publicKey = bundle.getString(KEY_PUBLIC_KEY);
+                    final String information = bundle.getString(KEY_INFORMATION);
+
+                    mScanWifiDppSuccessListener.onScanWifiDppSuccess(publicKey, information);
+                    break;
+
+                case MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS:
+                    if (mScanScanZxingWifiFormatSuccessListener == null) {
+                        return;
+                    }
+                    mScanScanZxingWifiFormatSuccessListener.onScanZxingWifiFormatSuccess(
+                            (WifiNetworkConfig)msg.obj);
+                    break;
+
+                default:
+                    return;
+            }
+        }
+    };
 }
diff --git a/src/com/android/settings/wifi/dpp/WifiDppUtils.java b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
index cc75d44..3a40e25 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppUtils.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
@@ -18,9 +18,15 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
 import android.text.TextUtils;
 import android.util.FeatureFlagUtils;
 
+import com.android.settingslib.wifi.AccessPoint;
+
+import java.util.List;
+
 /**
  * Here are the items shared by both WifiDppConfiguratorActivity & WifiDppEnrolleeActivity
  */
@@ -84,23 +90,81 @@
         return intent;
     }
 
+    private static String getPresharedKey(WifiManager wifiManager, WifiConfiguration config) {
+        String preSharedKey = config.preSharedKey;
+
+        final List<WifiConfiguration> wifiConfigs = wifiManager.getPrivilegedConfiguredNetworks();
+        for (WifiConfiguration wifiConfig : wifiConfigs) {
+            if (wifiConfig.networkId == config.networkId) {
+                preSharedKey = wifiConfig.preSharedKey;
+                break;
+            }
+        }
+
+        return preSharedKey;
+    }
+
+    private static String removeFirstAndLastDoubleQuotes(String str) {
+        if (TextUtils.isEmpty(str)) {
+            return str;
+        }
+
+        int begin = 0;
+        int end = str.length() - 1;
+        if (str.charAt(begin) == '\"') {
+            begin++;
+        }
+        if (str.charAt(end) == '\"') {
+            end--;
+        }
+        return str.substring(begin, end+1);
+    }
+
+    private static String getSecurityString(AccessPoint accessPoint) {
+        switch(accessPoint.getSecurity()) {
+            case AccessPoint.SECURITY_WEP:
+                return "WEP";
+            case AccessPoint.SECURITY_PSK:
+                return "WPA";
+            default:
+                return "nopass";
+        }
+    }
+
     /**
      * Returns an intent to launch QR code generator.
      *
-     * @param ssid     The data corresponding to {@code WifiConfiguration} SSID
-     * @param Security The data is from {@code AccessPoint.securityToString}
+     * @param context     The context to use for the content resolver
+     * @param wifiManager An instance of {@link WifiManager}
+     * @param accessPoint An instance of {@link AccessPoint}
      * @return Intent for launching QR code generator
      */
-    public static Intent getConfiguratorQrCodeGeneratorIntent(String ssid, String Security) {
-        //TODO: b/118794858#comment6 should put password & hideSsid in intent extra
-        final Intent intent = new Intent(
-                WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR);
+    public static Intent getConfiguratorQrCodeGeneratorIntent(Context context,
+            WifiManager wifiManager, AccessPoint accessPoint) {
+        final Intent intent = new Intent(context, WifiDppConfiguratorActivity.class);
+        intent.setAction(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR);
+
+        final WifiConfiguration wifiConfig = accessPoint.getConfig();
+        final String ssid = removeFirstAndLastDoubleQuotes(wifiConfig.SSID);
+        final String security = getSecurityString(accessPoint);
+        String preSharedKey = wifiConfig.preSharedKey;
+
+        if (preSharedKey != null) {
+            // When the value of this key is read, the actual key is not returned, just a "*".
+            // Call privileged system API to obtain actual key.
+            preSharedKey = removeFirstAndLastDoubleQuotes(getPresharedKey(wifiManager, wifiConfig));
+        }
+
         if (!TextUtils.isEmpty(ssid)) {
             intent.putExtra(EXTRA_WIFI_SSID, ssid);
         }
-        if (!TextUtils.isEmpty(Security)) {
-            intent.putExtra(EXTRA_WIFI_SECURITY, Security);
+        if (!TextUtils.isEmpty(security)) {
+            intent.putExtra(EXTRA_WIFI_SECURITY, security);
         }
+        if (!TextUtils.isEmpty(preSharedKey)) {
+            intent.putExtra(EXTRA_WIFI_PRE_SHARED_KEY, preSharedKey);
+        }
+
         return intent;
     }
 }
diff --git a/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java b/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
index bb64e05..c9bfbd6 100644
--- a/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
+++ b/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
@@ -16,8 +16,18 @@
 
 package com.android.settings.wifi.dpp;
 
+import static com.android.settings.wifi.dpp.WifiQrCode.SECURITY_NO_PASSWORD;
+import static com.android.settings.wifi.dpp.WifiQrCode.SECURITY_WEP;
+import static com.android.settings.wifi.dpp.WifiQrCode.SECURITY_WPA;
+
+import android.content.Context;
 import android.content.Intent;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.AuthAlgorithm;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiManager;
 import android.text.TextUtils;
+import android.util.Log;
 
 import androidx.annotation.Keep;
 
@@ -30,8 +40,7 @@
  * EXTRA_QR_CODE
  */
 public class WifiNetworkConfig {
-    // Ignores password if security is NO_PASSWORD or absent
-    public static final String NO_PASSWORD = "nopass";
+    private static final String TAG = "WifiNetworkConfig";
 
     private String mSecurity;
     private String mSsid;
@@ -47,18 +56,9 @@
     }
 
     public WifiNetworkConfig(WifiNetworkConfig config) {
-        if (config.mSecurity != null) {
-            mSecurity = new String(config.mSecurity);
-        }
-
-        if (config.mSsid != null) {
-            mSsid = new String(config.mSsid);
-        }
-
-        if (config.mPreSharedKey != null) {
-            mPreSharedKey = new String(config.mPreSharedKey);
-        }
-
+        mSecurity = config.mSecurity;
+        mSsid = config.mSsid;
+        mPreSharedKey = config.mPreSharedKey;
         mHiddenSsid = config.mHiddenSsid;
     }
 
@@ -106,7 +106,7 @@
 
     public static boolean isValidConfig(String security, String ssid, String preSharedKey,
             boolean hiddenSsid) {
-        if (!TextUtils.isEmpty(security) && !NO_PASSWORD.equals(security)) {
+        if (!TextUtils.isEmpty(security) && !SECURITY_NO_PASSWORD.equals(security)) {
             if (TextUtils.isEmpty(preSharedKey)) {
                 return false;
             }
@@ -119,6 +119,51 @@
         return true;
     }
 
+    /**
+     * Escaped special characters "\", ";", ":", "," with a backslash
+     * See https://github.com/zxing/zxing/wiki/Barcode-Contents
+     */
+    private String escapeSpecialCharacters(String str) {
+        if (TextUtils.isEmpty(str)) {
+            return str;
+        }
+
+        StringBuilder buf = new StringBuilder();
+        for (int i = 0; i < str.length(); i++) {
+            char ch = str.charAt(i);
+            if (ch =='\\' || ch == ',' || ch == ';' || ch == ':') {
+                buf.append('\\');
+            }
+            buf.append(ch);
+        }
+
+        return buf.toString();
+    }
+
+    /**
+     * Construct a barcode string for WiFi network login.
+     * See https://en.wikipedia.org/wiki/QR_code#WiFi_network_login
+     */
+    public String getQrCode() {
+        final String empty = "";
+        String barcode = new StringBuilder("WIFI:")
+                .append("S:")
+                .append(escapeSpecialCharacters(mSsid))
+                .append(";")
+                .append("T:")
+                .append(TextUtils.isEmpty(mSecurity) ? empty : mSecurity)
+                .append(";")
+                .append("P:")
+                .append(TextUtils.isEmpty(mPreSharedKey) ? empty
+                        : escapeSpecialCharacters(mPreSharedKey))
+                .append(";")
+                .append("H:")
+                .append(mHiddenSsid)
+                .append(";;")
+                .toString();
+        return barcode;
+    }
+
     @Keep
     public String getSecurity() {
         return mSecurity;
@@ -138,4 +183,77 @@
     public boolean getHiddenSsid() {
         return mHiddenSsid;
     }
+
+    public void connect(Context context, WifiManager.ActionListener listener) {
+        WifiConfiguration wifiConfiguration = getWifiConfigurationOrNull();
+        if (wifiConfiguration == null) {
+            if (listener != null) {
+                listener.onFailure(WifiManager.ERROR);
+            }
+            return;
+        }
+
+        WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
+        wifiManager.connect(wifiConfiguration, listener);
+    }
+
+    /**
+     * This is a simplified method from {@code WifiConfigController.getConfig()}
+     */
+    private WifiConfiguration getWifiConfigurationOrNull() {
+        if (!isValidConfig(this)) {
+            return null;
+        }
+
+        final WifiConfiguration wifiConfiguration = new WifiConfiguration();
+        wifiConfiguration.SSID = addQuotationIfNeeded(mSsid);
+        wifiConfiguration.hiddenSSID = mHiddenSsid;
+
+        if (TextUtils.isEmpty(mSecurity) || SECURITY_NO_PASSWORD.equals(mSecurity)) {
+            wifiConfiguration.allowedKeyManagement.set(KeyMgmt.NONE);
+            return wifiConfiguration;
+        }
+
+        if (mSecurity.startsWith(SECURITY_WEP)) {
+            wifiConfiguration.allowedKeyManagement.set(KeyMgmt.NONE);
+            wifiConfiguration.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
+            wifiConfiguration.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
+
+            // WEP-40, WEP-104, and 256-bit WEP (WEP-232?)
+            final int length = mPreSharedKey.length();
+            if ((length == 10 || length == 26 || length == 58)
+                    && mPreSharedKey.matches("[0-9A-Fa-f]*")) {
+                wifiConfiguration.wepKeys[0] = mPreSharedKey;
+            } else {
+                wifiConfiguration.wepKeys[0] = addQuotationIfNeeded(mPreSharedKey);
+            }
+        } else if (mSecurity.startsWith(SECURITY_WPA)) {
+            wifiConfiguration.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+
+            if (mPreSharedKey.matches("[0-9A-Fa-f]{64}")) {
+                wifiConfiguration.preSharedKey = mPreSharedKey;
+            } else {
+                wifiConfiguration.preSharedKey = addQuotationIfNeeded(mPreSharedKey);
+            }
+        } else {
+            Log.w(TAG, "Unsupported security");
+            return null;
+        }
+
+        return wifiConfiguration;
+    }
+
+    private String addQuotationIfNeeded(String input) {
+        if (TextUtils.isEmpty(input)) {
+            return "";
+        }
+
+        if (input.length() >= 2 && input.startsWith("\"") && input.endsWith("\"")) {
+            return input;
+        }
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("\"").append(input).append("\"");
+        return sb.toString();
+    }
 }
diff --git a/src/com/android/settings/wifi/dpp/WifiQrCode.java b/src/com/android/settings/wifi/dpp/WifiQrCode.java
index ebc39c3..a8562bb 100644
--- a/src/com/android/settings/wifi/dpp/WifiQrCode.java
+++ b/src/com/android/settings/wifi/dpp/WifiQrCode.java
@@ -22,7 +22,8 @@
 import androidx.annotation.Keep;
 import androidx.annotation.VisibleForTesting;
 
-import java.util.regex.Matcher;
+import java.util.Arrays;
+import java.util.List;
 import java.util.regex.Pattern;
 
 /**
@@ -62,7 +63,12 @@
     public static final String PREFIX_ZXING_PASSWORD = "P:";
     public static final String PREFIX_ZXING_HIDDEN_SSID = "H:";
 
-    public static final String SUFFIX_QR_CODE = ";";
+    public static final String DELIMITER_QR_CODE = ";";
+
+    // Ignores password if security is SECURITY_NO_PASSWORD or absent
+    public static final String SECURITY_NO_PASSWORD = "nopass";
+    public static final String SECURITY_WEP = "WEP";
+    public static final String SECURITY_WPA = "WPA";
 
     private String mQrCode;
 
@@ -100,22 +106,27 @@
 
     /** Parses Wi-Fi DPP QR code string */
     private void parseWifiDppQrCode(String qrCode) throws IllegalArgumentException {
-        String publicKey = getSubStringOrNull(qrCode, PREFIX_DPP_PUBLIC_KEY, SUFFIX_QR_CODE);
+        List keyValueList = getKeyValueList(qrCode, PREFIX_DPP, DELIMITER_QR_CODE);
+
+        String publicKey = getValueOrNull(keyValueList, PREFIX_DPP_PUBLIC_KEY);
         if (TextUtils.isEmpty(publicKey)) {
             throw new IllegalArgumentException("Invalid format");
         }
         mPublicKey = publicKey;
 
-        mInformation = getSubStringOrNull(qrCode, PREFIX_DPP_INFORMATION, SUFFIX_QR_CODE);
+        mInformation = getValueOrNull(keyValueList, PREFIX_DPP_INFORMATION);
     }
 
     /** Parses ZXing reader library's Wi-Fi Network config format */
     private void parseZxingWifiQrCode(String qrCode) throws IllegalArgumentException {
-        String security = getSubStringOrNull(qrCode, PREFIX_ZXING_SECURITY, SUFFIX_QR_CODE);
-        String ssid = getSubStringOrNull(qrCode, PREFIX_ZXING_SSID, SUFFIX_QR_CODE);
-        String password = getSubStringOrNull(qrCode, PREFIX_ZXING_PASSWORD, SUFFIX_QR_CODE);
-        String hiddenSsidString = getSubStringOrNull(qrCode, PREFIX_ZXING_HIDDEN_SSID,
-                SUFFIX_QR_CODE);
+        List keyValueList = getKeyValueList(qrCode, PREFIX_ZXING_WIFI_NETWORK_CONFIG,
+                DELIMITER_QR_CODE);
+
+        String security = getValueOrNull(keyValueList, PREFIX_ZXING_SECURITY);
+        String ssid = getValueOrNull(keyValueList, PREFIX_ZXING_SSID);
+        String password = getValueOrNull(keyValueList, PREFIX_ZXING_PASSWORD);
+        String hiddenSsidString = getValueOrNull(keyValueList, PREFIX_ZXING_HIDDEN_SSID);
+
         boolean hiddenSsid = "true".equalsIgnoreCase(hiddenSsidString);
 
         //"\", ";", "," and ":" are escaped with a backslash "\", should remove at first
@@ -132,33 +143,37 @@
     }
 
     /**
-     * Gets the substring between prefix & suffix from input.
+     * Splits key/value pairs from qrCode
      *
-     * @param prefix the string before the returned substring
-     * @param suffix the string after the returned substring
-     * @return null if not exists, non-null otherwise
+     * @param qrCode the QR code raw string
+     * @param prefixQrCode the string before all key/value pairs in qrCode
+     * @param delimiter the string to split key/value pairs, can't contain a backslash
+     * @return a list contains string of key/value (e.g. K:key1)
      */
-    private static String getSubStringOrNull(String input, String prefix, String suffix) {
-        StringBuilder sb = new StringBuilder();
-        String regex = sb.append(prefix).append("(.*?)").append(suffix).toString();
-        Pattern pattern = Pattern.compile(regex);
-        Matcher matcher = pattern.matcher(input);
+    private List<String> getKeyValueList(String qrCode, String prefixQrCode,
+                String delimiter) {
+        String keyValueString = qrCode.substring(prefixQrCode.length());
 
-        if (!matcher.find()) {
-            return null;
+        // Should not treat \delimiter as a delimiter
+        String regex = "(?<!\\\\)" + Pattern.quote(delimiter);
+
+        List<String> result = Arrays.asList(keyValueString.split(regex));
+        return result;
+    }
+
+    private String getValueOrNull(List<String> keyValueList, String prefix) {
+        for (String keyValue : keyValueList) {
+            if (keyValue.startsWith(prefix)) {
+                return  keyValue.substring(prefix.length());
+            }
         }
 
-        String target = matcher.group(1);
-        if (TextUtils.isEmpty(target)) {
-            return null;
-        }
-
-        return target;
+        return null;
     }
 
     @Keep
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    protected static String removeBackSlash(String input) {
+    protected String removeBackSlash(String input) {
         if (input == null) {
             return null;
         }
diff --git a/src/com/android/settings/wifi/qrcode/QrCamera.java b/src/com/android/settings/wifi/qrcode/QrCamera.java
index c60c30e..af366bc 100644
--- a/src/com/android/settings/wifi/qrcode/QrCamera.java
+++ b/src/com/android/settings/wifi/qrcode/QrCamera.java
@@ -152,6 +152,15 @@
          * @param transform The transform to apply to the content of preview
          */
         void setTransform(Matrix transform);
+
+        /**
+         * Verify QR code is valid or not. The camera will stop scanning if this callback returns
+         * true.
+         *
+         * @param qrCode The result QR code after decoding.
+         * @return Returns true if qrCode hold valid information.
+         */
+        boolean isValid(String qrCode);
     }
 
     private void setCameraParameter() {
@@ -245,7 +254,9 @@
                         mReader.reset();
                     }
                     if (qrCode != null) {
-                        return qrCode.getText();
+                        if (mScannerCallback.isValid(qrCode.getText())) {
+                            return qrCode.getText();
+                        }
                     }
                 } catch (InterruptedException e) {
                     Thread.currentThread().interrupt();
diff --git a/src/com/android/settings/wifi/qrcode/QrDecorateView.java b/src/com/android/settings/wifi/qrcode/QrDecorateView.java
index 253bdb8..6952a63 100644
--- a/src/com/android/settings/wifi/qrcode/QrDecorateView.java
+++ b/src/com/android/settings/wifi/qrcode/QrDecorateView.java
@@ -17,10 +17,13 @@
 package com.android.settings.wifi.qrcode;
 
 import android.content.Context;
+import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Point;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.util.AttributeSet;
@@ -33,11 +36,26 @@
  * Draws the lines at the corner of the inner frame.
  */
 public class QrDecorateView extends View {
-    private static final float CORNER_STROKE_WIDTH = 3f;    // 3dp
-    private static final float CORNER_LINE_LENGTH = 20f;    // 20dp
+    private static final float CORNER_STROKE_WIDTH = 4f;    // 4dp
+    private static final float CORNER_LINE_LENGTH = 264f;   // 264dp
+    private static final float CORNER_RADIUS = 16f;         // 16dp
 
-    final private Paint mPaint;
-    private RectF mFrame;
+    final private int mCornerColor;
+    final private int mFocusedCornerColor;
+    final private int mBackgroundColor;
+
+    final private Paint mStrokePaint;
+    final private Paint mTransparentPaint;
+    final private Paint mBackgroundPaint;
+
+    final private float mRadius;
+
+    private Bitmap mMaskBitmap;
+    private Canvas mMaskCanvas;
+
+    private RectF mOuterFrame;
+    private RectF mInnerFrame;
+
     private boolean mFocused;
 
     public QrDecorateView(Context context) {
@@ -54,78 +72,66 @@
 
     public QrDecorateView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        final float strokeWidth = TypedValue.applyDimension(
-                TypedValue.COMPLEX_UNIT_DIP,
-                CORNER_STROKE_WIDTH,
-                getResources().getDisplayMetrics()
-        );
-        mPaint = new Paint();
-        mPaint.setStrokeWidth(strokeWidth);
+
         mFocused = false;
+        mRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS,
+                getResources().getDisplayMetrics());
+
+        mCornerColor = context.getResources().getColor(R.color.qr_corner_line_color);
+        mFocusedCornerColor = context.getResources().getColor(R.color.qr_focused_corner_line_color);
+        mBackgroundColor = context.getResources().getColor(R.color.qr_background_color);
+
+        mStrokePaint = new Paint();
+        mStrokePaint.setAntiAlias(true);
+
+        mTransparentPaint = new Paint();
+        mTransparentPaint.setAntiAlias(true);
+        mTransparentPaint.setColor(getResources().getColor(android.R.color.transparent));
+        mTransparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+
+        mBackgroundPaint = new Paint();
+        mBackgroundPaint.setColor(mBackgroundColor);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        if(mMaskBitmap == null) {
+            mMaskBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
+            mMaskCanvas = new Canvas(mMaskBitmap);
+        }
+
+        calculateFramePos();
     }
 
     @Override
     protected void onDraw(Canvas canvas) {
-        calculateFramePos();
-        final float cornerLineLength = TypedValue.applyDimension(
-                TypedValue.COMPLEX_UNIT_DIP,
-                CORNER_LINE_LENGTH,
-                getResources().getDisplayMetrics()
-        );
-        mPaint.setColor(mFocused ? Color.GREEN : Color.WHITE);
-        drawCorner(mFrame, cornerLineLength, canvas);
-        super.onDraw(canvas);
-    }
+        // Set frame line color.
+        mStrokePaint.setColor(mFocused ? mFocusedCornerColor : mCornerColor);
+        // Draw background color.
+        mMaskCanvas.drawColor(mBackgroundColor);
+        // Draw outer corner.
+        mMaskCanvas.drawRoundRect(mOuterFrame, mRadius, mRadius, mStrokePaint);
+        // Draw inner transparent corner.
+        mMaskCanvas.drawRoundRect(mInnerFrame, mRadius, mRadius, mTransparentPaint);
 
-    private void drawCorner(RectF frame, float lineLength, Canvas canvas) {
-        final float strokeWidth = TypedValue.applyDimension(
-                TypedValue.COMPLEX_UNIT_DIP,
-                CORNER_STROKE_WIDTH,
-                getResources().getDisplayMetrics()
-        );
-        // Draw top-left corner.
-        canvas.drawLine(
-                frame.left - strokeWidth / 2,
-                frame.top,
-                frame.left + lineLength,
-                frame.top,
-                mPaint);
-        canvas.drawLine(frame.left, frame.top, frame.left, frame.top + lineLength, mPaint);
-        // Draw top-right corner.
-        canvas.drawLine(
-                frame.right + strokeWidth / 2,
-                frame.top,
-                frame.right - lineLength,
-                frame.top,
-                mPaint);
-        canvas.drawLine(frame.right, frame.top, frame.right, frame.top + lineLength, mPaint);
-        // Draw bottom-left corner.
-        canvas.drawLine(
-                frame.left - strokeWidth / 2,
-                frame.bottom,
-                frame.left + lineLength,
-                frame.bottom,
-                mPaint);
-        canvas.drawLine(frame.left, frame.bottom, frame.left, frame.bottom - lineLength, mPaint);
-        // Draw bottom-right corner.
-        canvas.drawLine(
-                frame.right + strokeWidth / 2,
-                frame.bottom,
-                frame.right - lineLength,
-                frame.bottom,
-                mPaint);
-        canvas.drawLine(frame.right, frame.bottom, frame.right, frame.bottom - lineLength, mPaint);
+        canvas.drawBitmap(mMaskBitmap, 0, 0, mBackgroundPaint);
+        super.onDraw(canvas);
     }
 
     private void calculateFramePos() {
         final int centralX = getWidth() / 2;
         final int centralY = getHeight() / 2;
-        final float halfFrameWidth = getWidth() / 3;
-        mFrame = new RectF(
-                centralX - halfFrameWidth,
-                centralY - halfFrameWidth,
-                centralX + halfFrameWidth,
-                centralY + halfFrameWidth);
+        final float cornerLineLength = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                CORNER_LINE_LENGTH, getResources().getDisplayMetrics()) / 2;
+        final float strokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                CORNER_STROKE_WIDTH, getResources().getDisplayMetrics()) / 2;
+
+        mOuterFrame = new RectF(centralX - cornerLineLength, centralY - cornerLineLength,
+                centralX + cornerLineLength, centralY + cornerLineLength);
+        mInnerFrame = new RectF(mOuterFrame.left + strokeWidth, mOuterFrame.top + strokeWidth,
+                mOuterFrame.right - strokeWidth, mOuterFrame.bottom - strokeWidth);
     }
 
     // Draws green lines if focued. Otherwise, draws white lines.
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
index c98fbdb..5f23f0c 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
@@ -178,6 +178,8 @@
         controllers.add(new WifiTetherSecurityPreferenceController(context, listener));
         controllers.add(new WifiTetherPasswordPreferenceController(context, listener));
         controllers.add(new WifiTetherApBandPreferenceController(context, listener));
+        controllers.add(
+                new WifiTetherAutoOffPreferenceController(context, KEY_WIFI_TETHER_AUTO_OFF));
 
         return controllers;
     }
diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider
index ab06f75..447de00 100644
--- a/tests/robotests/assets/grandfather_not_implementing_index_provider
+++ b/tests/robotests/assets/grandfather_not_implementing_index_provider
@@ -54,6 +54,12 @@
 com.android.settings.notification.RedactionInterstitial$RedactionInterstitialFragment
 com.android.settings.notification.ZenModeEventRuleSettings
 com.android.settings.notification.ZenModeScheduleRuleSettings
+com.android.settings.notification.ZenCustomRuleNotificationsSettings
+com.android.settings.notification.ZenCustomRuleCallsSettings
+com.android.settings.notification.ZenCustomRuleConfigSettings
+com.android.settings.notification.ZenCustomRuleSettings
+com.android.settings.notification.ZenCustomRuleBlockedEffectsSettings
+com.android.settings.notification.ZenCustomRuleMessagesSettings
 com.android.settings.password.ChooseLockGeneric$ChooseLockGenericFragment
 com.android.settings.password.SetupChooseLockGeneric$InternalActivity$InternalSetupChooseLockGenericFragment
 com.android.settings.password.SetupChooseLockGeneric$SetupChooseLockGenericFragment
diff --git a/tests/robotests/res/layout/preference.xml b/tests/robotests/res/layout/preference.xml
index 3f73161..7ac733f 100644
--- a/tests/robotests/res/layout/preference.xml
+++ b/tests/robotests/res/layout/preference.xml
@@ -30,7 +30,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:singleLine="true"
-        android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
         android:textColor="?android:attr/textColorPrimary"
         android:ellipsize="marquee"
         android:fadingEdge="horizontal" />
@@ -43,7 +43,7 @@
         android:layout_alignStart="@android:id/title"
         android:visibility="gone"
         android:textAlignment="viewStart"
-        android:textAppearance="@android:style/TextAppearance.Material.Body1"
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
         android:textColor="?android:attr/textColorSecondary"
         android:maxLines="10" />
 
diff --git a/tests/robotests/src/com/android/settings/MasterClearTest.java b/tests/robotests/src/com/android/settings/MasterClearTest.java
index 388440e..749373b 100644
--- a/tests/robotests/src/com/android/settings/MasterClearTest.java
+++ b/tests/robotests/src/com/android/settings/MasterClearTest.java
@@ -43,7 +43,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewTreeObserver;
-import android.widget.Button;
 import android.widget.CheckBox;
 import android.widget.LinearLayout;
 import android.widget.ScrollView;
@@ -51,7 +50,6 @@
 import androidx.fragment.app.FragmentActivity;
 
 import com.android.settings.testutils.shadow.ShadowUtils;
-import com.google.android.setupcompat.item.FooterButton;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -387,7 +385,7 @@
     public void testOnGlobalLayout_shouldNotRemoveListener() {
         final ViewTreeObserver viewTreeObserver = mock(ViewTreeObserver.class);
         mMasterClear.mScrollView = mScrollView;
-        mMasterClear.mInitiateButton = mock(FooterButton.class);
+        doNothing().when(mMasterClear).onGlobalLayout();
         doReturn(true).when(mMasterClear).hasReachedBottom(any());
         when(mScrollView.getViewTreeObserver()).thenReturn(viewTreeObserver);
 
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBaseTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBaseTest.java
index dd7cde2..529c0ee 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBaseTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBaseTest.java
@@ -18,13 +18,13 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
 
 import android.app.Activity;
 import android.content.Context;
+import android.content.Intent;
 import android.os.UserManager;
 
 import androidx.preference.Preference;
@@ -40,12 +40,15 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowActivity;
+import org.robolectric.shadows.ShadowUserManager;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = ShadowUserManager.class)
 public class DefaultAppShortcutPreferenceControllerBaseTest {
 
-    @Mock
-    private UserManager mUserManager;
+    private ShadowUserManager mShadowUserManager;
     @Mock
     private AppInfoDashboardFragment mFragment;
     @Mock
@@ -57,8 +60,8 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mActivity = spy(Robolectric.setupActivity(Activity.class));
-        when(mActivity.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+        mActivity = Robolectric.setupActivity(Activity.class);
+        mShadowUserManager = shadowOf(mActivity.getSystemService(UserManager.class));
         mController = new TestPreferenceController(mActivity, mFragment);
         final String key = mController.getPreferenceKey();
         when(mPreference.getKey()).thenReturn(key);
@@ -66,28 +69,28 @@
 
     @Test
     public void getAvailabilityStatus_managedProfile_shouldReturnDisabled() {
-        when(mUserManager.isManagedProfile()).thenReturn(true);
+        mShadowUserManager.setManagedProfile(true);
 
         assertThat(mController.getAvailabilityStatus())
-            .isEqualTo(DefaultAppShortcutPreferenceControllerBase.DISABLED_FOR_USER);
+                .isEqualTo(DefaultAppShortcutPreferenceControllerBase.DISABLED_FOR_USER);
     }
 
     @Test
     public void getAvailabilityStatus_hasAppCapability_shouldReturnAvailable() {
         mController.capable = true;
-        when(mUserManager.isManagedProfile()).thenReturn(false);
+        mShadowUserManager.setManagedProfile(false);
 
         assertThat(mController.getAvailabilityStatus())
-            .isEqualTo(DefaultAppShortcutPreferenceControllerBase.AVAILABLE);
+                .isEqualTo(DefaultAppShortcutPreferenceControllerBase.AVAILABLE);
     }
 
     @Test
     public void getAvailabilityStatus_noAppCapability_shouldReturnDisabled() {
         mController.capable = false;
-        when(mUserManager.isManagedProfile()).thenReturn(false);
+        mShadowUserManager.setManagedProfile(false);
 
         assertThat(mController.getAvailabilityStatus()).isEqualTo(
-            DefaultAppShortcutPreferenceControllerBase.UNSUPPORTED_ON_DEVICE);
+                DefaultAppShortcutPreferenceControllerBase.UNSUPPORTED_ON_DEVICE);
     }
 
     @Test
@@ -111,13 +114,17 @@
 
     @Test
     public void handlePreferenceTreeClick_shouldStartDefaultAppSettings() {
+        final ShadowActivity shadowActivity = shadowOf(mActivity);
+
         mController.handlePreferenceTreeClick(mPreference);
 
-        verify(mActivity).startActivity(argThat(intent -> intent != null
-                && intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT).equals(
-                DefaultAppSettings.class.getName())
-                && intent.getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS)
-                .getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY).equals("TestKey")));
+        final Intent nextIntent = shadowActivity.getNextStartedActivity();
+        assertThat(nextIntent).isNotNull();
+        assertThat(nextIntent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)).isEqualTo(
+                DefaultAppSettings.class.getName());
+        assertThat(
+                nextIntent.getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS).getString(
+                        SettingsActivity.EXTRA_FRAGMENT_ARG_KEY)).isEqualTo("TestKey");
     }
 
     private class TestPreferenceController extends DefaultAppShortcutPreferenceControllerBase {
diff --git a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultBrowserPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultBrowserPreferenceControllerTest.java
index 7bfd299..03b3867 100644
--- a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultBrowserPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultBrowserPreferenceControllerTest.java
@@ -109,10 +109,16 @@
         doReturn(null).when(spyController).getDefaultAppIcon();
         final List<ResolveInfo> resolveInfos = new ArrayList<>();
         final CharSequence PACKAGE_NAME = "com.test.package";
-        final ResolveInfo info1 = spy(createResolveInfo(PACKAGE_NAME.toString()));
-        when(info1.loadLabel(mPackageManager)).thenReturn(PACKAGE_NAME);
+
+        // This ResolveInfo will return a non-null label from loadLabel.
+        final ResolveInfo info1 = createResolveInfo(PACKAGE_NAME.toString());
+        info1.nonLocalizedLabel = PACKAGE_NAME;
         resolveInfos.add(info1);
-        resolveInfos.add(createResolveInfo(PACKAGE_NAME.toString()));
+
+        // This ResolveInfo will return a null label from loadLabel.
+        final ResolveInfo info2 = createResolveInfo(PACKAGE_NAME.toString());
+        resolveInfos.add(info2);
+
         when(mPackageManager.getDefaultBrowserPackageNameAsUser(anyInt())).thenReturn(null);
         when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt()))
             .thenReturn(resolveInfos);
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothSliceBuilderTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothSliceBuilderTest.java
index 4deec56..4504d84 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothSliceBuilderTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothSliceBuilderTest.java
@@ -25,14 +25,12 @@
 
 import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
-import androidx.slice.SliceItem;
 import androidx.slice.SliceMetadata;
 import androidx.slice.SliceProvider;
 import androidx.slice.core.SliceAction;
 import androidx.slice.widget.SliceLiveData;
 
 import com.android.settings.R;
-import com.android.settings.testutils.SliceTester;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -60,7 +58,10 @@
     @Test
     public void getBluetoothSlice_correctSliceContent() {
         final Slice BluetoothSlice = BluetoothSliceBuilder.getSlice(mContext);
+
         final SliceMetadata metadata = SliceMetadata.from(mContext, BluetoothSlice);
+        assertThat(metadata.getTitle()).isEqualTo(
+                mContext.getString(R.string.bluetooth_settings_title));
 
         final List<SliceAction> toggles = metadata.getToggles();
         assertThat(toggles).hasSize(1);
@@ -69,9 +70,6 @@
         final IconCompat expectedToggleIcon = IconCompat.createWithResource(mContext,
                 R.drawable.ic_settings_bluetooth);
         assertThat(primaryAction.getIcon().toString()).isEqualTo(expectedToggleIcon.toString());
-
-        final List<SliceItem> sliceItems = BluetoothSlice.getItems();
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.bluetooth_settings_title));
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/bluetooth/RemoteDeviceNameDialogFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/RemoteDeviceNameDialogFragmentTest.java
index bd7f79e..c8467b2 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/RemoteDeviceNameDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/RemoteDeviceNameDialogFragmentTest.java
@@ -38,7 +38,6 @@
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Answers;
@@ -80,7 +79,6 @@
         return (AlertDialog) ShadowDialog.getLatestDialog();
     }
 
-    @Ignore("b/119592320")
     @Test
     public void deviceNameDisplayIsCorrect() {
         String deviceName = "ABC Corp Headphones";
@@ -96,7 +94,6 @@
         assertThat(negativeButton.isEnabled()).isTrue();
     }
 
-    @Ignore("b/119592320")
     @Test
     public void deviceNameEditSucceeds() {
         String deviceNameInitial = "ABC Corp Headphones";
@@ -119,7 +116,6 @@
         verify(mCachedDevice).setName(deviceNameModified);
     }
 
-    @Ignore("b/119592320")
     @Test
     public void deviceNameEditThenCancelDoesntRename() {
         String deviceNameInitial = "ABC Corp Headphones";
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionPreferenceControllerTest.java
index fc674f0b..0c74525 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionPreferenceControllerTest.java
@@ -16,8 +16,11 @@
 
 package com.android.settings.deviceinfo.firmwareversion;
 
+import static android.content.Context.CLIPBOARD_SERVICE;
+
 import static com.google.common.truth.Truth.assertThat;
 
+import android.content.ClipboardManager;
 import android.content.Context;
 import android.os.Build;
 
@@ -108,6 +111,17 @@
         assertThat(mController.isSliceable()).isTrue();
     }
 
+    @Test
+    public void copy_shouldCopyVersionNumberToClipboard() {
+        mController.copy();
+
+        final Context context = RuntimeEnvironment.application;
+        final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(
+                CLIPBOARD_SERVICE);
+        final CharSequence data = clipboard.getPrimaryClip().getItemAt(0).getText();
+        assertThat(data.toString()).isEqualTo(Build.VERSION.RELEASE);
+    }
+
     @Implements(FirmwareVersionDialogFragment.class)
     public static class ShadowFirmwareVersionDialogFragment {
 
diff --git a/tests/robotests/src/com/android/settings/flashlight/FlashlightSliceTest.java b/tests/robotests/src/com/android/settings/flashlight/FlashlightSliceTest.java
index fe7a685..224d2ee 100644
--- a/tests/robotests/src/com/android/settings/flashlight/FlashlightSliceTest.java
+++ b/tests/robotests/src/com/android/settings/flashlight/FlashlightSliceTest.java
@@ -23,14 +23,12 @@
 import android.provider.Settings;
 
 import androidx.slice.Slice;
-import androidx.slice.SliceItem;
 import androidx.slice.SliceMetadata;
 import androidx.slice.SliceProvider;
 import androidx.slice.core.SliceAction;
 import androidx.slice.widget.SliceLiveData;
 
 import com.android.settings.R;
-import com.android.settings.testutils.SliceTester;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -57,13 +55,13 @@
     public void getFlashlightSlice_correctData() {
         Settings.Secure.putInt(
                 mContext.getContentResolver(), Settings.Secure.FLASHLIGHT_AVAILABLE, 1);
+
         final Slice slice = new FlashlightSlice(mContext).getSlice();
+
         final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+        assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.power_flashlight));
 
         final List<SliceAction> toggles = metadata.getToggles();
         assertThat(toggles).hasSize(1);
-
-        final List<SliceItem> sliceItems = slice.getItems();
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.power_flashlight));
     }
 }
diff --git a/tests/robotests/src/com/android/settings/gestures/WakeLockScreenGesturePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/WakeLockScreenGesturePreferenceControllerTest.java
index 10a3d90..cd21351 100644
--- a/tests/robotests/src/com/android/settings/gestures/WakeLockScreenGesturePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/gestures/WakeLockScreenGesturePreferenceControllerTest.java
@@ -71,7 +71,7 @@
 
     @Test
     public void getAvailabilityStatus_gestureNotSupported_UNSUPPORTED_ON_DEVICE() {
-        when(mAmbientDisplayConfiguration.wakeLockScreenGestureAvailable()).thenReturn(false);
+        when(mAmbientDisplayConfiguration.wakeScreenGestureAvailable()).thenReturn(false);
         final int availabilityStatus = mController.getAvailabilityStatus();
 
         assertThat(availabilityStatus).isEqualTo(UNSUPPORTED_ON_DEVICE);
@@ -79,7 +79,7 @@
 
     @Test
     public void getAvailabilityStatus_gestureSupported_AVAILABLE() {
-        when(mAmbientDisplayConfiguration.wakeLockScreenGestureAvailable()).thenReturn(true);
+        when(mAmbientDisplayConfiguration.wakeScreenGestureAvailable()).thenReturn(true);
         final int availabilityStatus = mController.getAvailabilityStatus();
 
         assertThat(availabilityStatus).isEqualTo(AVAILABLE);
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/BatterySliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/BatterySliceTest.java
index 4699587..289a57d 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/BatterySliceTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/BatterySliceTest.java
@@ -26,14 +26,12 @@
 
 import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
-import androidx.slice.SliceItem;
 import androidx.slice.SliceMetadata;
 import androidx.slice.SliceProvider;
 import androidx.slice.core.SliceAction;
 import androidx.slice.widget.SliceLiveData;
 
 import com.android.settings.R;
-import com.android.settings.testutils.SliceTester;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -41,8 +39,6 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
-import java.util.List;
-
 @RunWith(RobolectricTestRunner.class)
 public class BatterySliceTest {
 
@@ -64,14 +60,16 @@
         doNothing().when(mBatterySlice).loadBatteryInfo();
         doReturn("10%").when(mBatterySlice).getBatteryPercentString();
         doReturn("test").when(mBatterySlice).getSummary();
+
         final Slice slice = mBatterySlice.getSlice();
+
         final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+        assertThat(metadata.getTitle()).isEqualTo(
+                mContext.getString(R.string.power_usage_summary_title));
+
         final SliceAction primaryAction = metadata.getPrimaryAction();
         final IconCompat expectedIcon = IconCompat.createWithResource(mContext,
                 R.drawable.ic_settings_battery);
         assertThat(primaryAction.getIcon().toString()).isEqualTo(expectedIcon.toString());
-
-        final List<SliceItem> sliceItems = slice.getItems();
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.power_usage_summary_title));
     }
 }
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/DataUsageSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/DataUsageSliceTest.java
index 1a3be6c..588b7aa 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/DataUsageSliceTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/DataUsageSliceTest.java
@@ -69,24 +69,31 @@
         ShadowDataUsageUtils.HAS_SIM = true;
         doReturn(DATA_USAGE_TITLE).when(mDataUsageSlice).getDataUsageText(any());
         doReturn(DATA_USAGE_SUMMARY).when(mDataUsageSlice).getCycleTime(any());
+
         final Slice slice = mDataUsageSlice.getSlice();
+
         final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+        assertThat(metadata.getTitle()).isEqualTo(
+                mContext.getString(R.string.data_usage_summary_title));
+
         final SliceAction primaryAction = metadata.getPrimaryAction();
         final IconCompat expectedIcon = IconCompat.createWithResource(mContext,
                 R.drawable.ic_settings_data_usage);
         assertThat(primaryAction.getIcon().toString()).isEqualTo(expectedIcon.toString());
-
-        final List<SliceItem> sliceItems = slice.getItems();
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.data_usage_summary_title));
     }
 
     @Test
     public void getSlice_hasNoSim_shouldShowNoSimCard() {
         ShadowDataUsageUtils.HAS_SIM = false;
-        final Slice slice = mDataUsageSlice.getSlice();
-        final List<SliceItem> sliceItems = slice.getItems();
 
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.data_usage_summary_title));
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.no_sim_card));
+        final Slice slice = mDataUsageSlice.getSlice();
+
+        final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+        assertThat(metadata.getTitle()).isEqualTo(
+                mContext.getString(R.string.data_usage_summary_title));
+
+        final List<SliceItem> sliceItems = slice.getItems();
+        SliceTester.assertAnySliceItemContainsTitle(sliceItems,
+                mContext.getString(R.string.no_sim_card));
     }
 }
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/DeviceInfoSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/DeviceInfoSliceTest.java
index c1d7329..ddc7218 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/DeviceInfoSliceTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/DeviceInfoSliceTest.java
@@ -70,24 +70,30 @@
         final String phoneNumber = "1111111111";
         doReturn(mSubscriptionInfo).when(mDeviceInfoSlice).getFirstSubscriptionInfo();
         doReturn(phoneNumber).when(mDeviceInfoSlice).getPhoneNumber();
+
         final Slice slice = mDeviceInfoSlice.getSlice();
+
         final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+        assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.device_info_label));
+
         final SliceAction primaryAction = metadata.getPrimaryAction();
         final IconCompat expectedIcon = IconCompat.createWithResource(mContext,
                 R.drawable.ic_info_outline_24dp);
         assertThat(primaryAction.getIcon().toString()).isEqualTo(expectedIcon.toString());
 
         final List<SliceItem> sliceItems = slice.getItems();
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.device_info_label));
-        SliceTester.assertTitle(sliceItems, phoneNumber);
+        SliceTester.assertAnySliceItemContainsTitle(sliceItems, phoneNumber);
     }
 
     @Test
     public void getSlice_hasNoSubscriptionInfo_shouldShowUnknown() {
         final Slice slice = mDeviceInfoSlice.getSlice();
-        final List<SliceItem> sliceItems = slice.getItems();
 
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.device_info_label));
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.device_info_default));
+        final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+        assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.device_info_label));
+
+        final List<SliceItem> sliceItems = slice.getItems();
+        SliceTester.assertAnySliceItemContainsTitle(sliceItems,
+                mContext.getString(R.string.device_info_default));
     }
 }
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/StorageSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/StorageSliceTest.java
index dc125e2..a758a94 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/StorageSliceTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/StorageSliceTest.java
@@ -26,14 +26,12 @@
 
 import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
-import androidx.slice.SliceItem;
 import androidx.slice.SliceMetadata;
 import androidx.slice.SliceProvider;
 import androidx.slice.core.SliceAction;
 import androidx.slice.widget.SliceLiveData;
 
 import com.android.settings.R;
-import com.android.settings.testutils.SliceTester;
 import com.android.settingslib.deviceinfo.PrivateStorageInfo;
 
 import org.junit.Before;
@@ -42,8 +40,6 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
-import java.util.List;
-
 @RunWith(RobolectricTestRunner.class)
 public class StorageSliceTest {
     private static final String USED_BYTES_TEXT = "test used bytes";
@@ -68,14 +64,15 @@
         doReturn(info).when(mStorageSlice).getPrivateStorageInfo();
         doReturn(USED_BYTES_TEXT).when(mStorageSlice).getStorageUsedText(any());
         doReturn(SUMMARY_TEXT).when(mStorageSlice).getStorageSummaryText(any());
+
         final Slice slice = mStorageSlice.getSlice();
+
         final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+        assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.storage_label));
+
         final SliceAction primaryAction = metadata.getPrimaryAction();
         final IconCompat expectedIcon = IconCompat.createWithResource(mContext,
                 R.drawable.ic_homepage_storage);
         assertThat(primaryAction.getIcon().toString()).isEqualTo(expectedIcon.toString());
-
-        final List<SliceItem> sliceItems = slice.getItems();
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.storage_label));
     }
 }
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
index 12ae707..bc34fd5 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
@@ -106,8 +106,8 @@
 
         final Slice slice = mBluetoothDevicesSlice.getSlice();
 
-        final List<SliceItem> sliceItems = slice.getItems();
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.bluetooth_devices));
+        final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+        assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.bluetooth_devices));
     }
 
     @Test
@@ -118,7 +118,7 @@
         final Slice slice = mBluetoothDevicesSlice.getSlice();
 
         final List<SliceItem> sliceItems = slice.getItems();
-        SliceTester.assertTitle(sliceItems, BLUETOOTH_MOCK_TITLE);
+        SliceTester.assertAnySliceItemContainsTitle(sliceItems, BLUETOOTH_MOCK_TITLE);
     }
 
     @Test
@@ -129,7 +129,7 @@
         final Slice slice = mBluetoothDevicesSlice.getSlice();
 
         final List<SliceItem> sliceItems = slice.getItems();
-        SliceTester.assertTitle(sliceItems,
+        SliceTester.assertAnySliceItemContainsTitle(sliceItems,
                 mContext.getString(R.string.bluetooth_pairing_pref_title));
     }
 
@@ -139,8 +139,9 @@
 
         final Slice slice = mBluetoothDevicesSlice.getSlice();
 
-        final List<SliceItem> sliceItems = slice.getItems();
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.no_bluetooth_devices));
+        final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+        assertThat(metadata.getTitle()).isEqualTo(
+                mContext.getString(R.string.no_bluetooth_devices));
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/LowStorageSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/LowStorageSliceTest.java
index 3bd29b9..99f2723 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/LowStorageSliceTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/LowStorageSliceTest.java
@@ -23,12 +23,11 @@
 import android.content.Context;
 
 import androidx.slice.Slice;
-import androidx.slice.SliceItem;
+import androidx.slice.SliceMetadata;
 import androidx.slice.SliceProvider;
 import androidx.slice.widget.SliceLiveData;
 
 import com.android.settings.R;
-import com.android.settings.testutils.SliceTester;
 import com.android.settingslib.deviceinfo.PrivateStorageInfo;
 import com.android.settingslib.deviceinfo.StorageVolumeProvider;
 
@@ -43,8 +42,6 @@
 import org.robolectric.annotation.Implements;
 import org.robolectric.annotation.Resetter;
 
-import java.util.List;
-
 @RunWith(RobolectricTestRunner.class)
 public class LowStorageSliceTest {
 
@@ -73,8 +70,8 @@
 
         final Slice slice = mLowStorageSlice.getSlice();
 
-        final List<SliceItem> sliceItems = slice.getItems();
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.storage_menu_free));
+        final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+        assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.storage_menu_free));
     }
 
     @Test
@@ -94,8 +91,8 @@
 
         final Slice slice = mLowStorageSlice.getSlice();
 
-        final List<SliceItem> sliceItems = slice.getItems();
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.storage_settings));
+        final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+        assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.storage_settings));
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/location/LocationSliceTest.java b/tests/robotests/src/com/android/settings/location/LocationSliceTest.java
index 427307d..0618cd9 100644
--- a/tests/robotests/src/com/android/settings/location/LocationSliceTest.java
+++ b/tests/robotests/src/com/android/settings/location/LocationSliceTest.java
@@ -6,14 +6,12 @@
 
 import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
-import androidx.slice.SliceItem;
 import androidx.slice.SliceMetadata;
 import androidx.slice.SliceProvider;
 import androidx.slice.core.SliceAction;
 import androidx.slice.widget.SliceLiveData;
 
 import com.android.settings.R;
-import com.android.settings.testutils.SliceTester;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -39,7 +37,10 @@
     @Test
     public void getLocationSlice_correctSliceContent() {
         final Slice LocationSlice = new LocationSlice(mContext).getSlice();
+
         final SliceMetadata metadata = SliceMetadata.from(mContext, LocationSlice);
+        assertThat(metadata.getTitle()).isEqualTo(
+                mContext.getString(R.string.location_settings_title));
 
         final List<SliceAction> toggles = metadata.getToggles();
         assertThat(toggles).isEmpty();
@@ -48,8 +49,5 @@
         final IconCompat expectedToggleIcon = IconCompat.createWithResource(mContext,
                 R.drawable.ic_signal_location);
         assertThat(primaryAction.getIcon().toString()).isEqualTo(expectedToggleIcon.toString());
-
-        final List<SliceItem> sliceItems = LocationSlice.getItems();
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.location_settings_title));
     }
 }
diff --git a/tests/robotests/src/com/android/settings/location/TopLevelLocationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/TopLevelLocationPreferenceControllerTest.java
new file mode 100644
index 0000000..68e7f88
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/location/TopLevelLocationPreferenceControllerTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.location;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.location.LocationManager;
+
+import com.android.settings.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class TopLevelLocationPreferenceControllerTest {
+    private static final String PREFERENCE_KEY = "top_level_location";
+    private Context mContext;
+    private TopLevelLocationPreferenceController mController;
+    private LocationManager mLocationManager;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mController = new TopLevelLocationPreferenceController(mContext, PREFERENCE_KEY);
+        mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
+    }
+
+    @Test
+    public void isAvailable_byDefault_shouldReturnTrue() {
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void getSummary_whenLocationIsOff_shouldReturnStringForOff() {
+        mLocationManager.setLocationEnabledForUser(false, android.os.Process.myUserHandle());
+        assertThat(mController.getSummary()).isEqualTo(
+                mContext.getString(R.string.location_settings_summary_location_off));
+    }
+
+    @Test
+    public void getSummary_whenLocationIsOn_shouldShowLoadingString() {
+        mLocationManager.setLocationEnabledForUser(true, android.os.Process.myUserHandle());
+        assertThat(mController.getSummary()).isEqualTo(
+                mContext.getString(R.string.location_settings_loading_app_permission_stats));
+    }
+
+    @Test
+    public void getSummary_whenLocationAppCountIsOne_shouldShowSingularString() {
+        final int LOCATION_APP_COUNT = 1;
+        mLocationManager.setLocationEnabledForUser(true, android.os.Process.myUserHandle());
+        mController.setLocationAppCount(LOCATION_APP_COUNT);
+        assertThat(mController.getSummary()).isEqualTo(
+                mContext.getResources().getQuantityString(
+                        R.plurals.location_settings_summary_location_on,
+                        LOCATION_APP_COUNT, LOCATION_APP_COUNT));
+    }
+
+    @Test
+    public void getSummary_whenLocationAppCountIsGreaterThanOne_shouldShowPluralString() {
+        final int LOCATION_APP_COUNT = 5;
+        mLocationManager.setLocationEnabledForUser(true, android.os.Process.myUserHandle());
+        mController.setLocationAppCount(LOCATION_APP_COUNT);
+        assertThat(mController.getSummary()).isEqualTo(
+                mContext.getResources().getQuantityString(
+                        R.plurals.location_settings_summary_location_on,
+                        LOCATION_APP_COUNT, LOCATION_APP_COUNT));
+    }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/network/VpnPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/VpnPreferenceControllerTest.java
index 5144877..89d0465fa 100644
--- a/tests/robotests/src/com/android/settings/network/VpnPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/VpnPreferenceControllerTest.java
@@ -34,6 +34,7 @@
 import android.net.NetworkRequest;
 import android.os.IBinder;
 import android.os.UserHandle;
+import android.os.ServiceManager;
 import android.provider.SettingsSlicesContract;
 
 import androidx.lifecycle.LifecycleOwner;
@@ -50,7 +51,6 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
-import org.robolectric.shadows.ShadowServiceManager;
 
 @RunWith(RobolectricTestRunner.class)
 public class VpnPreferenceControllerTest {
@@ -78,7 +78,7 @@
                 .thenReturn(mConnectivityManager);
         when(mBinder.queryLocalInterface("android.net.IConnectivityManager"))
                 .thenReturn(mConnectivityManagerService);
-        ShadowServiceManager.addService(Context.CONNECTIVITY_SERVICE, mBinder);
+        ServiceManager.addService(Context.CONNECTIVITY_SERVICE, mBinder);
         when(mScreen.findPreference(anyString())).thenReturn(mPreference);
 
         mController = spy(new VpnPreferenceController(mContext));
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 9b8a3e3..ba8be90 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java
@@ -125,6 +125,18 @@
     }
 
     @Test
+    public void updateState_updateByNetworkMode_useDefaultValue() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.PREFERRED_NETWORK_MODE + SUB_ID,
+                TelephonyManager.NETWORK_MODE_LTE_GSM_WCDMA);
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.getValue()).isEqualTo(
+                String.valueOf(TelephonyManager.NETWORK_MODE_LTE_GSM_WCDMA));
+    }
+
+    @Test
     public void onPreferenceChange_updateSuccess() {
         doReturn(true).when(mTelephonyManager).setPreferredNetworkType(SUB_ID,
                 TelephonyManager.NETWORK_MODE_LTE_GSM_WCDMA);
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeBackendTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeBackendTest.java
index 6169f92..6cf19a6 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModeBackendTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeBackendTest.java
@@ -1,26 +1,58 @@
 package com.android.settings.notification;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static junit.framework.Assert.assertEquals;
 
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
 import android.app.AutomaticZenRule;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.database.Cursor;
 import android.provider.Settings;
 import android.service.notification.ZenModeConfig;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
 
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
-import org.robolectric.RobolectricTestRunner;
 
 @RunWith(RobolectricTestRunner.class)
 public class ZenModeBackendTest {
+    @Mock
+    private NotificationManager mNotificationManager;
 
     private static final String GENERIC_RULE_NAME = "test";
     private static final String DEFAULT_ID_1 = ZenModeConfig.EVENTS_DEFAULT_RULE_ID;
     private static final String DEFAULT_ID_2 = ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID;
 
+    private Context mContext;
+    private ZenModeBackend mBackend;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowApplication = ShadowApplication.getInstance();
+        shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
+
+        mContext = RuntimeEnvironment.application;
+        mBackend = new ZenModeBackend(mContext);
+    }
+
     @Test
     public void updateState_checkRuleOrderingDescending() {
         final int NUM_RULES = 4;
@@ -63,6 +95,39 @@
         }
     }
 
+    @Test
+    public void updateSummary_nullCursorValues() {
+        Cursor testCursorWithNullValues = createMockCursor(3);
+        when(testCursorWithNullValues.getString(0)).thenReturn(null);
+
+        // expected - no null values
+        List<String> contacts = mBackend.getStarredContacts(testCursorWithNullValues);
+        for (String contact : contacts) {
+            assertThat(contact).isNotNull();
+        }
+    }
+
+    private Cursor createMockCursor(int size) {
+        Cursor mockCursor = mock(Cursor.class);
+        when(mockCursor.moveToFirst()).thenReturn(true);
+
+        doAnswer(new Answer<Boolean>() {
+            int count = 0;
+
+            @Override
+            public Boolean answer(InvocationOnMock invocation) throws Throwable {
+                if (count < size) {
+                    count++;
+                    return true;
+                }
+                return false;
+            }
+
+        }).when(mockCursor).moveToNext();
+
+        return mockCursor;
+    }
+
     private Map.Entry<String, AutomaticZenRule>[] populateAutoZenRulesAscendingCreationTime(
             int numRules, boolean addDefaultRules) {
         Map<String, AutomaticZenRule> ruleMap = new HashMap<>();
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeMessagesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeMessagesPreferenceControllerTest.java
index 5589cae..808766d 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModeMessagesPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeMessagesPreferenceControllerTest.java
@@ -17,12 +17,16 @@
 package com.android.settings.notification;
 
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.NotificationManager;
 import android.content.Context;
 
+import androidx.preference.Preference;
+
 import com.android.settingslib.core.lifecycle.Lifecycle;
 
 import org.junit.Before;
@@ -67,11 +71,10 @@
         assertTrue(mController.isAvailable());
     }
 
-// TODO: (b/111475013 - beverlyt) set messages summary
-//    @Test
-//    public void testHasSummary() {
-//        Preference pref = mock(Preference.class);
-//        mController.updateState(pref);
-//        verify(pref).setSummary(any());
-//    }
+    @Test
+    public void testHasSummary() {
+        Preference pref = mock(Preference.class);
+        mController.updateState(pref);
+        verify(pref).setSummary(any());
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeSettingsFooterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeSettingsFooterPreferenceControllerTest.java
index 516d98f..3451868 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModeSettingsFooterPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeSettingsFooterPreferenceControllerTest.java
@@ -22,9 +22,8 @@
 import static android.provider.Settings.Global.ZEN_MODE_NO_INTERRUPTIONS;
 import static android.provider.Settings.Global.ZEN_MODE_OFF;
 
-import static org.junit.Assert.assertTrue;
-
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -40,6 +39,7 @@
 import android.service.notification.ZenModeConfig.ZenRule;
 import android.util.ArrayMap;
 
+import androidx.fragment.app.FragmentManager;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
@@ -92,8 +92,8 @@
         mContentResolver = RuntimeEnvironment.application.getContentResolver();
         when(mNotificationManager.getZenModeConfig()).thenReturn(mZenModeConfig);
 
-        mController =
-                new ZenModeSettingsFooterPreferenceController(mContext, mock(Lifecycle.class));
+        mController = new ZenModeSettingsFooterPreferenceController(mContext, mock(Lifecycle.class),
+                mock(FragmentManager.class));
         ReflectionHelpers.setField(mZenModeConfig, AUTOMATIC_RULES_FIELD, mInjectedAutomaticRules);
         ReflectionHelpers.setField(mController, "mZenModeConfigWrapper", mConfigWrapper);
 
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeSliceBuilderTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeSliceBuilderTest.java
index bc9e370..ac185ac 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModeSliceBuilderTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeSliceBuilderTest.java
@@ -26,14 +26,12 @@
 import android.provider.Settings;
 
 import androidx.slice.Slice;
-import androidx.slice.SliceItem;
 import androidx.slice.SliceMetadata;
 import androidx.slice.SliceProvider;
 import androidx.slice.core.SliceAction;
 import androidx.slice.widget.SliceLiveData;
 
 import com.android.settings.R;
-import com.android.settings.testutils.SliceTester;
 import com.android.settings.testutils.shadow.ShadowNotificationManager;
 
 import org.junit.Before;
@@ -62,16 +60,16 @@
     @Test
     public void getZenModeSlice_correctSliceContent() {
         final Slice dndSlice = ZenModeSliceBuilder.getSlice(mContext);
+
         final SliceMetadata metadata = SliceMetadata.from(mContext, dndSlice);
+        assertThat(metadata.getTitle()).isEqualTo(
+                mContext.getString(R.string.zen_mode_settings_title));
 
         final List<SliceAction> toggles = metadata.getToggles();
         assertThat(toggles).hasSize(1);
 
         final SliceAction primaryAction = metadata.getPrimaryAction();
         assertThat(primaryAction.getIcon()).isNull();
-
-        final List<SliceItem> sliceItems = dndSlice.getItems();
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.zen_mode_settings_title));
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeStarredContactsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeStarredContactsPreferenceControllerTest.java
index db551a2..fd6e639 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModeStarredContactsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeStarredContactsPreferenceControllerTest.java
@@ -30,7 +30,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.database.Cursor;
 
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
@@ -49,7 +48,6 @@
 import org.robolectric.shadows.ShadowApplication;
 import org.robolectric.util.ReflectionHelpers;
 
-import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
 public class ZenModeStarredContactsPreferenceControllerTest {
@@ -157,18 +155,6 @@
     }
 
     @Test
-    public void updateSummary_nullCursorValues() {
-        Cursor testCursorWithNullValues = createMockCursor(3);
-        when(testCursorWithNullValues.getString(0)).thenReturn(null);
-
-        // expected - no null  values
-        List<String> contacts = mMessagesController.getStarredContacts(testCursorWithNullValues);
-        for (String contact : contacts) {
-            assertThat(contact).isNotNull();
-        }
-    }
-
-    @Test
     public void nullPreference_displayPreference() {
         when(mPreferenceScreen.findPreference(mMessagesController.getPreferenceKey()))
                 .thenReturn(null);
@@ -176,25 +162,4 @@
         // should not throw a null pointer
         mMessagesController.displayPreference(mPreferenceScreen);
     }
-
-    private Cursor createMockCursor(int size) {
-        Cursor mockCursor = mock(Cursor.class);
-        when(mockCursor.moveToFirst()).thenReturn(true);
-
-        doAnswer(new Answer<Boolean>() {
-            int count = 0;
-
-            @Override
-            public Boolean answer(InvocationOnMock invocation) {
-                if (count < size) {
-                    count++;
-                    return true;
-                }
-                return false;
-            }
-
-        }).when(mockCursor).moveToNext();
-
-        return mockCursor;
-    }
 }
diff --git a/tests/robotests/src/com/android/settings/notification/ZenRuleCustomPolicyPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenRuleCustomPolicyPreferenceControllerTest.java
new file mode 100644
index 0000000..5d3a601
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ZenRuleCustomPolicyPreferenceControllerTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.notification;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationManager;
+import android.content.Context;
+import android.service.notification.ZenPolicy;
+
+import androidx.preference.PreferenceScreen;
+
+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.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+public class ZenRuleCustomPolicyPreferenceControllerTest extends
+        ZenRuleCustomPrefContrTestBase {
+
+    @Mock
+    private ZenModeBackend mBackend;
+    @Mock
+    private NotificationManager mNotificationManager;
+    @Mock
+    private ZenCustomRadioButtonPreference mockPref;
+    @Mock
+    private PreferenceScreen mScreen;
+
+    private Context mContext;
+    private ZenRuleCustomPolicyPreferenceController mController;
+
+    @Override
+    AbstractZenCustomRulePreferenceController getController() {
+        return mController;
+    }
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowApplication = ShadowApplication.getInstance();
+        shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
+
+        mContext = RuntimeEnvironment.application;
+        mController = new ZenRuleCustomPolicyPreferenceController(mContext, mock(Lifecycle.class),
+                PREF_KEY);
+        ReflectionHelpers.setField(mController, "mBackend", mBackend);
+        when(mBackend.getAutomaticZenRule(RULE_ID)).thenReturn(mRule);
+        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mockPref);
+        mController.displayPreference(mScreen);
+    }
+
+    @Test
+    public void updateState_nullZenPolicy() {
+        updateControllerZenPolicy(null);
+        mController.updateState(mockPref);
+        verify(mockPref).setChecked(false);
+    }
+
+    @Test
+    public void updateState_hasZenPolicy() {
+        updateControllerZenPolicy(new ZenPolicy.Builder().build());
+        mController.updateState(mockPref);
+        verify(mockPref).setChecked(true);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/ZenRuleCustomPrefContrTestBase.java b/tests/robotests/src/com/android/settings/notification/ZenRuleCustomPrefContrTestBase.java
new file mode 100644
index 0000000..10472a5
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ZenRuleCustomPrefContrTestBase.java
@@ -0,0 +1,40 @@
+/*
+ * 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.notification;
+
+import android.app.AutomaticZenRule;
+import android.app.NotificationManager;
+import android.service.notification.ZenPolicy;
+
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+abstract class ZenRuleCustomPrefContrTestBase {
+    public static final String RULE_ID = "test_rule_id";
+    public static final String PREF_KEY = "main_pref";
+
+    AutomaticZenRule mRule = new AutomaticZenRule("test", null, null, null, null,
+            NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+
+    abstract AbstractZenCustomRulePreferenceController getController();
+
+    void updateControllerZenPolicy(ZenPolicy policy) {
+        mRule.setZenPolicy(policy);
+        getController().onResume(mRule, RULE_ID);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/ZenRuleCustomSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenRuleCustomSwitchPreferenceControllerTest.java
new file mode 100644
index 0000000..e15eb60
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ZenRuleCustomSwitchPreferenceControllerTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.notification;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationManager;
+import android.content.Context;
+import android.service.notification.ZenPolicy;
+
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+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.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+public class ZenRuleCustomSwitchPreferenceControllerTest extends ZenRuleCustomPrefContrTestBase {
+    private ZenRuleCustomSwitchPreferenceController mController;
+
+    @Mock
+    private ZenModeBackend mBackend;
+    @Mock
+    private NotificationManager mNotificationManager;
+    @Mock
+    private SwitchPreference mockPref;
+    @Mock
+    private NotificationManager.Policy mPolicy;
+    @Mock
+    private PreferenceScreen mPreferenceScreen;
+
+    private Context mContext;
+
+    @Override
+    AbstractZenCustomRulePreferenceController getController() {
+        return mController;
+    }
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowApplication = ShadowApplication.getInstance();
+        shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
+
+        mContext = RuntimeEnvironment.application;
+        when(mNotificationManager.getNotificationPolicy()).thenReturn(mPolicy);
+        mController = new ZenRuleCustomSwitchPreferenceController(mContext, mock(Lifecycle.class),
+                PREF_KEY, ZenPolicy.PRIORITY_CATEGORY_ALARMS, 0);
+        ReflectionHelpers.setField(mController, "mBackend", mBackend);
+
+        when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
+                .thenReturn(mockPref);
+        mController.displayPreference(mPreferenceScreen);
+    }
+
+    @Test
+    public void onPreferenceChanged_enable() {
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .allowMedia(false)
+                .allowAlarms(false)
+                .build());
+        mController.onPreferenceChange(mockPref, true);
+        mRule.setZenPolicy(new ZenPolicy.Builder()
+                .allowMedia(false)
+                .allowAlarms(true)
+                .build());
+        verify(mBackend).updateZenRule(RULE_ID, mRule);
+    }
+
+    @Test
+    public void onPreferenceChanged_disable() {
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .allowMedia(false)
+                .allowAlarms(true)
+                .build());
+        mController.onPreferenceChange(mockPref, false);
+        mRule.setZenPolicy(new ZenPolicy.Builder()
+                .allowMedia(false)
+                .allowAlarms(false)
+                .build());
+        verify(mBackend).updateZenRule(RULE_ID, mRule);
+    }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/notification/ZenRuleDefaultPolicyPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenRuleDefaultPolicyPreferenceControllerTest.java
new file mode 100644
index 0000000..e350793
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ZenRuleDefaultPolicyPreferenceControllerTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.notification;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationManager;
+import android.content.Context;
+import android.service.notification.ZenPolicy;
+
+import androidx.preference.PreferenceScreen;
+
+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.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+public class ZenRuleDefaultPolicyPreferenceControllerTest extends
+        ZenRuleCustomPrefContrTestBase {
+
+    @Mock
+    private ZenModeBackend mBackend;
+    @Mock
+    private NotificationManager mNotificationManager;
+    @Mock
+    private ZenCustomRadioButtonPreference mockPref;
+    @Mock
+    private PreferenceScreen mScreen;
+
+    private Context mContext;
+    private ZenRuleDefaultPolicyPreferenceController mController;
+
+    @Override
+    AbstractZenCustomRulePreferenceController getController() {
+        return mController;
+    }
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowApplication = ShadowApplication.getInstance();
+        shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
+
+        mContext = RuntimeEnvironment.application;
+        mController = new ZenRuleDefaultPolicyPreferenceController(mContext, mock(Lifecycle.class),
+                PREF_KEY);
+        ReflectionHelpers.setField(mController, "mBackend", mBackend);
+        when(mBackend.getAutomaticZenRule(RULE_ID)).thenReturn(mRule);
+        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mockPref);
+        mController.displayPreference(mScreen);
+    }
+
+    @Test
+    public void updateState_nullZenPolicy() {
+        updateControllerZenPolicy(null);
+        mController.updateState(mockPref);
+        verify(mockPref).setChecked(true);
+    }
+
+    @Test
+    public void updateState_hasZenPolicy() {
+        updateControllerZenPolicy(new ZenPolicy.Builder().build());
+        mController.updateState(mockPref);
+        verify(mockPref).setChecked(false);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/ZenRulePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenRulePreferenceControllerTest.java
new file mode 100644
index 0000000..5d070e5
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ZenRulePreferenceControllerTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.notification;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.AutomaticZenRule;
+import android.app.NotificationManager;
+import android.content.Context;
+
+import androidx.preference.PreferenceScreen;
+
+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.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+public class ZenRulePreferenceControllerTest {
+
+    @Mock
+    private ZenModeBackend mBackend;
+    @Mock
+    private NotificationManager mNotificationManager;
+    @Mock
+    private ZenCustomRadioButtonPreference mockPref;
+    @Mock
+    private PreferenceScreen mScreen;
+
+    private Context mContext;
+    private TestablePreferenceController mController;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowApplication = ShadowApplication.getInstance();
+        shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
+
+        mContext = RuntimeEnvironment.application;
+        mController = new TestablePreferenceController(mContext,"test", mock(Lifecycle.class));
+        ReflectionHelpers.setField(mController, "mBackend", mBackend);
+        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mockPref);
+        mController.displayPreference(mScreen);
+    }
+
+    @Test
+    public void onResumeTest() {
+        final String id = "testid";
+        final AutomaticZenRule rule = new AutomaticZenRule("test", null, null,
+                null, null, NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+
+        assertTrue(mController.mRule == null);
+        assertTrue(mController.mId == null);
+
+        mController.onResume(rule, id);
+
+        assertEquals(mController.mId, id);
+        assertEquals(mController.mRule, rule);
+    }
+
+    class TestablePreferenceController extends AbstractZenCustomRulePreferenceController {
+        TestablePreferenceController(Context context, String key,
+                Lifecycle lifecycle) {
+            super(context, key, lifecycle);
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/ZenRuleRepeatCallersPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenRuleRepeatCallersPreferenceControllerTest.java
new file mode 100644
index 0000000..45062d4
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ZenRuleRepeatCallersPreferenceControllerTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.notification;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationManager;
+import android.content.Context;
+import android.service.notification.ZenPolicy;
+
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+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.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+public class ZenRuleRepeatCallersPreferenceControllerTest extends ZenRuleCustomPrefContrTestBase {
+
+    private ZenRuleRepeatCallersPreferenceController mController;
+
+    @Mock
+    private ZenModeBackend mBackend;
+    @Mock
+    private NotificationManager mNotificationManager;
+    @Mock
+    private SwitchPreference mockPref;
+    @Mock
+    private NotificationManager.Policy mPolicy;
+    @Mock
+    private PreferenceScreen mPreferenceScreen;
+    private Context mContext;
+
+    @Override
+    AbstractZenCustomRulePreferenceController getController() {
+        return mController;
+    }
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowApplication = ShadowApplication.getInstance();
+        shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
+
+        mContext = RuntimeEnvironment.application;
+        when(mNotificationManager.getNotificationPolicy()).thenReturn(mPolicy);
+        mController = new ZenRuleRepeatCallersPreferenceController(mContext, PREF_KEY,
+                mock(Lifecycle.class), 15);
+        ReflectionHelpers.setField(mController, "mBackend", mBackend);
+        when(mBackend.getAutomaticZenRule(anyString())).thenReturn(mRule);
+        when(mPreferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(
+                mockPref);
+        mController.displayPreference(mPreferenceScreen);
+    }
+
+    @Test
+    public void updateState_Priority_anyCallers() {
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .allowCalls(ZenPolicy.PEOPLE_TYPE_ANYONE)
+                .allowRepeatCallers(false)
+                .build());
+        mController.updateState(mockPref);
+
+        verify(mockPref).setEnabled(false);
+        verify(mockPref).setChecked(true);
+    }
+
+    @Test
+    public void onPreferenceChanged_EnableRepeatCallers() {
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS)
+                .allowRepeatCallers(false)
+                .build());
+        mController.updateState(mockPref);
+        mController.onPreferenceChange(mockPref, true);
+        mRule.setZenPolicy(new ZenPolicy.Builder()
+                .allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS)
+                .allowRepeatCallers(true)
+                .build());
+        verify(mBackend).updateZenRule(RULE_ID, mRule);
+    }
+
+    @Test
+    public void onPreferenceChanged_DisableRepeatCallers() {
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS)
+                .allowRepeatCallers(true)
+                .build());
+        mController.updateState(mockPref);
+        mController.onPreferenceChange(mockPref, false);
+        mRule.setZenPolicy(new ZenPolicy.Builder()
+                .allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS)
+                .allowRepeatCallers(false)
+                .build());
+        verify(mBackend).updateZenRule(RULE_ID, mRule);
+    }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/notification/ZenRuleStarredContactsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenRuleStarredContactsPreferenceControllerTest.java
new file mode 100644
index 0000000..6c422eb
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ZenRuleStarredContactsPreferenceControllerTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.notification;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.service.notification.ZenPolicy;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+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.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+public class ZenRuleStarredContactsPreferenceControllerTest extends ZenRuleCustomPrefContrTestBase {
+
+    private ZenRuleStarredContactsPreferenceController mCallsController;
+    private ZenRuleStarredContactsPreferenceController mMessagesController;
+    private static int CURR_CONTROLLER = ZenPolicy.PRIORITY_CATEGORY_CALLS;
+
+    @Mock
+    private ZenModeBackend mBackend;
+    @Mock
+    private NotificationManager mNotificationManager;
+    @Mock
+    private Preference mockPref;
+    @Mock
+    private PreferenceScreen mPreferenceScreen;
+    @Mock
+    private Intent testIntent;
+    @Mock
+    private ComponentName mComponentName;
+    private Context mContext;
+
+    @Override
+    AbstractZenCustomRulePreferenceController getController() {
+        if (CURR_CONTROLLER == ZenPolicy.PRIORITY_CATEGORY_MESSAGES) {
+            return mMessagesController;
+        } else {
+            return mCallsController;
+        }
+    }
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowApplication = ShadowApplication.getInstance();
+        shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
+
+        mContext = RuntimeEnvironment.application;
+        when(testIntent.resolveActivity(any())).thenReturn(mComponentName);
+
+        mCallsController = new ZenRuleStarredContactsPreferenceController(
+                mContext, mock(Lifecycle.class), ZenPolicy.PRIORITY_CATEGORY_CALLS,
+                "zen_mode_starred_contacts_callers");
+        when(mBackend.getAutomaticZenRule(RULE_ID)).thenReturn(mRule);
+        ReflectionHelpers.setField(mCallsController, "mBackend", mBackend);
+        ReflectionHelpers.setField(mCallsController, "mStarredContactsIntent", testIntent);
+        when(mPreferenceScreen.findPreference(mCallsController.getPreferenceKey()))
+                .thenReturn(mockPref);
+        mCallsController.displayPreference(mPreferenceScreen);
+
+        mMessagesController = new ZenRuleStarredContactsPreferenceController(
+                mContext, mock(Lifecycle.class), ZenPolicy.PRIORITY_CATEGORY_MESSAGES,
+                "zen_mode_starred_contacts_messages");
+        ReflectionHelpers.setField(mMessagesController, "mBackend", mBackend);
+        ReflectionHelpers.setField(mMessagesController, "mStarredContactsIntent", testIntent);
+        when(mPreferenceScreen.findPreference(mMessagesController.getPreferenceKey()))
+                .thenReturn(mockPref);
+        mMessagesController.displayPreference(mPreferenceScreen);
+    }
+
+    @Test
+    public void isAvailable_noCallers() {
+        CURR_CONTROLLER = ZenPolicy.PRIORITY_CATEGORY_CALLS;
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .allowCalls(ZenPolicy.PEOPLE_TYPE_NONE)
+                .build());
+        assertThat(mCallsController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_anyCallers() {
+        CURR_CONTROLLER = ZenPolicy.PRIORITY_CATEGORY_CALLS;
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .allowCalls(ZenPolicy.PEOPLE_TYPE_ANYONE)
+                .build());
+
+        assertThat(mCallsController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_starredCallers() {
+        CURR_CONTROLLER = ZenPolicy.PRIORITY_CATEGORY_CALLS;
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .allowCalls(ZenPolicy.PEOPLE_TYPE_STARRED)
+                .build());
+
+        assertThat(mCallsController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void isAvailable_noMessages() {
+        CURR_CONTROLLER = ZenPolicy.PRIORITY_CATEGORY_MESSAGES;
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .allowMessages(ZenPolicy.PEOPLE_TYPE_NONE)
+                .build());
+        assertThat(mCallsController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_anyMessages() {
+        CURR_CONTROLLER = ZenPolicy.PRIORITY_CATEGORY_MESSAGES;
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .allowMessages(ZenPolicy.PEOPLE_TYPE_ANYONE)
+                .build());
+
+        assertThat(mMessagesController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_starredMessageContacts() {
+        CURR_CONTROLLER = ZenPolicy.PRIORITY_CATEGORY_MESSAGES;
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .allowMessages(ZenPolicy.PEOPLE_TYPE_STARRED)
+                .build());
+
+        assertThat(mMessagesController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void nullPreference_displayPreference() {
+        when(mPreferenceScreen.findPreference(mMessagesController.getPreferenceKey()))
+                .thenReturn(null);
+
+        // should not throw a null pointer
+        mMessagesController.displayPreference(mPreferenceScreen);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/ZenRuleVisEffectPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenRuleVisEffectPreferenceControllerTest.java
new file mode 100644
index 0000000..c99d207
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ZenRuleVisEffectPreferenceControllerTest.java
@@ -0,0 +1,187 @@
+/*
+ * 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.notification;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.res.Resources;
+import android.service.notification.ZenPolicy;
+
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.widget.DisabledCheckBoxPreference;
+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.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+public class ZenRuleVisEffectPreferenceControllerTest extends ZenRuleCustomPrefContrTestBase {
+
+    private static final @ZenPolicy.VisualEffect int EFFECT_PEEK = ZenPolicy.VISUAL_EFFECT_PEEK;
+    private static final @ZenPolicy.VisualEffect int PARENT_EFFECT1 = ZenPolicy.VISUAL_EFFECT_BADGE;
+    private static final @ZenPolicy.VisualEffect int PARENT_EFFECT2 =
+            ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST;
+    private static final int PREF_METRICS = 1;
+
+    @Mock
+    private ZenModeBackend mBackend;
+    @Mock
+    private DisabledCheckBoxPreference mockPref;
+    @Mock
+    private PreferenceScreen mScreen;
+    @Mock
+    NotificationManager mNotificationManager;
+
+    private Context mContext;
+    private ZenRuleVisEffectPreferenceController mController;
+
+    @Override
+    AbstractZenCustomRulePreferenceController getController() {
+        return mController;
+    }
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowApplication = ShadowApplication.getInstance();
+        shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
+        when(mNotificationManager.getNotificationPolicy()).thenReturn(
+                mock(NotificationManager.Policy.class));
+
+        mContext = RuntimeEnvironment.application;
+        mController = new ZenRuleVisEffectPreferenceController(mContext, mock(Lifecycle.class),
+                PREF_KEY, EFFECT_PEEK, PREF_METRICS, null);
+        ReflectionHelpers.setField(mController, "mBackend", mBackend);
+        when(mBackend.getAutomaticZenRule(RULE_ID)).thenReturn(mRule);
+
+        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mockPref);
+        mController.displayPreference(mScreen);
+    }
+
+    @Test
+    public void isAvailable() {
+        // VISUAL_EFFECT_PEEK isn't available until after onResume is called
+        assertFalse(mController.isAvailable());
+        updateControllerZenPolicy(new ZenPolicy()); // calls onResume
+        assertTrue(mController.isAvailable());
+
+        // VISUAL_EFFECT_LIGHTS is only available if the device has an LED:
+        Context mockContext = mock(Context.class);
+        mController = new ZenRuleVisEffectPreferenceController(mockContext, mock(Lifecycle.class),
+                PREF_KEY, ZenPolicy.VISUAL_EFFECT_LIGHTS, PREF_METRICS, null);
+        updateControllerZenPolicy(new ZenPolicy()); // calls onResume
+
+        Resources mockResources = mock(Resources.class);
+        when(mockContext.getResources()).thenReturn(mockResources);
+
+        when(mockResources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed))
+                .thenReturn(false); // no light
+        assertFalse(mController.isAvailable());
+
+        when(mockResources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed))
+                .thenReturn(true); // has light
+        assertTrue(mController.isAvailable());
+    }
+
+    @Test
+    public void updateState_notChecked() {
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .showPeeking(true)
+                .build());
+        mController.updateState(mockPref);
+
+        verify(mockPref).setChecked(false);
+        verify(mockPref).enableCheckbox(true);
+    }
+
+    @Test
+    public void updateState_checked() {
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .showPeeking(false)
+                .build());
+        mController.updateState(mockPref);
+
+        verify(mockPref).setChecked(true);
+        verify(mockPref).enableCheckbox(true);
+    }
+
+    @Test
+    public void updateState_checkedFalse_parentChecked() {
+        mController.mParentSuppressedEffects = new int[]{PARENT_EFFECT1, PARENT_EFFECT2};
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .showVisualEffect(EFFECT_PEEK, true)
+                .showVisualEffect(PARENT_EFFECT1, true)
+                .showVisualEffect(PARENT_EFFECT2, false)
+                .build());
+        mController.updateState(mockPref);
+
+        verify(mockPref).setChecked(true);
+        verify(mockPref).enableCheckbox(false);
+    }
+
+    @Test
+    public void updateState_checkedFalse_parentNotChecked() {
+        mController.mParentSuppressedEffects = new int[]{PARENT_EFFECT1, PARENT_EFFECT2};
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .showVisualEffect(EFFECT_PEEK, true)
+                .showVisualEffect(PARENT_EFFECT1, true)
+                .showVisualEffect(PARENT_EFFECT2, true)
+                .build());
+        mController.updateState(mockPref);
+
+        verify(mockPref).setChecked(false);
+        verify(mockPref).enableCheckbox(true);
+    }
+
+    @Test
+    public void onPreferenceChanged_checkedFalse() {
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .showPeeking(false)
+                .build());
+        mController.onPreferenceChange(mockPref, false);
+        mRule.setZenPolicy(new ZenPolicy.Builder(mRule.getZenPolicy())
+                .showPeeking(true)
+                .build());
+        verify(mBackend).updateZenRule(RULE_ID, mRule);
+    }
+
+    @Test
+    public void onPreferenceChanged_checkedTrue() {
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .showPeeking(true)
+                .build());
+        mController.onPreferenceChange(mockPref, true);
+        mRule.setZenPolicy(new ZenPolicy.Builder(mRule.getZenPolicy())
+                .showPeeking(false)
+                .build());
+        verify(mBackend).updateZenRule(RULE_ID, mRule);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/ZenRuleVisEffectsAllPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenRuleVisEffectsAllPreferenceControllerTest.java
new file mode 100644
index 0000000..5ef6194
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ZenRuleVisEffectsAllPreferenceControllerTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.notification;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationManager;
+import android.content.Context;
+import android.service.notification.ZenPolicy;
+
+import androidx.preference.PreferenceScreen;
+
+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.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+public class ZenRuleVisEffectsAllPreferenceControllerTest extends
+        ZenRuleCustomPrefContrTestBase {
+
+    @Mock
+    private ZenModeBackend mBackend;
+    @Mock
+    private NotificationManager mNotificationManager;
+    @Mock
+    private ZenCustomRadioButtonPreference mockPref;
+    @Mock
+    private PreferenceScreen mScreen;
+
+    private ZenRuleVisEffectsAllPreferenceController mController;
+    private Context mContext;
+
+    @Override
+    AbstractZenCustomRulePreferenceController getController() {
+        return mController;
+    }
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowApplication = ShadowApplication.getInstance();
+        shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
+        mContext = RuntimeEnvironment.application;
+        mController = new ZenRuleVisEffectsAllPreferenceController(mContext, mock(Lifecycle.class),
+                PREF_KEY);
+        ReflectionHelpers.setField(mController, "mBackend", mBackend);
+        when(mBackend.getAutomaticZenRule(RULE_ID)).thenReturn(mRule);
+        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mockPref);
+        mController.displayPreference(mScreen);
+    }
+
+    @Test
+    public void updateState_noVisEffects() {
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .hideAllVisualEffects()
+                .build());
+        mController.updateState(mockPref);
+        verify(mockPref).setChecked(false);
+    }
+
+    @Test
+    public void updateState_showAllVisualEffects() {
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .showAllVisualEffects()
+                .build());
+        mController.updateState(mockPref);
+        verify(mockPref).setChecked(true);
+    }
+
+    @Test
+    public void updateState_customEffects() {
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .showPeeking(true)
+                .showBadges(false)
+                .build());
+        mController.updateState(mockPref);
+
+        verify(mockPref).setChecked(false);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/ZenRuleVisEffectsCustomPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenRuleVisEffectsCustomPreferenceControllerTest.java
new file mode 100644
index 0000000..79ef8d2
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ZenRuleVisEffectsCustomPreferenceControllerTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.notification;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationManager;
+import android.content.Context;
+import android.service.notification.ZenPolicy;
+
+import androidx.preference.PreferenceScreen;
+
+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.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+public class ZenRuleVisEffectsCustomPreferenceControllerTest extends
+        ZenRuleCustomPrefContrTestBase {
+
+    @Mock
+    private ZenModeBackend mBackend;
+    @Mock
+    private NotificationManager mNotificationManager;
+    @Mock
+    private ZenCustomRadioButtonPreference mockPref;
+    @Mock
+    private PreferenceScreen mScreen;
+
+    private ZenRuleVisEffectsCustomPreferenceController mController;
+    private Context mContext;
+
+    @Override
+    AbstractZenCustomRulePreferenceController getController() {
+        return mController;
+    }
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowApplication = ShadowApplication.getInstance();
+        shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
+        mContext = RuntimeEnvironment.application;
+        mController = new ZenRuleVisEffectsCustomPreferenceController(mContext, mock(Lifecycle.class),
+                PREF_KEY);
+        ReflectionHelpers.setField(mController, "mBackend", mBackend);
+        when(mBackend.getAutomaticZenRule(RULE_ID)).thenReturn(mRule);
+        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mockPref);
+        mController.displayPreference(mScreen);
+    }
+
+    @Test
+    public void updateState_noVisEffects() {
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .hideAllVisualEffects()
+                .build());
+        mController.updateState(mockPref);
+        verify(mockPref).setChecked(false);
+    }
+
+    @Test
+    public void updateState_showAllVisualEffects() {
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .showAllVisualEffects()
+                .build());
+        mController.updateState(mockPref);
+        verify(mockPref).setChecked(false);
+    }
+
+    @Test
+    public void updateState_customEffects() {
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .showPeeking(true)
+                .showBadges(false)
+                .build());
+        mController.updateState(mockPref);
+
+        verify(mockPref).setChecked(true);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/ZenRuleVisEffectsNonePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenRuleVisEffectsNonePreferenceControllerTest.java
new file mode 100644
index 0000000..d66433e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ZenRuleVisEffectsNonePreferenceControllerTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.notification;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationManager;
+import android.content.Context;
+import android.service.notification.ZenPolicy;
+
+import androidx.preference.PreferenceScreen;
+
+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.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+public class ZenRuleVisEffectsNonePreferenceControllerTest extends
+        ZenRuleCustomPrefContrTestBase {
+
+    @Mock
+    private ZenModeBackend mBackend;
+    @Mock
+    private NotificationManager mNotificationManager;
+    @Mock
+    private ZenCustomRadioButtonPreference mockPref;
+    @Mock
+    private PreferenceScreen mScreen;
+
+    private ZenRuleVisEffectsNonePreferenceController mController;
+    private Context mContext;
+
+    @Override
+    AbstractZenCustomRulePreferenceController getController() {
+        return mController;
+    }
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowApplication = ShadowApplication.getInstance();
+        shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
+        mContext = RuntimeEnvironment.application;
+        mController = new ZenRuleVisEffectsNonePreferenceController(mContext, mock(Lifecycle.class),
+                PREF_KEY);
+        ReflectionHelpers.setField(mController, "mBackend", mBackend);
+        when(mBackend.getAutomaticZenRule(RULE_ID)).thenReturn(mRule);
+        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mockPref);
+        mController.displayPreference(mScreen);
+    }
+
+    @Test
+    public void updateState_noVisEffects() {
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .hideAllVisualEffects()
+                .build());
+        mController.updateState(mockPref);
+        verify(mockPref).setChecked(true);
+    }
+
+    @Test
+    public void updateState_showAllVisualEffects() {
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .showAllVisualEffects()
+                .build());
+        mController.updateState(mockPref);
+        verify(mockPref).setChecked(false);
+    }
+
+    @Test
+    public void updateState_custom() {
+        updateControllerZenPolicy(new ZenPolicy.Builder()
+                .showPeeking(true)
+                .showBadges(false)
+                .build());
+        mController.updateState(mockPref);
+
+        verify(mockPref).setChecked(false);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentsPreferenceControllerTest.java
index 7eb64b9..d7aa42c 100644
--- a/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentsPreferenceControllerTest.java
@@ -28,6 +28,7 @@
 import android.content.pm.ServiceInfo;
 import android.service.trust.TrustAgentService;
 
+import android.text.TextUtils;
 import androidx.preference.PreferenceManager;
 import androidx.preference.PreferenceScreen;
 
@@ -96,7 +97,7 @@
     @Test
     public void onStart_noTrustAgent_shouldNotAddPreference() {
         final List<ResolveInfo> availableAgents = createFakeAvailableAgents();
-        mPackageManager.addResolveInfoForIntent(TEST_INTENT, availableAgents);
+        mPackageManager.setResolveInfosForIntent(TEST_INTENT, availableAgents);
 
         mController.displayPreference(mPreferenceScreen);
         mController.onStart();
@@ -109,15 +110,16 @@
     onStart_hasAUninstalledTrustAgent_shouldRemoveOnePreferenceAndLeaveTwoPreferences() {
         final List<ResolveInfo> availableAgents = createFakeAvailableAgents();
         final ResolveInfo uninstalledTrustAgent = availableAgents.get(0);
+
         for (ResolveInfo rInfo : availableAgents) {
             ShadowTrustAgentManager.grantPermissionToResolveInfo(rInfo);
         }
-        mPackageManager.addResolveInfoForIntent(TEST_INTENT, availableAgents);
+        mPackageManager.setResolveInfosForIntent(TEST_INTENT, availableAgents);
         mController.displayPreference(mPreferenceScreen);
         mController.onStart();
         availableAgents.remove(uninstalledTrustAgent);
 
-        mPackageManager.addResolveInfoForIntent(TEST_INTENT, availableAgents);
+        mPackageManager.setResolveInfosForIntent(TEST_INTENT, availableAgents);
         mController.onStart();
 
         assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(2);
@@ -131,13 +133,13 @@
         for (ResolveInfo rInfo : availableAgents) {
             ShadowTrustAgentManager.grantPermissionToResolveInfo(rInfo);
         }
-        mPackageManager.addResolveInfoForIntent(TEST_INTENT, availableAgents);
+        mPackageManager.setResolveInfosForIntent(TEST_INTENT, availableAgents);
         mController.displayPreference(mPreferenceScreen);
         mController.onStart();
         availableAgents.add(newTrustAgent);
         ShadowTrustAgentManager.grantPermissionToResolveInfo(newTrustAgent);
 
-        mPackageManager.addResolveInfoForIntent(TEST_INTENT, availableAgents);
+        mPackageManager.setResolveInfosForIntent(TEST_INTENT, availableAgents);
         mController.onStart();
 
         assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(4);
@@ -150,7 +152,7 @@
         for (ResolveInfo rInfo : availableAgents) {
             ShadowTrustAgentManager.grantPermissionToResolveInfo(rInfo);
         }
-        mPackageManager.addResolveInfoForIntent(TEST_INTENT, availableAgents);
+        mPackageManager.setResolveInfosForIntent(TEST_INTENT, availableAgents);
 
         mController.displayPreference(mPreferenceScreen);
         mController.onStart();
@@ -169,7 +171,7 @@
         for (ResolveInfo rInfo : availableAgents) {
             ShadowTrustAgentManager.grantPermissionToResolveInfo(rInfo);
         }
-        mPackageManager.addResolveInfoForIntent(TEST_INTENT, availableAgents);
+        mPackageManager.setResolveInfosForIntent(TEST_INTENT, availableAgents);
         ShadowRestrictedLockUtilsInternal.setKeyguardDisabledFeatures(
                 DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS);
 
@@ -213,8 +215,14 @@
         private final static List<ResolveInfo> sPermissionGrantedList = new ArrayList<>();
 
         @Implementation
-        public boolean shouldProvideTrust(ResolveInfo resolveInfo, PackageManager pm) {
-            return sPermissionGrantedList.contains(resolveInfo);
+        protected boolean shouldProvideTrust(ResolveInfo resolveInfo, PackageManager pm) {
+            for (ResolveInfo info : sPermissionGrantedList) {
+                if (info.serviceInfo.equals(resolveInfo.serviceInfo)) {
+                    return true;
+                }
+            }
+
+            return false;
         }
 
         private static void grantPermissionToResolveInfo(ResolveInfo rInfo) {
diff --git a/tests/robotests/src/com/android/settings/shortcut/CreateShortcutPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/shortcut/CreateShortcutPreferenceControllerTest.java
index e132aac..f9cedb3 100644
--- a/tests/robotests/src/com/android/settings/shortcut/CreateShortcutPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/shortcut/CreateShortcutPreferenceControllerTest.java
@@ -118,13 +118,13 @@
         ri2.activityInfo.applicationInfo = new ApplicationInfo();
         ri2.activityInfo.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
 
-        mPackageManager.addResolveInfoForIntent(
+        mPackageManager.setResolveInfosForIntent(
                 new Intent(CreateShortcutPreferenceController.SHORTCUT_PROBE),
                 Arrays.asList(ri1, ri2));
 
         final List<ResolveInfo> info = mController.queryShortcuts();
         assertThat(info).hasSize(1);
-        assertThat(info.get(0)).isEqualTo(ri2);
+        assertThat(info.get(0).activityInfo).isEqualTo(ri2.activityInfo);
     }
 
     @Test
@@ -143,13 +143,13 @@
         ri2.activityInfo.applicationInfo = new ApplicationInfo();
         ri2.activityInfo.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
 
-        mPackageManager.addResolveInfoForIntent(
+        mPackageManager.setResolveInfosForIntent(
                 new Intent(CreateShortcutPreferenceController.SHORTCUT_PROBE),
                 Arrays.asList(ri1, ri2));
 
         final List<ResolveInfo> info = mController.queryShortcuts();
         assertThat(info).hasSize(2);
-        assertThat(info.get(0)).isEqualTo(ri2);
-        assertThat(info.get(1)).isEqualTo(ri1);
+        assertThat(info.get(0).activityInfo).isEqualTo(ri2.activityInfo);
+        assertThat(info.get(1).activityInfo).isEqualTo(ri1.activityInfo);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/shortcut/ShortcutsUpdateTaskTest.java b/tests/robotests/src/com/android/settings/shortcut/ShortcutsUpdateTaskTest.java
index 0bc0414..8352e7a 100644
--- a/tests/robotests/src/com/android/settings/shortcut/ShortcutsUpdateTaskTest.java
+++ b/tests/robotests/src/com/android/settings/shortcut/ShortcutsUpdateTaskTest.java
@@ -80,12 +80,14 @@
                 .setComponent(new ComponentName(
                         mContext, Settings.ManageApplicationsActivity.class));
         final ResolveInfo ri1 = mock(ResolveInfo.class);
+        ri1.nonLocalizedLabel = "label1";
+
         final Intent shortcut2 = new Intent(CreateShortcutPreferenceController.SHORTCUT_PROBE)
                 .setComponent(new ComponentName(
                         mContext, Settings.SoundSettingsActivity.class));
         final ResolveInfo ri2 = mock(ResolveInfo.class);
-        when(ri1.loadLabel(any(PackageManager.class))).thenReturn("label1");
-        when(ri2.loadLabel(any(PackageManager.class))).thenReturn("label2");
+        ri2.nonLocalizedLabel = "label2";
+
         mPackageManager.addResolveInfoForIntent(shortcut1, ri1);
         mPackageManager.addResolveInfoForIntent(shortcut2, ri2);
 
diff --git a/tests/robotests/src/com/android/settings/testutils/SliceTester.java b/tests/robotests/src/com/android/settings/testutils/SliceTester.java
index c0ffdcd..17edb6e 100644
--- a/tests/robotests/src/com/android/settings/testutils/SliceTester.java
+++ b/tests/robotests/src/com/android/settings/testutils/SliceTester.java
@@ -79,8 +79,7 @@
         assertThat(primaryPendingIntent).isEqualTo(
                 SliceBuilderUtils.getContentPendingIntent(context, sliceData));
 
-        final List<SliceItem> sliceItems = slice.getItems();
-        assertTitle(sliceItems, sliceData.getTitle());
+        assertThat(metadata.getTitle()).isEqualTo(sliceData.getTitle());
 
         assertKeywords(metadata, sliceData);
     }
@@ -122,8 +121,7 @@
         assertThat(primaryPendingIntent).isEqualTo(
                 SliceBuilderUtils.getContentPendingIntent(context, sliceData));
 
-        final List<SliceItem> sliceItems = slice.getItems();
-        assertTitle(sliceItems, sliceData.getTitle());
+        assertThat(metadata.getTitle()).isEqualTo(sliceData.getTitle());
 
         assertKeywords(metadata, sliceData);
     }
@@ -160,8 +158,7 @@
         assertThat(primaryPendingIntent).isEqualTo(
                 SliceBuilderUtils.getContentPendingIntent(context, sliceData));
 
-        final List<SliceItem> sliceItems = slice.getItems();
-        assertTitle(sliceItems, sliceData.getTitle());
+        assertThat(metadata.getTitle()).isEqualTo(sliceData.getTitle());
 
         assertKeywords(metadata, sliceData);
     }
@@ -197,8 +194,7 @@
         assertThat(primaryPendingIntent).isEqualTo(
                 SliceBuilderUtils.getContentPendingIntent(context, sliceData));
 
-        final List<SliceItem> sliceItems = slice.getItems();
-        assertTitle(sliceItems, sliceData.getTitle());
+        assertThat(metadata.getTitle()).isEqualTo(sliceData.getTitle());
 
         assertKeywords(metadata, sliceData);
     }
@@ -230,14 +226,18 @@
         assertThat(primaryPendingIntent).isEqualTo(SliceBuilderUtils.getContentPendingIntent(
                 context, sliceData));
 
-        final List<SliceItem> sliceItems = slice.getItems();
-        assertTitle(sliceItems, sliceData.getTitle());
+        assertThat(metadata.getTitle()).isEqualTo(sliceData.getTitle());
 
         assertKeywords(metadata, sliceData);
     }
 
-    // TODO(b/120592507): Clean up method of SliceTester
-    public static void assertTitle(List<SliceItem> sliceItems, String title) {
+    /**
+     * Assert any slice item contains title.
+     *
+     * @param sliceItems All slice items of a Slice.
+     * @param title Title for asserting.
+     */
+    public static void assertAnySliceItemContainsTitle(List<SliceItem> sliceItems, String title) {
         boolean hasTitle = false;
         for (SliceItem item : sliceItems) {
             List<SliceItem> titleItems = SliceQuery.findAll(item, FORMAT_TEXT, HINT_TITLE,
@@ -256,7 +256,6 @@
         assertThat(hasTitle).isTrue();
     }
 
-    // TODO(b/120592507): Clean up method of SliceTester
     private static void assertKeywords(SliceMetadata metadata, SliceData data) {
         final List<String> keywords = metadata.getSliceKeywords();
         final Set<String> expectedKeywords = Arrays.stream(data.getKeywords().split(","))
@@ -266,4 +265,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/webview/WebViewAppPickerTest.java b/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java
index 1435529..363e046 100644
--- a/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java
+++ b/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java
@@ -39,6 +39,7 @@
 import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.graphics.drawable.ColorDrawable;
 import android.os.UserManager;
 import android.webkit.UserPackage;
 
@@ -56,6 +57,8 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
+import org.robolectric.shadows.ShadowPackageManager;
 import org.robolectric.util.ReflectionHelpers;
 
 import java.util.Arrays;
@@ -341,6 +344,11 @@
         when(mPackageManager.getPackageInfo(eq(DEFAULT_PACKAGE_NAME), anyInt())).thenReturn(
                 packageInfo);
 
+        // Subvert attempts to load an unbadged icon for the application.
+        PackageManager pm = RuntimeEnvironment.application.getPackageManager();
+        ShadowPackageManager spm = Shadows.shadowOf(pm);
+        spm.setUnbadgedApplicationIcon(DEFAULT_PACKAGE_NAME, new ColorDrawable());
+
         RadioButtonPreference mockPreference = mock(RadioButtonPreference.class);
         mPicker.bindPreference(mockPreference, DEFAULT_PACKAGE_NAME, webviewAppInfo, null);
         mPicker
diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiPrivacyPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiPrivacyPreferenceControllerTest.java
index 8bbb2be..20c5838 100644
--- a/tests/robotests/src/com/android/settings/wifi/details/WifiPrivacyPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/details/WifiPrivacyPreferenceControllerTest.java
@@ -38,8 +38,8 @@
 @RunWith(RobolectricTestRunner.class)
 public class WifiPrivacyPreferenceControllerTest {
 
-    private static final int PRIVACY_RANDOMIZED = 0;
-    private static final int PRIVACY_TRUSTED = 1;
+    private static final int PRIVACY_RANDOMIZED = WifiConfiguration.RANDOMIZATION_PERSISTENT;
+    private static final int PRIVACY_TRUSTED = WifiConfiguration.RANDOMIZATION_NONE;
 
     @Mock
     private WifiConfiguration mWifiConfiguration;
@@ -47,6 +47,7 @@
     private WifiPrivacyPreferenceController mPreferenceController;
     private Context mContext;
     private DropDownPreference mDropDownPreference;
+    private String[] perferenceString;
 
     @Before
     public void setUp() {
@@ -59,6 +60,8 @@
         mDropDownPreference = new DropDownPreference(mContext);
         mDropDownPreference.setEntries(R.array.wifi_privacy_entries);
         mDropDownPreference.setEntryValues(R.array.wifi_privacy_values);
+
+        perferenceString = mContext.getResources().getStringArray(R.array.wifi_privacy_entries);
     }
 
     @Test
@@ -67,7 +70,8 @@
 
         mPreferenceController.updateState(mDropDownPreference);
 
-        assertThat(mDropDownPreference.getEntry()).isEqualTo("Trusted");
+
+        assertThat(mDropDownPreference.getEntry()).isEqualTo(perferenceString[PRIVACY_TRUSTED]);
     }
 
     @Test
@@ -76,7 +80,7 @@
 
         mPreferenceController.updateState(mDropDownPreference);
 
-        assertThat(mDropDownPreference.getEntry()).isEqualTo("Default (use randomized MAC)");
+        assertThat(mDropDownPreference.getEntry()).isEqualTo(perferenceString[PRIVACY_RANDOMIZED]);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/wifi/dpp/WifiNetworkConfigTest.java b/tests/robotests/src/com/android/settings/wifi/dpp/WifiNetworkConfigTest.java
new file mode 100644
index 0000000..1b7c0a8
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/dpp/WifiNetworkConfigTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.wifi.dpp;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Intent;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class WifiNetworkConfigTest {
+    private WifiNetworkConfig mWifiConfig;
+
+    @Before
+    public void setUp() {
+        Intent intent = new Intent();
+        intent.putExtra(WifiDppUtils.EXTRA_WIFI_SSID, "Pixel:_ABCD;");
+        intent.putExtra(WifiDppUtils.EXTRA_WIFI_SECURITY, "WPA");
+        intent.putExtra(WifiDppUtils.EXTRA_WIFI_PRE_SHARED_KEY, "\\012345678,");
+        mWifiConfig = WifiNetworkConfig.getValidConfigOrNull(intent);
+    }
+
+    @Test
+    public void testInitConfig_IntentReceived_QRCodeValue() {
+        String qrcode = mWifiConfig.getQrCode();
+        assertThat(qrcode).isEqualTo("WIFI:S:Pixel\\:_ABCD\\;;T:WPA;P:\\\\012345678\\,;H:false;;");
+    }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/wifi/qrcode/QrCameraTest.java b/tests/robotests/src/com/android/settings/wifi/qrcode/QrCameraTest.java
index 0ef0273..a57fefc 100644
--- a/tests/robotests/src/com/android/settings/wifi/qrcode/QrCameraTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/qrcode/QrCameraTest.java
@@ -85,6 +85,11 @@
         public void setTransform(Matrix transform) {
             // Do nothing
         }
+
+        @Override
+        public boolean isValid(String qrCode) {
+            return true;
+        }
     }
 
     private ScannerTestCallback mScannerCallback;
diff --git a/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java
index bf5fba8..b7f713d 100644
--- a/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java
@@ -29,14 +29,12 @@
 
 import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
-import androidx.slice.SliceItem;
 import androidx.slice.SliceMetadata;
 import androidx.slice.SliceProvider;
 import androidx.slice.core.SliceAction;
 import androidx.slice.widget.SliceLiveData;
 
 import com.android.settings.R;
-import com.android.settings.testutils.SliceTester;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -87,7 +85,9 @@
         mWifiManager.connect(config, null /* listener */);
 
         final Slice wifiSlice = mWifiSlice.getSlice();
+
         final SliceMetadata metadata = SliceMetadata.from(mContext, wifiSlice);
+        assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.wifi_settings));
 
         final List<SliceAction> toggles = metadata.getToggles();
         assertThat(toggles).hasSize(1);
@@ -96,8 +96,5 @@
         final IconCompat expectedToggleIcon = IconCompat.createWithResource(mContext,
                 R.drawable.ic_settings_wireless);
         assertThat(primaryAction.getIcon().toString()).isEqualTo(expectedToggleIcon.toString());
-
-        final List<SliceItem> sliceItems = wifiSlice.getItems();
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.wifi_settings));
     }
 }
diff --git a/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
index 3c78749..ae352cc 100644
--- a/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
@@ -81,7 +81,9 @@
     @Test
     public void getWifiSlice_shouldHaveTitleAndToggle() {
         final Slice wifiSlice = mWifiSlice.getSlice();
+
         final SliceMetadata metadata = SliceMetadata.from(mContext, wifiSlice);
+        assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.wifi_settings));
 
         final List<SliceAction> toggles = metadata.getToggles();
         assertThat(toggles).hasSize(1);
@@ -90,9 +92,6 @@
         final IconCompat expectedToggleIcon = IconCompat.createWithResource(mContext,
                 R.drawable.ic_settings_wireless);
         assertThat(primaryAction.getIcon().toString()).isEqualTo(expectedToggleIcon.toString());
-
-        final List<SliceItem> sliceItems = wifiSlice.getItems();
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.wifi_settings));
     }
 
     @Test
@@ -119,7 +118,8 @@
         // All AP rows + title row
         assertThat(rows).isEqualTo(DEFAULT_EXPANDED_ROW_COUNT + 1);
         // Has scanning text
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.wifi_empty_list_wifi_on));
+        SliceTester.assertAnySliceItemContainsTitle(sliceItems,
+                mContext.getString(R.string.wifi_empty_list_wifi_on));
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
index 40d651e..cdc74b3 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
@@ -35,6 +35,9 @@
 import android.os.UserManager;
 import android.widget.TextView;
 
+import androidx.fragment.app.FragmentActivity;
+import androidx.preference.PreferenceScreen;
+
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.testutils.shadow.ShadowWifiManager;
 
@@ -51,15 +54,13 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import androidx.fragment.app.FragmentActivity;
-import androidx.preference.PreferenceScreen;
-
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {ShadowWifiManager.class})
 public class WifiTetherSettingsTest {
     private static final String[] WIFI_REGEXS = {"wifi_regexs"};
 
     private Context mContext;
+    private WifiTetherSettings mWifiTetherSettings;
 
     @Mock
     private ConnectivityManager mConnectivityManager;
@@ -75,6 +76,8 @@
                 .when(mContext).getSystemService(Context.CONNECTIVITY_SERVICE);
         doReturn(WIFI_REGEXS).when(mConnectivityManager).getTetherableWifiRegexs();
         doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE);
+
+        mWifiTetherSettings = new WifiTetherSettings();
     }
 
     @Test
@@ -136,6 +139,15 @@
         verify(screen).removeAll();
     }
 
+    @Test
+    public void createPreferenceControllers_hasAutoOffPreference() {
+        assertThat(mWifiTetherSettings.createPreferenceControllers(mContext)
+                .stream()
+                .filter(controller -> controller instanceof WifiTetherAutoOffPreferenceController)
+                .count())
+                .isEqualTo(1);
+    }
+
     private void setupIsTetherAvailable(boolean returnValue) {
         when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
 
diff --git a/tests/unit/src/com/android/settings/EncryptionInterstitialTest.java b/tests/unit/src/com/android/settings/EncryptionInterstitialTest.java
index 9a6b754..3b4abfe 100644
--- a/tests/unit/src/com/android/settings/EncryptionInterstitialTest.java
+++ b/tests/unit/src/com/android/settings/EncryptionInterstitialTest.java
@@ -35,6 +35,9 @@
 import androidx.test.filters.MediumTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.google.android.setupcompat.PartnerCustomizationLayout;
+import com.google.android.setupcompat.template.ButtonFooterMixin;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -63,10 +66,11 @@
 
     @Test
     public void clickYes_shouldRequirePassword() {
-        mInstrumentation.startActivitySync(
+        final Activity activity = mInstrumentation.startActivitySync(
                 new Intent(mContext, EncryptionInterstitial.class)
                         .putExtra("extra_unlock_method_intent", new Intent("test.unlock.intent")));
-        onView(withId(R.id.encrypt_require_password)).perform(click());
+        final PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout);
+        layout.getMixin(ButtonFooterMixin.class).getPrimaryButtonView().performClick();
 
         mActivityMonitor.waitForActivityWithTimeout(1000);
         assertEquals(1, mActivityMonitor.getHits());
@@ -77,10 +81,11 @@
 
     @Test
     public void clickNo_shouldNotRequirePassword() {
-        mInstrumentation.startActivitySync(
+        final Activity activity = mInstrumentation.startActivitySync(
                 new Intent(mContext, EncryptionInterstitial.class)
                         .putExtra("extra_unlock_method_intent", new Intent("test.unlock.intent")));
-        onView(withId(R.id.encrypt_dont_require_password)).perform(click());
+        final PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout);
+        layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView().performClick();
 
         mActivityMonitor.waitForActivityWithTimeout(1000);
         assertEquals(1, mActivityMonitor.getHits());
diff --git a/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
index 235f182..61033e9 100644
--- a/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
+++ b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
@@ -80,4 +80,20 @@
         assertThat(activity instanceof WifiDppQrCodeGeneratorFragment
                 .OnQrCodeGeneratorFragmentAddButtonClickedListener).isEqualTo(true);
     }
+
+    @Test
+    public void testActivity_shouldImplementsOnScanWifiDppSuccessCallback() {
+        WifiDppConfiguratorActivity activity = mActivityRule.getActivity();
+
+        assertThat(activity instanceof WifiDppQrCodeScannerFragment
+                .OnScanWifiDppSuccessListener).isEqualTo(true);
+    }
+
+    @Test
+    public void testActivity_shouldImplementsOnScanZxingWifiFormatSuccessCallback() {
+        WifiDppConfiguratorActivity activity = mActivityRule.getActivity();
+
+        assertThat(activity instanceof WifiDppQrCodeScannerFragment
+                .OnScanZxingWifiFormatSuccessListener).isEqualTo(true);
+    }
 }
diff --git a/tests/unit/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivityTest.java b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivityTest.java
new file mode 100644
index 0000000..283da13
--- /dev/null
+++ b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivityTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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.wifi.dpp;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class WifiDppEnrolleeActivityTest {
+    @Rule
+    public final ActivityTestRule<WifiDppEnrolleeActivity> mActivityRule =
+            new ActivityTestRule<>(WifiDppEnrolleeActivity.class);
+
+    @Test
+    public void testActivity_shouldImplementsOnScanWifiDppSuccessCallback() {
+        WifiDppEnrolleeActivity activity = mActivityRule.getActivity();
+
+        assertThat(activity instanceof WifiDppQrCodeScannerFragment
+                .OnScanWifiDppSuccessListener).isEqualTo(true);
+    }
+
+    @Test
+    public void testActivity_shouldImplementsOnScanZxingWifiFormatSuccessCallback() {
+        WifiDppEnrolleeActivity activity = mActivityRule.getActivity();
+
+        assertThat(activity instanceof WifiDppQrCodeScannerFragment
+                .OnScanZxingWifiFormatSuccessListener).isEqualTo(true);
+    }
+}
diff --git a/tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodetest.java b/tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodeTest.java
similarity index 83%
rename from tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodetest.java
rename to tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodeTest.java
index 775ca48..3595597 100644
--- a/tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodetest.java
+++ b/tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodeTest.java
@@ -29,7 +29,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class WifiQrCodetest {
+public class WifiQrCodeTest {
     // Valid Wi-Fi DPP QR code & it's parameters
     private static final String VALID_WIFI_DPP_QR_CODE = "DPP:I:SN=4774LH2b4044;M:010203040506;K:"
             + "MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgADURzxmttZoIRIPWGoQMV00XHWCAQIhXruVWOz0NjlkIA=;;";
@@ -57,6 +57,13 @@
     private static final String SSID_OF_VALID_ZXING_WIFI_QR_CODE = "mynetwork";
     private static final String PASSWORD_OF_VALID_ZXING_WIFI_QR_CODE = "mypass";
 
+    // Valid ZXing reader library's Wi-Fi Network config format - escaped characters
+    private static final String VALID_ZXING_WIFI_QR_CODE_SPECIAL_CHARACTERS =
+            "WIFI:T:WPA;S:mynetwork;P:m\\;y\\:p\\\\a\\,ss;H:true;;";
+
+    private static final String PASSWORD_OF_VALID_ZXING_WIFI_QR_CODE_SPECIAL_CHARACTERS =
+            "m;y:p\\a,ss";
+
     // Invalid scheme QR code
     private static final String INVALID_SCHEME_QR_CODE = "BT:T:WPA;S:mynetwork;P:mypass;H:true;;";
 
@@ -118,19 +125,35 @@
 
         assertEquals(WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG, wifiQrCode.getScheme());
         assertNotNull(config);
-        assertNull(config.getSecurity());
+        assertEquals("", config.getSecurity());
         assertEquals(SSID_OF_VALID_ZXING_WIFI_QR_CODE, config.getSsid());
-        assertNull(config.getPreSharedKey());
+        assertEquals("", config.getPreSharedKey());
         assertEquals(false, config.getHiddenSsid());
     }
 
     @Test
+    public void parseValidZxingWifiQrCode_specialCharacters() {
+        WifiQrCode wifiQrCode = new WifiQrCode(VALID_ZXING_WIFI_QR_CODE_SPECIAL_CHARACTERS);
+        WifiNetworkConfig config = wifiQrCode.getWifiNetworkConfig();
+
+        assertEquals(WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG, wifiQrCode.getScheme());
+        assertNotNull(config);
+        assertEquals(SECURITY_OF_VALID_ZXING_WIFI_QR_CODE, config.getSecurity());
+        assertEquals(SSID_OF_VALID_ZXING_WIFI_QR_CODE, config.getSsid());
+        assertEquals(PASSWORD_OF_VALID_ZXING_WIFI_QR_CODE_SPECIAL_CHARACTERS,
+                config.getPreSharedKey());
+        assertEquals(true, config.getHiddenSsid());
+    }
+
+    @Test
     public void testRemoveBackSlash() {
-        assertEquals("\\", WifiQrCode.removeBackSlash("\\\\"));
-        assertEquals("ab", WifiQrCode.removeBackSlash("a\\b"));
-        assertEquals("a", WifiQrCode.removeBackSlash("\\a"));
-        assertEquals("\\b", WifiQrCode.removeBackSlash("\\\\b"));
-        assertEquals("c\\", WifiQrCode.removeBackSlash("c\\\\"));
+        WifiQrCode wifiQrCode = new WifiQrCode(VALID_WIFI_DPP_QR_CODE);
+
+        assertEquals("\\", wifiQrCode.removeBackSlash("\\\\"));
+        assertEquals("ab", wifiQrCode.removeBackSlash("a\\b"));
+        assertEquals("a", wifiQrCode.removeBackSlash("\\a"));
+        assertEquals("\\b", wifiQrCode.removeBackSlash("\\\\b"));
+        assertEquals("c\\", wifiQrCode.removeBackSlash("c\\\\"));
     }
 
     @Test