Merge "Use short format to avoid truncated problem"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 7625e78..4bb1a8c 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3124,6 +3124,18 @@
 
         <activity android:name=".homepage.contextualcards.ContextualCardFeedbackDialog"
                   android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
+
+        <activity
+            android:name="Settings$WifiCallingDisclaimerActivity"
+            android:label="@string/wifi_calling_settings_title"
+            android:taskAffinity="com.android.settings">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+                android:value="com.android.settings.wifi.calling.WifiCallingDisclaimerFragment" />
+        </activity>
         <!-- This is the longest AndroidManifest.xml ever. -->
     </application>
 </manifest>
diff --git a/color-check-baseline.xml b/color-check-baseline.xml
index e9f8d58..7074481 100644
--- a/color-check-baseline.xml
+++ b/color-check-baseline.xml
@@ -37,54 +37,6 @@
         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:textColor=&quot;@color/bluetooth_dialog_text_color&quot;  />"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/layout/bluetooth_pin_confirm.xml"
-            line="44"
-            column="13"/>
-    </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:textColor=&quot;@color/bluetooth_dialog_text_color&quot;"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/layout/bluetooth_pin_confirm.xml"
-            line="67"
-            column="13"/>
-    </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:textColor=&quot;@color/bluetooth_dialog_text_color&quot;  />"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/layout/bluetooth_pin_confirm.xml"
-            line="77"
-            column="13"/>
-    </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
@@ -101,22 +53,6 @@
         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;black&quot;>#000&lt;/color>"
-        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/values/colors.xml"
-            line="18"
-            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;switch_bar_background&quot;>#dadce0&lt;/color>"
         errorLine2="  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
@@ -133,8 +69,8 @@
         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;red&quot;>#F00&lt;/color>"
-        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="    &lt;color name=&quot;crypt_keeper_clock_background&quot;>#ff9a9a9a&lt;/color>"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
             line="19"
@@ -165,8 +101,8 @@
         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;blue&quot;>#00F&lt;/color>"
-        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="    &lt;color name=&quot;crypt_keeper_clock_foreground&quot;>#ff666666&lt;/color>"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
             line="20"
@@ -181,6 +117,22 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="    &lt;color name=&quot;crypt_keeper_clock_am_pm&quot;>#ff9a9a9a&lt;/color>"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/values/colors.xml"
+            line="21"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
         errorLine1="  &lt;color name=&quot;homepage_accessibility_background&quot;>#783BE5&lt;/color>"
         errorLine2="  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
@@ -197,8 +149,8 @@
         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;bluetooth_dialog_text_color&quot;>#8a000000&lt;/color>"
-        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="    &lt;color name=&quot;crypt_keeper_password_background&quot;>#70606060&lt;/color>"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
             line="22"
@@ -229,8 +181,8 @@
         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;crypt_keeper_clock_background&quot;>#ff9a9a9a&lt;/color>"
-        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="    &lt;color name=&quot;divider_color&quot;>#20ffffff&lt;/color>"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
             line="24"
@@ -261,75 +213,11 @@
         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;crypt_keeper_clock_foreground&quot;>#ff666666&lt;/color>"
-        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/values/colors.xml"
-            line="25"
-            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;crypt_keeper_clock_am_pm&quot;>#ff9a9a9a&lt;/color>"
-        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/values/colors.xml"
-            line="26"
-            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;crypt_keeper_password_background&quot;>#70606060&lt;/color>"
-        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/values/colors.xml"
-            line="27"
-            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;divider_color&quot;>#20ffffff&lt;/color>"
-        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/values/colors.xml"
-            line="29"
-            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;setup_lock_pattern_view_success_color_dark&quot;>#ff84ffff&lt;/color>"
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="32"
+            line="27"
             column="5"/>
     </issue>
 
@@ -345,7 +233,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="34"
+            line="29"
             column="5"/>
     </issue>
 
@@ -361,7 +249,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="35"
+            line="30"
             column="5"/>
     </issue>
 
@@ -377,7 +265,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="36"
+            line="31"
             column="5"/>
     </issue>
 
@@ -393,7 +281,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="38"
+            line="33"
             column="5"/>
     </issue>
 
@@ -409,7 +297,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="39"
+            line="34"
             column="5"/>
     </issue>
 
@@ -425,7 +313,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="41"
+            line="36"
             column="5"/>
     </issue>
 
@@ -441,7 +329,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="46"
+            line="41"
             column="5"/>
     </issue>
 
@@ -457,7 +345,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="47"
+            line="42"
             column="5"/>
     </issue>
 
@@ -473,7 +361,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="49"
+            line="44"
             column="5"/>
     </issue>
 
@@ -489,7 +377,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="50"
+            line="45"
             column="5"/>
     </issue>
 
@@ -505,7 +393,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="54"
+            line="49"
             column="5"/>
     </issue>
 
@@ -521,7 +409,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="57"
+            line="52"
             column="5"/>
     </issue>
 
@@ -537,7 +425,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="60"
+            line="55"
             column="5"/>
     </issue>
 
@@ -553,7 +441,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="61"
+            line="56"
             column="5"/>
     </issue>
 
@@ -569,7 +457,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="62"
+            line="57"
             column="5"/>
     </issue>
 
@@ -585,7 +473,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="63"
+            line="58"
             column="5"/>
     </issue>
 
@@ -597,11 +485,11 @@
         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;switch_bar_background&quot;>#ff80868B&lt;/color>"
-        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="    &lt;color name=&quot;switch_bar_background&quot;>#757575&lt;/color>"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="64"
+            line="59"
             column="5"/>
     </issue>
 
@@ -617,7 +505,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="66"
+            line="61"
             column="5"/>
     </issue>
 
@@ -633,7 +521,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="67"
+            line="62"
             column="5"/>
     </issue>
 
@@ -649,7 +537,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="68"
+            line="63"
             column="5"/>
     </issue>
 
@@ -665,7 +553,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="69"
+            line="64"
             column="5"/>
     </issue>
 
@@ -681,7 +569,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="70"
+            line="65"
             column="5"/>
     </issue>
 
@@ -697,7 +585,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="71"
+            line="66"
             column="5"/>
     </issue>
 
@@ -713,7 +601,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="72"
+            line="67"
             column="5"/>
     </issue>
 
@@ -729,7 +617,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="73"
+            line="68"
             column="5"/>
     </issue>
 
@@ -745,7 +633,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="74"
+            line="69"
             column="5"/>
     </issue>
 
@@ -761,7 +649,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="75"
+            line="70"
             column="5"/>
     </issue>
 
@@ -777,7 +665,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="76"
+            line="71"
             column="5"/>
     </issue>
 
@@ -793,7 +681,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="78"
+            line="73"
             column="5"/>
     </issue>
 
@@ -809,7 +697,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="81"
+            line="76"
             column="5"/>
     </issue>
 
@@ -825,7 +713,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="84"
+            line="79"
             column="5"/>
     </issue>
 
@@ -841,7 +729,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="87"
+            line="82"
             column="5"/>
     </issue>
 
@@ -857,7 +745,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="90"
+            line="85"
             column="5"/>
     </issue>
 
@@ -873,7 +761,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="91"
+            line="86"
             column="5"/>
     </issue>
 
@@ -889,7 +777,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="92"
+            line="87"
             column="5"/>
     </issue>
 
@@ -905,7 +793,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="93"
+            line="88"
             column="5"/>
     </issue>
 
@@ -921,7 +809,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="94"
+            line="89"
             column="5"/>
     </issue>
 
@@ -937,7 +825,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="95"
+            line="90"
             column="5"/>
     </issue>
 
@@ -953,7 +841,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="96"
+            line="91"
             column="5"/>
     </issue>
 
@@ -969,7 +857,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="97"
+            line="92"
             column="5"/>
     </issue>
 
@@ -985,7 +873,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="98"
+            line="93"
             column="5"/>
     </issue>
 
@@ -1001,7 +889,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="99"
+            line="94"
             column="5"/>
     </issue>
 
@@ -1017,7 +905,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="100"
+            line="95"
             column="5"/>
     </issue>
 
@@ -1033,7 +921,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="101"
+            line="96"
             column="5"/>
     </issue>
 
@@ -1049,7 +937,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="102"
+            line="97"
             column="5"/>
     </issue>
 
@@ -1065,7 +953,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="103"
+            line="98"
             column="5"/>
     </issue>
 
@@ -1081,7 +969,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="104"
+            line="99"
             column="5"/>
     </issue>
 
@@ -1097,7 +985,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="105"
+            line="100"
             column="5"/>
     </issue>
 
@@ -1113,7 +1001,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="106"
+            line="102"
             column="5"/>
     </issue>
 
@@ -1129,7 +1017,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="110"
+            line="108"
             column="5"/>
     </issue>
 
@@ -1145,7 +1033,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="115"
+            line="113"
             column="5"/>
     </issue>
 
@@ -1161,7 +1049,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="116"
+            line="114"
             column="5"/>
     </issue>
 
@@ -1177,7 +1065,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="117"
+            line="115"
             column="5"/>
     </issue>
 
@@ -1193,7 +1081,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="118"
+            line="116"
             column="5"/>
     </issue>
 
@@ -1209,7 +1097,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="119"
+            line="117"
             column="5"/>
     </issue>
 
@@ -1225,7 +1113,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="120"
+            line="118"
             column="5"/>
     </issue>
 
@@ -1241,7 +1129,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="123"
+            line="121"
             column="5"/>
     </issue>
 
@@ -1257,7 +1145,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="124"
+            line="122"
             column="5"/>
     </issue>
 
@@ -1273,7 +1161,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="125"
+            line="123"
             column="5"/>
     </issue>
 
@@ -1289,7 +1177,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="126"
+            line="124"
             column="5"/>
     </issue>
 
@@ -1305,7 +1193,55 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="127"
+            line="125"
+            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;notification_block_color&quot;>#ffff0000&lt;/color>"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/values/colors.xml"
+            line="128"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="    &lt;color name=&quot;notification_silence_color&quot;>#fbbc04&lt;/color>"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/values/colors.xml"
+            line="129"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="    &lt;color name=&quot;notification_alert_color&quot;>#30a751&lt;/color>"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/values/colors.xml"
+            line="130"
             column="5"/>
     </issue>
 
@@ -1321,7 +1257,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="133"
+            line="136"
             column="5"/>
     </issue>
 
@@ -1337,7 +1273,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="136"
+            line="139"
             column="5"/>
     </issue>
 
@@ -1353,7 +1289,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="137"
+            line="140"
             column="5"/>
     </issue>
 
@@ -1369,7 +1305,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="138"
+            line="141"
             column="5"/>
     </issue>
 
@@ -1653,12 +1589,12 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="                android:color=&quot;@color/homepage_about_background&quot; />"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="            android:color=&quot;@color/homepage_about_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/drawable/ic_homepage_about.xml"
-            line="23"
-            column="17"/>
+            line="24"
+            column="13"/>
     </issue>
 
     <issue
@@ -1669,12 +1605,12 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="                android:color=&quot;@color/homepage_accessibility_background&quot; />"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="            android:color=&quot;@color/homepage_accessibility_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/drawable/ic_homepage_accessibility.xml"
-            line="23"
-            column="17"/>
+            line="24"
+            column="13"/>
     </issue>
 
     <issue
@@ -1685,12 +1621,12 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="                android:color=&quot;@color/homepage_accessibility_background&quot; />"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="            android:color=&quot;@color/homepage_accessibility_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/drawable/ic_homepage_accessibility.xml"
-            line="23"
-            column="17"/>
+            line="24"
+            column="13"/>
     </issue>
 
     <issue
@@ -1701,12 +1637,12 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="                android:color=&quot;@color/homepage_accounts_background&quot; />"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="            android:color=&quot;@color/homepage_accounts_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/drawable/ic_homepage_accounts.xml"
-            line="23"
-            column="17"/>
+            line="24"
+            column="13"/>
     </issue>
 
     <issue
@@ -1717,12 +1653,12 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="                android:color=&quot;@color/homepage_app_and_notification_background&quot; />"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="            android:color=&quot;@color/homepage_app_and_notification_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/drawable/ic_homepage_apps.xml"
-            line="23"
-            column="17"/>
+            line="24"
+            column="13"/>
     </issue>
 
     <issue
@@ -1733,12 +1669,12 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="                android:color=&quot;@color/homepage_battery_background&quot; />"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="            android:color=&quot;@color/homepage_battery_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/drawable/ic_homepage_battery.xml"
-            line="23"
-            column="17"/>
+            line="24"
+            column="13"/>
     </issue>
 
     <issue
@@ -1749,12 +1685,12 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="                android:color=&quot;@color/homepage_connected_device_background&quot; />"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="            android:color=&quot;@color/homepage_connected_device_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/drawable/ic_homepage_connected_device.xml"
-            line="23"
-            column="17"/>
+            line="24"
+            column="13"/>
     </issue>
 
     <issue
@@ -1765,12 +1701,12 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="                android:color=&quot;@color/homepage_display_background&quot; />"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="            android:color=&quot;@color/homepage_display_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/drawable/ic_homepage_display.xml"
-            line="23"
-            column="17"/>
+            line="24"
+            column="13"/>
     </issue>
 
     <issue
@@ -1781,28 +1717,12 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        android:color=&quot;@color/homepage_generic_icon_background&quot; />"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable/ic_homepage_generic_background.xml"
-            line="20"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="                android:color=&quot;@color/homepage_location_background&quot;/>"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="            android:color=&quot;@color/homepage_location_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/drawable/ic_homepage_location.xml"
-            line="23"
-            column="17"/>
+            line="24"
+            column="13"/>
     </issue>
 
     <issue
@@ -1813,12 +1733,12 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="                android:color=&quot;@color/homepage_network_background&quot; />"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="            android:color=&quot;@color/homepage_network_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/drawable/ic_homepage_network.xml"
-            line="23"
-            column="17"/>
+            line="24"
+            column="13"/>
     </issue>
 
     <issue
@@ -1829,12 +1749,12 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="                android:color=&quot;@color/homepage_privacy_background&quot;/>"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="            android:color=&quot;@color/homepage_privacy_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/drawable/ic_homepage_privacy.xml"
-            line="23"
-            column="17"/>
+            line="24"
+            column="13"/>
     </issue>
 
     <issue
@@ -1845,12 +1765,12 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="                android:color=&quot;@color/homepage_security_background&quot; />"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="            android:color=&quot;@color/homepage_security_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/drawable/ic_homepage_security.xml"
-            line="23"
-            column="17"/>
+            line="24"
+            column="13"/>
     </issue>
 
     <issue
@@ -1861,12 +1781,12 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="                android:color=&quot;@color/homepage_sound_background&quot; />"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="            android:color=&quot;@color/homepage_sound_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/drawable/ic_homepage_sound.xml"
-            line="23"
-            column="17"/>
+            line="24"
+            column="13"/>
     </issue>
 
     <issue
@@ -1877,12 +1797,12 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="                android:color=&quot;@color/homepage_storage_background&quot; />"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="            android:color=&quot;@color/homepage_storage_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/drawable/ic_homepage_storage.xml"
-            line="23"
-            column="17"/>
+            line="24"
+            column="13"/>
     </issue>
 
     <issue
@@ -1893,12 +1813,12 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="                android:color=&quot;@color/homepage_support_background&quot; />"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="            android:color=&quot;@color/homepage_support_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/drawable/ic_homepage_support.xml"
-            line="23"
-            column="17"/>
+            line="24"
+            column="13"/>
     </issue>
 
     <issue
@@ -1909,12 +1829,12 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="                android:color=&quot;@color/homepage_support_background&quot; />"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="            android:color=&quot;@color/homepage_support_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/drawable/ic_homepage_support.xml"
-            line="23"
-            column="17"/>
+            line="24"
+            column="13"/>
     </issue>
 
     <issue
@@ -1925,11 +1845,107 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="                android:color=&quot;@color/homepage_system_background&quot; />"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="            android:color=&quot;@color/homepage_system_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/drawable/ic_homepage_system_dashboard.xml"
-            line="23"
+            line="24"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="                    android:color=&quot;@color/notification_alert_color&quot;/>"
+        errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/ic_notification_alert.xml"
+            line="27"
+            column="21"/>
+    </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:fillColor=&quot;@color/notification_alert_color&quot;"
+        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/ic_notification_alert.xml"
+            line="39"
+            column="17"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="                    android:color=&quot;@color/notification_block_color&quot;/>"
+        errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/ic_notification_block.xml"
+            line="27"
+            column="21"/>
+    </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:fillColor=&quot;@color/notification_block_color&quot;"
+        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/ic_notification_block.xml"
+            line="39"
+            column="17"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="                    android:color=&quot;@color/notification_silence_color&quot;/>"
+        errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/ic_notification_silence.xml"
+            line="27"
+            column="21"/>
+    </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:fillColor=&quot;@color/notification_silence_color&quot;"
+        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/ic_notification_silence.xml"
+            line="39"
             column="17"/>
     </issue>
 
@@ -2437,12 +2453,12 @@
         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;string name=&quot;sync_plug&quot; msgid=&quot;3905078969081888738&quot;>&quot;‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‏‎‎‎‏‏‎‏‎‎‎‎‎‏‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎&quot;&lt;font fgcolor=&quot;#ffffffff&quot;>&quot;‎‏‎‎‏‏‏‎Welcome to Google sync!‎‏‎‎‏‏‎&quot;&lt;/font>&quot;‎‏‎‎‏‏‏‎ ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎A Google approach to syncing data to allow access to your contacts, appointments, and more from wherever you are.‎‏‎‎‏‎&quot;&lt;/string>"
-        errorLine2="                                                                                                                                                                       ~~~~~~~~~~~~~~~~~~~">
+        errorLine1="    &lt;string name=&quot;sync_plug&quot; msgid=&quot;3905078969081888738&quot;>&quot;‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‏‎‎‎‏‏‎‏‎‎‎‎‎‏‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎&quot;&lt;font fgcolor=&quot;#ffffffff&quot;>&quot;‎‏‎‎‏‏‏‎Welcome to Google sync!‎‏‎‎‏‏‎&quot;&lt;/font>&quot;‎‏‎‎‏‏‏‎ ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎A Google approach to syncing data to allow access to your contacts, appointments, and more from wherever you are.‎‏‎‎‏‎&quot;&lt;/string>"
+        errorLine2="                                                                                                                                                                        ~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values-en-rXC/strings.xml"
-            line="2533"
-            column="168"/>
+            line="2580"
+            column="169"/>
     </issue>
 
     <issue
@@ -2457,7 +2473,7 @@
         errorLine2="                                                               ~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values-en-rAU/strings.xml"
-            line="2534"
+            line="2581"
             column="64"/>
     </issue>
 
@@ -2473,7 +2489,7 @@
         errorLine2="                                                               ~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values-en-rCA/strings.xml"
-            line="2534"
+            line="2581"
             column="64"/>
     </issue>
 
@@ -2489,7 +2505,7 @@
         errorLine2="                                                               ~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values-en-rGB/strings.xml"
-            line="2534"
+            line="2581"
             column="64"/>
     </issue>
 
@@ -2505,7 +2521,7 @@
         errorLine2="                                                               ~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values-en-rIN/strings.xml"
-            line="2534"
+            line="2581"
             column="64"/>
     </issue>
 
@@ -2521,7 +2537,7 @@
         errorLine2="                                   ~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/strings.xml"
-            line="5885"
+            line="6026"
             column="36"/>
     </issue>
 
@@ -2537,7 +2553,7 @@
         errorLine2="                                        ^">
         <location
             file="res/values/styles.xml"
-            line="174"
+            line="163"
             column="41"/>
     </issue>
 
@@ -2553,7 +2569,7 @@
         errorLine2="                                           ^">
         <location
             file="res/values/styles.xml"
-            line="388"
+            line="380"
             column="44"/>
     </issue>
 
@@ -2569,7 +2585,7 @@
         errorLine2="                                           ^">
         <location
             file="res/values/styles.xml"
-            line="394"
+            line="386"
             column="44"/>
     </issue>
 
@@ -2585,7 +2601,7 @@
         errorLine2="                                           ^">
         <location
             file="res/values/styles.xml"
-            line="395"
+            line="387"
             column="44"/>
     </issue>
 
@@ -2601,7 +2617,7 @@
         errorLine2="                                 ^">
         <location
             file="res/values/styles.xml"
-            line="430"
+            line="423"
             column="34"/>
     </issue>
 
@@ -2729,7 +2745,7 @@
         errorLine2="                                            ^">
         <location
             file="res/values/themes.xml"
-            line="166"
+            line="169"
             column="45"/>
     </issue>
 
@@ -2745,7 +2761,7 @@
         errorLine2="                                                ^">
         <location
             file="res/values/themes.xml"
-            line="167"
+            line="170"
             column="49"/>
     </issue>
 
@@ -2761,7 +2777,7 @@
         errorLine2="                                            ^">
         <location
             file="res/values/themes.xml"
-            line="175"
+            line="178"
             column="45"/>
     </issue>
 
@@ -2777,7 +2793,7 @@
         errorLine2="                                                ^">
         <location
             file="res/values/themes.xml"
-            line="176"
+            line="179"
             column="49"/>
     </issue>
 
@@ -2793,7 +2809,7 @@
         errorLine2="                                      ^">
         <location
             file="res/values/themes.xml"
-            line="192"
+            line="195"
             column="39"/>
     </issue>
 
@@ -2809,7 +2825,7 @@
         errorLine2="                                       ^">
         <location
             file="res/values/themes.xml"
-            line="193"
+            line="196"
             column="40"/>
     </issue>
 
@@ -2825,7 +2841,7 @@
         errorLine2="                                     ^">
         <location
             file="res/values/themes.xml"
-            line="194"
+            line="197"
             column="38"/>
     </issue>
 
diff --git a/res/drawable/ic_face_header.xml b/res/drawable/ic_face_header.xml
index 4493d66..15ea7ae 100644
--- a/res/drawable/ic_face_header.xml
+++ b/res/drawable/ic_face_header.xml
@@ -1,4 +1,4 @@
-<!--
+<?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");
@@ -15,9 +15,17 @@
   -->
 
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
-    android:width="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-    <path android:fillColor="#000" android:pathData="M9,11.75A1.25,1.25 0 0,0 7.75,13A1.25,1.25 0 0,0 9,14.25A1.25,1.25 0 0,0 10.25,13A1.25,1.25 0 0,0 9,11.75M15,11.75A1.25,1.25 0 0,0 13.75,13A1.25,1.25 0 0,0 15,14.25A1.25,1.25 0 0,0 16.25,13A1.25,1.25 0 0,0 15,11.75M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20C7.59,20 4,16.41 4,12C4,11.71 4,11.42 4.05,11.14C6.41,10.09 8.28,8.16 9.26,5.77C11.07,8.33 14.05,10 17.42,10C18.2,10 18.95,9.91 19.67,9.74C19.88,10.45 20,11.21 20,12C20,16.41 16.41,20 12,20Z" />
+    android:width="32dp"
+    android:height="32dp"
+    android:tint="?android:attr/colorPrimary"
+    android:viewportHeight="24"
+    android:viewportWidth="24">
+
+    <path
+        android:fillColor="#000000"
+        android:pathData="M 12 13 C 13.1045694997 13 14 13.8954305003 14 15 C 14 16.1045694997 13.1045694997 17 12 17 C 10.8954305003 17 10 16.1045694997 10 15 C 10 13.8954305003 10.8954305003 13 12 13 Z" />
+    <path
+        android:fillColor="#000000"
+        android:pathData="M18.5,1C16.01,1,14,3.01,14,5.5V8H6c-1.1,0-2,0.9-2,2v10c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V10c0-1.1-0.9-2-2-2h-2V5.5 C16,4.12,17.12,3,18.5,3C19.88,3,21,4.12,21,5.5V6h2V5.5C23,3.01,20.99,1,18.5,1z M18,10v10H6V10H18z" />
+    <path android:pathData="M0,0h24v24H0V0z" />
 </vector>
\ No newline at end of file
diff --git a/res/drawable/ic_notification_alert.xml b/res/drawable/ic_notification_alert.xml
new file mode 100644
index 0000000..07e7b48
--- /dev/null
+++ b/res/drawable/ic_notification_alert.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2019 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/back">
+        <shape android:shape="oval">
+            <solid
+                android:color="@android:color/transparent" />
+            <size
+                android:height="48dp"
+                android:width="48dp"/>
+            <stroke android:width="1dp"
+                    android:color="@color/notification_alert_color"/>
+        </shape>
+    </item>
+    <item
+        android:id="@+id/fore"
+        android:gravity="center">
+        <vector
+            android:height="24dp"
+            android:width="24dp"
+            android:viewportHeight="24"
+            android:viewportWidth="24">
+            <path
+                android:fillColor="@color/notification_alert_color"
+                android:pathData="M7.58 4.08L6.15 2.65C3.75 4.48 2.17 7.3 2.03 10.5h2c.15-2.65 1.51-4.97 3.55-6.42zm12.39 6.42h2c-.15-3.2-1.73-6.02-4.12-7.85l-1.42 1.43c2.02 1.45 3.39 3.77 3.54 6.42zM18 11c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2v-5zm-6 11c.14 0 .27-.01.4-.04.65-.14 1.18-.58 1.44-1.18.1-.24.15-.5.15-.78h-4c.01 1.1.9 2 2.01 2z"/>
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/ic_notification_block.xml b/res/drawable/ic_notification_block.xml
new file mode 100644
index 0000000..d4f0a2a
--- /dev/null
+++ b/res/drawable/ic_notification_block.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2019 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/back">
+        <shape android:shape="oval">
+            <solid
+                android:color="@android:color/transparent" />
+            <size
+                android:height="48dp"
+                android:width="48dp"/>
+            <stroke android:width="1dp"
+                    android:color="@color/notification_block_color"/>
+        </shape>
+    </item>
+    <item
+        android:id="@+id/fore"
+        android:gravity="center">
+        <vector
+            android:height="24dp"
+            android:width="24dp"
+            android:viewportHeight="24"
+            android:viewportWidth="24">
+            <path
+                android:fillColor="@color/notification_block_color"
+                android:pathData="M12.0,2.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0zM4.0,12.0c0.0,-4.42 3.58,-8.0 8.0,-8.0 1.85,0.0 3.5,0.63 4.9,1.69L5.69,16.9C4.63,15.55 4.0,13.85 4.0,12.0zm8.0,8.0c-1.85,0.0 -3.55,-0.63 -4.9,-1.69L18.31,7.1C19.37,8.45 20.0,10.15 20.0,12.0c0.0,4.42 -3.58,8.0 -8.0,8.0z"/>
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/ic_notification_silence.xml b/res/drawable/ic_notification_silence.xml
new file mode 100644
index 0000000..673340f
--- /dev/null
+++ b/res/drawable/ic_notification_silence.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2019 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/back">
+        <shape android:shape="oval">
+            <solid
+                android:color="@android:color/transparent" />
+            <size
+                android:height="48dp"
+                android:width="48dp"/>
+            <stroke android:width="1dp"
+                    android:color="@color/notification_silence_color"/>
+        </shape>
+    </item>
+    <item
+        android:id="@+id/fore"
+        android:gravity="center">
+        <vector
+            android:height="24dp"
+            android:width="24dp"
+            android:viewportHeight="24"
+            android:viewportWidth="24">
+            <path
+                android:fillColor="@color/notification_silence_color"
+                android:pathData="M20 18.69L7.84 6.14 5.27 3.49 4 4.76l2.8 2.8v.01c-.52.99-.8 2.16-.8 3.42v5l-2 2v1h13.73l2 2L21 19.72l-1-1.03zM12 22c1.11 0 2-.89 2-2h-4c0 1.11.89 2 2 2zm6-7.32V11c0-3.08-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68c-.15.03-.29.08-.42.12-.1.03-.2.07-.3.11h-.01c-.01 0-.01 0-.02.01-.23.09-.46.2-.68.31 0 0-.01 0-.01.01L18 14.68z" />
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/layout/homepage_condition_footer.xml b/res/layout/homepage_condition_footer.xml
index 56687fe..cc84f52 100644
--- a/res/layout/homepage_condition_footer.xml
+++ b/res/layout/homepage_condition_footer.xml
@@ -29,6 +29,7 @@
         android:id="@+id/collapse_button"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:src="@drawable/ic_expand_less"/>
+        android:src="@drawable/ic_expand_less"
+        android:tint="?android:attr/colorAccent"/>
 
 </LinearLayout>
\ No newline at end of file
diff --git a/res/layout/homepage_condition_header.xml b/res/layout/homepage_condition_header.xml
index a2796ec..5c1b181 100644
--- a/res/layout/homepage_condition_header.xml
+++ b/res/layout/homepage_condition_header.xml
@@ -45,7 +45,8 @@
             android:paddingTop="@dimen/homepage_condition_header_indicator_padding_top"
             android:paddingStart="@dimen/homepage_condition_header_indicator_padding_start"
             android:paddingEnd="@dimen/homepage_condition_header_indicator_padding_end"
-            android:src="@*android:drawable/ic_expand_more"/>
+            android:src="@*android:drawable/ic_expand_more"
+            android:tint="?android:attr/colorAccent"/>
 
     </LinearLayout>
 
diff --git a/res/layout/notif_importance_preference.xml b/res/layout/notif_importance_preference.xml
new file mode 100644
index 0000000..5d79ff3
--- /dev/null
+++ b/res/layout/notif_importance_preference.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/app_entities_header"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center"
+    android:orientation="horizontal">
+
+    <LinearLayout
+        android:id="@+id/block"
+        android:layout_width="0dp"
+        android:layout_weight="33.33"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="16dp"
+        android:layout_marginTop="16dp"
+        android:orientation="vertical"
+        android:gravity="center">
+
+        <ImageButton
+            android:id="@+id/block_icon"
+            android:layout_width="@dimen/notification_importance_toggle_size"
+            android:layout_height="@dimen/notification_importance_toggle_size"
+            android:background="?android:attr/selectableItemBackgroundBorderless"
+            android:src="@drawable/ic_notification_block"
+            android:contentDescription="@string/notification_block_title" />
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/notification_block_title"
+            android:layout_marginTop="@dimen/notification_importance_toggle_marginTop"
+            android:layout_marginBottom="@dimen/notification_importance_toggle_marginBottom"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/silence"
+        android:layout_width="0dp"
+        android:layout_weight="33.33"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="16dp"
+        android:layout_marginTop="16dp"
+        android:orientation="vertical"
+        android:gravity="center">
+
+        <ImageButton
+            android:id="@+id/silence_icon"
+            android:layout_width="@dimen/notification_importance_toggle_size"
+            android:layout_height="@dimen/notification_importance_toggle_size"
+            android:background="?android:attr/selectableItemBackgroundBorderless"
+            android:src="@drawable/ic_notification_silence"
+            android:contentDescription="@string/notification_silence_title" />
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/notification_silence_title"
+            android:layout_marginTop="@dimen/notification_importance_toggle_marginTop"
+            android:layout_marginBottom="@dimen/notification_importance_toggle_marginBottom"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/alert"
+        android:layout_width="0dp"
+        android:layout_weight="33.33"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="16dp"
+        android:layout_marginTop="16dp"
+        android:orientation="vertical"
+        android:gravity="center">
+
+        <ImageButton
+            android:id="@+id/alert_icon"
+            android:layout_width="@dimen/notification_importance_toggle_size"
+            android:layout_height="@dimen/notification_importance_toggle_size"
+            android:background="?android:attr/selectableItemBackgroundBorderless"
+            android:src="@drawable/ic_notification_alert"
+            android:contentDescription="@string/notification_alert_title" />
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/notification_alert_title"
+            android:layout_marginTop="@dimen/notification_importance_toggle_marginTop"
+            android:layout_marginBottom="@dimen/notification_importance_toggle_marginBottom"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead" />
+    </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/preference_single_target.xml b/res/layout/preference_single_target.xml
new file mode 100644
index 0000000..b4a9de0
--- /dev/null
+++ b/res/layout/preference_single_target.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 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.
+  -->
+
+<!-- Based off preference_two_target.xml with Material ripple moved to parent for full ripple. -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:gravity="center_vertical"
+    android:background="?android:attr/selectableItemBackground"
+    android:clipToPadding="false">
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:gravity="start|center_vertical"
+        android:clipToPadding="false"
+        android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+        android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+        <LinearLayout
+            android:id="@+id/icon_frame"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="start|center_vertical"
+            android:minWidth="56dp"
+            android:orientation="horizontal"
+            android:clipToPadding="false"
+            android:paddingTop="4dp"
+            android:paddingBottom="4dp">
+            <androidx.preference.internal.PreferenceImageView
+                android:id="@android:id/icon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                settings:maxWidth="48dp"
+                settings:maxHeight="48dp" />
+        </LinearLayout>
+
+        <RelativeLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:paddingTop="16dp"
+            android:paddingBottom="16dp">
+
+            <TextView
+                android:id="@android:id/title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:textAppearance="?android:attr/textAppearanceListItem"
+                android:ellipsize="marquee" />
+
+            <TextView
+                android:id="@android:id/summary"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_below="@android:id/title"
+                android:layout_alignStart="@android:id/title"
+                android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+                android:textColor="?android:attr/textColorSecondary"
+                android:maxLines="10" />
+
+        </RelativeLayout>
+
+    </LinearLayout>
+
+    <include layout="@layout/preference_two_target_divider" />
+
+    <!-- Preference should place its actual preference widget here. -->
+    <LinearLayout
+        android:id="@android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:minWidth="64dp"
+        android:gravity="center"
+        android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/res/layout/vpn_dialog.xml b/res/layout/vpn_dialog.xml
index 71ce0ad..a626205 100644
--- a/res/layout/vpn_dialog.xml
+++ b/res/layout/vpn_dialog.xml
@@ -140,6 +140,46 @@
                     android:labelFor="@+id/routes"/>
             <EditText style="@style/vpn_value" android:id="@+id/routes"
                     android:hint="@string/vpn_not_used"/>
+
+            <TextView android:id="@+id/vpn_proxy_settings_title"
+                      style="@style/vpn_label"
+                      android:text="@string/proxy_settings_title"
+                      android:labelFor="@+id/vpn_proxy_settings" />
+
+            <Spinner android:id="@+id/vpn_proxy_settings"
+                     style="@style/vpn_value"
+                     android:prompt="@string/proxy_settings_title"
+                     android:entries="@array/vpn_proxy_settings" />
+
+            <LinearLayout
+                android:id="@+id/vpn_proxy_fields"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:visibility="gone" >
+
+                <TextView
+                    style="@style/vpn_label"
+                    android:text="@string/proxy_hostname_label"
+                    android:labelFor="@+id/vpn_proxy_host" />
+
+                <EditText
+                    android:id="@+id/vpn_proxy_host"
+                    style="@style/vpn_value"
+                    android:hint="@string/proxy_hostname_hint"
+                    android:inputType="textNoSuggestions" />
+
+                <TextView
+                    style="@style/vpn_label"
+                    android:text="@string/proxy_port_label"
+                    android:labelFor="@+id/vpn_proxy_port" />
+
+                <EditText
+                    android:id="@+id/vpn_proxy_port"
+                    style="@style/vpn_value"
+                    android:hint="@string/proxy_port_hint"
+                    android:inputType="number" />
+            </LinearLayout>
         </LinearLayout>
 
         <LinearLayout android:id="@+id/login"
diff --git a/res/layout/wfc_disclaimer_fragment.xml b/res/layout/wfc_disclaimer_fragment.xml
new file mode 100644
index 0000000..00baae5
--- /dev/null
+++ b/res/layout/wfc_disclaimer_fragment.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:layout_marginStart="16dp"
+        android:layout_marginBottom="20dp"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:text="@string/wfc_disclaimer_title_text" />
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:background="?android:attr/listDivider" />
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/disclaimer_item_list"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" >
+
+        <Button
+            android:id="@+id/disagree_button"
+            style="@style/DisclaimerNegativeButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:text="@string/wfc_disclaimer_disagree_text" />
+
+        <Space
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1" />
+
+        <Button
+            android:id="@+id/agree_button"
+            style="@style/DisclaimerPositiveButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:text="@string/wfc_disclaimer_agree_button_text" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/res/layout/wfc_simple_disclaimer_item.xml b/res/layout/wfc_simple_disclaimer_item.xml
new file mode 100644
index 0000000..ee43182
--- /dev/null
+++ b/res/layout/wfc_simple_disclaimer_item.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:paddingTop="16dp"
+    android:paddingBottom="20dp"
+    android:paddingStart="16dp"
+    android:paddingEnd="16dp"
+    android:gravity="center_vertical">
+    <TextView
+        android:id="@+id/disclaimer_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="@android:style/TextAppearance.Material.Subhead" />
+    <TextView
+        android:id="@+id/disclaimer_desc"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="@android:style/TextAppearance.Material.Body1"
+        android:textColor="?android:attr/textColorSecondary"
+        android:layout_below="@id/disclaimer_title" />
+</RelativeLayout>
\ No newline at end of file
diff --git a/res/layout/wifi_button_preference_widget.xml b/res/layout/wifi_button_preference_widget.xml
index 1ecb98c..0999d20 100644
--- a/res/layout/wifi_button_preference_widget.xml
+++ b/res/layout/wifi_button_preference_widget.xml
@@ -23,5 +23,4 @@
            android:minHeight="@dimen/min_tap_target_size"
            android:layout_gravity="center"
            android:background="@null"
-           android:visibility="gone"
-           android:contentDescription="@string/wifi_add_network" />
+           android:visibility="gone"/>
diff --git a/res/layout/wifi_dialog.xml b/res/layout/wifi_dialog.xml
index 1ae3bf5..333296c 100644
--- a/res/layout/wifi_dialog.xml
+++ b/res/layout/wifi_dialog.xml
@@ -71,7 +71,7 @@
                         android:layout_centerVertical="true"
                         android:background="@null"
                         android:src="@drawable/ic_scan_24dp"
-                        android:contentDescription="@string/wifi_add_network" />
+                        android:contentDescription="@string/wifi_dpp_scan_qr_code"/>
                 </RelativeLayout>
 
                 <LinearLayout android:id="@+id/ssid_too_long_warning"
@@ -307,7 +307,7 @@
                         android:layout_centerVertical="true"
                         android:background="@null"
                         android:src="@drawable/ic_scan_24dp"
-                        android:contentDescription="@string/wifi_add_network" />
+                        android:contentDescription="@string/wifi_dpp_scan_qr_code"/>
                 </RelativeLayout>
             </LinearLayout>
 
diff --git a/res/layout/wifi_dpp_fragment_header.xml b/res/layout/wifi_dpp_fragment_header.xml
index e8e71d1..364f360 100644
--- a/res/layout/wifi_dpp_fragment_header.xml
+++ b/res/layout/wifi_dpp_fragment_header.xml
@@ -40,27 +40,35 @@
         android:src="@drawable/ic_devices_check_circle_green"
         android:scaleType="fitCenter"/>
 
-    <TextView
-        android:id="@android:id/title"
-        style="@style/TextAppearance.EntityHeaderTitle"
-        android:layout_width="match_parent"
+    <!-- Add title_summary_container to group content for Talkback -->
+    <LinearLayout
+        android:id="@+id/title_summary_container"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:gravity="center_horizontal"
-        android:textAlignment="center"
-        android:layout_marginTop="8dp"
-        android:paddingStart="32dp"
-        android:paddingEnd="32dp"/>
+        android:orientation="vertical"
+        android:focusable="true">
 
-    <TextView
-        android:id="@android:id/summary"
-        style="@style/TextAppearance.EntityHeaderSummary"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:singleLine="false"
-        android:gravity="center_horizontal"
-        android:textAlignment="center"
-        android:layout_marginTop="2dp"
-        android:paddingStart="32dp"
-        android:paddingEnd="32dp"/>
+        <TextView
+            android:id="@android:id/title"
+            style="@style/TextAppearance.EntityHeaderTitle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_horizontal"
+            android:textAlignment="center"
+            android:layout_marginTop="8dp"
+            android:paddingStart="32dp"
+            android:paddingEnd="32dp"/>
 
+        <TextView
+            android:id="@android:id/summary"
+            style="@style/TextAppearance.EntityHeaderSummary"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:singleLine="false"
+            android:gravity="center_horizontal"
+            android:textAlignment="center"
+            android:layout_marginTop="2dp"
+            android:paddingStart="32dp"
+            android:paddingEnd="32dp"/>
+    </LinearLayout>
 </LinearLayout>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 6a03582..7e0ba10 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -931,6 +931,14 @@
         <item>IPSec VPN with certificates and hybrid authentication</item>
     </string-array>
 
+    <!-- VPN proxy settings. -->
+    <string-array name="vpn_proxy_settings">
+        <!-- No HTTP proxy is used for the current VPN [CHAR LIMIT=25] -->
+        <item>None</item>
+        <!-- Manual HTTP proxy settings are used for the current VPN [CHAR LIMIT=25] -->
+        <item>Manual</item>
+    </string-array>
+
     <!-- Match this with the constants in LegacyVpnInfo. --> <skip />
     <!-- Status for a VPN network. [CHAR LIMIT=100] -->
     <string-array name="vpn_states">
@@ -1357,4 +1365,17 @@
         <item>"9"</item>
     </string-array>
 
+    <!-- WiFi calling mode array -->
+    <string-array name="wifi_calling_mode_summaries" translatable="false">
+         <item>@string/wifi_calling_mode_wifi_preferred_summary</item>
+         <item>@string/wifi_calling_mode_cellular_preferred_summary</item>
+         <item>@string/wifi_calling_mode_wifi_only_summary</item>
+    </string-array>
+
+    <!-- WiFi calling mode array without wifi only mode -->
+    <string-array name="wifi_calling_mode_summaries_without_wifi_only" translatable="false">
+         <item>@string/wifi_calling_mode_wifi_preferred_summary</item>
+         <item>@string/wifi_calling_mode_cellular_preferred_summary</item>
+    </string-array>
+
 </resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index c7bf1c7..e099cf0 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -132,6 +132,11 @@
         <attr name="aspectRatio" format="float" />
     </declare-styleable>
 
+    <declare-styleable name="ListWithEntrySummaryPreference">
+        <!-- Summaries of entry -->
+        <attr name="entrySummaries" format="reference" />
+    </declare-styleable>
+
     <!-- For UsageView -->
     <declare-styleable name="UsageView">
         <attr name="android:colorAccent" />
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 7b55a2b..0afd288 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -56,7 +56,7 @@
     <color name="material_blue_700">#3367D6</color>
     <color name="material_grey_100">#f5f5f5</color>
     <color name="material_grey_200">#ffffff</color>
-    <color name="switch_bar_background">#ff80868B</color>
+    <color name="switch_bar_background">#757575</color>
 
     <color name="message_text_incoming">#ffffffff</color>
     <color name="message_text_outgoing">#ff323232</color>
@@ -124,6 +124,11 @@
     <color name="face_anim_particle_color_4">#fffdd835</color> <!-- Material Yellow 600 -->
     <color name="face_anim_particle_error">#ff9e9e9e</color> <!-- Material Gray 500 -->
 
+    <!-- notification settings -->
+    <color name="notification_block_color">#ffff0000</color>
+    <color name="notification_silence_color">#fbbc04</color>
+    <color name="notification_alert_color">#30a751</color>
+
     <!-- launcher icon color -->
     <color name="icon_launcher_setting_color">@*android:color/accent_device_default_light</color>
 
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index aeeb403..f5b6e95 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -68,6 +68,9 @@
     <dimen name="notification_app_icon_size">64dp</dimen>
     <dimen name="notification_app_icon_badge_size">20dp</dimen>
     <dimen name="notification_app_icon_badge_margin">4dp</dimen>
+    <dimen name="notification_importance_toggle_size">48dp</dimen>
+    <dimen name="notification_importance_toggle_marginTop">8dp</dimen>
+    <dimen name="notification_importance_toggle_marginBottom">16dp</dimen>
     <dimen name="zen_schedule_rule_checkbox_padding">7dp</dimen>
     <dimen name="zen_schedule_day_margin">17dp</dimen>
 
@@ -279,6 +282,15 @@
 
     <dimen name="password_requirement_textsize">14sp</dimen>
 
+    <!-- Visible vertical space we want to show below password edittext field when ime is shown.
+         The unit is sp as it is related to the text size of password requirement item. -->
+    <dimen name="visible_vertical_space_below_password">20sp</dimen>
+
+    <!-- Select dialog -->
+    <dimen name="select_dialog_padding_start">20dp</dimen>
+    <dimen name="select_dialog_item_margin_start">12dp</dimen>
+    <dimen name="select_dialog_summary_padding_bottom">8dp</dimen>
+
     <!-- Padding between the donut and the storage summary. -->
     <dimen name="storage_summary_padding_end">16dp</dimen>
     <!-- Text size of the big number in the donut. -->
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f3fe1f0..aa43f12 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2157,6 +2157,10 @@
     <string name="wifi_dpp_sharing_wifi_with_this_device">Sharing Wi\u2011Fi with this device\u2026</string>
     <!-- Hint for Wi-Fi DPP handshake running [CHAR LIMIT=NONE]  -->
     <string name="wifi_dpp_connecting">Connecting\u2026</string>
+    <!-- Title for the fragment to show that the QR code is for sharing Wi-Fi hotspot network [CHAR LIMIT=50] -->
+    <string name="wifi_dpp_share_hotspot">Share hotspot</string>
+    <!-- Hint for the user to share Wi-Fi hotspot network [CHAR LIMIT=NONE] -->
+    <string name="wifi_dpp_scan_qr_code_to_share_hotspot">Scan this QR code with another device to join hotspot \u201c<xliff:g id="ssid" example="OfficeWifi">%1$s</xliff:g>\u201d</string>
      <!-- Label for the try again button [CHAR LIMIT=20]-->
     <string name="retry">Retry</string>
     <!-- Label for the check box to share a network with other users on the same device -->
@@ -2221,6 +2225,14 @@
 
     <!-- Button label to connect to a Wi-Fi network -->
     <string name="wifi_connect">Connect</string>
+    <!-- Turned on notification for Wi-Fi [CHAR LIMIT=40] -->
+    <string name="wifi_turned_on_message">Wi\u2011Fi turned on</string>
+    <!-- Connected to notification for Wi-Fi [CHAR LIMIT=NONE] -->
+    <string name="wifi_connected_to_message">@string/bluetooth_connected_summary</string>
+    <!-- Button label to connecting progress to a Wi-Fi network [CHAR LIMIT=20] -->
+    <string name="wifi_connecting">Connecting\u2026</string>
+    <!-- Button label to disconnect to a Wi-Fi network [CHAR LIMIT=NONE] -->
+    <string name="wifi_disconnect">@string/bluetooth_device_context_disconnect</string>
     <!-- Failured notification for connect -->
     <string name="wifi_failed_connect_message">Failed to connect to network</string>
     <!-- Button label to delete a Wi-Fi network -->
@@ -2378,8 +2390,6 @@
     <string name="wifi_hotspot_configure_ap_text_summary">AndroidAP WPA2 PSK hotspot</string>
     <!-- Default access point SSID used for tethering -->
     <string name="wifi_tether_configure_ssid_default">AndroidHotspot</string>
-    <!-- Summary text when hotspot is disabled because airplane mode is on [CHAR LIMIT=80]-->
-    <string name="wifi_tether_disabled_by_airplane">Unavailable because airplane mode is turned on</string>
 
     <!-- Do not translate. Used for diagnostic screens, precise translation is not necessary
          Wi-Fi Testing on the diagnostic screen-->
@@ -2476,7 +2486,7 @@
     <!-- Title of WFC preference item [CHAR LIMIT=30] -->
     <string name="wifi_calling_mode_title">Calling preference</string>
     <!-- Title of WFC preference selection dialog [CHAR LIMIT=30] -->
-    <string name="wifi_calling_mode_dialog_title">Wi-Fi calling mode</string>
+    <string name="wifi_calling_mode_dialog_title">Calling preference</string>
     <!-- Title of WFC roaming preference item [CHAR LIMIT=45] -->
     <string name="wifi_calling_roaming_mode_title">Roaming preference</string>
     <!-- Summary of WFC roaming preference item [CHAR LIMIT=NONE]-->
@@ -2484,9 +2494,9 @@
     <!-- WFC mode dialog [CHAR LIMIT=45] -->
     <string name="wifi_calling_roaming_mode_dialog_title">Roaming preference</string>
     <string-array name="wifi_calling_mode_choices">
-        <item>Wi-Fi preferred</item>
-        <item>Mobile preferred</item>
-        <item>Wi-Fi only</item>
+        <item>@*android:string/wfc_mode_wifi_preferred_summary</item>
+        <item>@*android:string/wfc_mode_cellular_preferred_summary</item>
+        <item>@*android:string/wfc_mode_wifi_only_summary</item>
     </string-array>
     <string-array name="wifi_calling_mode_choices_v2">
         <item>Wi-Fi</item>
@@ -2499,8 +2509,8 @@
         <item>"0"</item>
     </string-array>
     <string-array name="wifi_calling_mode_choices_without_wifi_only">
-        <item>Wi-Fi preferred</item>
-        <item>Mobile preferred</item>
+        <item>@*android:string/wfc_mode_wifi_preferred_summary</item>
+        <item>@*android:string/wfc_mode_cellular_preferred_summary</item>
     </string-array>
     <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
         <item>Wi-Fi</item>
@@ -2510,6 +2520,14 @@
         <item>"2"</item>
         <item>"1"</item>
     </string-array>
+
+    <!-- Summary of WFC preference item on the WFC preference selection dialog. [CHAR LIMIT=70]-->
+    <string name="wifi_calling_mode_wifi_preferred_summary">If Wi\u2011Fi is unavailable, use mobile network</string>
+    <!-- Summary of WFC preference item on the WFC preference selection dialog. [CHAR LIMIT=70]-->
+    <string name="wifi_calling_mode_cellular_preferred_summary">If mobile network is unavailable, use Wi\u2011Fi</string>
+    <!-- Summary of WFC preference item on the WFC preference selection dialog. [CHAR LIMIT=70]-->
+    <string name="wifi_calling_mode_wifi_only_summary">Call over Wi\u2011Fi. If Wi\u2011Fi is lost, call will end.</string>
+
     <!-- Wi-Fi Calling settings. Text displayed when Wi-Fi Calling is off -->
     <string name="wifi_calling_off_explanation">When Wi-Fi calling is on, your phone can route calls via Wi-Fi networks or your carrier\u2019s network, depending on your preference and which signal is stronger. Before turning on this feature, check with your carrier regarding fees and other details.<xliff:g id="additional_text" example="Learn More">%1$s</xliff:g></string>
     <!-- Wi-Fi Calling settings. Additional text displayed when Wi-Fi Calling is off. Default empty. [CHAR LIMIT=NONE] -->
@@ -3004,14 +3022,14 @@
     <string name="status_prl_version">PRL version</string>
     <!-- About phone screen, title for MEID for multi-sim devices -->
     <string name="meid_multi_sim">MEID (sim slot %1$d)</string>
-    <!-- The status text when both Wi-Fi scanning and Bluetooth scanning are on. [CHAR LIMIT=120] -->
-    <string name="scanning_status_text_wifi_on_ble_on">Both Wi\u2011Fi and Bluetooth are allowed to determine location</string>
-    <!-- The status text when Wi-Fi scanning is on and Bluetooth scanning are off. [CHAR LIMIT=120] -->
-    <string name="scanning_status_text_wifi_on_ble_off">Only Wi\u2011Fi is allowed to determine location</string>
-    <!-- The status text when Wi-Fi scanning is off and Bluetooth scanning are on. [CHAR LIMIT=120] -->
-    <string name="scanning_status_text_wifi_off_ble_on">Only Bluetooth is allowed to determine location</string>
-    <!-- The status text when both Wi-Fi scanning and Bluetooth scanning are off. [CHAR LIMIT=120] -->
-    <string name="scanning_status_text_wifi_off_ble_off">Neither Wi\u2011Fi nor Bluetooth is allowed to determine location</string>
+    <!-- The status text when both Wi-Fi scanning and Bluetooth scanning are on. [CHAR LIMIT=100] -->
+    <string name="scanning_status_text_wifi_on_ble_on">Both Wi\u2011Fi and Bluetooth scanning are on</string>
+    <!-- The status text when Wi-Fi scanning is on and Bluetooth scanning are off. [CHAR LIMIT=100] -->
+    <string name="scanning_status_text_wifi_on_ble_off">Wi\u2011Fi scanning is on, Bluetooth scanning is off</string>
+    <!-- The status text when Wi-Fi scanning is off and Bluetooth scanning are on. [CHAR LIMIT=100] -->
+    <string name="scanning_status_text_wifi_off_ble_on">Bluetooth scanning is on, Wi\u2011Fi scanning is off</string>
+    <!-- The status text when both Wi-Fi scanning and Bluetooth scanning are off. [CHAR LIMIT=100] -->
+    <string name="scanning_status_text_wifi_off_ble_off">Both Wi\u2011Fi and Bluetooth scanning are off</string>
     <!-- About phone, status item title.  The phone MEID number of the current LTE/CDMA device. [CHAR LIMIT=30] -->
     <string name="status_meid_number">MEID</string>
     <!-- About phone, status item title.  The ICCID of the current LTE device. [CHAR LIMIT=30] -->
@@ -3736,13 +3754,25 @@
     <string name="location_app_level_permissions">App permission</string>
     <!-- Summary for app permission on Location settings page when location is off [CHAR LIMIT=NONE] -->
     <string name="location_app_permission_summary_location_off">Location is off</string>
-    <!-- Summary for Location settings when location is on, explaining how many apps have location permission [CHAR LIMIT=NONE]-->
+    <!--
+    Summary for Location settings when location is on, explaining how many apps have unlimited
+    location permission.
+
+    "Unlimited access" means the app can access the device location even when it's not being used
+    (on background), while "limited" means the app can only access the device location when the user
+    is using it (foreground only).
+
+    Please note that the distinction between singular and plural of this sentence only depends on
+    the quantity of "background_location_app_count" ("has" vs "have"). The quantity of
+    "total_location_app_count" is almost always greater than 1, so "apps" is always in plural form.
+
+    [CHAR LIMIT=NONE]-->
     <plurals name="location_app_permission_summary_location_on">
         <item quantity="one">
             <xliff:g id="background_location_app_count">%1$d</xliff:g>
             of
             <xliff:g id="total_location_app_count">%2$d</xliff:g>
-            app has unlimited access</item>
+            apps has unlimited access</item>
         <item quantity="other">
             <xliff:g id="background_location_app_count">%1$d</xliff:g>
             of
@@ -3753,8 +3783,12 @@
     <string name="location_category_recent_location_access">Recent location access</string>
     <!-- [CHAR LIMIT=30] Location settings screen, button to bring the user to view the details of recent location access -->
     <string name="location_recent_location_access_view_details">View details</string>
-    <!-- Location settings screen, displayed when there's no recent app accessing location -->
+    <!-- Location settings screen, displayed when there's no recent app accessing location
+      (for TV) [CHAR LIMIT=100] -->
     <string name="location_no_recent_apps">No apps have requested location recently</string>
+    <!-- Location settings screen, displayed when there's no recent app accessing location
+      (for phones and tablets) [CHAR LIMIT=100] -->
+    <string name="location_no_recent_accesses">No apps recently accessed location</string>
     <!-- [CHAR LIMIT=30] Location settings screen, recent location requests high battery use-->
     <string name="location_high_battery_use">High battery use</string>
     <!-- [CHAR LIMIT=30] Location settings screen, recent location requests low battery use-->
@@ -5222,8 +5256,8 @@
     <string name="battery_tip_high_usage_title" product="tablet">Tablet used more than usual</string>
     <!-- Title for the battery high usage tip [CHAR LIMIT=NONE] -->
     <string name="battery_tip_high_usage_title" product="device">Device used more than usual</string>
-    <!-- Summary for the battery high usage tip, which presents battery may run out soon [CHAR LIMIT=NONE] -->
-    <string name="battery_tip_high_usage_summary">Battery may run out soon</string>
+    <!-- Summary for the battery high usage tip, which presents battery may run out earlier [CHAR LIMIT=NONE] -->
+    <string name="battery_tip_high_usage_summary">Battery may run out earlier than usual</string>
     <!-- Message for battery tip dialog to show the status about the battery [CHAR LIMIT=NONE] -->
     <string name="battery_tip_dialog_message" product="default">Your phone has been used more than usual. Your battery may run out sooner than expected.\n\nTop <xliff:g id="number">%1$d</xliff:g> apps you used since full charge:</string>
     <!-- Message for battery tip dialog to show the status about the battery [CHAR LIMIT=NONE] -->
@@ -5612,9 +5646,9 @@
     <string name="battery_saver_turn_on_automatically_pct">at <xliff:g id="percent">%1$s</xliff:g> battery</string>
 
     <!-- [CHAR_LIMIT=40] Battery percentage: Title -->
-    <string name="battery_info">Battery Information</string>
+    <string name="battery_percentage">Battery percentage</string>
     <!-- [CHAR_LIMIT=NONE] Battery percentage: Description for preference -->
-    <string name="battery_info_description">Show percentage and time left before charge is needed</string>
+    <string name="battery_percentage_description">Show battery percentage in status bar</string>
 
     <!-- Process Stats strings -->
     <skip />
@@ -7753,7 +7787,7 @@
      summary on the channel page-->
 
     <!-- [CHAR LIMIT=100] Notification Importance title: min importance level title -->
-    <string name="notification_importance_min_title">Low</string>
+    <string name="notification_importance_min_title">Minimize</string>
 
     <!-- [CHAR LIMIT=100] Notification Importance title: low importance level title -->
     <string name="notification_importance_low_title">Medium</string>
@@ -7762,7 +7796,16 @@
     <string name="notification_importance_default_title">High</string>
 
     <!-- [CHAR LIMIT=100] Notification Importance title: high importance level title -->
-    <string name="notification_importance_high_title">Urgent</string>
+    <string name="notification_importance_high_title">Pop on screen</string>
+
+    <!-- [CHAR LIMIT=100] Notification Importance title -->
+    <string name="notification_block_title">Block</string>
+
+    <!-- [CHAR LIMIT=100] Notification Importance title -->
+    <string name="notification_silence_title">Show silently</string>
+
+    <!-- [CHAR LIMIT=100] Notification Importance title -->
+    <string name="notification_alert_title">Alert</string>
 
     <!-- [CHAR LIMIT=40] Notification importance title. This setting controls how notifications in older apps may alert the user (eg, sound, visual, vibrate). -->
     <string name="allow_interruption">Allow interruptions</string>
@@ -10719,8 +10762,8 @@
 
     <!-- Summary for the accessibility usage preference in the Privacy page.  [CHAR LIMIT=NONE] -->
     <plurals name="accessibility_usage_summary">
-        <item quantity="one">1 service has full access to your device</item>
-        <item quantity="other"><xliff:g id="service_count">%1$d</xliff:g> services have full access to your device</item>
+        <item quantity="one">1 app has full access to your device</item>
+        <item quantity="other"><xliff:g id="service_count">%1$d</xliff:g> apps have full access to your device</item>
     </plurals>
 
     <!-- Title for notification channel slice. [CHAR LIMIT=NONE] -->
@@ -10740,8 +10783,17 @@
     <!-- Summary for represent which device is playing media [CHAR LIMIT=NONE] -->
     <string name="media_output_panel_summary_of_playing_device">Currently playing on <xliff:g id="device_name" example="Bose headphone">%1$s</xliff:g></string>
 
+    <!-- Label for the title on wfc disclaimer fragment. [CHAR LIMIT=40] -->
+    <string name="wfc_disclaimer_title_text">Important information</string>
+
+    <!-- Label for the agree button on wfc disclaimer fragment. [CHAR LIMIT=30] -->
+    <string name="wfc_disclaimer_agree_button_text">CONTINUE</string>
+
+    <!-- Label for the disagree button on wfc disclaimer fragment. [CHAR LIMIT=30] -->
+    <string name="wfc_disclaimer_disagree_text">NO THANKS</string>
+
     <!-- Message for forget passpoint dialog [CHAR LIMIT=none] -->
-    <string name="forget_passpoint_dialog_message">Your subscription with this provider may be cancelled. Recurring subscriptions will not be cancelled. For more information, check with your provider.</string>
+    <string name="forget_passpoint_dialog_message">You may lose access to any remaining time or data. Check with your provider before removing.</string>
 
     <!-- Keywords for Content Capture feature [CHAR_LIMIT=32] -->
     <string name="keywords_content_capture">content capture</string>
@@ -10749,5 +10801,4 @@
     <string name="content_capture">Content Capture</string>
     <!-- Description of the 'Content Capture' feature toggle in the Settings -> Privacy screen [CHAR LIMIT=NONE]-->
     <string name="content_capture_summary">Allow Android to save information seen on your screen or heard in video or audio content. Android makes helpful suggestions based on your device activity.</string>
-
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 92a4098..8fde9a0 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -520,4 +520,17 @@
         <!-- Padding between content and the start icon is 8dp. -->
         <item name="contentStartPadding">8dp</item>
     </style>
+
+    <style name="DisclaimerPositiveButton" parent="@style/SudGlifButton.Primary">
+        <item name="android:layout_margin">16dp</item>
+        <item name="android:paddingStart">8dp</item>
+        <item name="android:paddingEnd">8dp</item>
+    </style>
+
+    <style name="DisclaimerNegativeButton" parent="@style/SudGlifButton.Secondary">
+        <item name="android:layout_margin">16dp</item>
+        <item name="android:paddingStart">8dp</item>
+        <item name="android:paddingEnd">8dp</item>
+    </style>
+
 </resources>
diff --git a/res/xml/app_notification_settings.xml b/res/xml/app_notification_settings.xml
index 54d6fe7..faad649 100644
--- a/res/xml/app_notification_settings.xml
+++ b/res/xml/app_notification_settings.xml
@@ -61,7 +61,7 @@
             android:order="1001"
             settings:restrictedSwitchSummary="@string/enabled_by_admin" />
         <com.android.settingslib.RestrictedSwitchPreference
-            android:key="bubble"
+            android:key="bubble_pref"
             android:title="@string/notification_bubbles_title"
             android:order="1002"
             settings:restrictedSwitchSummary="@string/enabled_by_admin" />
diff --git a/res/xml/channel_notification_settings.xml b/res/xml/channel_notification_settings.xml
index 94a2cdb..3158819 100644
--- a/res/xml/channel_notification_settings.xml
+++ b/res/xml/channel_notification_settings.xml
@@ -25,11 +25,6 @@
         android:order="1"
         android:layout="@layout/settings_entity_header" />
 
-    <com.android.settingslib.widget.LayoutPreference
-        android:key="block"
-        android:order="2"
-        android:layout="@layout/styled_switch_bar" />
-
     <!-- Importance toggle -->
     <com.android.settingslib.RestrictedSwitchPreference
         android:key="allow_sound"
@@ -38,10 +33,23 @@
         android:summary="@string/allow_interruption_summary" />
 
     <!-- Importance -->
-    <com.android.settings.RestrictedListPreference
+    <com.android.settings.notification.ImportancePreference
         android:key="importance"
-        android:order="10"
-        android:title="@string/notification_importance_title" />
+        android:order="4"
+        android:title="@string/notification_importance_title"
+        settings:allowDividerBelow="true"/>
+
+    <com.android.settingslib.RestrictedSwitchPreference
+        android:key="min_importance"
+        android:order="5"
+        settings:allowDividerAbove="true"
+        android:title="@string/notification_importance_min_title"/>
+
+    <com.android.settingslib.RestrictedSwitchPreference
+        android:key="high_importance"
+        android:order="6"
+        settings:allowDividerAbove="true"
+        android:title="@string/notification_importance_high_title"/>
 
     <PreferenceCategory
         android:key="channel_advanced"
@@ -87,7 +95,7 @@
             settings:restrictedSwitchSummary="@string/enabled_by_admin"/>
 
         <com.android.settingslib.RestrictedSwitchPreference
-            android:key="bubble"
+            android:key="bubble_pref"
             android:title="@string/notification_bubbles_title"
             android:order="16"
             settings:restrictedSwitchSummary="@string/enabled_by_admin" />
@@ -113,6 +121,7 @@
 
     <com.android.settings.notification.NotificationFooterPreference
         android:key="block_desc"
-        android:order="110"/>
+        android:order="110"
+        settings:allowDividerAbove="false"/>
 
 </PreferenceScreen>
diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml
index 0f4c1d3..91fe656 100644
--- a/res/xml/display_settings.xml
+++ b/res/xml/display_settings.xml
@@ -20,7 +20,7 @@
     android:key="display_settings_screen"
     android:title="@string/display_settings"
     settings:keywords="@string/keywords_display"
-    settings:initialExpandedChildrenCount="4">
+    settings:initialExpandedChildrenCount="5">
 
     <com.android.settingslib.RestrictedPreference
         android:key="brightness"
@@ -57,6 +57,15 @@
             android:targetClass="@string/config_wallpaper_picker_class" />
     </com.android.settingslib.RestrictedPreference>
 
+    <ListPreference
+        android:key="dark_ui_mode"
+        android:title="@string/dark_ui_mode"
+        android:dialogTitle="@string/dark_ui_mode_title"
+        android:entries="@array/dark_ui_mode_entries"
+        android:entryValues="@array/dark_ui_mode_values"
+        settings:keywords="@string/keywords_dark_ui_mode"
+        settings:controller="com.android.settings.display.DarkUIPreferenceController" />
+
     <!-- Cross-listed item, if you change this, also change it in power_usage_summary.xml -->
     <com.android.settings.display.TimeoutListPreference
         android:key="screen_timeout"
@@ -136,15 +145,6 @@
         android:summary="@string/tap_to_wake_summary" />
 
     <ListPreference
-        android:key="dark_ui_mode"
-        android:title="@string/dark_ui_mode"
-        android:dialogTitle="@string/dark_ui_mode_title"
-        android:entries="@array/dark_ui_mode_entries"
-        android:entryValues="@array/dark_ui_mode_values"
-        settings:keywords="@string/keywords_dark_ui_mode"
-        settings:controller="com.android.settings.display.DarkUIPreferenceController" />
-
-    <ListPreference
         android:key="theme"
         android:title="@string/device_theme"
         android:summary="@string/summary_placeholder" />
diff --git a/res/xml/firmware_version.xml b/res/xml/firmware_version.xml
index 2914ef1..75336ce 100644
--- a/res/xml/firmware_version.xml
+++ b/res/xml/firmware_version.xml
@@ -68,6 +68,7 @@
         android:title="@string/build_number"
         android:summary="@string/summary_placeholder"
         settings:enableCopying="true"
+        settings:allowDynamicSummaryInSlice="true"
         settings:controller="com.android.settings.deviceinfo.firmwareversion.SimpleBuildNumberPreferenceController"/>
 
 </PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/mobile_network_list.xml b/res/xml/mobile_network_list.xml
index b72540f..c2baf46 100644
--- a/res/xml/mobile_network_list.xml
+++ b/res/xml/mobile_network_list.xml
@@ -16,11 +16,13 @@
 
 <PreferenceScreen
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:key="mobile_network_list_screen"
     android:title="@string/network_settings_title">
 
     <Preference
         android:key="add_more"
+        settings:isPreferenceVisible="false"
         android:title="@string/mobile_network_list_add_more"
         android:icon="@drawable/ic_menu_add"
         android:order="100" >
diff --git a/res/xml/my_device_info.xml b/res/xml/my_device_info.xml
index 83bf5c4..bc498d2 100644
--- a/res/xml/my_device_info.xml
+++ b/res/xml/my_device_info.xml
@@ -115,6 +115,7 @@
         android:title="@string/status_imei"
         settings:keywords="@string/keywords_imei_info"
         android:summary="@string/summary_placeholder"
+        settings:allowDynamicSummaryInSlice="true"
         settings:controller="com.android.settings.deviceinfo.imei.ImeiInfoPreferenceController"/>
 
     <!-- Android version -->
diff --git a/res/xml/network_and_internet_v2.xml b/res/xml/network_and_internet_v2.xml
index fd29c41..44c3121 100644
--- a/res/xml/network_and_internet_v2.xml
+++ b/res/xml/network_and_internet_v2.xml
@@ -22,6 +22,7 @@
 
     <PreferenceCategory
         android:key="multi_network_header"
+        android:title="@string/summary_placeholder"
         settings:allowDividerBelow="true"
         android:order="-40"
         settings:controller="com.android.settings.network.MultiNetworkHeaderController"/>
@@ -79,7 +80,7 @@
         settings:useAdminDisabledSummary="true" />
 
     <com.android.settings.datausage.DataSaverPreference
-        android:key="restrict_background"
+        android:key="restrict_background_parent_entry"
         android:title="@string/data_saver_title"
         android:icon="@drawable/ic_settings_data_usage"
         android:order="10"
diff --git a/res/xml/power_usage_summary.xml b/res/xml/power_usage_summary.xml
index 9be0b7d..94ead86 100644
--- a/res/xml/power_usage_summary.xml
+++ b/res/xml/power_usage_summary.xml
@@ -50,8 +50,8 @@
 
     <SwitchPreference
         android:key="battery_percentage"
-        android:title="@string/battery_info"
-        android:summary="@string/battery_info_description"
+        android:title="@string/battery_percentage"
+        android:summary="@string/battery_percentage_description"
         settings:controller="com.android.settings.display.BatteryPercentagePreferenceController" />
 
 
diff --git a/res/xml/single_choice_list_item_2.xml b/res/xml/single_choice_list_item_2.xml
new file mode 100644
index 0000000..ca80f44
--- /dev/null
+++ b/res/xml/single_choice_list_item_2.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingStart="@dimen/select_dialog_padding_start"
+    android:paddingEnd="?android:attr/dialogPreferredPadding"
+    android:orientation="horizontal"
+    android:descendantFocusability="blocksDescendants">
+
+    <RadioButton
+        android:id="@+id/radio"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:clickable="false" />
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:layout_marginStart="@dimen/select_dialog_item_margin_start"
+        android:layout_gravity="center_vertical">
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorAlertDialogListItem"
+            android:ellipsize="marquee" />
+
+        <TextView
+            android:id="@+id/summary"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingBottom="@dimen/select_dialog_summary_padding_bottom"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+            android:textColor="?android:attr/textColorSecondary"
+            android:maxLines="10" />
+
+    </LinearLayout>
+</LinearLayout>
diff --git a/res/xml/sound_settings.xml b/res/xml/sound_settings.xml
index 81a0453..57bee1f 100644
--- a/res/xml/sound_settings.xml
+++ b/res/xml/sound_settings.xml
@@ -41,7 +41,7 @@
         settings:controller="com.android.settings.notification.MediaVolumePreferenceController"/>
 
     <!-- Media output switcher -->
-    <ListPreference
+    <Preference
         android:key="media_output"
         android:title="@string/media_output_title"
         android:dialogTitle="@string/media_output_title"
diff --git a/res/xml/wifi_calling_settings.xml b/res/xml/wifi_calling_settings.xml
index 0adb1e8..0276bdb 100644
--- a/res/xml/wifi_calling_settings.xml
+++ b/res/xml/wifi_calling_settings.xml
@@ -15,24 +15,27 @@
 -->
 
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+                  xmlns:settings="http://schemas.android.com/apk/res-auto"
                   android:key="wifi_calling_settings"
                   android:title="@string/wifi_calling_settings_title">
 
-    <ListPreference
+    <com.android.settings.wifi.calling.ListWithEntrySummaryPreference
             android:key="wifi_calling_mode"
             android:title="@string/wifi_calling_mode_title"
             android:summary="@string/wifi_calling_mode_title"
             android:entries="@array/wifi_calling_mode_choices"
             android:entryValues="@array/wifi_calling_mode_values"
-            android:dialogTitle="@string/wifi_calling_mode_dialog_title" />
+            android:dialogTitle="@string/wifi_calling_mode_dialog_title"
+            settings:entrySummaries="@array/wifi_calling_mode_summaries" />
 
-    <ListPreference
+    <com.android.settings.wifi.calling.ListWithEntrySummaryPreference
             android:key="wifi_calling_roaming_mode"
             android:title="@string/wifi_calling_roaming_mode_title"
             android:summary="@string/wifi_calling_roaming_mode_summary"
             android:entries="@array/wifi_calling_mode_choices_v2"
             android:entryValues="@array/wifi_calling_mode_values"
-            android:dialogTitle="@string/wifi_calling_roaming_mode_dialog_title" />
+            android:dialogTitle="@string/wifi_calling_roaming_mode_dialog_title"
+            settings:entrySummaries="@array/wifi_calling_mode_summaries" />
 
     <Preference
             android:key="emergency_address_key"
diff --git a/res/xml/wifi_network_details_fragment.xml b/res/xml/wifi_network_details_fragment.xml
index 7c542d8..8979efc 100644
--- a/res/xml/wifi_network_details_fragment.xml
+++ b/res/xml/wifi_network_details_fragment.xml
@@ -26,6 +26,11 @@
         android:order="-10000"
         settings:allowDividerBelow="true"/>
 
+    <com.android.settings.datausage.DataUsageSummaryPreference
+        android:key="status_header"
+        android:selectable="false"
+        settings:isPreferenceVisible="false"/>
+
     <!-- Buttons -->
     <com.android.settingslib.widget.ActionButtonsPreference
         android:key="buttons"
diff --git a/res/xml/wifi_tether_settings.xml b/res/xml/wifi_tether_settings.xml
index 6c5e3c4..81e60a2 100644
--- a/res/xml/wifi_tether_settings.xml
+++ b/res/xml/wifi_tether_settings.xml
@@ -23,7 +23,7 @@
     settings:searchable="false"
     settings:initialExpandedChildrenCount="3">
 
-    <com.android.settings.widget.ValidatedEditTextPreference
+    <com.android.settings.wifi.tether.WifiTetherSsidPreference
         android:key="wifi_tether_network_name"
         android:title="@string/wifi_hotspot_name_title"
         android:summary="@string/summary_placeholder"/>
diff --git a/src/com/android/settings/RadioInfo.java b/src/com/android/settings/RadioInfo.java
index 0af12fd..495d35c 100644
--- a/src/com/android/settings/RadioInfo.java
+++ b/src/com/android/settings/RadioInfo.java
@@ -457,6 +457,13 @@
         imsWfcProvisionedSwitch = (Switch) findViewById(R.id.wfc_provisioned_switch);
         eabProvisionedSwitch = (Switch) findViewById(R.id.eab_provisioned_switch);
 
+        if (!ImsManager.isImsSupportedOnDevice(phone.getContext())) {
+            imsVolteProvisionedSwitch.setVisibility(View.GONE);
+            imsVtProvisionedSwitch.setVisibility(View.GONE);
+            imsWfcProvisionedSwitch.setVisibility(View.GONE);
+            eabProvisionedSwitch.setVisibility(View.GONE);
+        }
+
         cbrsDataSwitch = (Switch) findViewById(R.id.cbrs_data_switch);
         cbrsDataSwitch.setVisibility(isCbrsSupported() ? View.VISIBLE : View.GONE);
 
@@ -631,8 +638,10 @@
                 R.string.radioInfo_menu_viewFDN).setOnMenuItemClickListener(mViewFDNCallback);
         menu.add(1, MENU_ITEM_VIEW_SDN, 0,
                 R.string.radioInfo_menu_viewSDN).setOnMenuItemClickListener(mViewSDNCallback);
-        menu.add(1, MENU_ITEM_GET_IMS_STATUS,
-                0, R.string.radioInfo_menu_getIMS).setOnMenuItemClickListener(mGetImsStatus);
+        if (ImsManager.isImsSupportedOnDevice(phone.getContext())) {
+            menu.add(1, MENU_ITEM_GET_IMS_STATUS,
+                    0, R.string.radioInfo_menu_getIMS).setOnMenuItemClickListener(mGetImsStatus);
+        }
         menu.add(1, MENU_ITEM_TOGGLE_DATA,
                 0, R.string.radio_info_data_connection_disable).setOnMenuItemClickListener(mToggleData);
         return true;
@@ -1384,6 +1393,9 @@
     }
 
     private void updateImsProvisionedState() {
+        if (!ImsManager.isImsSupportedOnDevice(phone.getContext())) {
+            return;
+        }
         log("updateImsProvisionedState isImsVolteProvisioned()=" + isImsVolteProvisioned());
         //delightful hack to prevent on-checked-changed calls from
         //actually forcing the ims provisioning to its transient/current value.
diff --git a/src/com/android/settings/ResetNetworkConfirm.java b/src/com/android/settings/ResetNetworkConfirm.java
index 7c21b55..72e1919 100644
--- a/src/com/android/settings/ResetNetworkConfirm.java
+++ b/src/com/android/settings/ResetNetworkConfirm.java
@@ -157,20 +157,9 @@
                      SubscriptionManager.getPhoneId(mSubId)).factoryReset();
             restoreDefaultApn(context);
             esimFactoryReset(context, context.getPackageName());
-            // There has been issues when Sms raw table somehow stores orphan
-            // fragments. They lead to garbled message when new fragments come
-            // in and combied with those stale ones. In case this happens again,
-            // user can reset all network settings which will clean up this table.
-            cleanUpSmsRawTable(context);
         }
     };
 
-    private void cleanUpSmsRawTable(Context context) {
-        ContentResolver resolver = context.getContentResolver();
-        Uri uri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw/permanentDelete");
-        resolver.delete(uri, null, null);
-    }
-
     @VisibleForTesting
     void esimFactoryReset(Context context, String packageName) {
         if (mEraseEsim) {
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index fac4253..97ff613 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -159,6 +159,7 @@
     public static class WebViewAppPickerActivity extends SettingsActivity { /* empty */ }
     public static class AdvancedConnectedDeviceActivity extends SettingsActivity { /* empty */ }
     public static class BluetoothDeviceDetailActivity extends SettingsActivity { /* empty */ }
+    public static class WifiCallingDisclaimerActivity extends SettingsActivity { /* empty */ }
 
     // Top level categories for new IA
     public static class NetworkDashboardActivity extends SettingsActivity {}
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 541ca3a..001e65b 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -50,6 +50,8 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.settings.Settings.WifiSettingsActivity;
 import com.android.settings.applications.manageapplications.ManageApplications;
+import com.android.settings.backup.BackupSettingsHelper;
+import com.android.settings.backup.UserBackupSettingsActivity;
 import com.android.settings.core.OnActivityResultListener;
 import com.android.settings.core.SettingsBaseActivity;
 import com.android.settings.core.SubSettingLauncher;
@@ -630,6 +632,12 @@
                 showDev, isAdmin)
                 || somethingChanged;
 
+        // Enable/disable backup settings depending on whether backup is activated for the user.
+        boolean isBackupActive = new BackupSettingsHelper(this).isBackupServiceActive();
+        somethingChanged = setTileEnabled(changedList, new ComponentName(packageName,
+                UserBackupSettingsActivity.class.getName()), isBackupActive, isAdmin)
+                || somethingChanged;
+
         somethingChanged = setTileEnabled(changedList, new ComponentName(packageName,
                         Settings.WifiDisplaySettingsActivity.class.getName()),
                 WifiDisplaySettings.isAvailable(this), isAdmin)
diff --git a/src/com/android/settings/accessibility/BalanceSeekBar.java b/src/com/android/settings/accessibility/BalanceSeekBar.java
index e18a593..b108e18 100644
--- a/src/com/android/settings/accessibility/BalanceSeekBar.java
+++ b/src/com/android/settings/accessibility/BalanceSeekBar.java
@@ -28,6 +28,8 @@
 import android.util.AttributeSet;
 import android.widget.SeekBar;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.settings.R;
 
 /**
@@ -37,14 +39,13 @@
  * Updates Settings.System for balance on progress changed.
  */
 public class BalanceSeekBar extends SeekBar {
-    private static final String TAG = "BalanceSeekBar";
     private final Context mContext;
     private final Object mListenerLock = new Object();
     private OnSeekBarChangeListener mOnSeekBarChangeListener;
     private final OnSeekBarChangeListener mProxySeekBarListener = new OnSeekBarChangeListener() {
         @Override
         public void onStopTrackingTouch(SeekBar seekBar) {
-            synchronized(mListenerLock) {
+            synchronized (mListenerLock) {
                 if (mOnSeekBarChangeListener != null) {
                     mOnSeekBarChangeListener.onStopTrackingTouch(seekBar);
                 }
@@ -53,7 +54,7 @@
 
         @Override
         public void onStartTrackingTouch(SeekBar seekBar) {
-            synchronized(mListenerLock) {
+            synchronized (mListenerLock) {
                 if (mOnSeekBarChangeListener != null) {
                     mOnSeekBarChangeListener.onStartTrackingTouch(seekBar);
                 }
@@ -79,7 +80,7 @@
 
             // after adjusting the seekbar, notify downstream listener.
             // note that progress may have been adjusted in the code above to mCenter.
-            synchronized(mListenerLock) {
+            synchronized (mListenerLock) {
                 if (mOnSeekBarChangeListener != null) {
                     mOnSeekBarChangeListener.onProgressChanged(seekBar, progress, fromUser);
                 }
@@ -88,7 +89,8 @@
     };
 
     // Percentage of max to be used as a snap to threshold
-    private static final float SNAP_TO_PERCENTAGE = 0.03f;
+    @VisibleForTesting
+    static final float SNAP_TO_PERCENTAGE = 0.03f;
     private final Paint mCenterMarkerPaint;
     private final Rect mCenterMarkerRect;
     // changed in setMax()
@@ -122,7 +124,7 @@
 
     @Override
     public void setOnSeekBarChangeListener(OnSeekBarChangeListener listener) {
-        synchronized(mListenerLock) {
+        synchronized (mListenerLock) {
             mOnSeekBarChangeListener = listener;
         }
     }
@@ -148,5 +150,10 @@
         canvas.restore();
         super.onDraw(canvas);
     }
+
+    @VisibleForTesting
+    OnSeekBarChangeListener getProxySeekBarListener() {
+        return mProxySeekBarListener;
+    }
 }
 
diff --git a/src/com/android/settings/accessibility/BalanceSeekBarPreference.java b/src/com/android/settings/accessibility/BalanceSeekBarPreference.java
index a40282c..b03c8ab 100644
--- a/src/com/android/settings/accessibility/BalanceSeekBarPreference.java
+++ b/src/com/android/settings/accessibility/BalanceSeekBarPreference.java
@@ -34,7 +34,9 @@
 
 /** A slider preference that directly controls audio balance **/
 public class BalanceSeekBarPreference extends SeekBarPreference {
-    private static final String TAG = "BalanceSeekBarPreference";
+    private static final int BALANCE_CENTER_VALUE = 100;
+    private static final int BALANCE_MAX_VALUE = 200;
+
     private final Context mContext;
     private BalanceSeekBar mSeekBar;
     private ImageView mIconView;
@@ -62,9 +64,9 @@
         final float balance = Settings.System.getFloatForUser(
                 mContext.getContentResolver(), Settings.System.MASTER_BALANCE,
                 0.f /* default */, UserHandle.USER_CURRENT);
-        // Rescale balance to range 0-200 centered at 100.
-        mSeekBar.setMax(200);
-        mSeekBar.setProgress((int)(balance * 100.f) + 100);
+        // Rescale balance to range 0-BALANCE_MAX_VALUE centered at BALANCE_MAX_VALUE / 2.
+        mSeekBar.setMax(BALANCE_MAX_VALUE);
+        mSeekBar.setProgress((int) (balance * 100.f) + BALANCE_CENTER_VALUE);
         mSeekBar.setEnabled(isEnabled());
     }
 }
diff --git a/src/com/android/settings/accounts/AvatarViewMixin.java b/src/com/android/settings/accounts/AvatarViewMixin.java
index 3ce8c0a..9e762c7 100644
--- a/src/com/android/settings/accounts/AvatarViewMixin.java
+++ b/src/com/android/settings/accounts/AvatarViewMixin.java
@@ -17,6 +17,7 @@
 package com.android.settings.accounts;
 
 import android.accounts.Account;
+import android.app.ActivityManager;
 import android.app.settings.SettingsEnums;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -64,11 +65,13 @@
     private final Context mContext;
     private final ImageView mAvatarView;
     private final MutableLiveData<Bitmap> mAvatarImage;
+    private final ActivityManager mActivityManager;
 
     private String mAccountName;
 
     public AvatarViewMixin(SettingsHomepageActivity activity, ImageView avatarView) {
         mContext = activity.getApplicationContext();
+        mActivityManager = mContext.getSystemService(ActivityManager.class);
         mAvatarView = avatarView;
         mAvatarView.setOnClickListener(v -> {
             Intent intent;
@@ -114,7 +117,11 @@
     @OnLifecycleEvent(Lifecycle.Event.ON_START)
     public void onStart() {
         if (!mContext.getResources().getBoolean(R.bool.config_show_avatar_in_homepage)) {
-            Log.d(TAG, "Feature disabled. Skipping");
+            Log.d(TAG, "Feature disabled by config. Skipping");
+            return;
+        }
+        if (mActivityManager.isLowRamDevice()) {
+            Log.d(TAG, "Feature disabled on low ram device. Skipping");
             return;
         }
         if (hasAccount()) {
diff --git a/src/com/android/settings/applications/defaultapps/DefaultEmergencyPicker.java b/src/com/android/settings/applications/defaultapps/DefaultEmergencyPicker.java
index f088967..32cc9a8 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultEmergencyPicker.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultEmergencyPicker.java
@@ -17,9 +17,7 @@
 package com.android.settings.applications.defaultapps;
 
 import android.app.role.RoleManager;
-import android.app.role.RoleManagerCallback;
 import android.app.settings.SettingsEnums;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
@@ -27,7 +25,6 @@
 import android.content.pm.ResolveInfo;
 import android.os.AsyncTask;
 import android.os.Process;
-import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -100,18 +97,13 @@
         final String previousValue = getDefaultKey();
 
         if (!TextUtils.isEmpty(key) && !TextUtils.equals(key, previousValue)) {
-            getContext().getSystemService(RoleManager.class)
-                      .addRoleHolderAsUser(
-                              RoleManager.ROLE_EMERGENCY, key, 0, Process.myUserHandle(),
-                              AsyncTask.THREAD_POOL_EXECUTOR, new RoleManagerCallback() {
-                                  @Override
-                                  public void onSuccess() {}
-
-                                  @Override
-                                  public void onFailure() {
-                                      Log.e(TAG, "Failed to set emergency default app.");
-                                  }
-                              });
+            getContext().getSystemService(RoleManager.class).addRoleHolderAsUser(
+                    RoleManager.ROLE_EMERGENCY, key, 0, Process.myUserHandle(),
+                    AsyncTask.THREAD_POOL_EXECUTOR, successful -> {
+                        if (!successful) {
+                            Log.e(TAG, "Failed to set emergency default app.");
+                        }
+                    });
             return true;
         }
         return false;
diff --git a/src/com/android/settings/backup/BackupSettingsHelper.java b/src/com/android/settings/backup/BackupSettingsHelper.java
index fa77154..b836e55 100644
--- a/src/com/android/settings/backup/BackupSettingsHelper.java
+++ b/src/com/android/settings/backup/BackupSettingsHelper.java
@@ -209,7 +209,7 @@
     }
 
     /** Checks if backup service is enabled for this user. */
-    private boolean isBackupServiceActive() {
+    public boolean isBackupServiceActive() {
         boolean backupOkay;
         try {
             backupOkay = mBackupManager.isBackupServiceActive(UserHandle.myUserId());
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollAccessibilityToggle.java b/src/com/android/settings/biometrics/face/FaceEnrollAccessibilityToggle.java
index 49f4f7f..2db654b 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollAccessibilityToggle.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollAccessibilityToggle.java
@@ -58,9 +58,14 @@
             a.recycle();
         }
         mSwitch = findViewById(R.id.toggle);
+        mSwitch.setChecked(false);
     }
 
     public boolean isChecked() {
         return mSwitch.isChecked();
     }
+
+    public void setChecked(boolean checked) {
+        mSwitch.setChecked(checked);
+    }
 }
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
index 5f2b675..c7966f2 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
@@ -53,6 +53,7 @@
         final LinearLayout accessibilityLayout = findViewById(R.id.accessibility_layout);
         final Button accessibilityButton = findViewById(R.id.accessibility_button);
         accessibilityButton.setOnClickListener(view -> {
+            mSwitchDiversity.setChecked(true);
             accessibilityButton.setVisibility(View.INVISIBLE);
             accessibilityLayout.setVisibility(View.VISIBLE);
         });
@@ -177,7 +178,7 @@
         } else {
             intent.setClass(this, FaceEnrollEnrolling.class);
         }
-        intent.putExtra(EXTRA_KEY_REQUIRE_DIVERSITY, mSwitchDiversity.isChecked());
+        intent.putExtra(EXTRA_KEY_REQUIRE_DIVERSITY, !mSwitchDiversity.isChecked());
         WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
         return intent;
     }
diff --git a/src/com/android/settings/core/FeatureFlags.java b/src/com/android/settings/core/FeatureFlags.java
index 6c2da07..fbb2ae3 100644
--- a/src/com/android/settings/core/FeatureFlags.java
+++ b/src/com/android/settings/core/FeatureFlags.java
@@ -26,4 +26,7 @@
     public static final String NETWORK_INTERNET_V2 = "settings_network_and_internet_v2";
     public static final String SLICE_INJECTION = "settings_slice_injection";
     public static final String MAINLINE_MODULE = "settings_mainline_module";
+    public static final String WIFI_DETAILS_SAVED_SCREEN = "settings_wifi_details_saved_screen";
+    public static final String WIFI_DETAILS_DATAUSAGE_HEADER =
+            "settings_wifi_details_datausage_header";
 }
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 147d0be..ba64a80 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -135,6 +135,7 @@
 import com.android.settings.wifi.WifiAPITest;
 import com.android.settings.wifi.WifiInfo;
 import com.android.settings.wifi.WifiSettings;
+import com.android.settings.wifi.calling.WifiCallingDisclaimerFragment;
 import com.android.settings.wifi.calling.WifiCallingSettings;
 import com.android.settings.wifi.p2p.WifiP2pSettings;
 import com.android.settings.wifi.savedaccesspoints.SavedAccessPointsWifiSettings;
@@ -260,6 +261,7 @@
             ConnectedDeviceDashboardFragment.class.getName(),
             UsbDetailsFragment.class.getName(),
             AppAndNotificationDashboardFragment.class.getName(),
+            WifiCallingDisclaimerFragment.class.getName(),
             AccountDashboardFragment.class.getName(),
             EnterprisePrivacySettings.class.getName(),
             WebViewAppPicker.class.getName(),
diff --git a/src/com/android/settings/datausage/DataUsageSummaryPreference.java b/src/com/android/settings/datausage/DataUsageSummaryPreference.java
index 481538d..93df2f1 100644
--- a/src/com/android/settings/datausage/DataUsageSummaryPreference.java
+++ b/src/com/android/settings/datausage/DataUsageSummaryPreference.java
@@ -69,6 +69,8 @@
     private boolean mDefaultTextColorSet;
     private int mDefaultTextColor;
     private int mNumPlans;
+    /** The specified un-initialized value for cycle time */
+    private final long CYCLE_TIME_UNINITIAL_VALUE = 0;
     /** The ending time of the billing cycle in milliseconds since epoch. */
     private long mCycleEndTimeMs;
     /** The time of the last update in standard milliseconds since the epoch */
@@ -94,6 +96,7 @@
     /** WiFi only mode */
     private boolean mWifiMode;
     private String mUsagePeriod;
+    private boolean mSingleWifi;    // Shows only one specified WiFi network usage
 
     public DataUsageSummaryPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -142,9 +145,10 @@
         notifyChanged();
     }
 
-    void setWifiMode(boolean isWifiMode, String usagePeriod) {
+    void setWifiMode(boolean isWifiMode, String usagePeriod, boolean isSingleWifi) {
         mWifiMode = isWifiMode;
         mUsagePeriod = usagePeriod;
+        mSingleWifi = isSingleWifi;
         notifyChanged();
     }
 
@@ -171,7 +175,16 @@
         Button launchButton = (Button) holder.findViewById(R.id.launch_mdp_app_button);
         TextView limitInfo = (TextView) holder.findViewById(R.id.data_limits);
 
-        if (mWifiMode) {
+        if (mWifiMode && mSingleWifi) {
+            updateCycleTimeText(holder);
+
+            usageTitle.setVisibility(View.GONE);
+            launchButton.setVisibility(View.GONE);
+            carrierInfo.setVisibility(View.GONE);
+
+            limitInfo.setVisibility(TextUtils.isEmpty(mLimitInfoText) ? View.GONE : View.VISIBLE);
+            limitInfo.setText(mLimitInfoText);
+        } else if (mWifiMode) {
             usageTitle.setText(R.string.data_usage_wifi_title);
             usageTitle.setVisibility(View.VISIBLE);
             TextView cycleTime = (TextView) holder.findViewById(R.id.cycle_left_time);
@@ -265,6 +278,13 @@
     private void updateCycleTimeText(PreferenceViewHolder holder) {
         TextView cycleTime = (TextView) holder.findViewById(R.id.cycle_left_time);
 
+        // Takes zero as a special case which value is never set.
+        if (mCycleEndTimeMs == CYCLE_TIME_UNINITIAL_VALUE) {
+            cycleTime.setVisibility(View.GONE);
+            return;
+        }
+
+        cycleTime.setVisibility(View.VISIBLE);
         long millisLeft = mCycleEndTimeMs - System.currentTimeMillis();
         if (millisLeft <= 0) {
             cycleTime.setText(getContext().getString(R.string.billing_cycle_none_left));
diff --git a/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java b/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java
index 353c5ee..a06bb77 100644
--- a/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java
+++ b/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java
@@ -65,10 +65,10 @@
     private final EntityHeaderController mEntityHeaderController;
     private final Lifecycle mLifecycle;
     private final PreferenceFragmentCompat mFragment;
-    private final DataUsageController mDataUsageController;
-    private final DataUsageInfoController mDataInfoController;
+    protected final DataUsageController mDataUsageController;
+    protected final DataUsageInfoController mDataInfoController;
     private final NetworkTemplate mDefaultTemplate;
-    private final NetworkPolicyEditor mPolicyEditor;
+    protected final NetworkPolicyEditor mPolicyEditor;
     private final int mDataUsageTemplate;
     private final boolean mHasMobileData;
     private final SubscriptionManager mSubscriptionManager;
@@ -200,11 +200,13 @@
         if (DataUsageUtils.hasSim(mActivity)) {
             info = mDataUsageController.getDataUsageInfo(mDefaultTemplate);
             mDataInfoController.updateDataLimit(info, mPolicyEditor.getPolicy(mDefaultTemplate));
-            summaryPreference.setWifiMode(/* isWifiMode */ false, /* usagePeriod */ null);
+            summaryPreference.setWifiMode(/* isWifiMode */ false,
+                    /* usagePeriod */ null, /* isSingleWifi */ false);
         } else {
             info = mDataUsageController.getDataUsageInfo(
                     NetworkTemplate.buildTemplateWifiWildcard());
-            summaryPreference.setWifiMode(/* isWifiMode */ true, /* usagePeriod */ info.period);
+            summaryPreference.setWifiMode(/* isWifiMode */ true, /* usagePeriod */
+                    info.period, /* isSingleWifi */ false);
             summaryPreference.setLimitInfo(null);
             summaryPreference.setUsageNumbers(info.usageLevel,
                     /* dataPlanSize */ -1L,
diff --git a/src/com/android/settings/datausage/WifiDataUsageSummaryPreferenceController.java b/src/com/android/settings/datausage/WifiDataUsageSummaryPreferenceController.java
new file mode 100644
index 0000000..8b6d10a
--- /dev/null
+++ b/src/com/android/settings/datausage/WifiDataUsageSummaryPreferenceController.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.datausage;
+
+import android.app.Activity;
+import android.net.NetworkTemplate;
+import android.telephony.SubscriptionManager;
+import android.text.format.Formatter;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragmentCompat;
+
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.net.DataUsageController;
+
+/**
+ *  The controller displays a data usage chart for the specified Wi-Fi network.
+ */
+public class WifiDataUsageSummaryPreferenceController extends DataUsageSummaryPreferenceController {
+    final String mNetworkId;
+
+    public WifiDataUsageSummaryPreferenceController(Activity activity,
+            Lifecycle lifecycle, PreferenceFragmentCompat fragment, CharSequence networkId) {
+        super(activity, lifecycle, fragment, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+
+        if (networkId == null) {
+            mNetworkId = null;
+        } else {
+            mNetworkId = String.valueOf(networkId);
+        }
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        if (preference == null) {
+            return;
+        }
+
+        final DataUsageSummaryPreference mPreference = (DataUsageSummaryPreference) preference;
+        // TODO(b/126299427): Currently gets data usage of whole Wi-Fi networks, but should get
+        //  specified one.
+        final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(mNetworkId);
+        final DataUsageController.DataUsageInfo info = mDataUsageController.getDataUsageInfo(
+                template);
+        mDataInfoController.updateDataLimit(info, mPolicyEditor.getPolicy(template));
+
+        mPreference.setWifiMode(/* isWifiMode */ true, /* usagePeriod */
+                info.period, /* isSingleWifi */ true);
+        mPreference.setChartEnabled(true);
+        // Treats Wi-Fi network as unlimited network, which has same usage level and limited level.
+        mPreference.setUsageNumbers(info.usageLevel, info.usageLevel, /* hasMobileData */ false);
+
+        // TODO(b/126142293): Passpoint Wi-Fi should have limit of data usage and time remaining
+        mPreference.setProgress(100);
+        mPreference.setLabels(Formatter.formatFileSize(mContext, /* sizeBytes */ 0),
+                DataUsageUtils.formatDataUsage(mContext, info.usageLevel));
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java b/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java
index f13af94..855a988 100644
--- a/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java
@@ -16,12 +16,8 @@
 
 package com.android.settings.deviceinfo;
 
-import static android.content.Context.CLIPBOARD_SERVICE;
-
 import android.app.Activity;
 import android.app.settings.SettingsEnums;
-import android.content.ClipData;
-import android.content.ClipboardManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -79,11 +75,7 @@
 
     @Override
     public CharSequence getSummary() {
-        try {
-            return BidiFormatter.getInstance().unicodeWrap(Build.DISPLAY);
-        } catch (Exception e) {
-            return mContext.getText(R.string.device_info_default);
-        }
+        return BidiFormatter.getInstance().unicodeWrap(Build.DISPLAY);
     }
 
     @Override
@@ -99,29 +91,7 @@
 
     @Override
     public int getAvailabilityStatus() {
-        return AVAILABLE;
-    }
-
-    @Override
-    public boolean isSliceable() {
-        return true;
-    }
-
-    @Override
-    public boolean isCopyableSlice() {
-        return true;
-    }
-
-    @Override
-    public void copy() {
-        final ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(
-                CLIPBOARD_SERVICE);
-        final ClipData clip = ClipData.newPlainText("text", getSummary());
-        clipboard.setPrimaryClip(clip);
-
-        final String toast = mContext.getString(R.string.copyable_slice_toast,
-                mContext.getText(R.string.build_number));
-        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
+        return AVAILABLE_UNSEARCHABLE;
     }
 
     @Override
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/SimpleBuildNumberPreferenceController.java b/src/com/android/settings/deviceinfo/firmwareversion/SimpleBuildNumberPreferenceController.java
index c7d4459..36f1a43 100644
--- a/src/com/android/settings/deviceinfo/firmwareversion/SimpleBuildNumberPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/firmwareversion/SimpleBuildNumberPreferenceController.java
@@ -16,10 +16,16 @@
 
 package com.android.settings.deviceinfo.firmwareversion;
 
+import static android.content.Context.CLIPBOARD_SERVICE;
+
+import android.content.ClipData;
+import android.content.ClipboardManager;
 import android.content.Context;
 import android.os.Build;
 import android.text.BidiFormatter;
+import android.widget.Toast;
 
+import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
 
 public class SimpleBuildNumberPreferenceController extends BasePreferenceController {
@@ -38,4 +44,26 @@
     public CharSequence getSummary() {
         return BidiFormatter.getInstance().unicodeWrap(Build.DISPLAY);
     }
+
+    @Override
+    public boolean isSliceable() {
+        return true;
+    }
+
+    @Override
+    public boolean isCopyableSlice() {
+        return true;
+    }
+
+    @Override
+    public void copy() {
+        final ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(
+                CLIPBOARD_SERVICE);
+        final ClipData clip = ClipData.newPlainText("text", getSummary());
+        clipboard.setPrimaryClip(clip);
+
+        final String toast = mContext.getString(R.string.copyable_slice_toast,
+                mContext.getText(R.string.build_number));
+        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
+    }
 }
diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java
index 9e869a9..9b83f88 100644
--- a/src/com/android/settings/homepage/SettingsHomepageActivity.java
+++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java
@@ -17,6 +17,7 @@
 package com.android.settings.homepage;
 
 import android.animation.LayoutTransition;
+import android.app.ActivityManager;
 import android.app.settings.SettingsEnums;
 import android.os.Bundle;
 import android.view.View;
@@ -53,7 +54,10 @@
         final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(this, avatarView);
         getLifecycle().addObserver(avatarViewMixin);
 
-        showFragment(new ContextualCardsFragment(), R.id.contextual_cards_content);
+        if (!getSystemService(ActivityManager.class).isLowRamDevice()) {
+            // Only allow contextual feature on high ram devices.
+            showFragment(new ContextualCardsFragment(), R.id.contextual_cards_content);
+        }
         showFragment(new TopLevelSettings(), R.id.main_content);
         ((FrameLayout) findViewById(R.id.main_content))
                 .getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
index 13564b5..ff2ee91 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
@@ -67,7 +67,8 @@
 
     @VisibleForTesting
     Uri mNotifyUri;
-    private Context mContext;
+
+    private final Context mContext;
 
     ContextualCardLoader(Context context) {
         super(context);
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
index c829015..8f7e84a 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
@@ -109,13 +109,13 @@
         }
     }
 
-    void loadContextualCards(ContextualCardsFragment fragment) {
+    void loadContextualCards(LoaderManager loaderManager) {
         mStartTime = System.currentTimeMillis();
         final CardContentLoaderCallbacks cardContentLoaderCallbacks =
                 new CardContentLoaderCallbacks(mContext);
         cardContentLoaderCallbacks.setListener(this);
         // Use the cached data when navigating back to the first page and upon screen rotation.
-        LoaderManager.getInstance(fragment).initLoader(CARD_CONTENT_LOADER_ID, null /* bundle */,
+        loaderManager.initLoader(CARD_CONTENT_LOADER_ID, null /* bundle */,
                 cardContentLoaderCallbacks);
     }
 
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java b/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java
index e598e4c..72ddb50 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java
@@ -19,16 +19,19 @@
 import static com.android.settings.homepage.contextualcards.ContextualCardsAdapter.SPAN_COUNT;
 
 import android.app.settings.SettingsEnums;
+import android.content.Context;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.loader.app.LoaderManager;
 import androidx.recyclerview.widget.GridLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.settings.R;
 import com.android.settings.core.InstrumentedFragment;
+import com.android.settings.overlay.FeatureFactory;
 
 public class ContextualCardsFragment extends InstrumentedFragment {
 
@@ -42,14 +45,19 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mContextualCardManager = new ContextualCardManager(getContext(), getSettingsLifecycle(),
+        final Context context = getContext();
+        if (savedInstanceState == null) {
+            FeatureFactory.getFactory(context).getSlicesFeatureProvider().newUiSession();
+        }
+        mContextualCardManager = new ContextualCardManager(context, getSettingsLifecycle(),
                 savedInstanceState);
+
     }
 
     @Override
     public void onStart() {
         super.onStart();
-        mContextualCardManager.loadContextualCards(this);
+        mContextualCardManager.loadContextualCards(LoaderManager.getInstance(this));
     }
 
     @Override
diff --git a/src/com/android/settings/homepage/contextualcards/EligibleCardChecker.java b/src/com/android/settings/homepage/contextualcards/EligibleCardChecker.java
index 5423ce3..fe68d02 100644
--- a/src/com/android/settings/homepage/contextualcards/EligibleCardChecker.java
+++ b/src/com/android/settings/homepage/contextualcards/EligibleCardChecker.java
@@ -51,6 +51,9 @@
 
     @VisibleForTesting
     boolean isCardEligibleToDisplay(ContextualCard card) {
+        if (card.getRankingScore() < 0) {
+            return false;
+        }
         if (card.isCustomCard()) {
             return true;
         }
diff --git a/src/com/android/settings/homepage/contextualcards/deviceinfo/BatteryInfoSlice.java b/src/com/android/settings/homepage/contextualcards/deviceinfo/BatteryInfoSlice.java
deleted file mode 100644
index 6c7f930..0000000
--- a/src/com/android/settings/homepage/contextualcards/deviceinfo/BatteryInfoSlice.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.homepage.contextualcards.deviceinfo;
-
-import android.app.PendingIntent;
-import android.app.settings.SettingsEnums;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.Uri;
-import android.os.PowerManager;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.core.graphics.drawable.IconCompat;
-import androidx.slice.Slice;
-import androidx.slice.builders.ListBuilder;
-import androidx.slice.builders.SliceAction;
-
-import com.android.settings.R;
-import com.android.settings.SubSettings;
-import com.android.settings.Utils;
-import com.android.settings.fuelgauge.BatteryInfo;
-import com.android.settings.fuelgauge.PowerUsageSummary;
-import com.android.settings.slices.CustomSliceRegistry;
-import com.android.settings.slices.CustomSliceable;
-import com.android.settings.slices.SliceBuilderUtils;
-
-/**
- * Utility class to build a Battery Slice, and handle all associated actions.
- */
-public class BatteryInfoSlice implements CustomSliceable {
-    private static final String TAG = "BatteryInfoSlice";
-
-    private final Context mContext;
-
-    private BatteryInfo mBatteryInfo;
-    private boolean mIsBatteryInfoLoading;
-
-    public BatteryInfoSlice(Context context) {
-        mContext = context;
-    }
-
-    @Override
-    public Slice getSlice() {
-        if (mBatteryInfo == null) {
-            mIsBatteryInfoLoading = true;
-            loadBatteryInfo();
-        }
-        final IconCompat icon = IconCompat.createWithResource(mContext,
-                R.drawable.ic_settings_battery);
-        final CharSequence title = mContext.getText(R.string.power_usage_summary_title);
-        final SliceAction primarySliceAction = SliceAction.createDeeplink(getPrimaryAction(), icon,
-                ListBuilder.ICON_IMAGE, title);
-        final Slice slice = new ListBuilder(mContext, CustomSliceRegistry.BATTERY_INFO_SLICE_URI,
-                ListBuilder.INFINITY)
-                .setAccentColor(Utils.getColorAccentDefaultColor(mContext))
-                .setHeader(new ListBuilder.HeaderBuilder().setTitle(title))
-                .addRow(new ListBuilder.RowBuilder()
-                        .setTitle(getBatteryPercentString(), mIsBatteryInfoLoading)
-                        .setSubtitle(getSummary(), mIsBatteryInfoLoading)
-                        .setPrimaryAction(primarySliceAction))
-                .build();
-        mBatteryInfo = null;
-        mIsBatteryInfoLoading = false;
-        return slice;
-    }
-
-    @Override
-    public Uri getUri() {
-        return CustomSliceRegistry.BATTERY_INFO_SLICE_URI;
-    }
-
-    @Override
-    public void onNotifyChange(Intent intent) {
-
-    }
-
-    @Override
-    public Intent getIntent() {
-        final String screenTitle = mContext.getText(R.string.power_usage_summary_title).toString();
-        return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
-                PowerUsageSummary.class.getName(), "" /* key */, screenTitle,
-                SettingsEnums.SLICE)
-                .setClassName(mContext.getPackageName(), SubSettings.class.getName())
-                .setData(CustomSliceRegistry.BATTERY_INFO_SLICE_URI);
-    }
-
-    @Override
-    public IntentFilter getIntentFilter() {
-        final IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
-        intentFilter.addAction(Intent.ACTION_POWER_CONNECTED);
-        intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
-        intentFilter.addAction(Intent.ACTION_BATTERY_LEVEL_CHANGED);
-        return intentFilter;
-    }
-
-    @VisibleForTesting
-    void loadBatteryInfo() {
-        BatteryInfo.getBatteryInfo(mContext, info -> {
-            mBatteryInfo = info;
-            mContext.getContentResolver().notifyChange(getUri(), null);
-        }, true);
-    }
-
-    @VisibleForTesting
-    CharSequence getBatteryPercentString() {
-        return mBatteryInfo == null ? null : mBatteryInfo.batteryPercentString;
-    }
-
-    @VisibleForTesting
-    CharSequence getSummary() {
-        if (mBatteryInfo == null) {
-            return null;
-        }
-        return mBatteryInfo.remainingLabel == null ? mBatteryInfo.statusLabel
-                : mBatteryInfo.remainingLabel;
-    }
-
-    private PendingIntent getPrimaryAction() {
-        final Intent intent = getIntent();
-        return PendingIntent.getActivity(mContext, 0 /* requestCode */,
-                intent, 0 /* flags */);
-    }
-}
\ No newline at end of file
diff --git a/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java b/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
index 3320be0..99fe219 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
@@ -16,11 +16,14 @@
 
 package com.android.settings.homepage.contextualcards.slices;
 
+import android.annotation.ColorInt;
 import android.app.PendingIntent;
 import android.app.settings.SettingsEnums;
 import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
@@ -87,6 +90,9 @@
 
     @Override
     public Slice getSlice() {
+        // Reload theme for switching dark mode on/off
+        mContext.getTheme().applyStyle(R.style.Theme_Settings_Home, true /* force */);
+
         final IconCompat icon = IconCompat.createWithResource(mContext,
                 com.android.internal.R.drawable.ic_settings_bluetooth);
         final CharSequence title = mContext.getText(R.string.bluetooth_devices);
@@ -98,7 +104,7 @@
                 ListBuilder.ICON_IMAGE, title);
         final ListBuilder listBuilder =
                 new ListBuilder(mContext, getUri(), ListBuilder.INFINITY)
-                        .setAccentColor(Utils.getColorAccentDefaultColor(mContext));
+                        .setAccentColor(COLOR_NOT_TINTED);
 
         // Get row builders by Bluetooth devices.
         final List<ListBuilder.RowBuilder> rows = getBluetoothRowBuilder();
@@ -207,13 +213,23 @@
     IconCompat getBluetoothDeviceIcon(CachedBluetoothDevice device) {
         final Pair<Drawable, String> pair = BluetoothUtils
                 .getBtClassDrawableWithDescription(mContext, device);
+        final Drawable drawable = pair.first;
 
-        if (pair.first != null) {
-            return Utils.createIconWithDrawable(pair.first);
-        } else {
+        // Use default bluetooth icon if can't get icon.
+        if (drawable == null) {
             return IconCompat.createWithResource(mContext,
                     com.android.internal.R.drawable.ic_settings_bluetooth);
         }
+
+        // Tint icon: Accent color for connected state; Disable color for busy state.
+        @ColorInt int color = Utils.getColorAccentDefaultColor(mContext);
+        if (device.isBusy()) {
+            color = Utils.getDisabled(mContext,
+                    Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorControlNormal));
+        }
+        drawable.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN));
+
+        return Utils.createIconWithDrawable(drawable);
     }
 
     private List<ListBuilder.RowBuilder> getBluetoothRowBuilder() {
@@ -227,7 +243,7 @@
                     .setSubtitle(bluetoothDevice.getConnectionSummary());
 
             if (bluetoothDevice.isConnectedA2dpDevice()) {
-                // For available media devices, the primary action is to active audio stream and
+                // For available media devices, the primary action is to activate audio stream and
                 // add setting icon to the end to link detail page.
                 rowBuilder.setPrimaryAction(buildMediaBluetoothAction(bluetoothDevice));
                 rowBuilder.addEndItem(buildBluetoothDetailDeepLinkAction(bluetoothDevice));
@@ -260,7 +276,7 @@
     SliceAction buildBluetoothDetailDeepLinkAction(CachedBluetoothDevice bluetoothDevice) {
         return SliceAction.createDeeplink(
                 getBluetoothDetailIntent(bluetoothDevice),
-                IconCompat.createWithResource(mContext, R.drawable.ic_settings_24dp),
+                IconCompat.createWithResource(mContext, R.drawable.ic_settings_accent),
                 ListBuilder.ICON_IMAGE,
                 bluetoothDevice.getName());
     }
diff --git a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
index 44d600e..a76d381 100644
--- a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
+++ b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
@@ -74,6 +74,7 @@
         mController = AppEntitiesHeaderController.newInstance(mContext, view)
                 .setHeaderTitleRes(R.string.location_category_recent_location_access)
                 .setHeaderDetailsRes(R.string.location_recent_location_access_view_details)
+                .setHeaderEmptyRes(R.string.location_no_recent_accesses)
                 .setHeaderDetailsClickListener((View v) -> {
                     final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE);
                     intent.putExtra(Intent.EXTRA_PERMISSION_NAME,
@@ -100,14 +101,20 @@
                         .setIcon(access.icon)
                         .setTitle(access.label)
                         .setSummary(access.contentDescription)
+                        .setOnClickListener((v) -> {
+                            final Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSION);
+                            intent.putExtra(Intent.EXTRA_PERMISSION_NAME,
+                                    Manifest.permission_group.LOCATION);
+                            intent.putExtra(Intent.EXTRA_PACKAGE_NAME, access.packageName);
+                            intent.putExtra(Intent.EXTRA_USER, access.userHandle);
+                            mContext.startActivity(intent);
+                        })
                         .build();
                 mController.setAppEntity(i, appEntityInfo);
             }
             for (; i < MAXIMUM_APP_COUNT; i++) {
                 mController.removeAppEntity(i);
             }
-        } else {
-            // If there's no item to display, add a "No recent apps" item.
         }
         mController.apply();
     }
diff --git a/src/com/android/settings/media/MediaDeviceUpdateWorker.java b/src/com/android/settings/media/MediaDeviceUpdateWorker.java
index 7416018..d1e55e4 100644
--- a/src/com/android/settings/media/MediaDeviceUpdateWorker.java
+++ b/src/com/android/settings/media/MediaDeviceUpdateWorker.java
@@ -70,7 +70,7 @@
 
     @Override
     public void close() {
-
+        mLocalMediaManager = null;
     }
 
     @Override
diff --git a/src/com/android/settings/media/MediaOutputSlice.java b/src/com/android/settings/media/MediaOutputSlice.java
index d52b441..232986c 100644
--- a/src/com/android/settings/media/MediaOutputSlice.java
+++ b/src/com/android/settings/media/MediaOutputSlice.java
@@ -20,13 +20,11 @@
 
 import android.annotation.ColorInt;
 import android.app.PendingIntent;
+import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.os.UserHandle;
-import android.util.IconDrawableFactory;
+import android.text.TextUtils;
 import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
@@ -58,37 +56,48 @@
 
     private MediaDeviceUpdateWorker mWorker;
     private String mPackageName;
-    private IconDrawableFactory mIconDrawableFactory;
 
     public MediaOutputSlice(Context context) {
         mContext = context;
         mPackageName = getUri().getQueryParameter(MEDIA_PACKAGE_NAME);
-        mIconDrawableFactory = IconDrawableFactory.newInstance(mContext);
     }
 
     @VisibleForTesting
-    void init(String packageName, MediaDeviceUpdateWorker worker, IconDrawableFactory factory) {
+    void init(String packageName, MediaDeviceUpdateWorker worker) {
         mPackageName = packageName;
         mWorker = worker;
-        mIconDrawableFactory = factory;
     }
 
     @Override
     public Slice getSlice() {
-        final PackageManager pm = mContext.getPackageManager();
+        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (!adapter.isEnabled()) {
+            Log.d(TAG, "getSlice() Bluetooth is off");
+            return null;
+        }
 
         final List<MediaDevice> devices = getMediaDevices();
-        final CharSequence title = Utils.getApplicationLabel(mContext, mPackageName);
-        final CharSequence summary =
-                mContext.getString(R.string.media_output_panel_summary_of_playing_device,
-                        getConnectedDeviceName());
-
-        final Drawable drawable =
-                Utils.getBadgedIcon(mIconDrawableFactory, pm, mPackageName, UserHandle.myUserId());
-        final IconCompat icon = Utils.createIconWithDrawable(drawable);
-
         @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
-        final SliceAction primarySliceAction = SliceAction.createDeeplink(getPrimaryAction(), icon,
+
+        final MediaDevice connectedDevice = getWorker().getCurrentConnectedMediaDevice();
+        final ListBuilder listBuilder = buildActiveDeviceHeader(color, connectedDevice);
+
+        for (MediaDevice device : devices) {
+            if (!TextUtils.equals(connectedDevice.getId(), device.getId())) {
+                listBuilder.addRow(getMediaDeviceRow(device));
+            }
+        }
+
+        return listBuilder.build();
+    }
+
+    private ListBuilder buildActiveDeviceHeader(@ColorInt int color, MediaDevice device) {
+        final String title = device.getName();
+        final IconCompat icon = IconCompat.createWithResource(mContext, device.getIcon());
+
+        final PendingIntent broadcastAction =
+                getBroadcastIntent(mContext, device.getId(), device.hashCode());
+        final SliceAction primarySliceAction = SliceAction.createDeeplink(broadcastAction, icon,
                 ListBuilder.ICON_IMAGE, title);
 
         final ListBuilder listBuilder = new ListBuilder(mContext, MEDIA_OUTPUT_SLICE_URI,
@@ -97,14 +106,10 @@
                 .addRow(new ListBuilder.RowBuilder()
                         .setTitleItem(icon, ListBuilder.ICON_IMAGE)
                         .setTitle(title)
-                        .setSubtitle(summary)
+                        .setSubtitle(device.getSummary())
                         .setPrimaryAction(primarySliceAction));
 
-        for (MediaDevice device : devices) {
-            listBuilder.addRow(getMediaDeviceRow(device));
-        }
-
-        return listBuilder.build();
+        return listBuilder;
     }
 
     private MediaDeviceUpdateWorker getWorker() {
@@ -120,18 +125,6 @@
         return devices;
     }
 
-    private String getConnectedDeviceName() {
-        final MediaDevice device = getWorker().getCurrentConnectedMediaDevice();
-        return device != null ? device.getName() : "";
-    }
-
-    private PendingIntent getPrimaryAction() {
-        final PackageManager pm = mContext.getPackageManager();
-        final Intent launchIntent = pm.getLaunchIntentForPackage(mPackageName);
-        final Intent intent = launchIntent;
-        return PendingIntent.getActivity(mContext, 0  /* requestCode */, intent, 0  /* flags */);
-    }
-
     private ListBuilder.RowBuilder getMediaDeviceRow(MediaDevice device) {
         final String title = device.getName();
         final PendingIntent broadcastAction =
@@ -141,7 +134,8 @@
                 .setTitleItem(deviceIcon, ListBuilder.ICON_IMAGE)
                 .setPrimaryAction(SliceAction.create(broadcastAction, deviceIcon,
                         ListBuilder.ICON_IMAGE, title))
-                .setTitle(title);
+                .setTitle(title)
+                .setSubtitle(device.getSummary());
 
         return rowBuilder;
     }
diff --git a/src/com/android/settings/network/MobileNetworkListController.java b/src/com/android/settings/network/MobileNetworkListController.java
index 7de6cdd..79715e3 100644
--- a/src/com/android/settings/network/MobileNetworkListController.java
+++ b/src/com/android/settings/network/MobileNetworkListController.java
@@ -24,14 +24,10 @@
 import android.provider.Settings;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
+import android.telephony.euicc.EuiccManager;
 import android.util.ArrayMap;
 
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleObserver;
-import androidx.lifecycle.OnLifecycleEvent;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
 import com.android.settings.network.telephony.MobileNetworkActivity;
 import com.android.settingslib.core.AbstractPreferenceController;
@@ -39,6 +35,12 @@
 import java.util.List;
 import java.util.Map;
 
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
 /**
  * This populates the entries on a page which lists all available mobile subscriptions. Each entry
  * has the name of the subscription with some subtext giving additional detail, and clicking on the
@@ -48,6 +50,9 @@
         LifecycleObserver, SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
     private static final String TAG = "MobileNetworkListCtlr";
 
+    @VisibleForTesting
+    static final String KEY_ADD_MORE = "add_more";
+
     private SubscriptionManager mSubscriptionManager;
     private SubscriptionsChangeListener mChangeListener;
     private PreferenceScreen mPreferenceScreen;
@@ -76,6 +81,8 @@
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
         mPreferenceScreen = screen;
+        final EuiccManager euiccManager = mContext.getSystemService(EuiccManager.class);
+        mPreferenceScreen.findPreference(KEY_ADD_MORE).setVisible(euiccManager.isEnabled());
         update();
     }
 
@@ -93,7 +100,7 @@
         final List<SubscriptionInfo> subscriptions = SubscriptionUtil.getAvailableSubscriptions(
                 mSubscriptionManager);
         for (SubscriptionInfo info : subscriptions) {
-            int subId = info.getSubscriptionId();
+            final int subId = info.getSubscriptionId();
             Preference pref = existingPreferences.remove(subId);
             if (pref == null) {
                 pref = new Preference(mPreferenceScreen.getContext());
diff --git a/src/com/android/settings/network/MobileNetworkSummaryController.java b/src/com/android/settings/network/MobileNetworkSummaryController.java
index a1fef4c..56735ab 100644
--- a/src/com/android/settings/network/MobileNetworkSummaryController.java
+++ b/src/com/android/settings/network/MobileNetworkSummaryController.java
@@ -16,8 +16,6 @@
 
 package com.android.settings.network;
 
-import static android.telephony.TelephonyManager.MultiSimVariants.UNKNOWN;
-
 import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
 import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
 
@@ -25,7 +23,6 @@
 import android.content.Intent;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
 import android.telephony.euicc.EuiccManager;
 
 import com.android.settings.R;
@@ -52,7 +49,6 @@
 
     private SubscriptionManager mSubscriptionManager;
     private SubscriptionsChangeListener mChangeListener;
-    private TelephonyManager mTelephonyMgr;
     private EuiccManager mEuiccManager;
     private AddPreference mPreference;
 
@@ -74,7 +70,6 @@
     public MobileNetworkSummaryController(Context context, Lifecycle lifecycle) {
         super(context);
         mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
-        mTelephonyMgr = mContext.getSystemService(TelephonyManager.class);
         mEuiccManager = mContext.getSystemService(EuiccManager.class);
         if (lifecycle != null) {
           mChangeListener = new SubscriptionsChangeListener(context, this);
@@ -124,48 +119,43 @@
         mContext.startActivity(intent);
     }
 
-    private boolean shouldShowAddButton() {
-        // The add button should only show up if the device is in multi-sim mode and the eSIM
-        // manager is enabled.
-        return mTelephonyMgr.getMultiSimConfiguration() != UNKNOWN && mEuiccManager.isEnabled();
-    }
-
     private void update() {
         if (mPreference == null) {
             return;
         }
-        final boolean showAddButton = shouldShowAddButton();
         refreshSummary(mPreference);
-        if (!showAddButton) {
-            mPreference.setOnAddClickListener(null);
-        } else {
-            mPreference.setAddWidgetEnabled(!mChangeListener.isAirplaneModeOn());
-            mPreference.setOnAddClickListener(p -> {
-                startAddSimFlow();
-            });
-        }
-        final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(
-                mSubscriptionManager);
         mPreference.setOnPreferenceClickListener(null);
+        mPreference.setOnAddClickListener(null);
         mPreference.setFragment(null);
         mPreference.setEnabled(!mChangeListener.isAirplaneModeOn());
+
+        final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(
+                mSubscriptionManager);
+
         if (subs.isEmpty()) {
-            if (showAddButton) {
-                mPreference.setEnabled(false);
-            } else if (mEuiccManager.isEnabled()) {
+            if (mEuiccManager.isEnabled()) {
                 mPreference.setOnPreferenceClickListener((Preference pref) -> {
                     startAddSimFlow();
                     return true;
                 });
             }
-        } else if (subs.size() == 1) {
-            mPreference.setOnPreferenceClickListener((Preference pref) -> {
-                final Intent intent = new Intent(mContext, MobileNetworkActivity.class);
-                mContext.startActivity(intent);
-                return true;
-            });
         } else {
-            mPreference.setFragment(MobileNetworkListFragment.class.getCanonicalName());
+            // We have one or more existing subscriptions, so we want the plus button if eSIM is
+            // supported.
+            if (mEuiccManager.isEnabled()) {
+                mPreference.setAddWidgetEnabled(!mChangeListener.isAirplaneModeOn());
+                mPreference.setOnAddClickListener(p -> startAddSimFlow());
+            }
+
+            if (subs.size() == 1) {
+                mPreference.setOnPreferenceClickListener((Preference pref) -> {
+                    final Intent intent = new Intent(mContext, MobileNetworkActivity.class);
+                    mContext.startActivity(intent);
+                    return true;
+                });
+            } else {
+                mPreference.setFragment(MobileNetworkListFragment.class.getCanonicalName());
+            }
         }
     }
 
diff --git a/src/com/android/settings/network/NetworkDashboardFragment.java b/src/com/android/settings/network/NetworkDashboardFragment.java
index 7672c2e..8c686a5 100644
--- a/src/com/android/settings/network/NetworkDashboardFragment.java
+++ b/src/com/android/settings/network/NetworkDashboardFragment.java
@@ -168,7 +168,12 @@
                 public List<SearchIndexableResource> getXmlResourcesToIndex(
                         Context context, boolean enabled) {
                     final SearchIndexableResource sir = new SearchIndexableResource(context);
-                    sir.xmlResId = R.xml.network_and_internet;
+                    if (FeatureFlagPersistent.isEnabled(context,
+                            FeatureFlags.NETWORK_INTERNET_V2)) {
+                        sir.xmlResId = R.xml.network_and_internet_v2;
+                    } else {
+                        sir.xmlResId = R.xml.network_and_internet;
+                    }
                     return Arrays.asList(sir);
                 }
 
diff --git a/src/com/android/settings/network/TopLevelNetworkEntryPreferenceController.java b/src/com/android/settings/network/TopLevelNetworkEntryPreferenceController.java
index 567e52e..1136736 100644
--- a/src/com/android/settings/network/TopLevelNetworkEntryPreferenceController.java
+++ b/src/com/android/settings/network/TopLevelNetworkEntryPreferenceController.java
@@ -22,6 +22,7 @@
 import android.text.TextUtils;
 
 import com.android.settings.R;
+import com.android.settings.Utils;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.wifi.WifiMasterSwitchPreferenceController;
 
@@ -45,7 +46,7 @@
 
     @Override
     public int getAvailabilityStatus() {
-        return AVAILABLE_UNSEARCHABLE;
+        return Utils.isDemoUser(mContext) ? UNSUPPORTED_ON_DEVICE : AVAILABLE_UNSEARCHABLE;
     }
 
     @Override
diff --git a/src/com/android/settings/network/telephony/NetworkSelectSettings.java b/src/com/android/settings/network/telephony/NetworkSelectSettings.java
index 088bfbf..d70bd62 100644
--- a/src/com/android/settings/network/telephony/NetworkSelectSettings.java
+++ b/src/com/android/settings/network/telephony/NetworkSelectSettings.java
@@ -318,7 +318,8 @@
             // Try to get the network registration states
             ServiceState ss = mTelephonyManager.getServiceState();
             List<NetworkRegistrationState> networkList =
-                    ss.getNetworkRegistrationStates(AccessNetworkConstants.TransportType.WWAN);
+                    ss.getNetworkRegistrationStatesForTransportType(
+                            AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
             if (networkList == null || networkList.size() == 0) {
                 // Remove the connected network operators category
                 mConnectedPreferenceCategory.setVisible(false);
diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java
index 9f5ece2..5fd26a6 100644
--- a/src/com/android/settings/notification/AppNotificationSettings.java
+++ b/src/com/android/settings/notification/AppNotificationSettings.java
@@ -152,6 +152,10 @@
                 context, mImportanceListener, mBackend));
         mControllers.add(new ImportancePreferenceController(
                 context, mImportanceListener, mBackend));
+        mControllers.add(new MinImportancePreferenceController(
+                context, mImportanceListener, mBackend));
+        mControllers.add(new HighImportancePreferenceController(
+                context, mImportanceListener, mBackend));
         mControllers.add(new SoundPreferenceController(context, this,
                 mImportanceListener, mBackend));
         mControllers.add(new LightsPreferenceController(context, mBackend));
diff --git a/src/com/android/settings/notification/BubblePreferenceController.java b/src/com/android/settings/notification/BubblePreferenceController.java
index e61de4b..5b3be44 100644
--- a/src/com/android/settings/notification/BubblePreferenceController.java
+++ b/src/com/android/settings/notification/BubblePreferenceController.java
@@ -30,7 +30,7 @@
         implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
 
     private static final String TAG = "BubblePrefContr";
-    private static final String KEY = "bubble";
+    private static final String KEY = "bubble_pref";
     private static final int SYSTEM_WIDE_ON = 1;
     private static final int SYSTEM_WIDE_OFF = 0;
 
diff --git a/src/com/android/settings/notification/ChannelNotificationSettings.java b/src/com/android/settings/notification/ChannelNotificationSettings.java
index f92e529..850fde2 100644
--- a/src/com/android/settings/notification/ChannelNotificationSettings.java
+++ b/src/com/android/settings/notification/ChannelNotificationSettings.java
@@ -94,9 +94,12 @@
     protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
         mControllers = new ArrayList<>();
         mControllers.add(new HeaderPreferenceController(context, this));
-        mControllers.add(new BlockPreferenceController(context, mImportanceListener, mBackend));
         mControllers.add(new ImportancePreferenceController(
                 context, mImportanceListener, mBackend));
+        mControllers.add(new MinImportancePreferenceController(
+                context, mImportanceListener, mBackend));
+        mControllers.add(new HighImportancePreferenceController(
+                context, mImportanceListener, mBackend));
         mControllers.add(new AllowSoundPreferenceController(
                 context, mImportanceListener, mBackend));
         mControllers.add(new SoundPreferenceController(context, this,
diff --git a/src/com/android/settings/notification/HighImportancePreferenceController.java b/src/com/android/settings/notification/HighImportancePreferenceController.java
new file mode 100644
index 0000000..fe843fd
--- /dev/null
+++ b/src/com/android/settings/notification/HighImportancePreferenceController.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2019 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 android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+
+import android.app.NotificationChannel;
+import android.content.Context;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+import androidx.preference.Preference;
+
+public class HighImportancePreferenceController extends NotificationPreferenceController
+        implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener  {
+
+    private static final String KEY_IMPORTANCE = "high_importance";
+    private NotificationSettingsBase.ImportanceListener mImportanceListener;
+
+    public HighImportancePreferenceController(Context context,
+            NotificationSettingsBase.ImportanceListener importanceListener,
+            NotificationBackend backend) {
+        super(context, backend);
+        mImportanceListener = importanceListener;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_IMPORTANCE;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        if (!super.isAvailable()) {
+            return false;
+        }
+        if (mChannel == null) {
+            return false;
+        }
+        if (isDefaultChannel()) {
+           return false;
+        }
+        return mChannel.getImportance() >= IMPORTANCE_DEFAULT;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        if (mAppRow!= null && mChannel != null) {
+            preference.setEnabled(mAdmin == null && isChannelConfigurable());
+
+            RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
+            pref.setChecked(mChannel.getImportance() >= IMPORTANCE_HIGH);
+        }
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        if (mChannel != null) {
+            final boolean checked = (boolean) newValue;
+
+            mChannel.setImportance(checked ? IMPORTANCE_HIGH : IMPORTANCE_DEFAULT);
+            mChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+            saveChannel();
+            mImportanceListener.onImportanceChanged();
+        }
+        return true;
+    }
+}
diff --git a/src/com/android/settings/notification/ImportancePreference.java b/src/com/android/settings/notification/ImportancePreference.java
new file mode 100644
index 0000000..b8f3e45
--- /dev/null
+++ b/src/com/android/settings/notification/ImportancePreference.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2019 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 android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
+import static android.app.NotificationManager.IMPORTANCE_NONE;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.LayerDrawable;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageButton;
+
+import com.android.settingslib.R;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+public class ImportancePreference extends Preference {
+
+    boolean mIsBlockable = true;
+    boolean mIsConfigurable = true;
+    int mImportance;
+    ImageButton blockButton;
+    ImageButton silenceButton;
+    ImageButton alertButton;
+    ArrayMap<ImageButton, Integer> mImageButtons = new ArrayMap<>();
+    Context mContext;
+
+    public ImportancePreference(Context context, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init(context);
+    }
+
+    public ImportancePreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context);
+    }
+
+    public ImportancePreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(context);
+    }
+
+    public ImportancePreference(Context context) {
+        super(context);
+        init(context);
+    }
+
+    private void init(Context context) {
+        mContext = context;
+        setLayoutResource(R.layout.notif_importance_preference);
+    }
+
+    public void setImportance(int importance) {
+        mImportance = importance;
+    }
+
+    public void setBlockable(boolean blockable) {
+        mIsBlockable = blockable;
+    }
+
+    public void setConfigurable(boolean configurable) {
+        mIsConfigurable = configurable;
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+
+        View blockView = holder.itemView.findViewById(R.id.block);
+        View alertView = holder.itemView.findViewById(R.id.alert);
+        View silenceView = holder.itemView.findViewById(R.id.silence);
+        if (!mIsBlockable) {
+            blockView.setVisibility(View.GONE);
+            if (mImportance == IMPORTANCE_NONE) {
+                mImportance = IMPORTANCE_LOW;
+                callChangeListener(IMPORTANCE_LOW);
+            }
+
+        }
+        blockButton = blockView.findViewById(R.id.block_icon);
+        silenceButton = silenceView.findViewById(R.id.silence_icon);
+        alertButton = alertView.findViewById(R.id.alert_icon);
+        mImageButtons.put(blockButton, mContext.getColor(R.color.notification_block_color));
+        mImageButtons.put(silenceButton, mContext.getColor(R.color.notification_silence_color));
+        mImageButtons.put(alertButton, mContext.getColor(R.color.notification_alert_color));
+
+        switch (mImportance) {
+            case IMPORTANCE_NONE:
+                colorizeImageButton(blockButton.getId());
+                if (!mIsConfigurable) {
+                    alertView.setVisibility(View.GONE);
+                    silenceView.setVisibility(View.GONE);
+                }
+                break;
+            case IMPORTANCE_MIN:
+            case IMPORTANCE_LOW:
+                colorizeImageButton(silenceButton.getId());
+                if (!mIsConfigurable) {
+                    alertView.setVisibility(View.GONE);
+                    blockView.setVisibility(View.GONE);
+                }
+                break;
+            case IMPORTANCE_HIGH:
+            default:
+                colorizeImageButton(alertButton.getId());
+                if (!mIsConfigurable) {
+                    blockView.setVisibility(View.GONE);
+                    silenceView.setVisibility(View.GONE);
+                }
+                break;
+        }
+
+        blockButton.setOnClickListener(v -> {
+            callChangeListener(IMPORTANCE_NONE);
+            colorizeImageButton(blockButton.getId());
+        });
+        silenceButton.setOnClickListener(v -> {
+            callChangeListener(IMPORTANCE_LOW);
+            colorizeImageButton(silenceButton.getId());
+        });
+        alertButton.setOnClickListener(v -> {
+            callChangeListener(IMPORTANCE_DEFAULT);
+            colorizeImageButton(alertButton.getId());
+        });
+    }
+
+    private void colorizeImageButton(int buttonId) {
+        if (mImageButtons != null) {
+            for (int i = 0; i < mImageButtons.size(); i++) {
+                final ImageButton imageButton = mImageButtons.keyAt(i);
+                final int color = mImageButtons.valueAt(i);
+                if (imageButton != null) {
+                    LayerDrawable drawable = (LayerDrawable) imageButton.getDrawable();
+                    Drawable foreground = drawable.findDrawableByLayerId(R.id.fore);
+                    GradientDrawable background =
+                            (GradientDrawable) drawable.findDrawableByLayerId(R.id.back);
+                    if (buttonId == imageButton.getId()) {
+                        foreground.setTint(Color.WHITE);
+                        background.setColor(color);
+                    } else {
+                        foreground.setTint(color);
+                        background.setColor(Color.TRANSPARENT);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/com/android/settings/notification/ImportancePreferenceController.java b/src/com/android/settings/notification/ImportancePreferenceController.java
index 4c20a46..0955571 100644
--- a/src/com/android/settings/notification/ImportancePreferenceController.java
+++ b/src/com/android/settings/notification/ImportancePreferenceController.java
@@ -18,21 +18,15 @@
 
 import static android.app.NotificationChannel.USER_LOCKED_SOUND;
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
-import static android.app.NotificationManager.IMPORTANCE_MIN;
-import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
 
 import android.app.NotificationChannel;
-import android.app.NotificationManager;
 import android.content.Context;
 import android.media.RingtoneManager;
 
-import androidx.preference.Preference;
-
-import com.android.settings.R;
-import com.android.settings.RestrictedListPreference;
 import com.android.settings.core.PreferenceControllerMixin;
 
+import androidx.preference.Preference;
+
 public class ImportancePreferenceController extends NotificationPreferenceController
         implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener  {
 
@@ -53,44 +47,33 @@
 
     @Override
     public boolean isAvailable() {
-        if (!super.isAvailable()) {
+        if (mAppRow == null) {
             return false;
         }
         if (mChannel == null) {
             return false;
         }
-        return !isDefaultChannel();
+        if (isDefaultChannel()) {
+            return false;
+        }
+        return true;
     }
 
     @Override
     public void updateState(Preference preference) {
         if (mAppRow!= null && mChannel != null) {
             preference.setEnabled(mAdmin == null && isChannelConfigurable());
-            preference.setSummary(getImportanceSummary(mChannel));
-
-            int importances = IMPORTANCE_HIGH - IMPORTANCE_MIN + 1;
-            CharSequence[] entries = new CharSequence[importances];
-            CharSequence[] values = new CharSequence[importances];
-
-            int index = 0;
-            for (int i = IMPORTANCE_HIGH; i >= IMPORTANCE_MIN; i--) {
-                NotificationChannel channel = new NotificationChannel("", "", i);
-                entries[index] = getImportanceSummary(channel);
-                values[index] = String.valueOf(i);
-                index++;
-            }
-
-            RestrictedListPreference pref = (RestrictedListPreference) preference;
-            pref.setEntries(entries);
-            pref.setEntryValues(values);
-            pref.setValue(String.valueOf(mChannel.getImportance()));
+            ImportancePreference pref = (ImportancePreference) preference;
+            pref.setBlockable(isChannelBlockable());
+            pref.setConfigurable(isChannelConfigurable());
+            pref.setImportance(mChannel.getImportance());
         }
     }
 
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         if (mChannel != null) {
-            final int importance = Integer.parseInt((String) newValue);
+            final int importance = (Integer) newValue;
 
             // If you are moving from an importance level without sound to one with sound,
             // but the sound you had selected was "Silence",
@@ -111,39 +94,4 @@
         }
         return true;
     }
-
-    protected String getImportanceSummary(NotificationChannel channel) {
-        String summary = "";
-        int importance = channel.getImportance();
-        switch (importance) {
-            case IMPORTANCE_UNSPECIFIED:
-                summary = mContext.getString(R.string.notification_importance_unspecified);
-                break;
-            case NotificationManager.IMPORTANCE_MIN:
-                summary = mContext.getString(R.string.notification_importance_min);
-                break;
-            case NotificationManager.IMPORTANCE_LOW:
-                summary = mContext.getString(R.string.notification_importance_low);
-                break;
-            case NotificationManager.IMPORTANCE_DEFAULT:
-                if (SoundPreferenceController.hasValidSound(channel)) {
-                    summary = mContext.getString(R.string.notification_importance_default);
-                } else {
-                    summary = mContext.getString(R.string.notification_importance_low);
-                }
-                break;
-            case NotificationManager.IMPORTANCE_HIGH:
-            case NotificationManager.IMPORTANCE_MAX:
-                if (SoundPreferenceController.hasValidSound(channel)) {
-                    summary = mContext.getString(R.string.notification_importance_high);
-                } else {
-                    summary = mContext.getString(R.string.notification_importance_high_silent);
-                }
-                break;
-            default:
-                return "";
-        }
-
-        return summary;
-    }
 }
diff --git a/src/com/android/settings/notification/MinImportancePreferenceController.java b/src/com/android/settings/notification/MinImportancePreferenceController.java
new file mode 100644
index 0000000..771ac60
--- /dev/null
+++ b/src/com/android/settings/notification/MinImportancePreferenceController.java
@@ -0,0 +1,84 @@
+/*
+ * 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 static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
+
+import android.app.NotificationChannel;
+import android.content.Context;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+import androidx.preference.Preference;
+
+public class MinImportancePreferenceController extends NotificationPreferenceController
+        implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener  {
+
+    private static final String KEY_IMPORTANCE = "min_importance";
+    private NotificationSettingsBase.ImportanceListener mImportanceListener;
+
+    public MinImportancePreferenceController(Context context,
+            NotificationSettingsBase.ImportanceListener importanceListener,
+            NotificationBackend backend) {
+        super(context, backend);
+        mImportanceListener = importanceListener;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_IMPORTANCE;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        if (!super.isAvailable()) {
+            return false;
+        }
+        if (mChannel == null) {
+            return false;
+        }
+        if (isDefaultChannel()) {
+            return false;
+        }
+        return mChannel.getImportance() <= IMPORTANCE_LOW;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        if (mAppRow!= null && mChannel != null) {
+            preference.setEnabled(mAdmin == null && isChannelConfigurable());
+
+            RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
+            pref.setChecked(mChannel.getImportance() == IMPORTANCE_MIN);
+        }
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        if (mChannel != null) {
+            final boolean checked = (boolean) newValue;
+
+            mChannel.setImportance(checked ? IMPORTANCE_MIN : IMPORTANCE_LOW);
+            mChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+            saveChannel();
+            mImportanceListener.onImportanceChanged();
+        }
+        return true;
+    }
+}
diff --git a/src/com/android/settings/notification/NotificationPreferenceController.java b/src/com/android/settings/notification/NotificationPreferenceController.java
index 22f07be..3f535fb 100644
--- a/src/com/android/settings/notification/NotificationPreferenceController.java
+++ b/src/com/android/settings/notification/NotificationPreferenceController.java
@@ -111,6 +111,9 @@
     }
 
     protected boolean isChannelConfigurable() {
+        if (mAppRow != null && mAppRow.lockedImportance) {
+            return false;
+        }
         if (mChannel != null && mAppRow != null) {
             return !Objects.equals(mChannel.getId(), mAppRow.lockedChannelId);
         }
diff --git a/src/com/android/settings/notification/RemoteVolumePreferenceController.java b/src/com/android/settings/notification/RemoteVolumePreferenceController.java
index 0ad307e..37a493e 100644
--- a/src/com/android/settings/notification/RemoteVolumePreferenceController.java
+++ b/src/com/android/settings/notification/RemoteVolumePreferenceController.java
@@ -35,6 +35,7 @@
 
 import java.io.IOException;
 import java.util.List;
+import java.util.Objects;
 
 public class RemoteVolumePreferenceController extends
     VolumeSeekBarPreferenceController {
@@ -58,14 +59,14 @@
             if (mActiveToken == null) {
                 updateToken(token);
             }
-            if (mActiveToken == token) {
+            if (Objects.equals(mActiveToken, token)) {
                 updatePreference(mPreference, mActiveToken, pi);
             }
         }
 
         @Override
         public void onRemoteRemoved(MediaSession.Token t) {
-            if (mActiveToken == t) {
+            if (Objects.equals(mActiveToken, t)) {
                 updateToken(null);
                 if (mPreference != null) {
                     mPreference.setVisible(false);
@@ -75,7 +76,7 @@
 
         @Override
         public void onRemoteVolumeChanged(MediaSession.Token token, int flags) {
-            if (mActiveToken == token) {
+            if (Objects.equals(mActiveToken, token)) {
                 final MediaController.PlaybackInfo pi = mMediaController.getPlaybackInfo();
                 if (pi != null) {
                     setSliderPosition(pi.getCurrentVolume());
@@ -116,13 +117,13 @@
     @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
     public void onResume() {
         super.onResume();
-        //TODO(b/126199571): register callback once b/126890783 is fixed
+        mMediaSessions.init();
     }
 
     @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
     public void onPause() {
         super.onPause();
-        //TODO(b/126199571): unregister callback once b/126890783 is fixed
+        mMediaSessions.destroy();
     }
 
     @Override
@@ -189,8 +190,7 @@
 
     @Override
     public Class<? extends SliceBackgroundWorker> getBackgroundWorkerClass() {
-        //TODO(b/126199571): return RemoteVolumeSliceWorker once b/126890783 is fixed
-        return null;
+        return RemoteVolumeSliceWorker.class;
     }
 
     private void updatePreference(VolumeSeekBarPreference seekBarPreference,
diff --git a/src/com/android/settings/notification/SoundSettings.java b/src/com/android/settings/notification/SoundSettings.java
index b26b921..eec0fb8 100644
--- a/src/com/android/settings/notification/SoundSettings.java
+++ b/src/com/android/settings/notification/SoundSettings.java
@@ -38,7 +38,6 @@
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.sound.HandsFreeProfileOutputPreferenceController;
-import com.android.settings.sound.MediaOutputPreferenceController;
 import com.android.settings.widget.PreferenceCategoryController;
 import com.android.settings.widget.UpdatableListPreferenceDialogFragment;
 import com.android.settingslib.core.AbstractPreferenceController;
@@ -77,7 +76,6 @@
 
     private RingtonePreference mRequestPreference;
     private UpdatableListPreferenceDialogFragment mDialogFragment;
-    private String mMediaOutputControllerKey;
     private String mHfpOutputControllerKey;
 
     @Override
@@ -132,8 +130,6 @@
         final int metricsCategory;
         if (mHfpOutputControllerKey.equals(preference.getKey())) {
             metricsCategory = SettingsEnums.DIALOG_SWITCH_HFP_DEVICES;
-        } else if (mMediaOutputControllerKey.equals(preference.getKey())) {
-            metricsCategory = SettingsEnums.DIALOG_SWITCH_A2DP_DEVICES;
         } else {
             metricsCategory = Instrumentable.METRICS_CATEGORY_UNKNOWN;
         }
@@ -186,9 +182,6 @@
         volumeControllers.add(use(CallVolumePreferenceController.class));
         volumeControllers.add(use(RemoteVolumePreferenceController.class));
 
-        use(MediaOutputPreferenceController.class).setCallback(listPreference ->
-                onPreferenceDataChanged(listPreference));
-        mMediaOutputControllerKey = use(MediaOutputPreferenceController.class).getPreferenceKey();
         use(HandsFreeProfileOutputPreferenceController.class).setCallback(listPreference ->
                 onPreferenceDataChanged(listPreference));
         mHfpOutputControllerKey =
diff --git a/src/com/android/settings/notification/ZenRulePreference.java b/src/com/android/settings/notification/ZenRulePreference.java
index 613eb1d..8bc602a 100644
--- a/src/com/android/settings/notification/ZenRulePreference.java
+++ b/src/com/android/settings/notification/ZenRulePreference.java
@@ -171,6 +171,9 @@
                 getSettingsActivity(rule, si);
         mIntent = AbstractZenModeAutomaticRulePreferenceController.getRuleIntent(action,
                 settingsActivity, mId);
+        if (mIntent.resolveActivity(mPm) == null) {
+            mIntent = null;
+        }
         setKey(mId);
     }
 
diff --git a/src/com/android/settings/panel/PanelSlicesAdapter.java b/src/com/android/settings/panel/PanelSlicesAdapter.java
index c1cb049..47ff631 100644
--- a/src/com/android/settings/panel/PanelSlicesAdapter.java
+++ b/src/com/android/settings/panel/PanelSlicesAdapter.java
@@ -94,6 +94,7 @@
             super(view);
             sliceView = view.findViewById(R.id.slice_view);
             sliceView.setMode(SliceView.MODE_LARGE);
+            sliceView.showTitleItems(true);
             mPanelContent = panelContent;
         }
 
diff --git a/src/com/android/settings/panel/SettingsPanelActivity.java b/src/com/android/settings/panel/SettingsPanelActivity.java
index 3819c80..8aee382 100644
--- a/src/com/android/settings/panel/SettingsPanelActivity.java
+++ b/src/com/android/settings/panel/SettingsPanelActivity.java
@@ -16,13 +16,11 @@
 
 package com.android.settings.panel;
 
-import static com.android.settingslib.media.MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT;
 import static com.android.settingslib.media.MediaOutputSliceConstants.EXTRA_PACKAGE_NAME;
 
 import android.app.settings.SettingsEnums;
 import android.content.Intent;
 import android.os.Bundle;
-import android.text.TextUtils;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.MotionEvent;
@@ -75,15 +73,8 @@
             return;
         }
 
-        final String mediaPackageName =
-                callingIntent.getStringExtra(EXTRA_PACKAGE_NAME);
-
-        if (TextUtils.equals(ACTION_MEDIA_OUTPUT, callingIntent.getAction())
-                && TextUtils.isEmpty(mediaPackageName)) {
-            Log.e(TAG, "Missing EXTRA_PACKAGE_NAME, closing Panel Activity");
-            finish();
-            return;
-        }
+        // We will use it once media output switch panel support remote device.
+        final String mediaPackageName = callingIntent.getStringExtra(EXTRA_PACKAGE_NAME);
 
         setContentView(R.layout.settings_panel);
 
diff --git a/src/com/android/settings/password/SetNewPasswordActivity.java b/src/com/android/settings/password/SetNewPasswordActivity.java
index d7445e6..4722c56 100644
--- a/src/com/android/settings/password/SetNewPasswordActivity.java
+++ b/src/com/android/settings/password/SetNewPasswordActivity.java
@@ -16,7 +16,7 @@
 
 package com.android.settings.password;
 
-import static android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY;
+import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;
 import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
 import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
 import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
@@ -83,7 +83,7 @@
         if (ACTION_SET_NEW_PASSWORD.equals(mNewPasswordAction)
                 && getIntent().hasExtra(EXTRA_PASSWORD_COMPLEXITY)) {
             final boolean hasPermission = PasswordUtils.isCallingAppPermitted(
-                    this, activityToken, REQUEST_SCREEN_LOCK_COMPLEXITY);
+                    this, activityToken, REQUEST_PASSWORD_COMPLEXITY);
             if (hasPermission) {
                 mRequestedMinComplexity =
                         PasswordMetrics.sanitizeComplexityLevel(getIntent()
@@ -91,7 +91,7 @@
             } else {
                 PasswordUtils.crashCallingApplication(activityToken,
                         "Must have permission "
-                                + REQUEST_SCREEN_LOCK_COMPLEXITY + " to use extra "
+                                + REQUEST_PASSWORD_COMPLEXITY + " to use extra "
                                 + EXTRA_PASSWORD_COMPLEXITY);
                 finish();
                 return;
diff --git a/src/com/android/settings/password/SetupChooseLockGeneric.java b/src/com/android/settings/password/SetupChooseLockGeneric.java
index 7fbb211..346e771 100644
--- a/src/com/android/settings/password/SetupChooseLockGeneric.java
+++ b/src/com/android/settings/password/SetupChooseLockGeneric.java
@@ -16,7 +16,7 @@
 
 package com.android.settings.password;
 
-import static android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY;
+import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;
 import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
 
 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
@@ -82,10 +82,10 @@
         if(getIntent().hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)) {
             IBinder activityToken = getActivityToken();
             boolean hasPermission = PasswordUtils.isCallingAppPermitted(
-                    this, activityToken, REQUEST_SCREEN_LOCK_COMPLEXITY);
+                    this, activityToken, REQUEST_PASSWORD_COMPLEXITY);
             if (!hasPermission) {
                 PasswordUtils.crashCallingApplication(activityToken,
-                        "Must have permission " + REQUEST_SCREEN_LOCK_COMPLEXITY
+                        "Must have permission " + REQUEST_PASSWORD_COMPLEXITY
                                 + " to use extra " + EXTRA_PASSWORD_COMPLEXITY);
                 finish();
                 return;
diff --git a/src/com/android/settings/slices/CustomSliceManager.java b/src/com/android/settings/slices/CustomSliceManager.java
deleted file mode 100644
index c9e473a..0000000
--- a/src/com/android/settings/slices/CustomSliceManager.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.slices;
-
-import android.content.Context;
-import android.net.Uri;
-import android.util.ArrayMap;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.settings.flashlight.FlashlightSlice;
-import com.android.settings.homepage.contextualcards.deviceinfo.BatteryInfoSlice;
-import com.android.settings.homepage.contextualcards.deviceinfo.DataUsageSlice;
-import com.android.settings.homepage.contextualcards.deviceinfo.DeviceInfoSlice;
-import com.android.settings.homepage.contextualcards.deviceinfo.EmergencyInfoSlice;
-import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice;
-import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice;
-import com.android.settings.homepage.contextualcards.slices.BluetoothDevicesSlice;
-import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
-import com.android.settings.homepage.contextualcards.slices.NotificationChannelSlice;
-import com.android.settings.location.LocationSlice;
-import com.android.settings.media.MediaOutputSlice;
-import com.android.settings.network.telephony.MobileDataSlice;
-import com.android.settings.wifi.slice.ContextualWifiSlice;
-import com.android.settings.wifi.slice.WifiSlice;
-
-import java.util.Map;
-import java.util.WeakHashMap;
-
-/**
- * Manages custom {@link androidx.slice.Slice Slices}, which are all Slices not backed by
- * preferences.
- */
-public class CustomSliceManager {
-
-    @VisibleForTesting
-    final Map<Uri, Class<? extends CustomSliceable>> mUriMap;
-
-    private final Context mContext;
-    private final Map<Uri, CustomSliceable> mSliceableCache;
-
-    public CustomSliceManager(Context context) {
-        mContext = context.getApplicationContext();
-        mUriMap = new ArrayMap<>();
-        mSliceableCache = new WeakHashMap<>();
-        addSlices();
-    }
-
-    /**
-     * Return a {@link CustomSliceable} associated to the Uri.
-     * <p>
-     * Do not change this method signature to accommodate for a special-case slicable - a context is
-     * the only thing that should be needed to create the object.
-     */
-    public CustomSliceable getSliceableFromUri(Uri uri) {
-        final Uri newUri = removeParameterFromUri(uri);
-        if (mSliceableCache.containsKey(newUri)) {
-            return mSliceableCache.get(newUri);
-        }
-
-        final Class clazz = mUriMap.get(newUri);
-        if (clazz == null) {
-            throw new IllegalArgumentException("No Slice found for uri: " + uri);
-        }
-
-        final CustomSliceable sliceable = CustomSliceable.createInstance(mContext, clazz);
-        mSliceableCache.put(newUri, sliceable);
-        return sliceable;
-    }
-
-    private Uri removeParameterFromUri(Uri uri) {
-        return uri != null ? uri.buildUpon().clearQuery().build() : null;
-    }
-
-    /**
-     * Return a {@link CustomSliceable} associated to the Action.
-     * <p>
-     * Do not change this method signature to accommodate for a special-case sliceable - a context
-     * is the only thing that should be needed to create the object.
-     */
-    public CustomSliceable getSliceableFromIntentAction(String action) {
-        return getSliceableFromUri(Uri.parse(action));
-    }
-
-    /**
-     * Returns {@code true} if {@param uri} is a valid Slice Uri handled by
-     * {@link CustomSliceManager}.
-     */
-    public boolean isValidUri(Uri uri) {
-        return mUriMap.containsKey(removeParameterFromUri(uri));
-    }
-
-    /**
-     * Returns {@code true} if {@param action} is a valid intent action handled by
-     * {@link CustomSliceManager}.
-     */
-    public boolean isValidAction(String action) {
-        return isValidUri(Uri.parse(action));
-    }
-
-    private void addSlices() {
-        mUriMap.put(CustomSliceRegistry.BATTERY_FIX_SLICE_URI, BatteryFixSlice.class);
-        mUriMap.put(CustomSliceRegistry.BATTERY_INFO_SLICE_URI, BatteryInfoSlice.class);
-        mUriMap.put(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI, BluetoothDevicesSlice.class);
-        mUriMap.put(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI, ContextualWifiSlice.class);
-        mUriMap.put(CustomSliceRegistry.DATA_USAGE_SLICE_URI, DataUsageSlice.class);
-        mUriMap.put(CustomSliceRegistry.DEVICE_INFO_SLICE_URI, DeviceInfoSlice.class);
-        mUriMap.put(CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI, EmergencyInfoSlice.class);
-        mUriMap.put(CustomSliceRegistry.FLASHLIGHT_SLICE_URI, FlashlightSlice.class);
-        mUriMap.put(CustomSliceRegistry.LOCATION_SLICE_URI, LocationSlice.class);
-        mUriMap.put(CustomSliceRegistry.LOW_STORAGE_SLICE_URI, LowStorageSlice.class);
-        mUriMap.put(CustomSliceRegistry.MOBILE_DATA_SLICE_URI, MobileDataSlice.class);
-        mUriMap.put(CustomSliceRegistry.NOTIFICATION_CHANNEL_SLICE_URI,
-                NotificationChannelSlice.class);
-        mUriMap.put(CustomSliceRegistry.STORAGE_SLICE_URI, StorageSlice.class);
-        mUriMap.put(CustomSliceRegistry.WIFI_SLICE_URI, WifiSlice.class);
-        mUriMap.put(CustomSliceRegistry.MEDIA_OUTPUT_SLICE_URI, MediaOutputSlice.class);
-    }
-}
diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java
index 3a1db69..9d88bc5 100644
--- a/src/com/android/settings/slices/CustomSliceRegistry.java
+++ b/src/com/android/settings/slices/CustomSliceRegistry.java
@@ -24,11 +24,30 @@
 import android.content.ContentResolver;
 import android.net.Uri;
 import android.provider.SettingsSlicesContract;
+import android.util.ArrayMap;
 
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.flashlight.FlashlightSlice;
 import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
+import com.android.settings.homepage.contextualcards.deviceinfo.DataUsageSlice;
+import com.android.settings.homepage.contextualcards.deviceinfo.DeviceInfoSlice;
+import com.android.settings.homepage.contextualcards.deviceinfo.EmergencyInfoSlice;
+import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice;
+import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice;
+import com.android.settings.homepage.contextualcards.slices.BluetoothDevicesSlice;
+import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
+import com.android.settings.homepage.contextualcards.slices.NotificationChannelSlice;
+import com.android.settings.location.LocationSlice;
+import com.android.settings.media.MediaOutputSlice;
+import com.android.settings.network.telephony.MobileDataSlice;
 import com.android.settings.wifi.calling.WifiCallingSliceHelper;
+import com.android.settings.wifi.slice.ContextualWifiSlice;
+import com.android.settings.wifi.slice.WifiSlice;
 import com.android.settingslib.media.MediaOutputSliceConstants;
 
+import java.util.Map;
+
 /**
  * A registry of custom slice Uris.
  */
@@ -53,15 +72,7 @@
             .appendEncodedPath(SettingsSlicesContract.PATH_SETTING_INTENT)
             .appendPath(BatteryTipPreferenceController.PREF_NAME)
             .build();
-    /**
-     * Backing Uri for the Battery info Slice.
-     */
-    public static final Uri BATTERY_INFO_SLICE_URI = new Uri.Builder()
-            .scheme(ContentResolver.SCHEME_CONTENT)
-            .authority(SettingsSliceProvider.SLICE_AUTHORITY)
-            .appendEncodedPath(SettingsSlicesContract.PATH_SETTING_INTENT)
-            .appendPath("battery_card")
-            .build();
+
     /**
      * Backing Uri for the Bluetooth Slice.
      */
@@ -287,4 +298,51 @@
             .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
             .appendPath(MediaOutputSliceConstants.KEY_MEDIA_OUTPUT)
             .build();
+
+    @VisibleForTesting
+    static final Map<Uri, Class<? extends CustomSliceable>> sUriToSlice;
+
+    static {
+        sUriToSlice = new ArrayMap<>();
+
+        sUriToSlice.put(BATTERY_FIX_SLICE_URI, BatteryFixSlice.class);
+        sUriToSlice.put(BLUETOOTH_DEVICES_SLICE_URI, BluetoothDevicesSlice.class);
+        sUriToSlice.put(CONTEXTUAL_WIFI_SLICE_URI, ContextualWifiSlice.class);
+        sUriToSlice.put(DATA_USAGE_SLICE_URI, DataUsageSlice.class);
+        sUriToSlice.put(DEVICE_INFO_SLICE_URI, DeviceInfoSlice.class);
+        sUriToSlice.put(EMERGENCY_INFO_SLICE_URI, EmergencyInfoSlice.class);
+        sUriToSlice.put(FLASHLIGHT_SLICE_URI, FlashlightSlice.class);
+        sUriToSlice.put(LOCATION_SLICE_URI, LocationSlice.class);
+        sUriToSlice.put(LOW_STORAGE_SLICE_URI, LowStorageSlice.class);
+        sUriToSlice.put(MOBILE_DATA_SLICE_URI, MobileDataSlice.class);
+        sUriToSlice.put(NOTIFICATION_CHANNEL_SLICE_URI, NotificationChannelSlice.class);
+        sUriToSlice.put(STORAGE_SLICE_URI, StorageSlice.class);
+        sUriToSlice.put(WIFI_SLICE_URI, WifiSlice.class);
+        sUriToSlice.put(MEDIA_OUTPUT_SLICE_URI, MediaOutputSlice.class);
+    }
+
+    public static Class<? extends CustomSliceable> getSliceClassByUri(Uri uri) {
+        return sUriToSlice.get(removeParameterFromUri(uri));
+    }
+
+    public static Uri removeParameterFromUri(Uri uri) {
+        return uri != null ? uri.buildUpon().clearQuery().build() : null;
+    }
+
+    /**
+     * Returns {@code true} if {@param uri} is a valid Slice Uri handled by
+     * {@link CustomSliceRegistry}.
+     */
+    public static boolean isValidUri(Uri uri) {
+        return sUriToSlice.containsKey(removeParameterFromUri(uri));
+    }
+
+    /**
+     * Returns {@code true} if {@param action} is a valid intent action handled by
+     * {@link CustomSliceRegistry}.
+     */
+    public static boolean isValidAction(String action) {
+        return isValidUri(Uri.parse(action));
+    }
+
 }
diff --git a/src/com/android/settings/slices/CustomSliceable.java b/src/com/android/settings/slices/CustomSliceable.java
index 0b97bed..93d08a2 100644
--- a/src/com/android/settings/slices/CustomSliceable.java
+++ b/src/com/android/settings/slices/CustomSliceable.java
@@ -19,7 +19,6 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.net.Uri;
 
 import androidx.slice.Slice;
@@ -106,16 +105,17 @@
     /**
      * Build an instance of a {@link CustomSliceable} which has a {@link Context}-only constructor.
      */
-    static CustomSliceable createInstance(Context context, Class<CustomSliceable> sliceableClass) {
+    static CustomSliceable createInstance(Context context,
+            Class<? extends CustomSliceable> sliceable) {
         try {
-            final Constructor<CustomSliceable> sliceable =
-                    sliceableClass.getConstructor(Context.class);
-            final Object[] params = new Object[]{context};
-            return sliceable.newInstance(params);
+            final Constructor<? extends CustomSliceable> constructor =
+                    sliceable.getConstructor(Context.class);
+            final Object[] params = new Object[]{context.getApplicationContext()};
+            return constructor.newInstance(params);
         } catch (NoSuchMethodException | InstantiationException |
                 IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
             throw new IllegalStateException(
-                    "Invalid sliceable class: " + sliceableClass, e);
+                    "Invalid sliceable class: " + sliceable, e);
         }
     }
 }
\ No newline at end of file
diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java
index 397b2fc..3187d10 100644
--- a/src/com/android/settings/slices/SettingsSliceProvider.java
+++ b/src/com/android/settings/slices/SettingsSliceProvider.java
@@ -118,9 +118,6 @@
     private static final KeyValueListParser KEY_VALUE_LIST_PARSER = new KeyValueListParser(',');
 
     @VisibleForTesting
-    CustomSliceManager mCustomSliceManager;
-
-    @VisibleForTesting
     SlicesDatabaseAccessor mSlicesDatabaseAccessor;
 
     @VisibleForTesting
@@ -140,15 +137,15 @@
         mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(getContext());
         mSliceDataCache = new ConcurrentHashMap<>();
         mSliceWeakDataCache = new WeakHashMap<>();
-        mCustomSliceManager = FeatureFactory.getFactory(
-                getContext()).getSlicesFeatureProvider().getCustomSliceManager(getContext());
         return true;
     }
 
     @Override
     public void onSlicePinned(Uri sliceUri) {
-        if (mCustomSliceManager.isValidUri(sliceUri)) {
-            final CustomSliceable sliceable = mCustomSliceManager.getSliceableFromUri(sliceUri);
+        if (CustomSliceRegistry.isValidUri(sliceUri)) {
+            final Context context = getContext();
+            final CustomSliceable sliceable = FeatureFactory.getFactory(context)
+                    .getSlicesFeatureProvider().getSliceableFromUri(context, sliceUri);
             final IntentFilter filter = sliceable.getIntentFilter();
             if (filter != null) {
                 registerIntentToUri(filter, sliceUri);
@@ -194,10 +191,11 @@
 
             // Before adding a slice to {@link CustomSliceManager}, please get approval
             // from the Settings team.
-            if (mCustomSliceManager.isValidUri(sliceUri)) {
-                final CustomSliceable sliceable = mCustomSliceManager.getSliceableFromUri(
-                        sliceUri);
-                return sliceable.getSlice();
+            if (CustomSliceRegistry.isValidUri(sliceUri)) {
+                final Context context = getContext();
+                return FeatureFactory.getFactory(context)
+                        .getSlicesFeatureProvider().getSliceableFromUri(context, sliceUri)
+                        .getSlice();
             }
 
             if (CustomSliceRegistry.WIFI_CALLING_URI.equals(sliceUri)) {
diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java
index b2ea583..9926a52 100644
--- a/src/com/android/settings/slices/SliceBroadcastReceiver.java
+++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java
@@ -61,11 +61,10 @@
         final boolean isPlatformSlice = intent.getBooleanExtra(EXTRA_SLICE_PLATFORM_DEFINED,
                 false /* default */);
 
-        final CustomSliceManager mCustomSliceManager = FeatureFactory.getFactory(
-                context).getSlicesFeatureProvider().getCustomSliceManager(context);
-        if (mCustomSliceManager.isValidAction(action)) {
+        if (CustomSliceRegistry.isValidAction(action)) {
             final CustomSliceable sliceable =
-                    mCustomSliceManager.getSliceableFromIntentAction(action);
+                    CustomSliceable.createInstance(context,
+                            CustomSliceRegistry.getSliceClassByUri(Uri.parse(action)));
             sliceable.onNotifyChange(intent);
             return;
         }
diff --git a/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java b/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
index f4afa16..2ff071e 100644
--- a/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
+++ b/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
@@ -23,7 +23,6 @@
 
 import com.android.settings.bluetooth.BluetoothSliceBuilder;
 import com.android.settings.notification.ZenModeSliceBuilder;
-import com.android.settings.overlay.FeatureFactory;
 
 public class SliceDeepLinkSpringBoard extends Activity {
 
@@ -45,11 +44,10 @@
             Intent launchIntent;
 
             // TODO (b/80263568) Avoid duplicating this list of Slice Uris.
-            final CustomSliceManager customSliceManager = FeatureFactory.getFactory(this)
-                    .getSlicesFeatureProvider().getCustomSliceManager(this);
-            if (customSliceManager.isValidUri(sliceUri)) {
+            if (CustomSliceRegistry.isValidUri(sliceUri)) {
                 final CustomSliceable sliceable =
-                        customSliceManager.getSliceableFromUri(sliceUri);
+                        CustomSliceable.createInstance(getApplicationContext(),
+                                CustomSliceRegistry.getSliceClassByUri(sliceUri));
                 launchIntent = sliceable.getIntent();
             } else if (CustomSliceRegistry.ZEN_MODE_SLICE_URI.equals(sliceUri)) {
                 launchIntent = ZenModeSliceBuilder.getIntent(this /* context */);
diff --git a/src/com/android/settings/slices/SlicesFeatureProvider.java b/src/com/android/settings/slices/SlicesFeatureProvider.java
index 1a9fd98..ae94f29 100644
--- a/src/com/android/settings/slices/SlicesFeatureProvider.java
+++ b/src/com/android/settings/slices/SlicesFeatureProvider.java
@@ -1,6 +1,7 @@
 package com.android.settings.slices;
 
 import android.content.Context;
+import android.net.Uri;
 
 import com.android.settings.network.telephony.Enhanced4gLteSliceHelper;
 import com.android.settings.wifi.calling.WifiCallingSliceHelper;
@@ -12,11 +13,23 @@
 
     boolean DEBUG = false;
 
-    SlicesIndexer getSliceIndexer(Context context);
-
     SliceDataConverter getSliceDataConverter(Context context);
 
     /**
+     * Starts a new UI session for the purpose of using Slices.
+     *
+     * A UI session is defined as an duration of time when user stays in a UI screen. Screen
+     * rotation does not break the continuation of session, going to a sub-page and coming out does
+     * not break the continuation either. Leaving the page and coming back breaks it.
+     */
+    void newUiSession();
+
+    /**
+     * Returns the token created in {@link #newUiSession}.
+     */
+    long getUiSessionToken();
+
+    /**
      * Asynchronous call to index the data used to build Slices.
      * If the data is already indexed, the data will not change.
      */
@@ -28,7 +41,14 @@
      */
     void indexSliceData(Context context);
 
-    CustomSliceManager getCustomSliceManager(Context context);
+
+    /**
+     * Return a {@link CustomSliceable} associated to the Uri.
+     * <p>
+     * Do not change this method signature to accommodate for a special-case sliceable - a context
+     * is the only thing that should be needed to create the object.
+     */
+    CustomSliceable getSliceableFromUri(Context context, Uri uri);
 
     /**
      * Gets new WifiCallingSliceHelper object
diff --git a/src/com/android/settings/slices/SlicesFeatureProviderImpl.java b/src/com/android/settings/slices/SlicesFeatureProviderImpl.java
index 508eb1c..297f2c1 100644
--- a/src/com/android/settings/slices/SlicesFeatureProviderImpl.java
+++ b/src/com/android/settings/slices/SlicesFeatureProviderImpl.java
@@ -17,27 +17,23 @@
 package com.android.settings.slices;
 
 import android.content.Context;
+import android.net.Uri;
+import android.os.SystemClock;
 
 import com.android.settings.network.telephony.Enhanced4gLteSliceHelper;
 import com.android.settings.wifi.calling.WifiCallingSliceHelper;
 import com.android.settingslib.utils.ThreadUtils;
 
+import java.util.Random;
+
 /**
  * Manages Slices in Settings.
  */
 public class SlicesFeatureProviderImpl implements SlicesFeatureProvider {
 
+    private long mUiSessionToken;
     private SlicesIndexer mSlicesIndexer;
     private SliceDataConverter mSliceDataConverter;
-    private CustomSliceManager mCustomSliceManager;
-
-    @Override
-    public SlicesIndexer getSliceIndexer(Context context) {
-        if (mSlicesIndexer == null) {
-            mSlicesIndexer = new SlicesIndexer(context.getApplicationContext());
-        }
-        return mSlicesIndexer;
-    }
 
     @Override
     public SliceDataConverter getSliceDataConverter(Context context) {
@@ -48,11 +44,13 @@
     }
 
     @Override
-    public CustomSliceManager getCustomSliceManager(Context context) {
-        if (mCustomSliceManager == null) {
-            mCustomSliceManager = new CustomSliceManager(context.getApplicationContext());
-        }
-        return mCustomSliceManager;
+    public void newUiSession() {
+        mUiSessionToken = SystemClock.elapsedRealtime();
+    }
+
+    @Override
+    public long getUiSessionToken() {
+        return mUiSessionToken;
     }
 
     @Override
@@ -76,4 +74,23 @@
     public Enhanced4gLteSliceHelper getNewEnhanced4gLteSliceHelper(Context context) {
         return new Enhanced4gLteSliceHelper(context);
     }
+
+    @Override
+    public CustomSliceable getSliceableFromUri(Context context, Uri uri) {
+        final Uri newUri = CustomSliceRegistry.removeParameterFromUri(uri);
+        final Class clazz = CustomSliceRegistry.getSliceClassByUri(newUri);
+        if (clazz == null) {
+            throw new IllegalArgumentException("No Slice found for uri: " + uri);
+        }
+
+        final CustomSliceable sliceable = CustomSliceable.createInstance(context, clazz);
+        return sliceable;
+    }
+
+    private SlicesIndexer getSliceIndexer(Context context) {
+        if (mSlicesIndexer == null) {
+            mSlicesIndexer = new SlicesIndexer(context.getApplicationContext());
+        }
+        return mSlicesIndexer;
+    }
 }
diff --git a/src/com/android/settings/sound/AudioSwitchPreferenceController.java b/src/com/android/settings/sound/AudioSwitchPreferenceController.java
index f77dfca..0da0f21 100644
--- a/src/com/android/settings/sound/AudioSwitchPreferenceController.java
+++ b/src/com/android/settings/sound/AudioSwitchPreferenceController.java
@@ -32,7 +32,6 @@
 import android.media.MediaRouter.Callback;
 import android.os.Handler;
 import android.os.Looper;
-import android.text.TextUtils;
 import android.util.FeatureFlagUtils;
 import android.util.Log;
 
@@ -40,7 +39,6 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
-import com.android.settings.R;
 import com.android.settings.bluetooth.Utils;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.core.FeatureFlags;
@@ -63,15 +61,11 @@
 /**
  * Abstract class for audio switcher controller to notify subclass
  * updating the current status of switcher entry. Subclasses must overwrite
- * {@link #setActiveBluetoothDevice(BluetoothDevice)} to set the
- * active device for corresponding profile.
  */
 public abstract class AudioSwitchPreferenceController extends BasePreferenceController
-        implements Preference.OnPreferenceChangeListener, BluetoothCallback,
-        LifecycleObserver, OnStart, OnStop {
+        implements BluetoothCallback, LifecycleObserver, OnStart, OnStop {
 
     private static final String TAG = "AudioSwitchPrefCtrl";
-    private static final int INVALID_INDEX = -1;
 
     protected final List<BluetoothDevice> mConnectedDevices;
     protected final AudioManager mAudioManager;
@@ -129,35 +123,6 @@
     }
 
     @Override
-    public boolean onPreferenceChange(Preference preference, Object newValue) {
-        final String address = (String) newValue;
-        if (!(preference instanceof ListPreference)) {
-            return false;
-        }
-
-        final ListPreference listPreference = (ListPreference) preference;
-        if (TextUtils.equals(address, mContext.getText(R.string.media_output_default_summary))) {
-            // Switch to default device which address is device name
-            mSelectedIndex = getDefaultDeviceIndex();
-            setActiveBluetoothDevice(null);
-            listPreference.setSummary(mContext.getText(R.string.media_output_default_summary));
-        } else {
-            // Switch to BT device which address is hardware address
-            final int connectedDeviceIndex = getConnectedDeviceIndex(address);
-            if (connectedDeviceIndex == INVALID_INDEX) {
-                return false;
-            }
-            final BluetoothDevice btDevice = mConnectedDevices.get(connectedDeviceIndex);
-            mSelectedIndex = connectedDeviceIndex;
-            setActiveBluetoothDevice(btDevice);
-            listPreference.setSummary(btDevice.getAliasName());
-        }
-        return true;
-    }
-
-    public abstract void setActiveBluetoothDevice(BluetoothDevice device);
-
-    @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
         mPreference = screen.findPreference(mPreferenceKey);
@@ -185,6 +150,12 @@
     }
 
     @Override
+    public void onBluetoothStateChanged(int bluetoothState) {
+        // To handle the case that Bluetooth on and no connected devices
+        updateState(mPreference);
+    }
+
+    @Override
     public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) {
         updateState(mPreference);
     }
@@ -236,21 +207,15 @@
     }
 
     /**
-     * get A2dp connected device
+     * get A2dp devices on all states
+     * (STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED,  STATE_DISCONNECTING)
      */
-    protected List<BluetoothDevice> getConnectedA2dpDevices() {
-        final List<BluetoothDevice> connectedDevices = new ArrayList<>();
+    protected List<BluetoothDevice> getConnectableA2dpDevices() {
         final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
         if (a2dpProfile == null) {
-            return connectedDevices;
+            return new ArrayList<>();
         }
-        final List<BluetoothDevice> devices = a2dpProfile.getConnectedDevices();
-        for (BluetoothDevice device : devices) {
-            if (device.isConnected()) {
-                connectedDevices.add(device);
-            }
-        }
-        return connectedDevices;
+        return a2dpProfile.getConnectableDevices();
     }
 
     /**
@@ -277,6 +242,31 @@
     }
 
     /**
+     * get hearing aid profile devices on all states
+     * (STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED,  STATE_DISCONNECTING)
+     * exclude other devices with same hiSyncId.
+     */
+    protected List<BluetoothDevice> getConnectableHearingAidDevices() {
+        final List<BluetoothDevice> connectedDevices = new ArrayList<>();
+        final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
+        if (hapProfile == null) {
+            return connectedDevices;
+        }
+        final List<Long> devicesHiSyncIds = new ArrayList<>();
+        final List<BluetoothDevice> devices = hapProfile.getConnectableDevices();
+        for (BluetoothDevice device : devices) {
+            final long hiSyncId = hapProfile.getHiSyncId(device);
+            // device with same hiSyncId should not be shown in the UI.
+            // So do not add it into connectedDevices.
+            if (!devicesHiSyncIds.contains(hiSyncId)) {
+                devicesHiSyncIds.add(hiSyncId);
+                connectedDevices.add(device);
+            }
+        }
+        return connectedDevices;
+    }
+
+    /**
      * Find active hearing aid device
      */
     protected BluetoothDevice findActiveHearingAidDevice() {
@@ -306,52 +296,6 @@
      */
     public abstract BluetoothDevice findActiveDevice();
 
-    int getDefaultDeviceIndex() {
-        // Default device is after all connected devices.
-        return mConnectedDevices.size();
-    }
-
-    void setupPreferenceEntries(CharSequence[] mediaOutputs, CharSequence[] mediaValues,
-            BluetoothDevice activeDevice) {
-        // default to current device
-        mSelectedIndex = getDefaultDeviceIndex();
-        // default device is after all connected devices.
-        mediaOutputs[mSelectedIndex] = mContext.getText(R.string.media_output_default_summary);
-        // use default device name as address
-        mediaValues[mSelectedIndex] = mContext.getText(R.string.media_output_default_summary);
-        for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
-            final BluetoothDevice btDevice = mConnectedDevices.get(i);
-            mediaOutputs[i] = btDevice.getAliasName();
-            mediaValues[i] = btDevice.getAddress();
-            if (btDevice.equals(activeDevice)) {
-                // select the active connected device.
-                mSelectedIndex = i;
-            }
-        }
-    }
-
-    void setPreference(CharSequence[] mediaOutputs, CharSequence[] mediaValues,
-            Preference preference) {
-        final ListPreference listPreference = (ListPreference) preference;
-        listPreference.setEntries(mediaOutputs);
-        listPreference.setEntryValues(mediaValues);
-        listPreference.setValueIndex(mSelectedIndex);
-        listPreference.setSummary(mediaOutputs[mSelectedIndex]);
-        mAudioSwitchPreferenceCallback.onPreferenceDataChanged(listPreference);
-    }
-
-    private int getConnectedDeviceIndex(String hardwareAddress) {
-        if (mConnectedDevices != null) {
-            for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
-                final BluetoothDevice btDevice = mConnectedDevices.get(i);
-                if (TextUtils.equals(btDevice.getAddress(), hardwareAddress)) {
-                    return i;
-                }
-            }
-        }
-        return INVALID_INDEX;
-    }
-
     private void register() {
         mLocalBluetoothManager.getEventManager().registerCallback(this);
         mAudioManager.registerAudioDeviceCallback(mAudioManagerAudioDeviceCallback, mHandler);
diff --git a/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java b/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java
index a02c0b2..9157477 100644
--- a/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java
+++ b/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java
@@ -20,7 +20,9 @@
 
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
+import android.text.TextUtils;
 
+import androidx.preference.ListPreference;
 import androidx.preference.Preference;
 
 import com.android.settings.R;
@@ -32,14 +34,56 @@
  * This class allows switching between HFP-connected & HAP-connected BT devices
  * while in on-call state.
  */
-public class HandsFreeProfileOutputPreferenceController extends
-        AudioSwitchPreferenceController {
+public class HandsFreeProfileOutputPreferenceController extends AudioSwitchPreferenceController
+        implements Preference.OnPreferenceChangeListener {
+
+    private static final int INVALID_INDEX = -1;
 
     public HandsFreeProfileOutputPreferenceController(Context context, String key) {
         super(context, key);
     }
 
     @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        final String address = (String) newValue;
+        if (!(preference instanceof ListPreference)) {
+            return false;
+        }
+
+        final CharSequence defaultSummary = mContext.getText(R.string.media_output_default_summary);
+        final ListPreference listPreference = (ListPreference) preference;
+        if (TextUtils.equals(address, defaultSummary)) {
+            // Switch to default device which address is device name
+            mSelectedIndex = getDefaultDeviceIndex();
+            setActiveBluetoothDevice(null);
+            listPreference.setSummary(defaultSummary);
+        } else {
+            // Switch to BT device which address is hardware address
+            final int connectedDeviceIndex = getConnectedDeviceIndex(address);
+            if (connectedDeviceIndex == INVALID_INDEX) {
+                return false;
+            }
+            final BluetoothDevice btDevice = mConnectedDevices.get(connectedDeviceIndex);
+            mSelectedIndex = connectedDeviceIndex;
+            setActiveBluetoothDevice(btDevice);
+            listPreference.setSummary(btDevice.getAliasName());
+        }
+        return true;
+    }
+
+    private int getConnectedDeviceIndex(String hardwareAddress) {
+        if (mConnectedDevices != null) {
+            for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
+                final BluetoothDevice btDevice = mConnectedDevices.get(i);
+                if (TextUtils.equals(btDevice.getAddress(), hardwareAddress)) {
+                    return i;
+                }
+            }
+        }
+        return INVALID_INDEX;
+    }
+
+    @Override
     public void updateState(Preference preference) {
         if (preference == null) {
             // In case UI is not ready.
@@ -83,7 +127,41 @@
         setPreference(mediaOutputs, mediaValues, preference);
     }
 
-    @Override
+    int getDefaultDeviceIndex() {
+        // Default device is after all connected devices.
+        return mConnectedDevices.size();
+    }
+
+    void setupPreferenceEntries(CharSequence[] mediaOutputs, CharSequence[] mediaValues,
+            BluetoothDevice activeDevice) {
+        // default to current device
+        mSelectedIndex = getDefaultDeviceIndex();
+        // default device is after all connected devices.
+        final CharSequence defaultSummary = mContext.getText(R.string.media_output_default_summary);
+        mediaOutputs[mSelectedIndex] = defaultSummary;
+        // use default device name as address
+        mediaValues[mSelectedIndex] = defaultSummary;
+        for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
+            final BluetoothDevice btDevice = mConnectedDevices.get(i);
+            mediaOutputs[i] = btDevice.getAliasName();
+            mediaValues[i] = btDevice.getAddress();
+            if (btDevice.equals(activeDevice)) {
+                // select the active connected device.
+                mSelectedIndex = i;
+            }
+        }
+    }
+
+    void setPreference(CharSequence[] mediaOutputs, CharSequence[] mediaValues,
+            Preference preference) {
+        final ListPreference listPreference = (ListPreference) preference;
+        listPreference.setEntries(mediaOutputs);
+        listPreference.setEntryValues(mediaValues);
+        listPreference.setValueIndex(mSelectedIndex);
+        listPreference.setSummary(mediaOutputs[mSelectedIndex]);
+        mAudioSwitchPreferenceCallback.onPreferenceDataChanged(listPreference);
+    }
+
     public void setActiveBluetoothDevice(BluetoothDevice device) {
         if (!Utils.isAudioModeOngoingCall(mContext)) {
             return;
diff --git a/src/com/android/settings/sound/MediaOutputPreferenceController.java b/src/com/android/settings/sound/MediaOutputPreferenceController.java
index ce476ad..47810f7 100644
--- a/src/com/android/settings/sound/MediaOutputPreferenceController.java
+++ b/src/com/android/settings/sound/MediaOutputPreferenceController.java
@@ -16,13 +16,14 @@
 
 package com.android.settings.sound;
 
-import static android.bluetooth.IBluetoothHearingAid.HI_SYNC_ID_INVALID;
 import static android.media.AudioManager.STREAM_MUSIC;
 import static android.media.AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
 
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
+import android.content.Intent;
 import android.media.AudioManager;
+import android.text.TextUtils;
 
 import androidx.preference.Preference;
 
@@ -30,12 +31,16 @@
 import com.android.settingslib.Utils;
 import com.android.settingslib.bluetooth.A2dpProfile;
 import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.media.MediaOutputSliceConstants;
+
+import java.util.List;
 
 /**
- * This class which allows switching between A2dp-connected & HAP-connected BT devices.
- * A few conditions will disable this switcher:
- * - No available BT device(s)
- * - Media stream captured by cast device
+ * This class allows launching MediaOutputSlice to switch output device.
+ * Preference would hide only when
+ * - Bluetooth = OFF
+ * - Bluetooth = ON and Connected Devices = 0 and Previously Connected = 0
+ * - Media stream captured by remote device
  * - During a call.
  */
 public class MediaOutputPreferenceController extends AudioSwitchPreferenceController {
@@ -66,40 +71,22 @@
             return;
         }
 
-        mConnectedDevices.clear();
-        // Otherwise, list all of the A2DP connected device and display the active device.
-        if (mAudioManager.getMode() == AudioManager.MODE_NORMAL) {
-            mConnectedDevices.addAll(getConnectedA2dpDevices());
-            mConnectedDevices.addAll(getConnectedHearingAidDevices());
+        boolean deviceConnectable = false;
+        BluetoothDevice activeDevice = null;
+        // Show preference if there is connected or previously connected device
+        // Find active device and set its name as the preference's summary
+        List<BluetoothDevice> connectableA2dpDevices = getConnectableA2dpDevices();
+        List<BluetoothDevice> connectableHADevices = getConnectableHearingAidDevices();
+        if (mAudioManager.getMode() == AudioManager.MODE_NORMAL
+                && ((connectableA2dpDevices != null && !connectableA2dpDevices.isEmpty())
+                || (connectableHADevices != null && !connectableHADevices.isEmpty()))) {
+            deviceConnectable = true;
+            activeDevice = findActiveDevice();
         }
-
-        final int numDevices = mConnectedDevices.size();
-        mPreference.setVisible((numDevices == 0) ? false : true);
-        CharSequence[] mediaOutputs = new CharSequence[numDevices + 1];
-        CharSequence[] mediaValues = new CharSequence[numDevices + 1];
-
-        // Setup devices entries, select active connected device
-        setupPreferenceEntries(mediaOutputs, mediaValues, findActiveDevice());
-
-        // Display connected devices, default device and show the active device
-        setPreference(mediaOutputs, mediaValues, preference);
-    }
-
-    @Override
-    public void setActiveBluetoothDevice(BluetoothDevice device) {
-        if (mAudioManager.getMode() != AudioManager.MODE_NORMAL) {
-            return;
-        }
-        final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
-        final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
-        if (hapProfile != null && a2dpProfile != null && device == null) {
-            hapProfile.setActiveDevice(null);
-            a2dpProfile.setActiveDevice(null);
-        } else if (hapProfile != null && hapProfile.getHiSyncId(device) != HI_SYNC_ID_INVALID) {
-            hapProfile.setActiveDevice(device);
-        } else if (a2dpProfile != null) {
-            a2dpProfile.setActiveDevice(device);
-        }
+        mPreference.setVisible(deviceConnectable);
+        mPreference.setSummary((activeDevice == null) ?
+                mContext.getText(R.string.media_output_default_summary) :
+                activeDevice.getAliasName());
     }
 
     @Override
@@ -112,4 +99,34 @@
         }
         return activeDevice;
     }
+
+    /**
+     * Find active hearing aid device
+     */
+    @Override
+    protected BluetoothDevice findActiveHearingAidDevice() {
+        final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
+
+        if (hearingAidProfile != null) {
+            List<BluetoothDevice> activeDevices = hearingAidProfile.getActiveDevices();
+            for (BluetoothDevice btDevice : activeDevices) {
+                if (btDevice != null) {
+                    return btDevice;
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+            final Intent intent = new Intent()
+                    .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT)
+                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mContext.startActivity(intent);
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/src/com/android/settings/vpn2/ConfigDialog.java b/src/com/android/settings/vpn2/ConfigDialog.java
index de2755e..07e957d 100644
--- a/src/com/android/settings/vpn2/ConfigDialog.java
+++ b/src/com/android/settings/vpn2/ConfigDialog.java
@@ -18,6 +18,8 @@
 
 import android.content.Context;
 import android.content.DialogInterface;
+import android.net.Proxy;
+import android.net.ProxyInfo;
 import android.os.Bundle;
 import android.os.SystemProperties;
 import android.security.Credentials;
@@ -67,6 +69,9 @@
     private TextView mSearchDomains;
     private TextView mDnsServers;
     private TextView mRoutes;
+    private Spinner mProxySettings;
+    private TextView mProxyHost;
+    private TextView mProxyPort;
     private CheckBox mMppe;
     private TextView mL2tpSecret;
     private TextView mIpsecIdentifier;
@@ -105,6 +110,9 @@
         mSearchDomains = (TextView) mView.findViewById(R.id.search_domains);
         mDnsServers = (TextView) mView.findViewById(R.id.dns_servers);
         mRoutes = (TextView) mView.findViewById(R.id.routes);
+        mProxySettings = (Spinner) mView.findViewById(R.id.vpn_proxy_settings);
+        mProxyHost = (TextView) mView.findViewById(R.id.vpn_proxy_host);
+        mProxyPort = (TextView) mView.findViewById(R.id.vpn_proxy_port);
         mMppe = (CheckBox) mView.findViewById(R.id.mppe);
         mL2tpSecret = (TextView) mView.findViewById(R.id.l2tp_secret);
         mIpsecIdentifier = (TextView) mView.findViewById(R.id.ipsec_identifier);
@@ -128,6 +136,11 @@
         mSearchDomains.setText(mProfile.searchDomains);
         mDnsServers.setText(mProfile.dnsServers);
         mRoutes.setText(mProfile.routes);
+        if (mProfile.proxy != null) {
+            mProxyHost.setText(mProfile.proxy.getHost());
+            int port = mProfile.proxy.getPort();
+            mProxyPort.setText(port == 0 ? "" : Integer.toString(port));
+        }
         mMppe.setChecked(mProfile.mppe);
         mL2tpSecret.setText(mProfile.l2tpSecret);
         mIpsecIdentifier.setText(mProfile.ipsecIdentifier);
@@ -153,6 +166,9 @@
         mPassword.addTextChangedListener(this);
         mDnsServers.addTextChangedListener(this);
         mRoutes.addTextChangedListener(this);
+        mProxySettings.setOnItemSelectedListener(this);
+        mProxyHost.addTextChangedListener(this);
+        mProxyPort.addTextChangedListener(this);
         mIpsecSecret.addTextChangedListener(this);
         mIpsecUserCert.setOnItemSelectedListener(this);
         mShowOptions.setOnClickListener(this);
@@ -175,7 +191,8 @@
 
             // Switch to advanced view immediately if any advanced options are on
             if (!mProfile.searchDomains.isEmpty() || !mProfile.dnsServers.isEmpty() ||
-                    !mProfile.routes.isEmpty()) {
+                    !mProfile.routes.isEmpty() || (mProfile.proxy != null &&
+                    (!mProfile.proxy.getHost().isEmpty() || mProfile.proxy.getPort() != 0))) {
                 showAdvancedOptions();
             }
 
@@ -246,6 +263,8 @@
     public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
         if (parent == mType) {
             changeType(position);
+        } else if (parent == mProxySettings) {
+            updateProxyFieldsVisibility(position);
         }
         updateUiControls();
     }
@@ -271,6 +290,7 @@
      * These include:
      * "Always-on VPN" checkbox
      * Reason for "Always-on VPN" being disabled, when necessary
+     * Proxy info if manually configured
      * "Save account information" checkbox
      * "Save" and "Connect" buttons
      */
@@ -298,6 +318,13 @@
             mAlwaysOnInvalidReason.setVisibility(View.VISIBLE);
         }
 
+        // Show proxy fields if any proxy field is filled.
+        if (mProfile.proxy != null && (!mProfile.proxy.getHost().isEmpty() ||
+                mProfile.proxy.getPort() != 0)) {
+            mProxySettings.setSelection(VpnProfile.PROXY_MANUAL);
+            updateProxyFieldsVisibility(VpnProfile.PROXY_MANUAL);
+        }
+
         // Save account information
         if (mAlwaysOnVpn.isChecked()) {
             mSaveLogin.setChecked(true);
@@ -311,6 +338,11 @@
         getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(validate(mEditing));
     }
 
+    private void updateProxyFieldsVisibility(int position) {
+        final int visible = position == VpnProfile.PROXY_MANUAL ? View.VISIBLE : View.GONE;
+        mView.findViewById(R.id.vpn_proxy_fields).setVisibility(visible);
+    }
+
     private void showAdvancedOptions() {
         mView.findViewById(R.id.options).setVisibility(View.VISIBLE);
         mShowOptions.setVisibility(View.GONE);
@@ -361,6 +393,11 @@
                 !validateAddresses(mRoutes.getText().toString(), true)) {
             return false;
         }
+
+        if (!validateProxy()) {
+            return false;
+        }
+
         switch (mType.getSelectedItemPosition()) {
             case VpnProfile.TYPE_PPTP:
             case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
@@ -435,6 +472,10 @@
         return mEditing;
     }
 
+    boolean hasProxy() {
+        return mProxySettings.getSelectedItemPosition() == VpnProfile.PROXY_MANUAL;
+    }
+
     VpnProfile getProfile() {
         // First, save common fields.
         VpnProfile profile = new VpnProfile(mProfile.key);
@@ -446,7 +487,16 @@
         profile.searchDomains = mSearchDomains.getText().toString().trim();
         profile.dnsServers = mDnsServers.getText().toString().trim();
         profile.routes = mRoutes.getText().toString().trim();
-
+        if (hasProxy()) {
+            String proxyHost = mProxyHost.getText().toString().trim();
+            String proxyPort = mProxyPort.getText().toString().trim();
+            // 0 is a last resort default, but the interface validates that the proxy port is
+            // present and non-zero.
+            int port = proxyPort.isEmpty() ? 0 : Integer.parseInt(proxyPort);
+            profile.proxy = new ProxyInfo(proxyHost, port, null);
+        } else {
+            profile.proxy = null;
+        }
         // Then, save type-specific fields.
         switch (profile.type) {
             case VpnProfile.TYPE_PPTP:
@@ -483,4 +533,15 @@
         profile.saveLogin = mSaveLogin.isChecked() || (mEditing && hasLogin);
         return profile;
     }
+
+    private boolean validateProxy() {
+        if (!hasProxy()) {
+            return true;
+        }
+
+        final String host = mProxyHost.getText().toString().trim();
+        final String port = mProxyPort.getText().toString().trim();
+        return Proxy.validate(host, port, "") == Proxy.PROXY_VALID;
+    }
+
 }
diff --git a/src/com/android/settings/widget/SingleTargetGearPreference.java b/src/com/android/settings/widget/SingleTargetGearPreference.java
index 48876fa..f6496ed 100644
--- a/src/com/android/settings/widget/SingleTargetGearPreference.java
+++ b/src/com/android/settings/widget/SingleTargetGearPreference.java
@@ -18,9 +18,10 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
+import android.view.View;
 
-import androidx.core.content.res.TypedArrayUtils;
 import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
 
 import com.android.settings.R;
 
@@ -28,23 +29,38 @@
  * A preference with single target and a gear icon on the side.
  */
 public class SingleTargetGearPreference extends Preference {
-
-    public SingleTargetGearPreference(Context context, AttributeSet attrs,
-            int defStyleAttr, int defStyleRes) {
+    public SingleTargetGearPreference(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        setWidgetLayoutResource(R.layout.preference_widget_gear_no_bg);
+        init();
     }
 
     public SingleTargetGearPreference(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0 /* defStyleRes */);
+        super(context, attrs, defStyleAttr);
+        init();
     }
 
     public SingleTargetGearPreference(Context context, AttributeSet attrs) {
-        this(context, attrs, TypedArrayUtils.getAttr(context, R.attr.preferenceStyle,
-                android.R.attr.preferenceStyle));
+        super(context, attrs);
+        init();
     }
 
     public SingleTargetGearPreference(Context context) {
-        this(context, null /* attrs */);
+        super(context);
+        init();
     }
-}
\ No newline at end of file
+
+    private void init() {
+        setLayoutResource(R.layout.preference_single_target);
+        setWidgetLayoutResource(R.layout.preference_widget_gear_optional_background);
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+        final View divider = holder.findViewById(com.android.settingslib.R.id.two_target_divider);
+        if (divider != null) {
+            divider.setVisibility(View.INVISIBLE);
+        }
+    }
+}
diff --git a/src/com/android/settings/wifi/ButtonPreference.java b/src/com/android/settings/wifi/ButtonPreference.java
index 9a0abf6..5169d7a 100644
--- a/src/com/android/settings/wifi/ButtonPreference.java
+++ b/src/com/android/settings/wifi/ButtonPreference.java
@@ -49,6 +49,7 @@
     private ImageButton mImageButton;
     private Drawable mButtonIcon;
     private View.OnClickListener mClickListener;
+    private String mContentDescription;
 
     // Used for dummy pref.
     public ButtonPreference(Context context, AttributeSet attrs) {
@@ -57,6 +58,7 @@
         mImageButton = null;
         mButtonIcon = null;
         mClickListener = null;
+        mContentDescription = null;
     }
 
     public ButtonPreference(Context context) {
@@ -83,6 +85,7 @@
         if (mImageButton != null) {
             mImageButton.setImageDrawable(mButtonIcon);
             mImageButton.setOnClickListener(mClickListener);
+            mImageButton.setContentDescription(mContentDescription);
         }
         setButtonVisibility();
     }
@@ -96,9 +99,9 @@
     /**
      * Sets the drawable to be displayed in button.
      */
-    public ButtonPreference setButtonIcon(@DrawableRes int iconResId) {
+    public void setButtonIcon(@DrawableRes int iconResId) {
         if (iconResId == 0) {
-            return this;
+            return;
         }
 
         try {
@@ -107,17 +110,26 @@
         } catch (Resources.NotFoundException exception) {
             Log.e(TAG, "Resource does not exist: " + iconResId);
         }
-        return this;
     }
 
     /**
      * Register a callback to be invoked when button is clicked.
      */
-    public ButtonPreference setButtonOnClickListener(View.OnClickListener listener) {
+    public void setButtonOnClickListener(View.OnClickListener listener) {
         if (listener != mClickListener) {
             mClickListener = listener;
             notifyChanged();
         }
-        return this;
+    }
+
+    /**
+     * A content description briefly describes the button and is primarily used for accessibility
+     * support to determine how a button should be presented to the user.
+     */
+    public void setButtonContentDescription(String contentDescription) {
+        if (contentDescription != mContentDescription) {
+            mContentDescription = contentDescription;
+            notifyChanged();
+        }
     }
 }
diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java
index 916d330..0adbd8d 100644
--- a/src/com/android/settings/wifi/WifiConfigController.java
+++ b/src/com/android/settings/wifi/WifiConfigController.java
@@ -249,7 +249,7 @@
         mHiddenSettingsSpinner = mView.findViewById(R.id.hidden_settings);
         mPrivacySettingsSpinner = mView.findViewById(R.id.privacy_settings);
         if (mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_wifi_p2p_mac_randomization_supported)) {
+                com.android.internal.R.bool.config_wifi_connected_mac_randomization_supported)) {
             View privacySettingsLayout = mView.findViewById(R.id.privacy_settings_fields);
             privacySettingsLayout.setVisibility(View.VISIBLE);
         }
@@ -265,11 +265,7 @@
             configureSecuritySpinner();
             mConfigUi.setSubmitButton(res.getString(R.string.wifi_save));
         } else {
-            if (!mAccessPoint.isPasspointConfig()) {
-                mConfigUi.setTitle(mAccessPoint.getSsid());
-            } else {
-                mConfigUi.setTitle(mAccessPoint.getConfigName());
-            }
+            mConfigUi.setTitle(mAccessPoint.getTitle());
 
             ViewGroup group = (ViewGroup) mView.findViewById(R.id.info);
 
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index c00fe24..a8fc34d 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -67,6 +67,7 @@
 import com.android.settings.widget.SwitchBarController;
 import com.android.settings.wifi.details.WifiNetworkDetailsFragment;
 import com.android.settings.wifi.dpp.WifiDppUtils;
+import com.android.settings.wifi.savedaccesspoints.SavedAccessPointsWifiSettings;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.settingslib.search.SearchIndexable;
@@ -247,6 +248,7 @@
             getContext().startActivity(
                     WifiDppUtils.getEnrolleeQrCodeScannerIntent(/* ssid */ null));
         });
+        mAddPreference.setButtonContentDescription(getString(R.string.wifi_dpp_scan_qr_code));
         mStatusMessagePreference = (LinkablePreference) findPreference(PREF_KEY_STATUS_MESSAGE);
 
         mUserBadgeCache = new AccessPointPreference.UserBadgeCache(getPackageManager());
@@ -483,7 +485,7 @@
         if (preference instanceof LongPressAccessPointPreference) {
             mSelectedAccessPoint =
                     ((LongPressAccessPointPreference) preference).getAccessPoint();
-            menu.setHeaderTitle(mSelectedAccessPoint.getSsid());
+            menu.setHeaderTitle(mSelectedAccessPoint.getTitle());
             if (mSelectedAccessPoint.isConnectable()) {
                 menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect);
             }
@@ -967,8 +969,13 @@
     }
 
     private void launchNetworkDetailsFragment(ConnectedAccessPointPreference pref) {
+        final AccessPoint accessPoint = pref.getAccessPoint();
+        final Context context = getContext();
+        final CharSequence title = SavedAccessPointsWifiSettings.usingDetailsFragment(context) ?
+                accessPoint.getTitle() : context.getText(R.string.pref_title_network_details);
+
         new SubSettingLauncher(getContext())
-                .setTitleRes(R.string.pref_title_network_details)
+                .setTitleText(title)
                 .setDestination(WifiNetworkDetailsFragment.class.getName())
                 .setArguments(pref.getExtras())
                 .setSourceMetricsCategory(getMetricsCategory())
diff --git a/src/com/android/settings/wifi/calling/DisclaimerItem.java b/src/com/android/settings/wifi/calling/DisclaimerItem.java
new file mode 100644
index 0000000..6fd8b70
--- /dev/null
+++ b/src/com/android/settings/wifi/calling/DisclaimerItem.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.calling;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Interface to control disclaimer item from {@link WifiCallingDisclaimerFragment}.
+ */
+@VisibleForTesting
+public abstract class DisclaimerItem {
+    private static final String SHARED_PREFERENCES_NAME = "wfc_disclaimer_prefs";
+
+    protected final Context mContext;
+    protected final int mSubId;
+    private final CarrierConfigManager mCarrierConfigManager;
+
+    DisclaimerItem(Context context, int subId) {
+        mContext = context;
+        mSubId = subId;
+        mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
+    }
+
+    /**
+     * Called by the {@link WifiCallingDisclaimerFragment} when a user has clicked the agree button.
+     */
+    void onAgreed() {
+        setBooleanSharedPrefs(getPrefKey(), true);
+    }
+
+    /**
+     * Checks whether the disclaimer item need to be displayed or not.
+     *
+     * @return Returns {@code true} if disclaimer item need to be displayed,
+     * {@code false} if not displayed.
+     */
+    boolean shouldShow() {
+        if (getBooleanSharedPrefs(getPrefKey(), false)) {
+            logd("shouldShow: false due to a user has already agreed.");
+            return false;
+        }
+        logd("shouldShow: true");
+        return true;
+    }
+
+    /**
+     * Gets the configuration values for a particular sub id.
+     *
+     * @return The {@link PersistableBundle} instance containing the config value for a
+     * particular phone id, or default values.
+     */
+    protected PersistableBundle getCarrierConfig() {
+        PersistableBundle config = mCarrierConfigManager.getConfigForSubId(mSubId);
+        if (config != null) {
+            return config;
+        }
+        // Return static default defined in CarrierConfigManager.
+        return CarrierConfigManager.getDefaultConfig();
+    }
+
+    protected void logd(String msg) {
+        Log.d(getName(), "[" + mSubId +  "] " + msg);
+    }
+
+    /**
+     * Gets a title id for disclaimer item.
+     *
+     * @return Title id for disclaimer item.
+     */
+    protected abstract int getTitleId();
+
+    /**
+     * Gets a message id for disclaimer item.
+     *
+     * @return Message id for disclaimer item.
+     */
+    protected abstract int getMessageId();
+
+    /**
+     * Gets a name of disclaimer item.
+     *
+     * @return Name of disclaimer item.
+     */
+    protected abstract String getName();
+
+    /**
+     * Gets a preference key to keep user's consent.
+     *
+     * @return Preference key to keep user's consent.
+     */
+    protected abstract String getPrefKey();
+
+    /**
+     * Gets the boolean value from shared preferences.
+     *
+     * @param key The key for the preference item.
+     * @param defValue Value to return if this preference does not exist.
+     * @return The boolean value of corresponding key, or defValue.
+     */
+    private boolean getBooleanSharedPrefs(String key, boolean defValue) {
+        SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
+                Context.MODE_PRIVATE);
+        return prefs.getBoolean(key + mSubId, defValue);
+    }
+
+    /**
+     * Sets the boolean value to shared preferences.
+     *
+     * @param key The key for the preference item.
+     * @param value The value to be set for shared preferences.
+     */
+    private void setBooleanSharedPrefs(String key, boolean value) {
+        SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
+                Context.MODE_PRIVATE);
+        prefs.edit().putBoolean(key + mSubId, value).apply();
+    }
+}
diff --git a/src/com/android/settings/wifi/calling/DisclaimerItemFactory.java b/src/com/android/settings/wifi/calling/DisclaimerItemFactory.java
new file mode 100644
index 0000000..6d8dc8f
--- /dev/null
+++ b/src/com/android/settings/wifi/calling/DisclaimerItemFactory.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.wifi.calling;
+
+import android.content.Context;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Factory class to create disclaimer items list.
+ */
+@VisibleForTesting
+public final class DisclaimerItemFactory {
+
+    /**
+     * Creates disclaimer items list.
+     *
+     * @param context The application context
+     * @param subId The subscription id.
+     * @return The {@link DisclaimerItem} list instance, if there are no items, return empty list.
+     */
+    public static List<DisclaimerItem> create(Context context, int subId) {
+        List<DisclaimerItem> itemList = getDisclaimerItemList(context, subId);
+        Iterator itr = itemList.iterator();
+        while (itr.hasNext()) {
+            DisclaimerItem item = (DisclaimerItem) itr.next();
+            if (!item.shouldShow()) {
+                itr.remove();
+            }
+        }
+        return itemList;
+    }
+
+    private static List<DisclaimerItem> getDisclaimerItemList(Context context, int subId) {
+        List<DisclaimerItem> itemList = new ArrayList<DisclaimerItem>();
+
+        return itemList;
+    }
+}
diff --git a/src/com/android/settings/wifi/calling/DisclaimerItemListAdapter.java b/src/com/android/settings/wifi/calling/DisclaimerItemListAdapter.java
new file mode 100644
index 0000000..4b5d19c
--- /dev/null
+++ b/src/com/android/settings/wifi/calling/DisclaimerItemListAdapter.java
@@ -0,0 +1,78 @@
+/*
+ * 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.calling;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+
+import java.util.List;
+
+/**
+ * Adapter for disclaimer items list.
+ */
+public class DisclaimerItemListAdapter extends
+        RecyclerView.Adapter<DisclaimerItemListAdapter.DisclaimerItemViewHolder> {
+
+    private List<DisclaimerItem> mDisclaimerItemList;
+
+    public DisclaimerItemListAdapter(List<DisclaimerItem> list) {
+        mDisclaimerItemList = list;
+    }
+
+    @Override
+    public DisclaimerItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        LayoutInflater inflater = (LayoutInflater) parent.getContext().getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+        View view = inflater.inflate(R.layout.wfc_simple_disclaimer_item, null, false);
+        return new DisclaimerItemViewHolder(view);
+    }
+
+    @Override
+    public void onBindViewHolder(DisclaimerItemViewHolder holder, int position) {
+        holder.titleView.setText(mDisclaimerItemList.get(position).getTitleId());
+        holder.descriptionView.setText(mDisclaimerItemList.get(position).getMessageId());
+    }
+
+    @Override
+    public int getItemCount() {
+        return mDisclaimerItemList.size();
+    }
+
+    public static class DisclaimerItemViewHolder extends RecyclerView.ViewHolder {
+        @VisibleForTesting
+        static final int ID_DISCLAIMER_ITEM_TITLE = R.id.disclaimer_title;
+        @VisibleForTesting
+        static final int ID_DISCLAIMER_ITEM_DESCRIPTION = R.id.disclaimer_desc;
+
+        public final TextView titleView;
+        public final TextView descriptionView;
+
+        public DisclaimerItemViewHolder(View itemView) {
+            super(itemView);
+            titleView = itemView.findViewById(ID_DISCLAIMER_ITEM_TITLE);
+            descriptionView = itemView.findViewById(ID_DISCLAIMER_ITEM_DESCRIPTION);
+        }
+    }
+}
diff --git a/src/com/android/settings/wifi/calling/ListWithEntrySummaryPreference.java b/src/com/android/settings/wifi/calling/ListWithEntrySummaryPreference.java
new file mode 100644
index 0000000..a44fcbe
--- /dev/null
+++ b/src/com/android/settings/wifi/calling/ListWithEntrySummaryPreference.java
@@ -0,0 +1,203 @@
+/*
+ * 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.calling;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.TypedArray;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+import android.widget.RadioButton;
+import android.widget.TextView;
+import androidx.appcompat.app.AlertDialog.Builder;
+import com.android.settings.CustomListPreference;
+import com.android.settings.R;
+
+/**
+ * ListPreference contain the entry summary.
+ */
+public class ListWithEntrySummaryPreference extends CustomListPreference {
+    private static final String LOG_TAG = "ListWithEntrySummaryPreference";
+    private final Context mContext;
+    private CharSequence[] mSummaries;
+
+    /**
+     * ListWithEntrySummaryPreference constructor.
+     *
+     * @param context The context of view.
+     * @param attrs The attributes of the XML tag that is inflating the linear layout.
+     */
+    public ListWithEntrySummaryPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mContext = context;
+
+        TypedArray array = context.obtainStyledAttributes(attrs,
+                R.styleable.ListWithEntrySummaryPreference, 0, 0);
+        mSummaries = array.getTextArray(R.styleable.ListWithEntrySummaryPreference_entrySummaries);
+        array.recycle();
+    }
+
+    /**
+     * Sets the summaries of mode items to be shown in the mode select dialog.
+     *
+     * @param summariesResId The summaries of mode items.
+     */
+    public void setEntrySummaries(int summariesResId) {
+        mSummaries = getContext().getResources().getTextArray(summariesResId);
+    }
+
+    /**
+     * Sets the summaries of mode items to be shown in the mode select dialog.
+     *
+     * @param summaries The summaries of mode items.
+     */
+    public void setEntrySummaries(CharSequence[] summaries) {
+        mSummaries = summaries;
+    }
+
+    private CharSequence getEntrySummary(int index) {
+        if (mSummaries == null) {
+            Log.w(LOG_TAG, "getEntrySummary : mSummaries is null");
+            return "";
+        }
+        return mSummaries[index];
+    }
+
+    @Override
+    protected void onPrepareDialogBuilder(Builder builder,
+            DialogInterface.OnClickListener listener) {
+        ListAdapter la = (ListAdapter) new SelectorAdapter(mContext,
+                R.xml.single_choice_list_item_2, this);
+        builder.setSingleChoiceItems(la, findIndexOfValue(getValue()), listener);
+        super.onPrepareDialogBuilder(builder, listener);
+    }
+
+    private static class SelectorAdapter extends ArrayAdapter<CharSequence> {
+        private final Context mContext;
+        private ListWithEntrySummaryPreference mSelector;
+
+        /**
+         * SelectorAdapter constructor.
+         *
+         * @param context The current context.
+         * @param rowResourceId The resource id of the XML tag that is inflating the linear layout.
+         * @param listPreference The instance of ListWithEntrySummaryPreference.
+         */
+        public SelectorAdapter(Context context, int rowResourceId,
+                ListWithEntrySummaryPreference listPreference) {
+            super(context, rowResourceId, listPreference.getEntryValues());
+            mContext = context;
+            mSelector = listPreference;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            LayoutInflater inflater = LayoutInflater.from(mContext);
+            View row = inflater.inflate(R.xml.single_choice_list_item_2, parent, false);
+
+            TextView title = (TextView) row.findViewById(R.id.title);
+            title.setText(mSelector.getEntries()[position]);
+
+            TextView summary = (TextView) row.findViewById(R.id.summary);
+            summary.setText(mSelector.getEntrySummary(position));
+
+            RadioButton rb = (RadioButton) row.findViewById(R.id.radio);
+            if (position == mSelector.findIndexOfValue(mSelector.getValue())) {
+                rb.setChecked(true);
+            }
+
+            return row;
+        }
+    }
+
+    @Override
+    protected Parcelable onSaveInstanceState() {
+        final Parcelable superState = super.onSaveInstanceState();
+
+        final SavedState myState = new SavedState(superState);
+        myState.mEntries = getEntries();
+        myState.mEntryValues = getEntryValues();
+        myState.mSummaries = mSummaries;
+        return myState;
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Parcelable state) {
+        if (state == null || !state.getClass().equals(SavedState.class)) {
+            // Didn't save state for us in onSaveInstanceState
+            super.onRestoreInstanceState(state);
+            return;
+        }
+
+        SavedState myState = (SavedState) state;
+        super.onRestoreInstanceState(myState.getSuperState());
+        setEntries(myState.mEntries);
+        setEntryValues(myState.mEntryValues);
+        mSummaries = myState.mSummaries;
+    }
+
+    /**
+     *  We save entries, entryValues and summaries into bundle.
+     *  At onCreate of fragment, dialog will be restored if it was open. In this case,
+     *  we need to restore entries, entryValues and summaries. Without those information,
+     *  crash when entering multi window during wfc modes dialog shown.
+     */
+    private static class SavedState extends BaseSavedState {
+        private CharSequence[] mEntries;
+        private CharSequence[] mEntryValues;
+        private CharSequence[] mSummaries;
+
+        public SavedState(Parcel source) {
+            super(source);
+            mEntries = source.readCharSequenceArray();
+            mEntryValues = source.readCharSequenceArray();
+            mSummaries = source.readCharSequenceArray();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeCharSequenceArray(mEntries);
+            dest.writeCharSequenceArray(mEntryValues);
+            dest.writeCharSequenceArray(mSummaries);
+        }
+
+        public SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR =
+                new Parcelable.Creator<SavedState>() {
+            @Override
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            @Override
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
+}
diff --git a/src/com/android/settings/wifi/calling/WifiCallingDisclaimerFragment.java b/src/com/android/settings/wifi/calling/WifiCallingDisclaimerFragment.java
new file mode 100644
index 0000000..7763226
--- /dev/null
+++ b/src/com/android/settings/wifi/calling/WifiCallingDisclaimerFragment.java
@@ -0,0 +1,148 @@
+/*
+ * 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.calling;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.telephony.SubscriptionManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+import androidx.recyclerview.widget.DividerItemDecoration;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.core.InstrumentedFragment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Fragment for displaying disclaimers for WFC.
+ */
+public class WifiCallingDisclaimerFragment extends InstrumentedFragment
+        implements View.OnClickListener {
+    private static final String TAG = "WifiCallingDisclaimerFragment";
+
+    private static final String STATE_IS_SCROLL_TO_BOTTOM = "state_is_scroll_to_bottom";
+
+    private List<DisclaimerItem> mDisclaimerItemList = new ArrayList<DisclaimerItem>();
+    private Button mAgreeButton;
+    private Button mDisagreeButton;
+    private boolean mScrollToBottom;
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsEvent.WIFI_CALLING;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final Bundle args = getArguments();
+        final int subId = (args != null) ? args.getInt(WifiCallingSettingsForSub.EXTRA_SUB_ID)
+                : SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+
+        mDisclaimerItemList = DisclaimerItemFactory.create(getActivity(), subId);
+        if (mDisclaimerItemList.isEmpty()) {
+            finish(Activity.RESULT_OK);
+            return;
+        }
+
+        if (savedInstanceState != null) {
+            mScrollToBottom = savedInstanceState.getBoolean(
+                    STATE_IS_SCROLL_TO_BOTTOM, mScrollToBottom);
+        }
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+
+        final View view = inflater.inflate(R.layout.wfc_disclaimer_fragment, container, false);
+
+        mAgreeButton = view.findViewById(R.id.agree_button);
+        mAgreeButton.setOnClickListener(this);
+        mDisagreeButton = view.findViewById(R.id.disagree_button);
+        mDisagreeButton.setOnClickListener(this);
+
+        final RecyclerView recyclerView = (RecyclerView) view.findViewById(
+                R.id.disclaimer_item_list);
+        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
+        recyclerView.setAdapter(new DisclaimerItemListAdapter(mDisclaimerItemList));
+
+        RecyclerView.ItemDecoration itemDecoration =
+                new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL);
+        recyclerView.addItemDecoration(itemDecoration);
+
+        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+            @Override
+            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+                super.onScrolled(recyclerView, dx, dy);
+                if (!recyclerView.canScrollVertically(1 /* scrolling down */)) {
+                    mScrollToBottom = true;
+                    updateButtonState();
+                    recyclerView.removeOnScrollListener(this);
+                }
+            }
+        });
+
+        return view;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        updateButtonState();
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putBoolean(STATE_IS_SCROLL_TO_BOTTOM, mScrollToBottom);
+    }
+
+    private void updateButtonState() {
+        mAgreeButton.setEnabled(mScrollToBottom);
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v == mAgreeButton) {
+            for (DisclaimerItem item : mDisclaimerItemList) {
+                item.onAgreed();
+            }
+            finish(Activity.RESULT_OK);
+        } else if (v == mDisagreeButton) {
+            finish(Activity.RESULT_CANCELED);
+        }
+    }
+
+    @VisibleForTesting
+    void finish(int result) {
+        Activity activity = getActivity();
+        activity.setResult(result, null);
+        activity.finish();
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
index 6fe1795..525b59b 100644
--- a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
+++ b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
@@ -40,7 +40,6 @@
 import android.widget.TextView;
 
 import androidx.appcompat.app.AlertDialog;
-import androidx.preference.ListPreference;
 import androidx.preference.Preference;
 import androidx.preference.Preference.OnPreferenceClickListener;
 import androidx.preference.PreferenceScreen;
@@ -54,6 +53,7 @@
 import com.android.settings.SettingsActivity;
 import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.Utils;
+import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.widget.SwitchBar;
 
 /**
@@ -70,9 +70,13 @@
     private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode";
     private static final String PREFERENCE_EMERGENCY_ADDRESS = "emergency_address_key";
 
-    private static final int REQUEST_CHECK_WFC_EMERGENCY_ADDRESS = 1;
+    @VisibleForTesting
+    static final int REQUEST_CHECK_WFC_EMERGENCY_ADDRESS = 1;
+    @VisibleForTesting
+    static final int REQUEST_CHECK_WFC_DISCLAIMER = 2;
 
     public static final String EXTRA_LAUNCH_CARRIER_APP = "EXTRA_LAUNCH_CARRIER_APP";
+    public static final String EXTRA_SUB_ID = "EXTRA_SUB_ID";
 
     protected static final String FRAGMENT_BUNDLE_SUBID = "subId";
 
@@ -82,8 +86,8 @@
     //UI objects
     private SwitchBar mSwitchBar;
     private Switch mSwitch;
-    private ListPreference mButtonWfcMode;
-    private ListPreference mButtonWfcRoamingMode;
+    private ListWithEntrySummaryPreference mButtonWfcMode;
+    private ListWithEntrySummaryPreference mButtonWfcRoamingMode;
     private Preference mUpdateAddress;
     private TextView mEmptyView;
 
@@ -141,20 +145,17 @@
         }
     };
 
+    /*
+     * Launch carrier emergency address managemnent activity
+     */
     private final OnPreferenceClickListener mUpdateAddressListener =
-            new OnPreferenceClickListener() {
-                /*
-                 * Launch carrier emergency address managemnent activity
-                 */
-                @Override
-                public boolean onPreferenceClick(Preference preference) {
-                    Intent carrierAppIntent = getCarrierActivityIntent();
-                    if (carrierAppIntent != null) {
-                        carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_UPDATE);
-                        startActivity(carrierAppIntent);
-                    }
-                    return true;
+            preference -> {
+                Intent carrierAppIntent = getCarrierActivityIntent();
+                if (carrierAppIntent != null) {
+                    carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_UPDATE);
+                    startActivity(carrierAppIntent);
                 }
+                return true;
             };
 
     private final ProvisioningManager.Callback mProvisioningCallback =
@@ -174,11 +175,9 @@
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
 
-        final SettingsActivity activity = (SettingsActivity) getActivity();
-
         mEmptyView = getView().findViewById(android.R.id.empty);
         setEmptyView(mEmptyView);
-        final Resources res = SubscriptionManager.getResourcesForSubId(getContext(), mSubId);
+        final Resources res = getResourcesForSubId();
         String emptyViewText = res.getString(R.string.wifi_calling_off_explanation,
                 res.getString(R.string.wifi_calling_off_explanation_2));
         mEmptyView.setText(emptyViewText);
@@ -265,13 +264,13 @@
         mTelephonyManager = ((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE))
                 .createForSubscriptionId(mSubId);
 
-        mButtonWfcMode = (ListPreference) findPreference(BUTTON_WFC_MODE);
+        mButtonWfcMode = findPreference(BUTTON_WFC_MODE);
         mButtonWfcMode.setOnPreferenceChangeListener(this);
 
-        mButtonWfcRoamingMode = (ListPreference) findPreference(BUTTON_WFC_ROAMING_MODE);
+        mButtonWfcRoamingMode =  findPreference(BUTTON_WFC_ROAMING_MODE);
         mButtonWfcRoamingMode.setOnPreferenceChangeListener(this);
 
-        mUpdateAddress = (Preference) findPreference(PREFERENCE_EMERGENCY_ADDRESS);
+        mUpdateAddress = findPreference(PREFERENCE_EMERGENCY_ADDRESS);
         mUpdateAddress.setOnPreferenceClickListener(mUpdateAddressListener);
 
         mIntentFilter = new IntentFilter();
@@ -329,10 +328,14 @@
         if (!isWifiOnlySupported) {
             mButtonWfcMode.setEntries(R.array.wifi_calling_mode_choices_without_wifi_only);
             mButtonWfcMode.setEntryValues(R.array.wifi_calling_mode_values_without_wifi_only);
+            mButtonWfcMode.setEntrySummaries(R.array.wifi_calling_mode_summaries_without_wifi_only);
+
             mButtonWfcRoamingMode.setEntries(
                     R.array.wifi_calling_mode_choices_v2_without_wifi_only);
             mButtonWfcRoamingMode.setEntryValues(
                     R.array.wifi_calling_mode_values_without_wifi_only);
+            mButtonWfcRoamingMode.setEntrySummaries(
+                    R.array.wifi_calling_mode_summaries_without_wifi_only);
         }
 
 
@@ -418,14 +421,17 @@
             return;
         }
 
-        // Call address management activity before turning on WFC
-        Intent carrierAppIntent = getCarrierActivityIntent();
-        if (carrierAppIntent != null) {
-            carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_ACTIVATE);
-            startActivityForResult(carrierAppIntent, REQUEST_CHECK_WFC_EMERGENCY_ADDRESS);
-        } else {
-            updateWfcMode(true);
-        }
+        // Launch disclaimer fragment before turning on WFC
+        final Context context = getActivity();
+        final Bundle args = new Bundle();
+        args.putInt(EXTRA_SUB_ID, mSubId);
+        new SubSettingLauncher(context)
+                .setDestination(WifiCallingDisclaimerFragment.class.getName())
+                .setArguments(args)
+                .setTitleRes(R.string.wifi_calling_settings_title)
+                .setSourceMetricsCategory(getMetricsCategory())
+                .setResultListener(this, REQUEST_CHECK_WFC_DISCLAIMER)
+                .launch();
     }
 
     /*
@@ -478,12 +484,30 @@
 
         final Context context = getActivity();
 
-        if (requestCode == REQUEST_CHECK_WFC_EMERGENCY_ADDRESS) {
-            Log.d(TAG, "WFC emergency address activity result = " + resultCode);
+        Log.d(TAG, "WFC activity request = " + requestCode + " result = " + resultCode);
 
-            if (resultCode == Activity.RESULT_OK) {
-                updateWfcMode(true);
-            }
+        switch (requestCode) {
+            case REQUEST_CHECK_WFC_EMERGENCY_ADDRESS:
+                if (resultCode == Activity.RESULT_OK) {
+                    updateWfcMode(true);
+                }
+                break;
+            case REQUEST_CHECK_WFC_DISCLAIMER:
+                if (resultCode == Activity.RESULT_OK) {
+                    // Call address management activity before turning on WFC
+                    Intent carrierAppIntent = getCarrierActivityIntent();
+                    if (carrierAppIntent != null) {
+                        carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_ACTIVATE);
+                        startActivityForResult(carrierAppIntent,
+                                REQUEST_CHECK_WFC_EMERGENCY_ADDRESS);
+                    } else {
+                        updateWfcMode(true);
+                    }
+                }
+                break;
+            default:
+                Log.e(TAG, "Unexpected request: " + requestCode);
+                break;
         }
     }
 
@@ -570,4 +594,9 @@
         }
         return resId;
     }
+
+    @VisibleForTesting
+    Resources getResourcesForSubId() {
+        return SubscriptionManager.getResourcesForSubId(getContext(), mSubId, false);
+    }
 }
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
index 01673e3..89565df 100644
--- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -21,16 +21,12 @@
 
 import android.app.Activity;
 import android.app.AlertDialog;
-import android.app.KeyguardManager;
 import android.app.settings.SettingsEnums;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.graphics.drawable.Drawable;
-import android.hardware.biometrics.BiometricPrompt;
-import android.os.CancellationSignal;
-import android.os.Looper;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.LinkAddress;
@@ -46,6 +42,7 @@
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.text.TextUtils;
+import android.util.FeatureFlagUtils;
 import android.util.Log;
 import android.widget.ImageView;
 import android.widget.Toast;
@@ -55,12 +52,14 @@
 import androidx.fragment.app.Fragment;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceFragmentCompat;
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.R;
 import com.android.settings.Utils;
 import com.android.settings.core.FeatureFlags;
 import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.datausage.WifiDataUsageSummaryPreferenceController;
 import com.android.settings.development.featureflags.FeatureFlagPersistent;
 import com.android.settings.widget.EntityHeaderController;
 import com.android.settings.wifi.WifiDialog;
@@ -154,6 +153,9 @@
     private Preference mDnsPref;
     private PreferenceCategory mIpv6Category;
     private Preference mIpv6AddressPref;
+    private Lifecycle mLifecycle;
+    Preference mDataUsageSummaryPref;
+    WifiDataUsageSummaryPreferenceController mSummaryHeaderController;
 
     private final IconInjector mIconInjector;
     private final IntentFilter mFilter;
@@ -266,6 +268,7 @@
         mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
         mFilter.addAction(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
 
+        mLifecycle = lifecycle;
         lifecycle.addObserver(this);
     }
 
@@ -317,6 +320,17 @@
 
     private void setupEntityHeader(PreferenceScreen screen) {
         LayoutPreference headerPref = screen.findPreference(KEY_HEADER);
+
+        if (usingDataUsageHeader(mContext)) {
+            headerPref.setVisible(false);
+            mDataUsageSummaryPref = screen.findPreference("status_header");
+            mDataUsageSummaryPref.setVisible(true);
+            mSummaryHeaderController =
+                new WifiDataUsageSummaryPreferenceController(mFragment.getActivity(),
+                        mLifecycle, (PreferenceFragmentCompat) mFragment, mAccessPoint.getSsid());
+            return;
+        }
+
         mEntityHeaderController =
                 EntityHeaderController.newInstance(
                         mFragment.getActivity(), mFragment,
@@ -327,7 +341,16 @@
                 mContext.getDrawable(R.drawable.ic_settings_widget_background));
         iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
 
-        mEntityHeaderController.setLabel(mAccessPoint.getSsidStr());
+        mEntityHeaderController.setLabel(mAccessPoint.getTitle());
+    }
+
+    private void refreshEntityHeader() {
+        if (usingDataUsageHeader(mContext)) {
+            mSummaryHeaderController.updateState(mDataUsageSummaryPref);
+        } else {
+            mEntityHeaderController.setSummary(mAccessPoint.getSettingsSummary())
+                    .done(mFragment.getActivity(), true /* rebind */);
+        }
     }
 
     @Override
@@ -364,9 +387,7 @@
         // MAC Address Pref
         mMacAddressPref.setSummary(mWifiConfig.getRandomizedMacAddress().toString());
 
-        // TODO(b/124700353): Change header to data usage chart
-        mEntityHeaderController.setSummary(mAccessPoint.getSettingsSummary())
-                .done(mFragment.getActivity(), true /* rebind */);
+        refreshEntityHeader();
 
         updateIpLayerInfo();
 
@@ -433,8 +454,7 @@
 
     private void refreshNetworkState() {
         mAccessPoint.update(mWifiConfig, mWifiInfo, mNetworkInfo);
-        mEntityHeaderController.setSummary(mAccessPoint.getSettingsSummary())
-                .done(mFragment.getActivity(), true /* rebind */);
+        refreshEntityHeader();
     }
 
     private void refreshRssiViews() {
@@ -447,7 +467,10 @@
         Drawable wifiIcon = mIconInjector.getIcon(mRssiSignalLevel);
 
         wifiIcon.setTintList(Utils.getColorAccent(mContext));
-        mEntityHeaderController.setIcon(wifiIcon).done(mFragment.getActivity(), true /* rebind */);
+        if (mEntityHeaderController != null) {
+            mEntityHeaderController.setIcon(wifiIcon).done(mFragment.getActivity(),
+                    true /* rebind */);
+        }
 
         Drawable wifiIconDark = wifiIcon.getConstantState().newDrawable().mutate();
         wifiIconDark.setTintList(Utils.getColorAttr(mContext, android.R.attr.colorControlNormal));
@@ -619,48 +642,16 @@
      * Share the wifi network with QR code.
      */
     private void shareNetwork() {
-        final KeyguardManager keyguardManager = (KeyguardManager) mContext.getSystemService(
-                Context.KEYGUARD_SERVICE);
-        if (keyguardManager.isKeyguardSecure()) {
-            // Show authentication screen to confirm credentials (pin, pattern or password) for
-            // the current user of the device.
-            final String title = mContext.getString(
-                    R.string.lockpassword_confirm_your_pattern_header);
-            final String description = String.format(
-                    mContext.getString(R.string.wifi_sharing_message),
-                    mAccessPoint.getSsidStr());
+        final String title = mContext.getString(
+                R.string.lockpassword_confirm_your_pattern_header);
+        final String description = String.format(
+                mContext.getString(R.string.wifi_sharing_message),
+                mAccessPoint.getSsidStr());
 
-            final BiometricPrompt.Builder builder = new BiometricPrompt.Builder(mContext)
-                    .setTitle(title)
-                    .setDescription(description);
-
-            if (keyguardManager.isDeviceSecure()) {
-                builder.setDeviceCredentialAllowed(true);
-            }
-
-            final BiometricPrompt bp = builder.build();
-            final Handler handler = new Handler(Looper.getMainLooper());
-            bp.authenticate(new CancellationSignal(),
-                    runnable -> handler.post(runnable),
-                    mAuthenticationCallback);
-        } else {
-            launchWifiDppConfiguratorActivity();
-        }
+        WifiDppUtils.showLockScreen(mContext, title, description,
+                () -> launchWifiDppConfiguratorActivity());
     }
 
-    private BiometricPrompt.AuthenticationCallback mAuthenticationCallback =
-            new BiometricPrompt.AuthenticationCallback() {
-        @Override
-        public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
-            launchWifiDppConfiguratorActivity();
-        }
-
-        @Override
-        public void onAuthenticationError(int errorCode, CharSequence errString) {
-            //Do nothing
-        }
-    };
-
     /**
      * Sign in to the captive portal found on this wifi network associated with this preference.
      */
@@ -706,4 +697,8 @@
             return mContext.getDrawable(Utils.getWifiIconResource(level)).mutate();
         }
     }
+
+    private boolean usingDataUsageHeader(Context context) {
+        return FeatureFlagUtils.isEnabled(context, FeatureFlags.WIFI_DETAILS_DATAUSAGE_HEADER);
+    }
 }
diff --git a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
index fd2e14a..7edd227 100644
--- a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
+++ b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
@@ -153,11 +153,11 @@
 
         controllers.add(mWifiDetailPreferenceController);
         controllers.add(new WifiMeteredPreferenceController(context, mAccessPoint.getConfig()));
-        WifiPrivacyPreferenceController preferenceController = new WifiPrivacyPreferenceController(
+        WifiPrivacyPreferenceController privacyController = new WifiPrivacyPreferenceController(
                 context);
-        preferenceController.setWifiConfiguration(mAccessPoint.getConfig());
-        preferenceController.setIsEphemeral(mAccessPoint.isEphemeral());
-        controllers.add(preferenceController);
+        privacyController.setWifiConfiguration(mAccessPoint.getConfig());
+        privacyController.setIsEphemeral(mAccessPoint.isEphemeral());
+        controllers.add(privacyController);
 
         return controllers;
     }
diff --git a/src/com/android/settings/wifi/details/WifiPrivacyPreferenceController.java b/src/com/android/settings/wifi/details/WifiPrivacyPreferenceController.java
index 97ddc53..a549e21 100644
--- a/src/com/android/settings/wifi/details/WifiPrivacyPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiPrivacyPreferenceController.java
@@ -59,7 +59,7 @@
     @Override
     public int getAvailabilityStatus() {
         return mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_wifi_p2p_mac_randomization_supported) ?
+                com.android.internal.R.bool.config_wifi_connected_mac_randomization_supported) ?
                 AVAILABLE : CONDITIONALLY_UNAVAILABLE;
     }
 
diff --git a/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java b/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java
index 9e731ba..3a9308e 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java
@@ -29,6 +29,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.ProgressBar;
@@ -99,6 +100,7 @@
 
         if (!isConfigurationChange) {
             mLatestStatusCode = WifiDppUtils.EASY_CONNECT_EVENT_SUCCESS;
+            changeFocusAndAnnounceChange(mButtonRight, mTitle);
         }
     }
 
@@ -168,15 +170,17 @@
             mButtonLeft.setVisibility(View.INVISIBLE);
         }
 
-        if (!isConfigurationChange) {
-            mLatestStatusCode = code;
-        }
-
         if (isGoingInitiator()) {
             mSummary.setText(R.string.wifi_dpp_sharing_wifi_with_this_device);
         }
+
         mProgressBar.setVisibility(isGoingInitiator() ? View.VISIBLE : View.INVISIBLE);
         mButtonRight.setVisibility(isGoingInitiator() ? View.INVISIBLE : View.VISIBLE);
+
+        if (!isConfigurationChange) {
+            mLatestStatusCode = code;
+            changeFocusAndAnnounceChange(mButtonRight, mSummary);
+        }
     }
 
     private boolean hasRetryButton(int code) {
@@ -277,6 +281,7 @@
             mButtonRight.setVisibility(View.INVISIBLE);
             startWifiDppConfiguratorInitiator();
             updateSummary();
+            mTitleSummaryContainer.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
         });
 
         if (savedInstanceState != null) {
@@ -288,6 +293,8 @@
             } else {
                 showErrorUi(mLatestStatusCode, /* isConfigurationChange */ true);
             }
+        } else {
+            changeFocusAndAnnounceChange(mButtonRight, mTitleSummaryContainer);
         }
     }
 
@@ -354,4 +361,17 @@
             mSummary.setText(getString(R.string.wifi_dpp_add_device_to_wifi, getSsid()));
         }
     }
+
+    /**
+     * This fragment will change UI display and text messages for events. To improve Talkback user
+     * experienience, using this method to focus on a right component and announce a changed text
+     * after an UI changing event.
+     *
+     * @param focusView The UI component which will be focused
+     * @param announceView The UI component's text will be talked
+     */
+    private void changeFocusAndAnnounceChange(View focusView, View announceView) {
+        focusView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+        announceView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+    }
 }
diff --git a/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java b/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java
index 72e845f..ddba933 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java
@@ -23,6 +23,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.Button;
 import android.widget.ListView;
 
@@ -105,5 +106,11 @@
 
         mButtonRight = view.findViewById(R.id.button_right);
         mButtonRight.setVisibility(View.GONE);
+
+        if (savedInstanceState == null) {
+            // For Talkback to describe this fragment
+            mTitleSummaryContainer.sendAccessibilityEvent(
+                    AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+        }
     }
 }
diff --git a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
index 0a2c09b..7308741 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
@@ -75,6 +75,7 @@
     private static final String KEY_WIFI_PRESHARED_KEY = "key_wifi_preshared_key";
     private static final String KEY_WIFI_HIDDEN_SSID = "key_wifi_hidden_ssid";
     private static final String KEY_WIFI_NETWORK_ID = "key_wifi_network_id";
+    private static final String KEY_IS_HOTSPOT = "key_is_hotspot";
 
     private FragmentManager mFragmentManager;
 
@@ -104,14 +105,15 @@
 
             mWifiDppQrCode = WifiQrCode.getValidWifiDppQrCodeOrNull(qrCode);
 
-            String security = savedInstanceState.getString(KEY_WIFI_SECURITY);
-            String ssid = savedInstanceState.getString(KEY_WIFI_SSID);
-            String preSharedKey = savedInstanceState.getString(KEY_WIFI_PRESHARED_KEY);
-            boolean hiddenSsid = savedInstanceState.getBoolean(KEY_WIFI_HIDDEN_SSID);
-            int networkId = savedInstanceState.getInt(KEY_WIFI_NETWORK_ID);
+            final String security = savedInstanceState.getString(KEY_WIFI_SECURITY);
+            final String ssid = savedInstanceState.getString(KEY_WIFI_SSID);
+            final String preSharedKey = savedInstanceState.getString(KEY_WIFI_PRESHARED_KEY);
+            final boolean hiddenSsid = savedInstanceState.getBoolean(KEY_WIFI_HIDDEN_SSID);
+            final int networkId = savedInstanceState.getInt(KEY_WIFI_NETWORK_ID);
+            final boolean isHotspot = savedInstanceState.getBoolean(KEY_IS_HOTSPOT);
 
             mWifiNetworkConfig = WifiNetworkConfig.getValidConfigOrNull(security, ssid,
-                    preSharedKey, hiddenSsid, networkId);
+                    preSharedKey, hiddenSsid, networkId, isHotspot);
         } else {
             handleIntent(getIntent());
         }
@@ -361,6 +363,7 @@
             outState.putString(KEY_WIFI_PRESHARED_KEY, mWifiNetworkConfig.getPreSharedKey());
             outState.putBoolean(KEY_WIFI_HIDDEN_SSID, mWifiNetworkConfig.getHiddenSsid());
             outState.putInt(KEY_WIFI_NETWORK_ID, mWifiNetworkConfig.getNetworkId());
+            outState.putBoolean(KEY_IS_HOTSPOT, mWifiNetworkConfig.isHotspot());
         }
 
         super.onSaveInstanceState(outState);
@@ -393,7 +396,8 @@
                     wifiConfiguration.getPrintableSsid(),
                     wifiConfiguration.preSharedKey,
                     /* hiddenSsid */ false,
-                    wifiConfiguration.networkId);
+                    wifiConfiguration.networkId,
+                    /* isHotspot */ false);
             }
         }
 
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java
index fab495d..eafbe68 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java
@@ -38,6 +38,7 @@
     private ImageView mDevicesCheckCircleGreenHeaderIcon;
     protected TextView mTitle;
     protected TextView mSummary;
+    protected View mTitleSummaryContainer;
 
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
@@ -48,6 +49,10 @@
                 view.findViewById(R.id.devices_check_circle_green_icon);
         mTitle = view.findViewById(android.R.id.title);
         mSummary = view.findViewById(android.R.id.summary);
+
+        // This is the LinearLayout which groups mTitle and mSummary for Talkback to announce the
+        // content in a way that reflects its natural groupings.
+        mTitleSummaryContainer =  view.findViewById(R.id.title_summary_container);
     }
 
     protected void setHeaderIconImageResource(int resId) {
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java
index daa41d9f..2cd5e23 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java
@@ -60,6 +60,14 @@
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
 
+        // setTitle for Talkback
+        final WifiNetworkConfig wifiNetworkConfig = getWifiNetworkConfigFromHostActivity();
+        if (wifiNetworkConfig.isHotspot()) {
+            getActivity().setTitle(R.string.wifi_dpp_share_hotspot);
+        } else {
+            getActivity().setTitle(R.string.wifi_dpp_share_wifi);
+        }
+
         setHasOptionsMenu(true);
         final ActionBar actionBar = getActivity().getActionBar();
         if (actionBar != null) {
@@ -86,7 +94,8 @@
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         final WifiNetworkConfig wifiNetworkConfig = getWifiNetworkConfigFromHostActivity();
         MenuItem menuItem;
-        if (wifiNetworkConfig.isSupportWifiDpp(getActivity())) {
+        if (!wifiNetworkConfig.isHotspot() &&
+                wifiNetworkConfig.isSupportWifiDpp(getActivity())) {
             menuItem = menu.add(0, Menu.FIRST, 0, R.string.next_label);
             menuItem.setIcon(R.drawable.ic_scan_24dp);
             menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
@@ -127,9 +136,15 @@
         setHeaderIconImageResource(R.drawable.ic_qrcode_24dp);
 
         final WifiNetworkConfig wifiNetworkConfig = getWifiNetworkConfigFromHostActivity();
-        mTitle.setText(R.string.wifi_dpp_share_wifi);
-        mSummary.setText(getString(R.string.wifi_dpp_scan_qr_code_with_another_device,
-                wifiNetworkConfig.getSsid()));
+        if (wifiNetworkConfig.isHotspot()) {
+            mTitle.setText(R.string.wifi_dpp_share_hotspot);
+            mSummary.setText(getString(R.string.wifi_dpp_scan_qr_code_to_share_hotspot,
+                    wifiNetworkConfig.getSsid()));
+        } else {
+            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();
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
index a19069b..4535599 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
@@ -41,6 +41,7 @@
 import android.view.TextureView.SurfaceTextureListener;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
@@ -174,6 +175,13 @@
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
 
+        // setTitle for Talkback
+        if (mIsConfiguratorMode) {
+            getActivity().setTitle(R.string.wifi_dpp_add_device_to_network);
+        } else {
+            getActivity().setTitle(R.string.wifi_dpp_scan_qr_code);
+        }
+
         final ActionBar actionBar = getActivity().getActionBar();
         if (actionBar != null) {
             actionBar.setDisplayHomeAsUpEnabled(true);
@@ -380,6 +388,7 @@
     public void showErrorMessage(String message) {
         mErrorMessage.setVisibility(View.VISIBLE);
         mErrorMessage.setText(message);
+        mErrorMessage.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
 
         mHandler.removeMessages(MESSAGE_HIDE_ERROR_MESSAGE);
         mHandler.sendEmptyMessageDelayed(MESSAGE_HIDE_ERROR_MESSAGE,
@@ -410,6 +419,8 @@
                         mProgressBar.setVisibility(View.VISIBLE);
                         startWifiDppEnrolleeInitiator((WifiQrCode)msg.obj);
                         updateEnrolleeSummary();
+                        mSummary.sendAccessibilityEvent(
+                                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
                     }
                     break;
 
diff --git a/src/com/android/settings/wifi/dpp/WifiDppUtils.java b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
index 4d8cca5..fe7af27 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppUtils.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
@@ -16,11 +16,16 @@
 
 package com.android.settings.wifi.dpp;
 
+import android.app.KeyguardManager;
 import android.content.Context;
 import android.content.Intent;
+import android.hardware.biometrics.BiometricPrompt;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.Looper;
 import android.text.TextUtils;
 import android.util.FeatureFlagUtils;
 
@@ -70,6 +75,9 @@
     /** The data corresponding to {@code WifiConfiguration} networkId */
     public static final String EXTRA_WIFI_NETWORK_ID = "networkId";
 
+    /** The data to recognize if it's a Wi-Fi hotspot for configuration */
+    public static final String EXTRA_IS_HOTSPOT = "isHotspot";
+
     /** Used by {@link android.provider.Settings#ACTION_PROCESS_WIFI_EASY_CONNECT_URI} to
      * indicate test mode UI should be shown. Test UI does not make API calls. Value is a boolean.*/
     public static final String EXTRA_TEST = "test";
@@ -142,24 +150,12 @@
         return str.substring(begin, end+1);
     }
 
-    private static String getSecurityString(AccessPoint accessPoint) {
-        switch(accessPoint.getSecurity()) {
-            case AccessPoint.SECURITY_WEP:
-                return WifiQrCode.SECURITY_WEP;
-            case AccessPoint.SECURITY_PSK:
-                return WifiQrCode.SECURITY_WPA_PSK;
-            case AccessPoint.SECURITY_SAE:
-                return WifiQrCode.SECURITY_SAE;
-            default:
-                return WifiQrCode.SECURITY_NO_PASSWORD;
-        }
-    }
-
     static String getSecurityString(WifiConfiguration config) {
         if (config.allowedKeyManagement.get(KeyMgmt.SAE)) {
             return WifiQrCode.SECURITY_SAE;
         }
-        if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
+        if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ||
+                config.allowedKeyManagement.get(KeyMgmt.WPA2_PSK)) {
             return WifiQrCode.SECURITY_WPA_PSK;
         }
         return (config.wepKeys[0] == null) ?
@@ -171,6 +167,9 @@
      * security. It may return null if the security is not supported by QR code generator nor
      * scanner.
      *
+     * Do not use this method for Wi-Fi hotspot network, use
+     * {@code getHotspotConfiguratorIntentOrNull} instead.
+     *
      * @param context     The context to use for the content resolver
      * @param wifiManager An instance of {@link WifiManager}
      * @param accessPoint An instance of {@link AccessPoint}
@@ -187,15 +186,63 @@
             return null;
         }
 
-        final WifiConfiguration wifiConfig = accessPoint.getConfig();
-        final String ssid = removeFirstAndLastDoubleQuotes(wifiConfig.SSID);
-        final String security = getSecurityString(accessPoint);
-        String preSharedKey = wifiConfig.preSharedKey;
+        final WifiConfiguration wifiConfiguration = accessPoint.getConfig();
+        setConfiguratorIntentExtra(intent, wifiManager, wifiConfiguration);
+
+        if (wifiConfiguration.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
+            throw new IllegalArgumentException("Invalid network ID");
+        } else {
+            intent.putExtra(EXTRA_WIFI_NETWORK_ID, wifiConfiguration.networkId);
+        }
+
+        return intent;
+    }
+
+    /**
+     * Returns an intent to launch QR code generator for the Wi-Fi hotspot. It may return null if
+     * the security is not supported by QR code generator.
+     *
+     * @param context The context to use for the content resolver
+     * @param wifiManager An instance of {@link WifiManager}
+     * @param wifiConfiguration {@link WifiConfiguration} of the Wi-Fi hotspot
+     * @return Intent for launching QR code generator
+     */
+    public static Intent getHotspotConfiguratorIntentOrNull(Context context,
+            WifiManager wifiManager, WifiConfiguration wifiConfiguration) {
+        final Intent intent = new Intent(context, WifiDppConfiguratorActivity.class);
+        if (isSupportHotspotConfiguratorQrCodeGenerator(wifiConfiguration)) {
+            intent.setAction(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR);
+        } else {
+            return null;
+        }
+
+        setConfiguratorIntentExtra(intent, wifiManager, wifiConfiguration);
+
+        intent.putExtra(EXTRA_WIFI_NETWORK_ID, WifiConfiguration.INVALID_NETWORK_ID);
+        intent.putExtra(EXTRA_IS_HOTSPOT, true);
+
+        return intent;
+    }
+
+    /**
+     * Set all extra except {@code EXTRA_WIFI_NETWORK_ID} for the intent to
+     * launch configurator activity later.
+     *
+     * @param intent the target to set extra
+     * @param wifiManager an instance of {@code WifiManager}
+     * @param wifiConfiguration the Wi-Fi network for launching configurator activity
+     */
+    private static void setConfiguratorIntentExtra(Intent intent, WifiManager wifiManager,
+            WifiConfiguration wifiConfiguration) {
+        final String ssid = removeFirstAndLastDoubleQuotes(wifiConfiguration.SSID);
+        final String security = getSecurityString(wifiConfiguration);
+        String preSharedKey = wifiConfiguration.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));
+            preSharedKey = removeFirstAndLastDoubleQuotes(getPresharedKey(wifiManager,
+                    wifiConfiguration));
         }
 
         if (!TextUtils.isEmpty(ssid)) {
@@ -207,13 +254,6 @@
         if (!TextUtils.isEmpty(preSharedKey)) {
             intent.putExtra(EXTRA_WIFI_PRE_SHARED_KEY, preSharedKey);
         }
-        if (wifiConfig.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
-            throw new IllegalArgumentException("Invalid network ID");
-        } else {
-            intent.putExtra(EXTRA_WIFI_NETWORK_ID, wifiConfig.networkId);
-        }
-
-        return intent;
     }
 
     /**
@@ -228,6 +268,54 @@
                 isSupportConfiguratorQrCodeGenerator(accessPoint);
     }
 
+    /**
+     * Shows authentication screen to confirm credentials (pin, pattern or password) for the current
+     * user of the device.
+     *
+     * @param context The {@code Context} used to get {@code KeyguardManager} service
+     * @param title The title on lock screen
+     * @param description The description on lock screen
+     * @param successRunnable The {@code Runnable} which will be executed if the user does not setup
+     *                        device security or if lock screen is unlocked
+     */
+    public static void showLockScreen(Context context, String title, String description,
+            Runnable successRunnable) {
+        final KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(
+                Context.KEYGUARD_SERVICE);
+
+        if (keyguardManager.isKeyguardSecure()) {
+            final BiometricPrompt.AuthenticationCallback authenticationCallback =
+                    new BiometricPrompt.AuthenticationCallback() {
+                        @Override
+                        public void onAuthenticationSucceeded(
+                                    BiometricPrompt.AuthenticationResult result) {
+                            successRunnable.run();
+                        }
+
+                        @Override
+                        public void onAuthenticationError(int errorCode, CharSequence errString) {
+                            //Do nothing
+                        }
+            };
+
+            final BiometricPrompt.Builder builder = new BiometricPrompt.Builder(context)
+                    .setTitle(title)
+                    .setDescription(description);
+
+            if (keyguardManager.isDeviceSecure()) {
+                builder.setDeviceCredentialAllowed(true);
+            }
+
+            final BiometricPrompt bp = builder.build();
+            final Handler handler = new Handler(Looper.getMainLooper());
+            bp.authenticate(new CancellationSignal(),
+                    runnable -> handler.post(runnable),
+                    authenticationCallback);
+        } else {
+            successRunnable.run();
+        }
+    }
+
     private static boolean isSupportConfiguratorQrCodeScanner(Context context,
             AccessPoint accessPoint) {
         if (!isWifiDppEnabled(context)) {
@@ -254,4 +342,13 @@
 
         return false;
     }
+
+    private static boolean isSupportHotspotConfiguratorQrCodeGenerator(
+            WifiConfiguration wifiConfiguration) {
+        // QR code generator produces QR code with ZXing's Wi-Fi network config format,
+        // it supports PSK and WEP and non security
+        // KeyMgmt.NONE is for WEP or non security
+        return wifiConfiguration.allowedKeyManagement.get(KeyMgmt.WPA2_PSK) ||
+                wifiConfiguration.allowedKeyManagement.get(KeyMgmt.NONE);
+    }
 }
diff --git a/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java b/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
index a483073..fdc74d8 100644
--- a/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
+++ b/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
@@ -30,7 +30,6 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import androidx.annotation.Keep;
 import androidx.annotation.VisibleForTesting;
 
 /**
@@ -52,15 +51,17 @@
     private String mPreSharedKey;
     private boolean mHiddenSsid;
     private int mNetworkId;
+    private boolean mIsHotspot;
 
     @VisibleForTesting
     WifiNetworkConfig(String security, String ssid, String preSharedKey,
-            boolean hiddenSsid, int networkId) {
+            boolean hiddenSsid, int networkId, boolean isHotspot) {
         mSecurity = security;
         mSsid = ssid;
         mPreSharedKey = preSharedKey;
         mHiddenSsid = hiddenSsid;
         mNetworkId = networkId;
+        mIsHotspot = isHotspot;
     }
 
     public WifiNetworkConfig(WifiNetworkConfig config) {
@@ -69,6 +70,7 @@
         mPreSharedKey = config.mPreSharedKey;
         mHiddenSsid = config.mHiddenSsid;
         mNetworkId = config.mNetworkId;
+        mIsHotspot = config.mIsHotspot;
     }
 
     /**
@@ -86,23 +88,26 @@
      * android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_SCANNER
      */
     public static WifiNetworkConfig getValidConfigOrNull(Intent intent) {
-        String security = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_SECURITY);
-        String ssid = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_SSID);
-        String preSharedKey = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_PRE_SHARED_KEY);
-        boolean hiddenSsid = intent.getBooleanExtra(WifiDppUtils.EXTRA_WIFI_HIDDEN_SSID, false);
-        int networkId = intent.getIntExtra(WifiDppUtils.EXTRA_WIFI_NETWORK_ID,
+        final String security = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_SECURITY);
+        final String ssid = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_SSID);
+        final String preSharedKey = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_PRE_SHARED_KEY);
+        final boolean hiddenSsid = intent.getBooleanExtra(WifiDppUtils.EXTRA_WIFI_HIDDEN_SSID,
+                false);
+        final int networkId = intent.getIntExtra(WifiDppUtils.EXTRA_WIFI_NETWORK_ID,
                 WifiConfiguration.INVALID_NETWORK_ID);
+        final boolean isHotspot = intent.getBooleanExtra(WifiDppUtils.EXTRA_IS_HOTSPOT, false);
 
-        return getValidConfigOrNull(security, ssid, preSharedKey, hiddenSsid, networkId);
+        return getValidConfigOrNull(security, ssid, preSharedKey, hiddenSsid, networkId, isHotspot);
     }
 
     public static WifiNetworkConfig getValidConfigOrNull(String security, String ssid,
-            String preSharedKey, boolean hiddenSsid, int networkId) {
+            String preSharedKey, boolean hiddenSsid, int networkId, boolean isHotspot) {
         if (!isValidConfig(security, ssid, preSharedKey, hiddenSsid)) {
             return null;
         }
 
-        return new WifiNetworkConfig(security, ssid, preSharedKey, hiddenSsid, networkId);
+        return new WifiNetworkConfig(security, ssid, preSharedKey, hiddenSsid, networkId,
+                isHotspot);
     }
 
     public static boolean isValidConfig(WifiNetworkConfig config) {
@@ -174,31 +179,30 @@
         return barcode;
     }
 
-    @Keep
     public String getSecurity() {
         return mSecurity;
     }
 
-    @Keep
     public String getSsid() {
         return mSsid;
     }
 
-    @Keep
     public String getPreSharedKey() {
         return mPreSharedKey;
     }
 
-    @Keep
     public boolean getHiddenSsid() {
         return mHiddenSsid;
     }
 
-    @Keep
     public int getNetworkId() {
         return mNetworkId;
     }
 
+    public boolean isHotspot() {
+        return mIsHotspot;
+    }
+
     public void connect(Context context, WifiManager.ActionListener listener) {
         WifiConfiguration wifiConfiguration = getWifiConfigurationOrNull();
         if (wifiConfiguration == null) {
diff --git a/src/com/android/settings/wifi/dpp/WifiNetworkListFragment.java b/src/com/android/settings/wifi/dpp/WifiNetworkListFragment.java
index ce92f90..4688d76 100644
--- a/src/com/android/settings/wifi/dpp/WifiNetworkListFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiNetworkListFragment.java
@@ -218,7 +218,7 @@
             final WifiNetworkConfig networkConfig = WifiNetworkConfig.getValidConfigOrNull(
                     selectedAccessPoint.getSecurityString(/* concise */ true),
                     wifiConfig.getPrintableSsid(), wifiConfig.preSharedKey, /* hiddenSsid */ false,
-                    wifiConfig.networkId);
+                    wifiConfig.networkId, /* isHotspot */ false);
             if (mOnChooseNetworkListener != null) {
                 mOnChooseNetworkListener.onChooseNetwork(networkConfig);
             }
@@ -232,7 +232,8 @@
                                 /* ssid */ WifiNetworkConfig.FAKE_SSID,
                                 /* preSharedKey */ WifiNetworkConfig.FAKE_PASSWORD,
                                 /* hiddenSsid */ true,
-                                /* networkId */ WifiConfiguration.INVALID_NETWORK_ID));
+                                /* networkId */ WifiConfiguration.INVALID_NETWORK_ID,
+                                /* isHotspot*/ false));
             }
         } else {
             return super.onPreferenceTreeClick(preference);
diff --git a/src/com/android/settings/wifi/dpp/WifiQrCode.java b/src/com/android/settings/wifi/dpp/WifiQrCode.java
index 10971cf..8296a62 100644
--- a/src/com/android/settings/wifi/dpp/WifiQrCode.java
+++ b/src/com/android/settings/wifi/dpp/WifiQrCode.java
@@ -133,7 +133,7 @@
         password = removeBackSlash(password);
 
         mWifiNetworkConfig = WifiNetworkConfig.getValidConfigOrNull(security, ssid, password,
-                hiddenSsid, WifiConfiguration.INVALID_NETWORK_ID);
+                hiddenSsid, WifiConfiguration.INVALID_NETWORK_ID, /* isHotspot */ false);
 
         if (mWifiNetworkConfig == null) {
             throw new IllegalArgumentException("Invalid format");
diff --git a/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettings.java b/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettings.java
index 867c2f8..ea858f3 100644
--- a/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettings.java
+++ b/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettings.java
@@ -199,11 +199,7 @@
      * Checks if showing WifiNetworkDetailsFragment when clicking saved network item.
      */
     public static boolean usingDetailsFragment(Context context) {
-        if (FeatureFlagUtils.isEnabled(context, FeatureFlags.MOBILE_NETWORK_V2)
-                && FeatureFlagPersistent.isEnabled(context, FeatureFlags.NETWORK_INTERNET_V2)) {
-            return false;    // TODO(b/124695272): mark true when UI is ready.
-        }
-        return false;
+        return FeatureFlagUtils.isEnabled(context, FeatureFlags.WIFI_DETAILS_SAVED_SCREEN);
     }
 
     boolean isSubscriptionsFeatureEnabled() {
diff --git a/src/com/android/settings/wifi/slice/ContextualWifiSlice.java b/src/com/android/settings/wifi/slice/ContextualWifiSlice.java
index fa8c267..4a799d1 100644
--- a/src/com/android/settings/wifi/slice/ContextualWifiSlice.java
+++ b/src/com/android/settings/wifi/slice/ContextualWifiSlice.java
@@ -25,6 +25,7 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.slice.Slice;
 
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.slices.CustomSliceRegistry;
 import com.android.settings.slices.CustomSliceable;
 
@@ -35,7 +36,9 @@
 
     private static final String TAG = "ContextualWifiSlice";
     @VisibleForTesting
-    boolean mPreviouslyDisplayed;
+    static long sActiveUiSession = -1000;
+    @VisibleForTesting
+    static boolean sPreviouslyDisplayed;
 
     public ContextualWifiSlice(Context context) {
         super(context);
@@ -48,13 +51,19 @@
 
     @Override
     public Slice getSlice() {
-        if (!mPreviouslyDisplayed && !TextUtils.equals(getActiveSSID(), WifiSsid.NONE)) {
+        final long currentUiSession = FeatureFactory.getFactory(mContext)
+                .getSlicesFeatureProvider().getUiSessionToken();
+        if (currentUiSession != sActiveUiSession) {
+            sActiveUiSession = currentUiSession;
+            sPreviouslyDisplayed = false;
+        }
+        if (!sPreviouslyDisplayed && !TextUtils.equals(getActiveSSID(), WifiSsid.NONE)) {
             Log.d(TAG, "Wifi is connected, no point showing any suggestion.");
             return null;
         }
-        // Set mPreviouslyDisplayed to true - we will show *something* on the screen. So we should
+        // Set sPreviouslyDisplayed to true - we will show *something* on the screen. So we should
         // keep showing this card to keep UI stable, even if wifi connects to a network later.
-        mPreviouslyDisplayed = true;
+        sPreviouslyDisplayed = true;
 
         return super.getSlice();
     }
diff --git a/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java
index 2ae6b58..8f6d489 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java
@@ -43,9 +43,6 @@
         implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop {
 
     private static final String WIFI_TETHER_SETTINGS = "wifi_tether";
-    private static final IntentFilter AIRPLANE_INTENT_FILTER = new IntentFilter(
-            Intent.ACTION_AIRPLANE_MODE_CHANGED);
-    private static final int ID_NULL = -1;
 
     private final ConnectivityManager mConnectivityManager;
     private final String[] mWifiRegexs;
@@ -103,8 +100,6 @@
     @Override
     public void onStart() {
         if (mPreference != null) {
-            mContext.registerReceiver(mReceiver, AIRPLANE_INTENT_FILTER);
-            clearSummaryForAirplaneMode();
             if (mWifiTetherSoftApManager != null) {
                 mWifiTetherSoftApManager.registerSoftApCallback();
             }
@@ -114,7 +109,6 @@
     @Override
     public void onStop() {
         if (mPreference != null) {
-            mContext.unregisterReceiver(mReceiver);
             if (mWifiTetherSoftApManager != null) {
                 mWifiTetherSoftApManager.unRegisterSoftApCallback();
             }
@@ -146,19 +140,6 @@
                 });
     }
 
-    //
-    // Everything below is copied from WifiApEnabler
-    //
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
-                clearSummaryForAirplaneMode(R.string.wifi_hotspot_off_subtext);
-            }
-        }
-    };
-
     @VisibleForTesting
     void handleWifiApStateChanged(int state, int reason) {
         switch (state) {
@@ -174,7 +155,6 @@
                 break;
             case WifiManager.WIFI_AP_STATE_DISABLED:
                 mPreference.setSummary(R.string.wifi_hotspot_off_subtext);
-                clearSummaryForAirplaneMode();
                 break;
             default:
                 if (reason == WifiManager.SAP_START_FAILURE_NO_CHANNEL) {
@@ -182,7 +162,6 @@
                 } else {
                     mPreference.setSummary(R.string.wifi_error);
                 }
-                clearSummaryForAirplaneMode();
         }
     }
 
@@ -194,21 +173,4 @@
                 BidiFormatter.getInstance().unicodeWrap(
                         (wifiConfig == null) ? s : wifiConfig.SSID)));
     }
-
-    private void clearSummaryForAirplaneMode() {
-        clearSummaryForAirplaneMode(ID_NULL);
-    }
-
-    private void clearSummaryForAirplaneMode(int defaultId) {
-        boolean isAirplaneMode = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
-        if (isAirplaneMode) {
-            mPreference.setSummary(R.string.wifi_tether_disabled_by_airplane);
-        } else if (defaultId != ID_NULL){
-            mPreference.setSummary(defaultId);
-        }
-    }
-    //
-    // Everything above is copied from WifiApEnabler
-    //
 }
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java
index eb6a123..10f3e56 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java
@@ -17,13 +17,18 @@
 package com.android.settings.wifi.tether;
 
 import android.content.Context;
+import android.content.Intent;
 import android.net.wifi.WifiConfiguration;
+import android.util.Log;
+import android.view.View;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.EditTextPreference;
 import androidx.preference.Preference;
 
+import com.android.settings.R;
 import com.android.settings.widget.ValidatedEditTextPreference;
+import com.android.settings.wifi.dpp.WifiDppUtils;
 
 public class WifiTetherSSIDPreferenceController extends WifiTetherBasePreferenceController
         implements ValidatedEditTextPreference.Validator {
@@ -56,6 +61,23 @@
             mSSID = DEFAULT_SSID;
         }
         ((ValidatedEditTextPreference) mPreference).setValidator(this);
+
+        if (mWifiManager.isWifiApEnabled() && config != null) {
+            final Intent intent = WifiDppUtils.getHotspotConfiguratorIntentOrNull(mContext,
+                    mWifiManager, config);
+
+            if (intent == null) {
+                Log.e(TAG, "Invalid security to share hotspot");
+                ((WifiTetherSsidPreference) mPreference).setButtonVisible(false);
+            } else {
+                ((WifiTetherSsidPreference) mPreference).setButtonOnClickListener(
+                        view -> shareHotspotNetwork(intent));
+                ((WifiTetherSsidPreference) mPreference).setButtonVisible(true);
+            }
+        } else {
+            ((WifiTetherSsidPreference) mPreference).setButtonVisible(false);
+        }
+
         updateSsidDisplay((EditTextPreference) mPreference);
     }
 
@@ -80,4 +102,19 @@
         preference.setText(mSSID);
         preference.setSummary(mSSID);
     }
+
+    private void shareHotspotNetwork(Intent intent) {
+        final String title = mContext.getString(
+                R.string.lockpassword_confirm_your_pattern_header);
+        final String description = String.format(
+                mContext.getString(R.string.wifi_sharing_message), mSSID);
+
+        WifiDppUtils.showLockScreen(mContext, title, description,
+                () -> mContext.startActivity(intent));
+    }
+
+    @VisibleForTesting
+    boolean isQrCodeButtonAvailable() {
+        return ((WifiTetherSsidPreference) mPreference).isQrCodeButtonAvailable();
+    }
 }
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSsidPreference.java b/src/com/android/settings/wifi/tether/WifiTetherSsidPreference.java
new file mode 100644
index 0000000..64014d9
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/WifiTetherSsidPreference.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2019 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.tether;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageButton;
+
+import androidx.annotation.DrawableRes;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settings.widget.ValidatedEditTextPreference;
+
+/**
+ * Support a QR code share button for {@code EditTextPreference} that supports input validation.
+ */
+public class WifiTetherSsidPreference extends ValidatedEditTextPreference {
+    private static final String TAG = "WifiTetherSsidPreference";
+
+    private ImageButton mImageButton;
+    private Drawable mButtonIcon;
+    private View.OnClickListener mClickListener;
+    private boolean mVisible;
+
+    public WifiTetherSsidPreference(Context context, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+
+        initialize();
+    }
+
+    public WifiTetherSsidPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        initialize();
+    }
+
+    public WifiTetherSsidPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        initialize();
+    }
+
+    public WifiTetherSsidPreference(Context context) {
+        super(context);
+
+        initialize();
+    }
+
+    private void initialize() {
+        setWidgetLayoutResource(R.layout.wifi_button_preference_widget);
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+
+        if (mImageButton == null) {
+            mImageButton = (ImageButton) holder.findViewById(R.id.button_icon);
+
+            mImageButton.setContentDescription(
+                    getContext().getString(R.string.wifi_dpp_share_hotspot));
+            setButtonIcon(R.drawable.ic_qrcode_24dp);
+            mImageButton.setImageDrawable(mButtonIcon);
+        }
+
+        if (mVisible) {
+            mImageButton.setOnClickListener(mClickListener);
+            mImageButton.setVisibility(View.VISIBLE);
+        } else {
+            mImageButton.setVisibility(View.GONE);
+        }
+    }
+
+    public void setButtonOnClickListener(View.OnClickListener listener) {
+        mClickListener = listener;
+    }
+
+    public void setButtonVisible(boolean visible) {
+        mVisible = visible;
+    }
+
+    private void setButtonIcon(@DrawableRes int iconResId) {
+        try {
+            mButtonIcon = getContext().getDrawable(iconResId);
+        } catch (Resources.NotFoundException exception) {
+            Log.e(TAG, "Resource does not exist: " + iconResId);
+        }
+    }
+
+    @VisibleForTesting
+    boolean isQrCodeButtonAvailable() {
+        return mVisible && mClickListener != null;
+    }
+}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java b/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
index 8d87b32..0f31d19 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
@@ -61,7 +61,6 @@
 
     static {
         WIFI_INTENT_FILTER = new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
-        WIFI_INTENT_FILTER.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
     }
 
     WifiTetherSwitchBarController(Context context, SwitchWidgetController switchBar) {
@@ -119,8 +118,6 @@
                 final int state = intent.getIntExtra(
                         WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED);
                 handleWifiApStateChanged(state);
-            } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
-                updateWifiSwitch();
             }
         }
     };
@@ -154,13 +151,7 @@
     }
 
     private void updateWifiSwitch() {
-        boolean isAirplaneMode = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
-        if (!isAirplaneMode) {
-            mSwitchBar.setEnabled(!mDataSaverBackend.isDataSaverEnabled());
-        } else {
-            mSwitchBar.setEnabled(false);
-        }
+        mSwitchBar.setEnabled(!mDataSaverBackend.isDataSaverEnabled());
     }
 
     @Override
diff --git a/tests/robotests/assets/grandfather_invalid_base_preference_controller_constructor b/tests/robotests/assets/grandfather_invalid_base_preference_controller_constructor
index ce03d95..675108d 100644
--- a/tests/robotests/assets/grandfather_invalid_base_preference_controller_constructor
+++ b/tests/robotests/assets/grandfather_invalid_base_preference_controller_constructor
@@ -6,6 +6,7 @@
 com.android.settings.bluetooth.BluetoothDeviceNamePreferenceController
 com.android.settings.bluetooth.BluetoothDeviceRenamePreferenceController
 com.android.settings.datausage.DataUsageSummaryPreferenceController
+com.android.settings.datausage.WifiDataUsageSummaryPreferenceController
 com.android.settings.fuelgauge.RestrictAppPreferenceController
 com.android.settings.fuelgauge.batterysaver.BatterySaverButtonPreferenceController
 com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController
diff --git a/tests/robotests/src/com/android/settings/accessibility/BalanceSeekBarPreferenceTest.java b/tests/robotests/src/com/android/settings/accessibility/BalanceSeekBarPreferenceTest.java
new file mode 100644
index 0000000..ba7bd2c
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/BalanceSeekBarPreferenceTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 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.accessibility;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import androidx.preference.PreferenceViewHolder;
+
+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 BalanceSeekBarPreferenceTest {
+    private static final int BALANCE_CENTER_VALUE = 100;
+    private static final int BALANCE_MAX_VALUE = 200;
+
+    private Context mContext;
+    private AttributeSet mAttrs;
+    private PreferenceViewHolder mHolder;
+    private BalanceSeekBar mSeekBar;
+    private BalanceSeekBarPreference mSeekBarPreference;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mSeekBarPreference = new BalanceSeekBarPreference(mContext, mAttrs);
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        final View view =
+                inflater.inflate(mSeekBarPreference.getLayoutResource(),
+                        new LinearLayout(mContext), false);
+        mHolder = PreferenceViewHolder.createInstanceForTests(view);
+        mSeekBar = (BalanceSeekBar) view.findViewById(com.android.internal.R.id.seekbar);
+    }
+
+    @Test
+    public void seekBarPreferenceOnBindViewHolder_shouldInitSeekBarValue() {
+        mSeekBarPreference.onBindViewHolder(mHolder);
+
+        assertThat(mSeekBar.getMax()).isEqualTo(BALANCE_MAX_VALUE);
+        assertThat(mSeekBar.getProgress()).isEqualTo(BALANCE_CENTER_VALUE);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/BalanceSeekBarTest.java b/tests/robotests/src/com/android/settings/accessibility/BalanceSeekBarTest.java
new file mode 100644
index 0000000..e0dc681
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/BalanceSeekBarTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2019 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.accessibility;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.SeekBar;
+
+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 BalanceSeekBarTest {
+    // Fix the maximum process value to 200 for testing the BalanceSeekBar.
+    // It affects the SeekBar value of center(100) and snapThreshold(200 * SNAP_TO_PERCENTAGE).
+    private static final int MAX_PROGRESS_VALUE = 200;
+
+    private Context mContext;
+    private AttributeSet mAttrs;
+    private BalanceSeekBar mSeekBar;
+    private BalanceSeekBar.OnSeekBarChangeListener mProxySeekBarListener;
+    private SeekBar.OnSeekBarChangeListener mockSeekBarChangeListener;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mSeekBar = new BalanceSeekBar(mContext, mAttrs);
+        mProxySeekBarListener = mSeekBar.getProxySeekBarListener();
+        mockSeekBarChangeListener = mock(SeekBar.OnSeekBarChangeListener.class);
+        mSeekBar.setOnSeekBarChangeListener(mockSeekBarChangeListener);
+    }
+
+    @Test
+    public void onStartTrackingTouch_shouldInvokeMethod() {
+        mProxySeekBarListener.onStartTrackingTouch(mSeekBar);
+
+        verify(mockSeekBarChangeListener, times(1)).onStartTrackingTouch(mSeekBar);
+    }
+
+    @Test
+    public void onStopTrackingTouch_shouldInvokeMethod() {
+        mProxySeekBarListener.onStopTrackingTouch(mSeekBar);
+
+        verify(mockSeekBarChangeListener, times(1)).onStopTrackingTouch(mSeekBar);
+    }
+
+    @Test
+    public void onProgressChanged_shouldInvokeMethod() {
+        // Assign the test value of SeekBar progress
+        mProxySeekBarListener.onProgressChanged(mSeekBar, MAX_PROGRESS_VALUE, true);
+
+        verify(mockSeekBarChangeListener, times(1)).onProgressChanged(eq(mSeekBar),
+                eq(MAX_PROGRESS_VALUE), eq(true));
+    }
+
+    @Test
+    public void setMaxTest_shouldSetValue() {
+        mSeekBar.setMax(MAX_PROGRESS_VALUE);
+
+        assertThat(getBalanceSeekBarCenter(mSeekBar)).isEqualTo(MAX_PROGRESS_VALUE / 2);
+        assertThat(getBalanceSeekBarSnapThreshold(mSeekBar)).isEqualTo(
+                MAX_PROGRESS_VALUE * BalanceSeekBar.SNAP_TO_PERCENTAGE);
+    }
+
+    @Test
+    public void setProgressTest_shouldSnapToCenter() {
+        // Assign the test value of SeekBar progress within the threshold (94-106 in this case).
+        final int progressWithinThreshold = 102;
+        mSeekBar.setMax(MAX_PROGRESS_VALUE);
+        mSeekBar.setProgress(progressWithinThreshold + 10); //set progress which is over threshold.
+        mProxySeekBarListener.onProgressChanged(mSeekBar, progressWithinThreshold, true);
+
+        assertThat(mSeekBar.getProgress()).isEqualTo(getBalanceSeekBarCenter(mSeekBar));
+    }
+
+    @Test
+    public void setProgressTest_shouldMaintainInputValue() {
+        // Assign the test value of SeekBar progress without the threshold.
+        final int progressWithoutThreshold = 107;
+        mSeekBar.setMax(MAX_PROGRESS_VALUE);
+        mSeekBar.setProgress(progressWithoutThreshold);
+        mProxySeekBarListener.onProgressChanged(mSeekBar, progressWithoutThreshold, true);
+
+        assertThat(mSeekBar.getProgress()).isEqualTo(progressWithoutThreshold);
+    }
+
+    // method to get the center from BalanceSeekBar for testing setMax().
+    private int getBalanceSeekBarCenter(BalanceSeekBar seekBar) {
+        return seekBar.getMax() / 2;
+    }
+
+    // method to get the snapThreshold from BalanceSeekBar for testing setMax().
+    private float getBalanceSeekBarSnapThreshold(BalanceSeekBar seekBar) {
+        return seekBar.getMax() * BalanceSeekBar.SNAP_TO_PERCENTAGE;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java b/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java
index 6a2348c..8c75e33 100644
--- a/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.verify;
 
 import android.accounts.Account;
+import android.app.ActivityManager;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -55,6 +56,7 @@
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
 import org.robolectric.shadow.api.Shadow;
+import org.robolectric.shadows.ShadowActivityManager;
 import org.robolectric.shadows.ShadowContentResolver;
 import org.robolectric.shadows.ShadowPackageManager;
 
@@ -101,6 +103,19 @@
     }
 
     @Test
+    public void onStart_lowRamDevice_doNothing() {
+        final AvatarViewMixin mixin = spy(new AvatarViewMixin(mActivity, mImageView));
+
+        final ShadowActivityManager activityManager =
+                Shadow.extract(mContext.getSystemService(ActivityManager.class));
+        activityManager.setIsLowRamDevice(true);
+
+        mixin.onStart();
+
+        verify(mixin, never()).hasAccount();
+    }
+
+    @Test
     @Config(qualifiers = "mcc999",
             shadows = {
                     BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
diff --git a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultEmergencyPickerTest.java b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultEmergencyPickerTest.java
index 5d97f52..b7b046c 100644
--- a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultEmergencyPickerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultEmergencyPickerTest.java
@@ -19,7 +19,6 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -27,15 +26,10 @@
 
 import android.app.Activity;
 import android.app.role.RoleManager;
-import android.app.role.RoleManagerCallback;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.os.AsyncTask;
-import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.provider.Settings;
-import android.util.Log;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -50,6 +44,7 @@
 
 import java.util.Arrays;
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 @RunWith(RobolectricTestRunner.class)
 public class DefaultEmergencyPickerTest {
@@ -90,7 +85,7 @@
             eq(0),
             any(UserHandle.class),
             any(Executor.class),
-            any(RoleManagerCallback.class));
+            any(Consumer.class));
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java
index 4347637..eab3dde 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java
@@ -164,7 +164,8 @@
         verify(mSummaryPreference).setUsageInfo(info.cycleEnd, now - UPDATE_BACKOFF_MS,
                 CARRIER_NAME, 1 /* numPlans */, intent);
         verify(mSummaryPreference).setChartEnabled(true);
-        verify(mSummaryPreference).setWifiMode(false, null);
+        verify(mSummaryPreference).setWifiMode(false /* isWifiMode */, null /* usagePeriod */,
+                false /* isSingleWifi */);
     }
 
     @Test
@@ -188,7 +189,8 @@
         verify(mSummaryPreference).setUsageInfo(info.cycleEnd, now - UPDATE_BACKOFF_MS,
                 CARRIER_NAME, 0 /* numPlans */, intent);
         verify(mSummaryPreference).setChartEnabled(true);
-        verify(mSummaryPreference).setWifiMode(false, null);
+        verify(mSummaryPreference).setWifiMode(false /* isWifiMode */, null /* usagePeriod */,
+                false /* isSingleWifi */);
     }
 
     @Test
@@ -214,7 +216,8 @@
                 0 /* numPlans */,
                 null /* launchIntent */);
         verify(mSummaryPreference).setChartEnabled(true);
-        verify(mSummaryPreference).setWifiMode(false, null);
+        verify(mSummaryPreference).setWifiMode(false /* isWifiMode */, null /* usagePeriod */,
+                false /* isSingleWifi */);
     }
 
     @Test
@@ -240,7 +243,8 @@
                 0 /* numPlans */,
                 null /* launchIntent */);
         verify(mSummaryPreference).setChartEnabled(false);
-        verify(mSummaryPreference).setWifiMode(false, null);
+        verify(mSummaryPreference).setWifiMode(false /* isWifiMode */, null /* usagePeriod */,
+                false /* isSingleWifi */);
     }
 
     @Test
@@ -321,7 +325,8 @@
         verify(mSummaryPreference).setLimitInfo(captor.capture());
         CharSequence value = captor.getValue();
         assertThat(value.toString()).isEqualTo("1.00 MB data warning / 1.00 MB data limit");
-        verify(mSummaryPreference).setWifiMode(false, null);
+        verify(mSummaryPreference).setWifiMode(false /* isWifiMode */, null /* usagePeriod */,
+                false /* isSingleWifi */);
     }
 
     @Test
@@ -340,7 +345,8 @@
         when(mTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_ABSENT);
         mController.updateState(mSummaryPreference);
 
-        verify(mSummaryPreference).setWifiMode(true, info.period);
+        verify(mSummaryPreference).setWifiMode(true /* isWifiMode */, info.period /* usagePeriod */,
+                false /* isSingleWifi */);
         verify(mSummaryPreference).setLimitInfo(null);
         verify(mSummaryPreference).setUsageNumbers(info.usageLevel, -1L, true);
         verify(mSummaryPreference).setChartEnabled(false);
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java
index 525b82e..35e6b1d 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java
@@ -488,7 +488,7 @@
                 new Intent());
         mSummaryPreference.setUsageNumbers(1000000L, -1L, true);
         final String cycleText = "The quick fox";
-        mSummaryPreference.setWifiMode(true, cycleText);
+        mSummaryPreference.setWifiMode(true /* isWifiMode */, cycleText, false /* isSingleWifi */);
         doReturn(200L).when(mSummaryPreference).getHistoricalUsageLevel();
 
         bindViewHolder();
@@ -524,7 +524,8 @@
     @Test
     public void testSetWifiMode_noUsageInfo_shouldDisableLaunchButton() {
         mSummaryPreference = spy(mSummaryPreference);
-        mSummaryPreference.setWifiMode(true, "Test cycle text");
+        mSummaryPreference.setWifiMode(true /* isWifiMode */, "Test cycle text",
+                false /* isSingleWifi */);
         doReturn(0L).when(mSummaryPreference).getHistoricalUsageLevel();
 
         bindViewHolder();
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/BuildNumberPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/BuildNumberPreferenceControllerTest.java
index 8fae45c..18ddd8a 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/BuildNumberPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/BuildNumberPreferenceControllerTest.java
@@ -16,18 +16,14 @@
 
 package com.android.settings.deviceinfo;
 
-import static android.content.Context.CLIPBOARD_SERVICE;
-
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.Answers.RETURNS_DEEP_STUBS;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 
 import android.app.Activity;
-import android.content.ClipboardManager;
 import android.content.Context;
 import android.os.Process;
 import android.os.UserManager;
@@ -35,7 +31,6 @@
 
 import androidx.lifecycle.LifecycleOwner;
 import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.core.InstrumentedPreferenceFragment;
@@ -62,13 +57,8 @@
 public class BuildNumberPreferenceControllerTest {
 
     private static final String KEY_BUILD_NUMBER = "build_number";
-
-    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
-    private Activity mActivity;
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private InstrumentedPreferenceFragment mFragment;
-    @Mock(answer = RETURNS_DEEP_STUBS)
-    private PreferenceScreen mScreen;
 
     private ShadowUserManager mShadowUserManager;
 
@@ -200,14 +190,4 @@
         assertThat(activityResultHandled).isTrue();
         assertThat(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)).isTrue();
     }
-
-    @Test
-    public void copy_shouldCopyBuildNumberToClipboard() {
-        mController.copy();
-
-        final ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(
-                CLIPBOARD_SERVICE);
-        final CharSequence data = clipboard.getPrimaryClip().getItemAt(0).getText();
-        assertThat(data.toString()).isEqualTo(mController.getSummary());
-    }
 }
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/SimpleBuildNumberPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/SimpleBuildNumberPreferenceControllerTest.java
new file mode 100644
index 0000000..3784f08
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/SimpleBuildNumberPreferenceControllerTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deviceinfo.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 org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class SimpleBuildNumberPreferenceControllerTest {
+
+    private SimpleBuildNumberPreferenceController mController;
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+
+        mController = new SimpleBuildNumberPreferenceController(mContext, "test");
+    }
+
+    @Test
+    public void copy_shouldCopyBuildNumberToClipboard() {
+        mController.copy();
+
+        final ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(
+                CLIPBOARD_SERVICE);
+        final CharSequence data = clipboard.getPrimaryClip().getItemAt(0).getText();
+        assertThat(data.toString()).isEqualTo(mController.getSummary());
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceControllerTest.java
index 7999dc8..3509330 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceControllerTest.java
@@ -94,13 +94,13 @@
     public void setChecked_on_setPowerSaveMode() {
         mController.setChecked(true);
 
-        verify(mPowerManager).setPowerSaveMode(true);
+        verify(mPowerManager).setPowerSaveModeEnabled(true);
     }
 
     @Test
     public void setChecked_off_unsetPowerSaveMode() {
         mController.setChecked(false);
 
-        verify(mPowerManager).setPowerSaveMode(false);
+        verify(mPowerManager).setPowerSaveModeEnabled(false);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
index 8b04ef3..40e6939 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
@@ -22,7 +22,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -87,6 +87,19 @@
     }
 
     @Test
+    public void isCardEligibleToDisplay_invalidRankingScore_returnFalse() {
+        final ContextualCard card = new ContextualCard.Builder()
+                .setName("test_card")
+                .setCardType(ContextualCard.CardType.SLICE)
+                .setSliceUri(CustomSliceRegistry.FLASHLIGHT_SLICE_URI)
+                .setRankingScore(-1)
+                .build();
+
+        assertThat(mEligibleCardChecker.isCardEligibleToDisplay(card))
+                .isFalse();
+    }
+
+    @Test
     public void isCardEligibleToDisplay_nullSlice_returnFalse() {
         doReturn(null).when(mEligibleCardChecker).bindSlice(Uri.parse(TEST_SLICE_URI));
 
@@ -108,7 +121,7 @@
     public void getDisplayableCards_twoEligibleCards_shouldShowAll() {
         final List<ContextualCard> cards = getContextualCardList().stream().limit(2)
                 .collect(Collectors.toList());
-        doReturn(cards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
+        doReturn(cards).when(mContextualCardLoader).filterEligibleCards(anyList());
 
         final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(cards);
 
@@ -118,7 +131,7 @@
     @Test
     public void getDisplayableCards_fiveEligibleCardsNoLarge_shouldShowDefaultCardCount() {
         final List<ContextualCard> fiveCards = getContextualCardListWithNoLargeCard();
-        doReturn(fiveCards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
+        doReturn(fiveCards).when(mContextualCardLoader).filterEligibleCards(anyList());
 
         final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(
                 fiveCards);
@@ -136,7 +149,7 @@
                 .setSliceUri(Uri.parse(
                         "content://com.android.settings.test.slices/action/gesture_pick_up"))
                 .build());
-        doReturn(cards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
+        doReturn(cards).when(mContextualCardLoader).filterEligibleCards(anyList());
 
         final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(cards);
 
@@ -147,7 +160,7 @@
     public void getDisplayableCards_threeEligibleCardsTwoLarge_shouldShowTwoCards() {
         final List<ContextualCard> threeCards = getContextualCardList().stream().limit(3)
                 .collect(Collectors.toList());
-        doReturn(threeCards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
+        doReturn(threeCards).when(mContextualCardLoader).filterEligibleCards(anyList());
 
         final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(
                 threeCards);
@@ -167,25 +180,26 @@
     public void getDisplayableCards_refreshCardUri_shouldLogContextualCardDisplay() {
         mContextualCardLoader.mNotifyUri = CardContentProvider.REFRESH_CARD_URI;
 
-        mContextualCardLoader.getDisplayableCards(new ArrayList<ContextualCard>());
+        mContextualCardLoader.getDisplayableCards(new ArrayList<>());
 
         verify(mFakeFeatureFactory.mContextualCardFeatureProvider).logContextualCardDisplay(
-                any(List.class), any(List.class));
+                anyList(), anyList());
     }
 
     @Test
     public void getDisplayableCards_deleteCardUri_shouldNotLogContextualCardDisplay() {
         mContextualCardLoader.mNotifyUri = CardContentProvider.DELETE_CARD_URI;
 
-        mContextualCardLoader.getDisplayableCards(new ArrayList<ContextualCard>());
+        mContextualCardLoader.getDisplayableCards(new ArrayList<>());
 
         verify(mFakeFeatureFactory.mContextualCardFeatureProvider, never())
-                .logContextualCardDisplay(any(List.class), any(List.class));
+                .logContextualCardDisplay(anyList(), anyList());
     }
 
     private ContextualCard getContextualCard(String sliceUri) {
         return new ContextualCard.Builder()
                 .setName("test_card")
+                .setRankingScore(0.5)
                 .setCardType(ContextualCard.CardType.SLICE)
                 .setSliceUri(Uri.parse(sliceUri))
                 .build();
@@ -215,11 +229,6 @@
                 .setSliceUri(Uri.parse(
                         "content://com.android.settings.test.slices/action/gesture_pick_up"))
                 .build());
-        cards.add(new ContextualCard.Builder()
-                .setName("test_battery")
-                .setCardType(ContextualCard.CardType.SLICE)
-                .setSliceUri(CustomSliceRegistry.BATTERY_INFO_SLICE_URI)
-                .build());
         return cards;
     }
 
@@ -248,11 +257,6 @@
                 .setSliceUri(Uri.parse(
                         "content://com.android.settings.test.slices/action/gesture_pick_up"))
                 .build());
-        cards.add(new ContextualCard.Builder()
-                .setName("test_battery")
-                .setCardType(ContextualCard.CardType.SLICE)
-                .setSliceUri(CustomSliceRegistry.BATTERY_INFO_SLICE_URI)
-                .build());
         return cards;
     }
 }
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
index eb9a461..8087716 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
@@ -460,7 +460,7 @@
         cards.add(new ContextualCard.Builder()
                 .setName("test_battery")
                 .setCardType(ContextualCard.CardType.SLICE)
-                .setSliceUri(CustomSliceRegistry.BATTERY_INFO_SLICE_URI)
+                .setSliceUri(CustomSliceRegistry.BATTERY_FIX_SLICE_URI)
                 .setViewType(VIEW_TYPE_FULL_WIDTH)
                 .build());
         return cards;
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/BatteryInfoSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/BatteryInfoSliceTest.java
deleted file mode 100644
index ff276d6..0000000
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/deviceinfo/BatteryInfoSliceTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.homepage.contextualcards.deviceinfo;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-
-import android.content.Context;
-
-import androidx.core.graphics.drawable.IconCompat;
-import androidx.slice.Slice;
-import androidx.slice.SliceMetadata;
-import androidx.slice.SliceProvider;
-import androidx.slice.core.SliceAction;
-import androidx.slice.widget.SliceLiveData;
-
-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 BatteryInfoSliceTest {
-
-    private Context mContext;
-    private BatteryInfoSlice mBatteryInfoSlice;
-
-    @Before
-    public void setUp() {
-        mContext = RuntimeEnvironment.application;
-
-        // Set-up specs for SliceMetadata.
-        SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
-
-        mBatteryInfoSlice = spy(new BatteryInfoSlice(mContext));
-    }
-
-    @Test
-    public void getSlice_shouldBeCorrectSliceContent() {
-        doNothing().when(mBatteryInfoSlice).loadBatteryInfo();
-        doReturn("10%").when(mBatteryInfoSlice).getBatteryPercentString();
-        doReturn("test").when(mBatteryInfoSlice).getSummary();
-
-        final Slice slice = mBatteryInfoSlice.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());
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java
index daaba90..da0d85b 100644
--- a/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java
+++ b/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java
@@ -21,21 +21,15 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
-import android.util.IconDrawableFactory;
 
 import androidx.slice.Slice;
 import androidx.slice.SliceMetadata;
@@ -43,6 +37,7 @@
 import androidx.slice.core.SliceAction;
 import androidx.slice.widget.SliceLiveData;
 
+import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
 import com.android.settingslib.media.LocalMediaManager;
 import com.android.settingslib.media.MediaDevice;
 
@@ -53,70 +48,64 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
 
 import java.util.ArrayList;
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class})
 public class MediaOutputSliceTest {
 
     private static final String TEST_PACKAGE_NAME = "com.fake.android.music";
-    private static final String TEST_LABEL = "Test app";
     private static final String TEST_DEVICE_1_ID = "test_device_1_id";
+    private static final String TEST_DEVICE_1_NAME = "test_device_1_name";
+    private static final int TEST_DEVICE_1_ICON =
+            com.android.internal.R.drawable.ic_bt_headphones_a2dp;
 
     @Mock
-    private PackageManager mPackageManager;
-    @Mock
-    private ApplicationInfo mApplicationInfo;
-    @Mock
-    private ApplicationInfo mApplicationInfo2;
-    @Mock
     private LocalMediaManager mLocalMediaManager;
-    @Mock
-    private IconDrawableFactory mIconDrawableFactory;
-    @Mock
-    private Drawable mTestDrawable;
 
     private final List<MediaDevice> mDevices = new ArrayList<>();
 
     private Context mContext;
     private MediaOutputSlice mMediaOutputSlice;
     private MediaDeviceUpdateWorker mMediaDeviceUpdateWorker;
+    private ShadowBluetoothAdapter mShadowBluetoothAdapter;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         mContext = spy(RuntimeEnvironment.application);
 
-        when(mContext.getPackageManager()).thenReturn(mPackageManager);
-        when(mPackageManager.getApplicationInfo(eq(TEST_PACKAGE_NAME), anyInt()))
-                .thenReturn(mApplicationInfo);
-        when(mPackageManager.getApplicationInfoAsUser(eq(TEST_PACKAGE_NAME), anyInt(), anyInt()))
-                .thenReturn(mApplicationInfo2);
-        when(mApplicationInfo.loadLabel(mPackageManager)).thenReturn(TEST_LABEL);
-        when(mIconDrawableFactory.getBadgedIcon(mApplicationInfo2, UserHandle.myUserId()))
-                .thenReturn(mTestDrawable);
-        when(mTestDrawable.getIntrinsicWidth()).thenReturn(100);
-        when(mTestDrawable.getIntrinsicHeight()).thenReturn(100);
-
         // Set-up specs for SliceMetadata.
         SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+        // Setup BluetoothAdapter
+        mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
+        mShadowBluetoothAdapter.setEnabled(true);
 
         mMediaOutputSlice = new MediaOutputSlice(mContext);
         mMediaDeviceUpdateWorker = new MediaDeviceUpdateWorker(mContext, MEDIA_OUTPUT_SLICE_URI);
         mMediaDeviceUpdateWorker.setPackageName(TEST_PACKAGE_NAME);
         mMediaDeviceUpdateWorker.onDeviceListUpdate(mDevices);
         mMediaDeviceUpdateWorker.mLocalMediaManager = mLocalMediaManager;
-        mMediaOutputSlice.init(TEST_PACKAGE_NAME, mMediaDeviceUpdateWorker, mIconDrawableFactory);
+        mMediaOutputSlice.init(TEST_PACKAGE_NAME, mMediaDeviceUpdateWorker);
     }
 
     @Test
-    public void getSlice_shouldHaveAppTitle() {
+    public void getSlice_shouldHaveActiveDeviceName() {
+        mDevices.clear();
+        final MediaDevice device = mock(MediaDevice.class);
+        when(device.getName()).thenReturn(TEST_DEVICE_1_NAME);
+        when(device.getIcon()).thenReturn(TEST_DEVICE_1_ICON);
+        when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(device);
+
         final Slice mediaSlice = mMediaOutputSlice.getSlice();
         final SliceMetadata metadata = SliceMetadata.from(mContext, mediaSlice);
 
         final SliceAction primaryAction = metadata.getPrimaryAction();
-        assertThat(primaryAction.getTitle().toString()).isEqualTo(TEST_LABEL);
+        assertThat(primaryAction.getTitle().toString()).isEqualTo(TEST_DEVICE_1_NAME);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkListControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkListControllerTest.java
index 1325650..10264ab 100644
--- a/tests/robotests/src/com/android/settings/network/MobileNetworkListControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/MobileNetworkListControllerTest.java
@@ -21,6 +21,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
@@ -31,6 +32,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.telephony.SubscriptionInfo;
+import android.telephony.euicc.EuiccManager;
 
 import org.junit.After;
 import org.junit.Before;
@@ -51,6 +53,9 @@
 @RunWith(RobolectricTestRunner.class)
 public class MobileNetworkListControllerTest {
     @Mock
+    EuiccManager mEuiccManager;
+
+    @Mock
     private Lifecycle mLifecycle;
 
     @Mock
@@ -58,12 +63,17 @@
 
     private Context mContext;
     private MobileNetworkListController mController;
+    private Preference mAddMorePreference;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = spy(Robolectric.setupActivity(Activity.class));
+        when(mContext.getSystemService(EuiccManager.class)).thenReturn(mEuiccManager);
         when(mPreferenceScreen.getContext()).thenReturn(mContext);
+        mAddMorePreference = new Preference(mContext);
+        when(mPreferenceScreen.findPreference(MobileNetworkListController.KEY_ADD_MORE)).thenReturn(
+                mAddMorePreference);
         mController = new MobileNetworkListController(mContext, mLifecycle);
     }
 
@@ -79,6 +89,22 @@
     }
 
     @Test
+    public void displayPreference_eSimNotSupported_addMoreLinkNotVisible() {
+        when(mEuiccManager.isEnabled()).thenReturn(false);
+        mController.displayPreference(mPreferenceScreen);
+        mController.onResume();
+        assertThat(mAddMorePreference.isVisible()).isFalse();
+    }
+
+    @Test
+    public void displayPreference_eSimSupported_addMoreLinkIsVisible() {
+        when(mEuiccManager.isEnabled()).thenReturn(true);
+        mController.displayPreference(mPreferenceScreen);
+        mController.onResume();
+        assertThat(mAddMorePreference.isVisible()).isTrue();
+    }
+
+    @Test
     public void displayPreference_twoSubscriptions_correctlySetup() {
         final SubscriptionInfo sub1 = createMockSubscription(1, "sub1");
         final SubscriptionInfo sub2 = createMockSubscription(2, "sub2");
diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
index ba152b9..3404ca2 100644
--- a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
@@ -16,13 +16,9 @@
 
 package com.android.settings.network;
 
-import static android.telephony.TelephonyManager.MultiSimVariants.DSDS;
-import static android.telephony.TelephonyManager.MultiSimVariants.UNKNOWN;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.ArgumentMatchers.notNull;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
@@ -37,7 +33,6 @@
 import android.net.ConnectivityManager;
 import android.provider.Settings;
 import android.telephony.SubscriptionInfo;
-import android.telephony.TelephonyManager;
 import android.telephony.euicc.EuiccManager;
 import android.text.TextUtils;
 
@@ -64,8 +59,6 @@
     @Mock
     private Lifecycle mLifecycle;
     @Mock
-    private TelephonyManager mTelephonyManager;
-    @Mock
     private EuiccManager mEuiccManager;
     @Mock
     private PreferenceScreen mPreferenceScreen;
@@ -78,9 +71,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = spy(Robolectric.setupActivity(Activity.class));
-        when(mContext.getSystemService(eq(TelephonyManager.class))).thenReturn(mTelephonyManager);
         when(mContext.getSystemService(EuiccManager.class)).thenReturn(mEuiccManager);
-        when(mTelephonyManager.getMultiSimConfiguration()).thenReturn(UNKNOWN);
         when(mEuiccManager.isEnabled()).thenReturn(true);
 
         mController = new MobileNetworkSummaryController(mContext, mLifecycle);
@@ -97,7 +88,7 @@
 
     @Test
     public void isAvailable_wifiOnlyMode_notAvailable() {
-        ConnectivityManager cm = mock(ConnectivityManager.class);
+        final ConnectivityManager cm = mock(ConnectivityManager.class);
         when(cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
         when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(cm);
         assertThat(mController.isAvailable()).isFalse();
@@ -212,24 +203,7 @@
     }
 
     @Test
-    public void addButton_noSubscriptionsSingleSimMode_noAddClickListener() {
-        mController.displayPreference(mPreferenceScreen);
-        mController.onResume();
-        verify(mPreference, never()).setOnAddClickListener(notNull());
-    }
-
-    @Test
-    public void addButton_oneSubscriptionSingleSimMode_noAddClickListener() {
-        final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
-        SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
-        mController.displayPreference(mPreferenceScreen);
-        mController.onResume();
-        verify(mPreference, never()).setOnAddClickListener(notNull());
-    }
-
-    @Test
-    public void addButton_noSubscriptionsMultiSimModeNoEuiccMgr_noAddClickListener() {
-        when(mTelephonyManager.getMultiSimConfiguration()).thenReturn(DSDS);
+    public void addButton_noSubscriptionsNoEuiccMgr_noAddClickListener() {
         when(mEuiccManager.isEnabled()).thenReturn(false);
         mController.displayPreference(mPreferenceScreen);
         mController.onResume();
@@ -237,41 +211,43 @@
     }
 
     @Test
-    public void addButton_noSubscriptionsMultiSimMode_hasAddClickListenerAndPrefDisabled() {
-        when(mTelephonyManager.getMultiSimConfiguration()).thenReturn(DSDS);
-        mController.displayPreference(mPreferenceScreen);
-        mController.onResume();
-        assertThat(mPreference.isEnabled()).isFalse();
-        verify(mPreference, never()).setOnAddClickListener(isNull());
-        verify(mPreference).setOnAddClickListener(notNull());
-    }
-
-    @Test
-    public void addButton_oneSubscriptionMultiSimMode_hasAddClickListener() {
-        when(mTelephonyManager.getMultiSimConfiguration()).thenReturn(DSDS);
+    public void addButton_oneSubscriptionNoEuiccMgr_noAddClickListener() {
+        when(mEuiccManager.isEnabled()).thenReturn(false);
         final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
         SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
         mController.displayPreference(mPreferenceScreen);
         mController.onResume();
-        verify(mPreference, never()).setOnAddClickListener(isNull());
+        verify(mPreference, never()).setOnAddClickListener(notNull());
+    }
+
+    @Test
+    public void addButton_noSubscriptions_noAddClickListener() {
+        mController.displayPreference(mPreferenceScreen);
+        mController.onResume();
+        verify(mPreference, never()).setOnAddClickListener(notNull());
+    }
+
+    @Test
+    public void addButton_oneSubscription_hasAddClickListener() {
+        final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
+        mController.displayPreference(mPreferenceScreen);
+        mController.onResume();
         verify(mPreference).setOnAddClickListener(notNull());
     }
 
     @Test
-    public void addButton_twoSubscriptionsMultiSimMode_hasAddClickListener() {
-        when(mTelephonyManager.getMultiSimConfiguration()).thenReturn(DSDS);
+    public void addButton_twoSubscriptions_hasAddClickListener() {
         final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
         final SubscriptionInfo sub2 = mock(SubscriptionInfo.class);
         SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
         mController.displayPreference(mPreferenceScreen);
         mController.onResume();
-        verify(mPreference, never()).setOnAddClickListener(isNull());
         verify(mPreference).setOnAddClickListener(notNull());
     }
 
     @Test
     public void addButton_oneSubscriptionAirplaneModeTurnedOn_addButtonGetsDisabled() {
-        when(mTelephonyManager.getMultiSimConfiguration()).thenReturn(DSDS);
         final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
         SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
         mController.displayPreference(mPreferenceScreen);
@@ -280,14 +256,13 @@
         Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
         mController.onAirplaneModeChanged(true);
 
-        ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+        final ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
         verify(mPreference, atLeastOnce()).setAddWidgetEnabled(captor.capture());
         assertThat(captor.getValue()).isFalse();
     }
 
     @Test
     public void onResume_oneSubscriptionAirplaneMode_isDisabled() {
-        when(mTelephonyManager.getMultiSimConfiguration()).thenReturn(DSDS);
         Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
         final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
         SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
@@ -296,7 +271,7 @@
 
         assertThat(mPreference.isEnabled()).isFalse();
 
-        ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+        final ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
         verify(mPreference, atLeastOnce()).setAddWidgetEnabled(captor.capture());
         assertThat(captor.getValue()).isFalse();
     }
@@ -318,7 +293,6 @@
 
     @Test
     public void onAirplaneModeChanged_oneSubscriptionAirplaneModeGetsTurnedOff_isEnabled() {
-        when(mTelephonyManager.getMultiSimConfiguration()).thenReturn(DSDS);
         Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
         final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
         SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
@@ -332,7 +306,7 @@
 
         assertThat(mPreference.isEnabled()).isTrue();
 
-        ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+        final ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
         verify(mPreference, atLeastOnce()).setAddWidgetEnabled(eq(false));
         verify(mPreference, atLeastOnce()).setAddWidgetEnabled(captor.capture());
         assertThat(captor.getValue()).isTrue();
diff --git a/tests/robotests/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.java
index 2135331..e04262f 100644
--- a/tests/robotests/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.network;
 
+import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.when;
@@ -24,8 +26,10 @@
 import android.os.UserManager;
 
 import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
+import com.android.settings.testutils.shadow.ShadowUtils;
 import com.android.settings.wifi.WifiMasterSwitchPreferenceController;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -39,7 +43,7 @@
 import org.robolectric.util.ReflectionHelpers;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowRestrictedLockUtilsInternal.class)
+@Config(shadows = {ShadowRestrictedLockUtilsInternal.class, ShadowUtils.class})
 public class TopLevelNetworkEntryPreferenceControllerTest {
 
     @Mock
@@ -70,6 +74,17 @@
                 mTetherPreferenceController);
     }
 
+    @After
+    public void tearDown() {
+        ShadowUtils.reset();
+    }
+
+    @Test
+    public void getAvailabilityStatus_demoUser_unsupported() {
+        ShadowUtils.setIsDemoUser(true);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+    }
+
     @Test
     public void getSummary_hasMobileAndHotspot_shouldReturnMobileSummary() {
         when(mWifiPreferenceController.isAvailable()).thenReturn(true);
diff --git a/tests/robotests/src/com/android/settings/network/telephony/Enhanced4gLteSliceHelperTest.java b/tests/robotests/src/com/android/settings/network/telephony/Enhanced4gLteSliceHelperTest.java
index 072c835..a9882d9 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/Enhanced4gLteSliceHelperTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/Enhanced4gLteSliceHelperTest.java
@@ -22,7 +22,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -43,7 +42,6 @@
 
 import com.android.ims.ImsManager;
 import com.android.settings.R;
-import com.android.settings.slices.CustomSliceManager;
 import com.android.settings.slices.CustomSliceRegistry;
 import com.android.settings.slices.SettingsSliceProvider;
 import com.android.settings.slices.SliceBroadcastReceiver;
@@ -85,10 +83,6 @@
         mFeatureFactory = FakeFeatureFactory.setupForTest();
         mSlicesFeatureProvider = mFeatureFactory.getSlicesFeatureProvider();
 
-        CustomSliceManager manager = new CustomSliceManager(mContext);
-        when(mSlicesFeatureProvider.getCustomSliceManager(any(Context.class)))
-                .thenReturn(manager);
-
         //setup for SettingsSliceProvider tests
         mProvider = spy(new SettingsSliceProvider());
         doReturn(mContext).when(mProvider).getContext();
diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileDataSliceTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileDataSliceTest.java
index 31daa37..e488d0c 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/MobileDataSliceTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/MobileDataSliceTest.java
@@ -184,6 +184,6 @@
         final PendingIntent pendingIntent = primaryAction.getAction();
         final Intent actionIntent = pendingIntent.getIntent();
 
-        assertThat(actionIntent.getAction()).isNull();
+        assertThat(actionIntent).isNull();
     }
 }
diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java
index 55a4224..011bca5 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java
@@ -30,6 +30,8 @@
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
 
+import androidx.fragment.app.FragmentActivity;
+
 import com.android.settings.core.FeatureFlags;
 import com.android.settings.datausage.DataUsageSummaryPreferenceController;
 import com.android.settings.development.featureflags.FeatureFlagPersistent;
@@ -48,8 +50,6 @@
 
 import java.util.List;
 
-import androidx.fragment.app.FragmentActivity;
-
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = ShadowEntityHeaderController.class)
 public class MobileNetworkSettingsTest {
@@ -86,6 +86,7 @@
 
     @Test
     public void onAttach_noV2Flag_noCrash() {
+        FeatureFlagPersistent.setEnabled(mContext, FeatureFlags.NETWORK_INTERNET_V2, false);
         mFragment.onAttach(mContext);
     }
 
@@ -97,6 +98,7 @@
 
     @Test
     public void createPreferenceControllers_noV2Flag_noDataUsageSummaryController() {
+        FeatureFlagPersistent.setEnabled(mContext, FeatureFlags.NETWORK_INTERNET_V2, false);
         final List<AbstractPreferenceController> controllers =
                 mFragment.createPreferenceControllers(mContext);
         assertThat(controllers.stream().filter(
diff --git a/tests/robotests/src/com/android/settings/notification/BlockPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/BlockPreferenceControllerTest.java
index 4f6944a..bdbf40a 100644
--- a/tests/robotests/src/com/android/settings/notification/BlockPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/BlockPreferenceControllerTest.java
@@ -111,6 +111,26 @@
     }
 
     @Test
+    public void testIsAvailable_notIfChannelNonDefault() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        appRow.systemApp = true;
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
+        mController.onResume(appRow, channel, null, null);
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable_ifChannelDefault() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
+        when(channel.getId()).thenReturn(DEFAULT_CHANNEL_ID);
+        mController.onResume(appRow, channel, null, null);
+        assertTrue(mController.isAvailable());
+    }
+
+    @Test
     public void testIsAvailable_notIfGroupNotBlockable() {
         NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
         appRow.systemApp = true;
diff --git a/tests/robotests/src/com/android/settings/notification/HighImportancePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/HighImportancePreferenceControllerTest.java
new file mode 100644
index 0000000..6e6dad4
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/HighImportancePreferenceControllerTest.java
@@ -0,0 +1,199 @@
+/*
+ * 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 static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_NONE;
+
+import static org.junit.Assert.assertEquals;
+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.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.os.UserManager;
+
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+@RunWith(RobolectricTestRunner.class)
+public class HighImportancePreferenceControllerTest {
+
+    private Context mContext;
+    @Mock
+    private NotificationManager mNm;
+    @Mock
+    private NotificationBackend mBackend;
+    @Mock
+    private NotificationSettingsBase.ImportanceListener mImportanceListener;
+    @Mock
+    private UserManager mUm;
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private PreferenceScreen mScreen;
+
+    private HighImportancePreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowApplication = ShadowApplication.getInstance();
+        shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
+        shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
+        mContext = RuntimeEnvironment.application;
+        mController = spy(new HighImportancePreferenceController(
+                mContext, mImportanceListener, mBackend));
+    }
+
+    @Test
+    public void testNoCrashIfNoOnResume() {
+        mController.isAvailable();
+        mController.updateState(mock(Preference.class));
+    }
+
+    @Test
+    public void testIsAvailable_notIfNull() {
+        mController.onResume(null, null, null, null);
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable_ifAppBlocked() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        appRow.banned = true;
+        mController.onResume(appRow, mock(NotificationChannel.class), null, null);
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable_notIfChannelBlocked() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_NONE);
+        mController.onResume(appRow, channel, null, null);
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable_notForDefaultChannel() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
+        when(channel.getId()).thenReturn(DEFAULT_CHANNEL_ID);
+        mController.onResume(appRow, channel, null, null);
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_DEFAULT);
+        mController.onResume(appRow, channel, null, null);
+        assertTrue(mController.isAvailable());
+    }
+
+    @Test
+    public void testUpdateState_disabledByAdmin() {
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
+        mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
+                RestrictedLockUtils.EnforcedAdmin.class));
+
+        Preference pref = new RestrictedSwitchPreference(mContext, null);
+        mController.updateState(pref);
+
+        assertFalse(pref.isEnabled());
+    }
+
+    @Test
+    public void testUpdateState_notConfigurable() {
+        String lockedId = "locked";
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        appRow.lockedChannelId = lockedId;
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getId()).thenReturn(lockedId);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
+        mController.onResume(appRow, channel, null, null);
+
+        Preference pref = new RestrictedSwitchPreference(mContext, null);
+        mController.updateState(pref);
+
+        assertFalse(pref.isEnabled());
+    }
+
+    @Test
+    public void testUpdateState_high() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_HIGH);
+        mController.onResume(appRow, channel, null, null);
+
+        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
+        mController.updateState(pref);
+
+        assertTrue(pref.isChecked());
+    }
+
+    @Test
+    public void testUpdateState_default() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT);
+        mController.onResume(appRow, channel, null, null);
+
+        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
+        mController.updateState(pref);
+
+        assertFalse(pref.isChecked());
+    }
+    
+    @Test
+    public void onPreferenceChange() {
+        NotificationChannel channel =
+                new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_HIGH);
+        mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
+
+        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext, null);
+        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
+        mController.displayPreference(mScreen);
+        mController.updateState(pref);
+
+        mController.onPreferenceChange(pref, false);
+
+        assertEquals(IMPORTANCE_DEFAULT, channel.getImportance());
+        verify(mImportanceListener, times(1)).onImportanceChanged();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/ImportancePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ImportancePreferenceControllerTest.java
index 99d3376..c180ace 100644
--- a/tests/robotests/src/com/android/settings/notification/ImportancePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ImportancePreferenceControllerTest.java
@@ -27,8 +27,11 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.Notification;
@@ -36,12 +39,10 @@
 import android.app.NotificationManager;
 import android.content.Context;
 import android.os.UserManager;
-import android.text.TextUtils;
 
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
-import com.android.settings.RestrictedListPreference;
 import com.android.settingslib.RestrictedLockUtils;
 
 import org.junit.Before;
@@ -95,20 +96,20 @@
     }
 
     @Test
-    public void testIsAvailable_notIfAppBlocked() {
+    public void testIsAvailable_ifAppBlocked() {
         NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
         appRow.banned = true;
         mController.onResume(appRow, mock(NotificationChannel.class), null, null);
-        assertFalse(mController.isAvailable());
+        assertTrue(mController.isAvailable());
     }
 
     @Test
-    public void testIsAvailable_notIfChannelBlocked() {
+    public void testIsAvailable_evenIfChannelBlocked() {
         NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
         NotificationChannel channel = mock(NotificationChannel.class);
         when(channel.getImportance()).thenReturn(IMPORTANCE_NONE);
         mController.onResume(appRow, channel, null, null);
-        assertFalse(mController.isAvailable());
+        assertTrue(mController.isAvailable());
     }
 
     @Test
@@ -137,11 +138,10 @@
         mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
                 RestrictedLockUtils.EnforcedAdmin.class));
 
-        Preference pref = new RestrictedListPreference(mContext, null);
+        Preference pref = new ImportancePreference(mContext, null);
         mController.updateState(pref);
 
         assertFalse(pref.isEnabled());
-        assertFalse(TextUtils.isEmpty(pref.getSummary()));
     }
 
     @Test
@@ -154,11 +154,10 @@
         when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
         mController.onResume(appRow, channel, null, null);
 
-        Preference pref = new RestrictedListPreference(mContext, null);
+        Preference pref = new ImportancePreference(mContext, null);
         mController.updateState(pref);
 
         assertFalse(pref.isEnabled());
-        assertFalse(TextUtils.isEmpty(pref.getSummary()));
     }
 
     @Test
@@ -167,11 +166,12 @@
         NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_HIGH);
         mController.onResume(appRow, channel, null, null);
 
-        Preference pref = new RestrictedListPreference(mContext, null);
+        ImportancePreference pref = mock(ImportancePreference.class);
         mController.updateState(pref);
 
-        assertTrue(pref.isEnabled());
-        assertFalse(TextUtils.isEmpty(pref.getSummary()));
+        verify(pref, times(1)).setConfigurable(anyBoolean());
+        verify(pref, times(1)).setBlockable(anyBoolean());
+        verify(pref, times(1)).setImportance(IMPORTANCE_HIGH);
     }
     
     @Test
@@ -181,13 +181,12 @@
         channel.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
         mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
 
-        RestrictedListPreference pref = new RestrictedListPreference(mContext, null);
+        ImportancePreference pref = new ImportancePreference(mContext, null);
         when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
         mController.displayPreference(mScreen);
         mController.updateState(pref);
 
-        pref.setValue(String.valueOf(IMPORTANCE_HIGH));
-        mController.onPreferenceChange(pref, pref.getValue());
+        mController.onPreferenceChange(pref, IMPORTANCE_HIGH);
 
         assertEquals(IMPORTANCE_HIGH, channel.getImportance());
         assertNotNull(channel.getSound());
@@ -200,13 +199,12 @@
         channel.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
         mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
 
-        RestrictedListPreference pref = new RestrictedListPreference(mContext, null);
+        ImportancePreference pref = new ImportancePreference(mContext, null);
         when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
         mController.displayPreference(mScreen);
         mController.updateState(pref);
 
-        pref.setValue(String.valueOf(IMPORTANCE_LOW));
-        mController.onPreferenceChange(pref, pref.getValue());
+        mController.onPreferenceChange(pref, IMPORTANCE_LOW);
 
         assertEquals(IMPORTANCE_LOW, channel.getImportance());
         assertNull(channel.getSound());
diff --git a/tests/robotests/src/com/android/settings/notification/ImportancePreferenceTest.java b/tests/robotests/src/com/android/settings/notification/ImportancePreferenceTest.java
new file mode 100644
index 0000000..eebfbd1
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ImportancePreferenceTest.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2019 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 android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.LayerDrawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.Switch;
+
+import com.android.settings.R;
+import com.android.settingslib.RestrictedLockUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+@RunWith(RobolectricTestRunner.class)
+public class ImportancePreferenceTest {
+
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+    }
+
+    private GradientDrawable getBackground(ImageButton button) {
+        return (GradientDrawable) ((LayerDrawable) button.getDrawable())
+                .findDrawableByLayerId(R.id.back);
+    }
+
+    @Test
+    public void createNewPreference_shouldSetLayout() {
+        final ImportancePreference preference = new ImportancePreference(mContext);
+        assertThat(preference.getLayoutResource()).isEqualTo(
+                R.layout.notif_importance_preference);
+    }
+
+    @Test
+    public void onBindViewHolder_hideBlockNonBlockable() {
+        final ImportancePreference preference = new ImportancePreference(mContext);
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
+                inflater.inflate(R.layout.notif_importance_preference, null));
+
+        preference.setBlockable(false);
+        preference.setConfigurable(true);
+        preference.setImportance(IMPORTANCE_DEFAULT);
+        preference.onBindViewHolder(holder);
+
+        assertThat(holder.itemView.findViewById(R.id.block).getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void onBindViewHolder_hideNonSelectedNonConfigurable() {
+        final ImportancePreference preference = new ImportancePreference(mContext);
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
+                inflater.inflate(R.layout.notif_importance_preference, null));
+
+        preference.setBlockable(true);
+        preference.setConfigurable(false);
+        preference.setImportance(IMPORTANCE_DEFAULT);
+        preference.onBindViewHolder(holder);
+
+        assertThat(holder.itemView.findViewById(R.id.block).getVisibility()).isEqualTo(View.GONE);
+        assertThat(holder.itemView.findViewById(R.id.silence).getVisibility()).isEqualTo(View.GONE);
+        assertThat(holder.itemView.findViewById(R.id.alert).getVisibility())
+                .isEqualTo(View.VISIBLE);
+
+        // other button
+        preference.setImportance(IMPORTANCE_LOW);
+        holder = PreferenceViewHolder.createInstanceForTests(
+                inflater.inflate(R.layout.notif_importance_preference, null));
+        preference.onBindViewHolder(holder);
+
+        assertThat(holder.itemView.findViewById(R.id.block).getVisibility()).isEqualTo(View.GONE);
+        assertThat(holder.itemView.findViewById(R.id.silence).getVisibility())
+                .isEqualTo(View.VISIBLE);
+        assertThat(holder.itemView.findViewById(R.id.alert).getVisibility())
+                .isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void onBindViewHolder_selectButton() {
+        final ImportancePreference preference = new ImportancePreference(mContext);
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
+                inflater.inflate(R.layout.notif_importance_preference, null));
+
+        preference.setBlockable(true);
+        preference.setConfigurable(true);
+        preference.setImportance(IMPORTANCE_DEFAULT);
+
+        ImageButton blockButton = (ImageButton) holder.findViewById(R.id.block_icon);
+        ImageButton silenceButton = (ImageButton) holder.findViewById(R.id.silence_icon);
+        ImageButton alertButton = (ImageButton) holder.findViewById(R.id.alert_icon);
+
+        preference.onBindViewHolder(holder);
+
+        // selected has full color background. others are transparent
+        assertThat(getBackground(alertButton).getColor().getColors()[0]).isNotEqualTo(
+                Color.TRANSPARENT);
+        assertThat(getBackground(silenceButton).getColor().getColors()[0]).isEqualTo(
+                Color.TRANSPARENT);
+        assertThat(getBackground(blockButton).getColor().getColors()[0]).isEqualTo(
+                Color.TRANSPARENT);
+    }
+
+    @Test
+    public void onClick_changesUICallsListener() {
+        final ImportancePreference preference = spy(new ImportancePreference(mContext));
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
+                inflater.inflate(R.layout.notif_importance_preference, null));
+
+        preference.setBlockable(true);
+        preference.setConfigurable(true);
+        preference.setImportance(IMPORTANCE_DEFAULT);
+        preference.onBindViewHolder(holder);
+
+        ImageButton blockButton = (ImageButton) holder.findViewById(R.id.block_icon);
+        ImageButton silenceButton = (ImageButton) holder.findViewById(R.id.silence_icon);
+        ImageButton alertButton = (ImageButton) holder.findViewById(R.id.alert_icon);
+
+        silenceButton.callOnClick();
+
+        // selected has full color background. others are transparent
+        assertThat(getBackground(silenceButton).getColor().getColors()[0]).isNotEqualTo(
+                Color.TRANSPARENT);
+        assertThat(getBackground(alertButton).getColor().getColors()[0]).isEqualTo(
+                Color.TRANSPARENT);
+        assertThat(getBackground(blockButton).getColor().getColors()[0]).isEqualTo(
+                Color.TRANSPARENT);
+
+        verify(preference, times(1)).callChangeListener(IMPORTANCE_LOW);
+    }
+
+    @Test
+    public void onBindViewHolder_allButtonsVisible() {
+        final ImportancePreference preference = new ImportancePreference(mContext);
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
+                inflater.inflate(R.layout.notif_importance_preference, null));
+
+        preference.setBlockable(true);
+        preference.setConfigurable(true);
+        preference.onBindViewHolder(holder);
+
+        assertThat(holder.itemView.findViewById(R.id.block).getVisibility())
+                .isEqualTo(View.VISIBLE);
+        assertThat(holder.itemView.findViewById(R.id.silence).getVisibility())
+                .isEqualTo(View.VISIBLE);
+        assertThat(holder.itemView.findViewById(R.id.alert).getVisibility())
+                .isEqualTo(View.VISIBLE);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/MinImportancePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/MinImportancePreferenceControllerTest.java
new file mode 100644
index 0000000..28058a4
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/MinImportancePreferenceControllerTest.java
@@ -0,0 +1,199 @@
+/*
+ * 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 static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
+import static android.app.NotificationManager.IMPORTANCE_NONE;
+
+import static org.junit.Assert.assertEquals;
+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.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.os.UserManager;
+
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+@RunWith(RobolectricTestRunner.class)
+public class MinImportancePreferenceControllerTest {
+
+    private Context mContext;
+    @Mock
+    private NotificationManager mNm;
+    @Mock
+    private NotificationBackend mBackend;
+    @Mock
+    private NotificationSettingsBase.ImportanceListener mImportanceListener;
+    @Mock
+    private UserManager mUm;
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private PreferenceScreen mScreen;
+
+    private MinImportancePreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowApplication = ShadowApplication.getInstance();
+        shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
+        shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
+        mContext = RuntimeEnvironment.application;
+        mController = spy(new MinImportancePreferenceController(
+                mContext, mImportanceListener, mBackend));
+    }
+
+    @Test
+    public void testNoCrashIfNoOnResume() {
+        mController.isAvailable();
+        mController.updateState(mock(Preference.class));
+    }
+
+    @Test
+    public void testIsAvailable_notIfNull() {
+        mController.onResume(null, null, null, null);
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable_ifAppBlocked() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        appRow.banned = true;
+        mController.onResume(appRow, mock(NotificationChannel.class), null, null);
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable_notIfChannelBlocked() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_NONE);
+        mController.onResume(appRow, channel, null, null);
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable_notForDefaultChannel() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
+        when(channel.getId()).thenReturn(DEFAULT_CHANNEL_ID);
+        mController.onResume(appRow, channel, null, null);
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
+        mController.onResume(appRow, channel, null, null);
+        assertTrue(mController.isAvailable());
+    }
+
+    @Test
+    public void testUpdateState_disabledByAdmin() {
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
+        mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
+                RestrictedLockUtils.EnforcedAdmin.class));
+
+        Preference pref = new RestrictedSwitchPreference(mContext, null);
+        mController.updateState(pref);
+
+        assertFalse(pref.isEnabled());
+    }
+
+    @Test
+    public void testUpdateState_notConfigurable() {
+        String lockedId = "locked";
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        appRow.lockedChannelId = lockedId;
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getId()).thenReturn(lockedId);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
+        mController.onResume(appRow, channel, null, null);
+
+        Preference pref = new RestrictedSwitchPreference(mContext, null);
+        mController.updateState(pref);
+
+        assertFalse(pref.isEnabled());
+    }
+
+    @Test
+    public void testUpdateState_min() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_MIN);
+        mController.onResume(appRow, channel, null, null);
+
+        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
+        mController.updateState(pref);
+
+        assertTrue(pref.isChecked());
+    }
+
+    @Test
+    public void testUpdateState_low() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_LOW);
+        mController.onResume(appRow, channel, null, null);
+
+        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
+        mController.updateState(pref);
+
+        assertFalse(pref.isChecked());
+    }
+    
+    @Test
+    public void onPreferenceChange() {
+        NotificationChannel channel =
+                new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_LOW);
+        mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
+
+        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext, null);
+        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
+        mController.displayPreference(mScreen);
+        mController.updateState(pref);
+
+        mController.onPreferenceChange(pref, true);
+
+        assertEquals(IMPORTANCE_MIN, channel.getImportance());
+        verify(mImportanceListener, times(1)).onImportanceChanged();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/NotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/NotificationPreferenceControllerTest.java
index 1ad9378..2368af5 100644
--- a/tests/robotests/src/com/android/settings/notification/NotificationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/NotificationPreferenceControllerTest.java
@@ -219,6 +219,20 @@
     }
 
     @Test
+    public void testIsConfigurable_appLevel() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        appRow.lockedChannelId = "something";
+        appRow.lockedImportance = true;
+
+        mController.onResume(appRow, mock(NotificationChannel.class), null, null);
+        assertFalse(mController.isChannelConfigurable());
+
+        appRow.lockedImportance = false;
+        mController.onResume(appRow, mock(NotificationChannel.class), null, null);
+        assertTrue(mController.isChannelConfigurable());
+    }
+
+    @Test
     public void testIsChannelBlockable_nonSystemAppsBlockable() {
         NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
         appRow.systemApp = false;
diff --git a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
index a51b7b0..1d5c3c2 100644
--- a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
+++ b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
@@ -76,15 +76,16 @@
     }
 
     @Test
-    public void startMediaOutputSlice_withoutPackageName_bundleShouldNotHaveValue() {
+    public void startMediaOutputSlice_withoutPackageName_bundleShouldHaveValue() {
         final Intent intent = new Intent()
                 .setAction("com.android.settings.panel.action.MEDIA_OUTPUT");
 
         final SettingsPanelActivity activity =
                 Robolectric.buildActivity(SettingsPanelActivity.class, intent).create().get();
 
-        assertThat(activity.mBundle.containsKey(KEY_MEDIA_PACKAGE_NAME)).isFalse();
-        assertThat(activity.mBundle.containsKey(KEY_PANEL_TYPE_ARGUMENT)).isFalse();
+        assertThat(activity.mBundle.containsKey(KEY_MEDIA_PACKAGE_NAME)).isTrue();
+        assertThat(activity.mBundle.getString(KEY_PANEL_TYPE_ARGUMENT))
+                .isEqualTo("com.android.settings.panel.action.MEDIA_OUTPUT");
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java b/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java
index 48f9fb4..bed09cb 100644
--- a/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java
@@ -16,7 +16,7 @@
 
 package com.android.settings.password;
 
-import static android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY;
+import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;
 import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
 import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
 import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
@@ -139,7 +139,7 @@
     public void testLaunchChooseLock_setNewPasswordExtraWithPermission() {
         ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
         ShadowPasswordUtils.setCallingAppPackageName(PKG_NAME);
-        ShadowPasswordUtils.addGrantedPermission(REQUEST_SCREEN_LOCK_COMPLEXITY);
+        ShadowPasswordUtils.addGrantedPermission(REQUEST_PASSWORD_COMPLEXITY);
         Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
                 Settings.Global.DEVICE_PROVISIONED, 1);
 
@@ -169,7 +169,7 @@
     public void testLaunchChooseLock_setNewPasswordExtraInvalidValue() {
         ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
         ShadowPasswordUtils.setCallingAppPackageName(PKG_NAME);
-        ShadowPasswordUtils.addGrantedPermission(REQUEST_SCREEN_LOCK_COMPLEXITY);
+        ShadowPasswordUtils.addGrantedPermission(REQUEST_PASSWORD_COMPLEXITY);
         Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
                 Settings.Global.DEVICE_PROVISIONED, 1);
 
@@ -197,7 +197,7 @@
     public void testLaunchChooseLock_setNewPasswordExtraNoneComplexity() {
         ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
         ShadowPasswordUtils.setCallingAppPackageName(PKG_NAME);
-        ShadowPasswordUtils.addGrantedPermission(REQUEST_SCREEN_LOCK_COMPLEXITY);
+        ShadowPasswordUtils.addGrantedPermission(REQUEST_PASSWORD_COMPLEXITY);
         Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
                 Settings.Global.DEVICE_PROVISIONED, 1);
 
@@ -225,7 +225,7 @@
     public void testLaunchChooseLock_setNewPasswordWithoutExtra() {
         ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
         ShadowPasswordUtils.setCallingAppPackageName(PKG_NAME);
-        ShadowPasswordUtils.addGrantedPermission(REQUEST_SCREEN_LOCK_COMPLEXITY);
+        ShadowPasswordUtils.addGrantedPermission(REQUEST_PASSWORD_COMPLEXITY);
         Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
                 Settings.Global.DEVICE_PROVISIONED, 1);
 
@@ -252,7 +252,7 @@
     public void testLaunchChooseLock_setNewParentProfilePasswordExtraWithPermission() {
         ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
         ShadowPasswordUtils.setCallingAppPackageName(PKG_NAME);
-        ShadowPasswordUtils.addGrantedPermission(REQUEST_SCREEN_LOCK_COMPLEXITY);
+        ShadowPasswordUtils.addGrantedPermission(REQUEST_PASSWORD_COMPLEXITY);
         Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
                 Settings.Global.DEVICE_PROVISIONED, 1);
 
@@ -280,7 +280,7 @@
     public void testLaunchChooseLock_setNewParentProfilePasswordWithoutExtra() {
         ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
         ShadowPasswordUtils.setCallingAppPackageName(PKG_NAME);
-        ShadowPasswordUtils.addGrantedPermission(REQUEST_SCREEN_LOCK_COMPLEXITY);
+        ShadowPasswordUtils.addGrantedPermission(REQUEST_PASSWORD_COMPLEXITY);
         Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
                 Settings.Global.DEVICE_PROVISIONED, 1);
 
diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java
index d35b38a..cd79f58 100644
--- a/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java
@@ -16,7 +16,7 @@
 
 package com.android.settings.password;
 
-import static android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY;
+import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
 
 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
@@ -68,7 +68,7 @@
     @Test
     @Config(shadows = {ShadowPasswordUtils.class})
     public void setupChooseLockGenericPasswordComplexityExtraWithPermission() {
-        ShadowPasswordUtils.addGrantedPermission(REQUEST_SCREEN_LOCK_COMPLEXITY);
+        ShadowPasswordUtils.addGrantedPermission(REQUEST_PASSWORD_COMPLEXITY);
 
         Intent intent = new Intent("com.android.settings.SETUP_LOCK_SCREEN");
         intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
index a693f34..23025b2 100644
--- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
@@ -135,7 +135,6 @@
         mProvider.mSliceWeakDataCache = new HashMap<>();
         mProvider.mSliceDataCache = new HashMap<>();
         mProvider.mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(mContext);
-        mProvider.mCustomSliceManager = new CustomSliceManager(mContext);
         when(mProvider.getContext()).thenReturn(mContext);
 
         SlicesDatabaseHelper.getInstance(mContext).setIndexedState();
diff --git a/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java
index 74f4ac2..1ea324d 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java
@@ -19,14 +19,12 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.app.settings.SettingsEnums;
 import android.app.slice.Slice;
@@ -82,9 +80,6 @@
         mSearchFeatureProvider = new SearchFeatureProviderImpl();
         mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
         mFakeFeatureFactory.searchFeatureProvider = mSearchFeatureProvider;
-        CustomSliceManager manager = new CustomSliceManager(mContext);
-        when(mFakeFeatureFactory.slicesFeatureProvider.getCustomSliceManager(any()))
-                .thenReturn(manager);
     }
 
     @After
diff --git a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java
index 0e92c05..96bca07 100644
--- a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java
@@ -55,6 +55,7 @@
     @After
     public void cleanUp() {
         DatabaseTestUtils.clearDb(mContext);
+        mDatabase.close();
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/slices/SpecialCaseSliceManagerTest.java b/tests/robotests/src/com/android/settings/slices/SpecialCaseSliceManagerTest.java
index 82726df..d483f9e 100644
--- a/tests/robotests/src/com/android/settings/slices/SpecialCaseSliceManagerTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SpecialCaseSliceManagerTest.java
@@ -19,8 +19,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.Mockito.spy;
-
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -39,44 +37,50 @@
 @RunWith(RobolectricTestRunner.class)
 public class SpecialCaseSliceManagerTest {
 
-    private Context mContext;
+    private final String FAKE_PARAMETER_KEY = "fake_parameter_key";
+    private final String FAKE_PARAMETER_VALUE = "fake_value";
 
-    private CustomSliceManager mCustomSliceManager;
+    private Context mContext;
 
     @Before
     public void setUp() {
         mContext = RuntimeEnvironment.application;
-        mCustomSliceManager = spy(new CustomSliceManager(mContext));
-        mCustomSliceManager.mUriMap.clear();
-        mCustomSliceManager.mUriMap.put(FakeSliceable.URI, FakeSliceable.class);
+        CustomSliceRegistry.sUriToSlice.clear();
+        CustomSliceRegistry.sUriToSlice.put(FakeSliceable.URI, FakeSliceable.class);
     }
 
     @Test
     public void getSliceableFromUri_returnsCorrectObject() {
-        final CustomSliceable sliceable = mCustomSliceManager.getSliceableFromUri(
-                FakeSliceable.URI);
+        final CustomSliceable sliceable = CustomSliceable.createInstance(
+                mContext, CustomSliceRegistry.getSliceClassByUri(FakeSliceable.URI));
 
         assertThat(sliceable).isInstanceOf(FakeSliceable.class);
     }
 
     @Test
-    public void getSliceableFromIntentAction_returnsCorrectObject() {
-        final CustomSliceable sliceable =
-                mCustomSliceManager.getSliceableFromIntentAction(FakeSliceable.URI.toString());
+    public void getSliceableFromUriWithParameter_returnsCorrectObject() {
+        final Uri parameterUri = FakeSliceable.URI
+                .buildUpon()
+                .clearQuery()
+                .appendQueryParameter(FAKE_PARAMETER_KEY, FAKE_PARAMETER_VALUE)
+                .build();
+
+        final CustomSliceable sliceable = CustomSliceable.createInstance(
+                mContext, CustomSliceRegistry.getSliceClassByUri(parameterUri));
 
         assertThat(sliceable).isInstanceOf(FakeSliceable.class);
     }
 
     @Test
     public void isValidUri_validUri_returnsTrue() {
-        final boolean isValidUri = mCustomSliceManager.isValidUri(FakeSliceable.URI);
+        final boolean isValidUri = CustomSliceRegistry.isValidUri(FakeSliceable.URI);
 
         assertThat(isValidUri).isTrue();
     }
 
     @Test
     public void isValidUri_invalidUri_returnsFalse() {
-        final boolean isValidUri = mCustomSliceManager.isValidUri(null);
+        final boolean isValidUri = CustomSliceRegistry.isValidUri(null);
 
         assertThat(isValidUri).isFalse();
     }
@@ -84,14 +88,14 @@
     @Test
     public void isValidAction_validActions_returnsTrue() {
         final boolean isValidAction =
-                mCustomSliceManager.isValidAction(FakeSliceable.URI.toString());
+                CustomSliceRegistry.isValidAction(FakeSliceable.URI.toString());
 
         assertThat(isValidAction).isTrue();
     }
 
     @Test
     public void isValidAction_invalidAction_returnsFalse() {
-        final boolean isValidAction = mCustomSliceManager.isValidAction("action");
+        final boolean isValidAction = CustomSliceRegistry.isValidAction("action");
 
         assertThat(isValidAction).isFalse();
     }
diff --git a/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java
index 54a79f4..5b7c863 100644
--- a/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java
@@ -238,63 +238,6 @@
         verify(mLocalBluetoothManager).setForegroundActivity(null);
     }
 
-    @Test
-    public void onPreferenceChange_toThisDevice_shouldSetDefaultSummary() {
-        mController.mConnectedDevices.clear();
-        mController.mConnectedDevices.add(mBluetoothDevice);
-
-        mController.onPreferenceChange(mPreference,
-                mContext.getText(R.string.media_output_default_summary));
-
-        assertThat(mPreference.getSummary()).isEqualTo(
-                mContext.getText(R.string.media_output_default_summary));
-    }
-
-    /**
-     * One Bluetooth devices are available, and select the device.
-     * Preference summary should be device name.
-     */
-    @Test
-    public void onPreferenceChange_toBtDevice_shouldSetBtDeviceName() {
-        mController.mConnectedDevices.clear();
-        mController.mConnectedDevices.add(mBluetoothDevice);
-
-        mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_1);
-
-        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_1);
-    }
-
-    /**
-     * More than one Bluetooth devices are available, and select second device.
-     * Preference summary should be second device name.
-     */
-    @Test
-    public void onPreferenceChange_toBtDevices_shouldSetSecondBtDeviceName() {
-        ShadowBluetoothDevice shadowBluetoothDevice;
-        BluetoothDevice secondBluetoothDevice;
-        secondBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_2);
-        shadowBluetoothDevice = Shadows.shadowOf(secondBluetoothDevice);
-        shadowBluetoothDevice.setName(TEST_DEVICE_NAME_2);
-        mController.mConnectedDevices.clear();
-        mController.mConnectedDevices.add(mBluetoothDevice);
-        mController.mConnectedDevices.add(secondBluetoothDevice);
-
-        mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_2);
-
-        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_2);
-    }
-
-    /**
-     * mConnectedDevices is empty.
-     * onPreferenceChange should return false.
-     */
-    @Test
-    public void onPreferenceChange_connectedDeviceIsNull_shouldReturnFalse() {
-        mController.mConnectedDevices.clear();
-
-        assertThat(mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_1)).isFalse();
-    }
-
     /**
      * Audio stream output to bluetooth sco headset which is the subset of all sco device.
      * isStreamFromOutputDevice should return true.
@@ -416,39 +359,6 @@
     }
 
     /**
-     * One A2dp device is connected.
-     * getConnectedA2dpDevices should add this device to list.
-     */
-    @Test
-    public void getConnectedA2dpDevices_oneConnectedA2dpDevice_shouldAddDeviceToList() {
-        mEmptyDevices.clear();
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-
-        mEmptyDevices.addAll(mController.getConnectedA2dpDevices());
-
-        assertThat(mEmptyDevices).containsExactly(mBluetoothDevice);
-    }
-
-    /**
-     * More than one A2dp devices are connected.
-     * getConnectedA2dpDevices should add all devices to list.
-     */
-    @Test
-    public void getConnectedA2dpDevices_moreThanOneConnectedA2dpDevice_shouldAddDeviceToList() {
-        mEmptyDevices.clear();
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-
-        mEmptyDevices.addAll(mController.getConnectedA2dpDevices());
-
-        assertThat(mEmptyDevices).containsExactly(mBluetoothDevice, mLeftBluetoothHapDevice);
-    }
-
-    /**
      * One hands free profile device is connected.
      * getConnectedA2dpDevices should add this device to list.
      */
@@ -488,10 +398,6 @@
         }
 
         @Override
-        public void setActiveBluetoothDevice(BluetoothDevice device) {
-        }
-
-        @Override
         public BluetoothDevice findActiveDevice() {
             return null;
         }
diff --git a/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java
index 4010145..0eada60 100644
--- a/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java
@@ -57,6 +57,7 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowBluetoothDevice;
 
@@ -107,7 +108,7 @@
     private BluetoothDevice mLeftBluetoothHapDevice;
     private BluetoothDevice mRightBluetoothHapDevice;
     private LocalBluetoothManager mLocalBluetoothManager;
-    private AudioSwitchPreferenceController mController;
+    private HandsFreeProfileOutputPreferenceController mController;
     private List<BluetoothDevice> mProfileConnectedDevices;
     private List<BluetoothDevice> mHearingAidActiveDevices;
 
@@ -478,4 +479,61 @@
 
         assertThat(mController.findActiveDevice()).isNull();
     }
+
+    /**
+     * One Bluetooth devices are available, and select the device.
+     * Preference summary should be device name.
+     */
+    @Test
+    public void onPreferenceChange_toBtDevice_shouldSetBtDeviceName() {
+        mController.mConnectedDevices.clear();
+        mController.mConnectedDevices.add(mBluetoothDevice);
+
+        mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_1);
+
+        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_1);
+    }
+
+    /**
+     * More than one Bluetooth devices are available, and select second device.
+     * Preference summary should be second device name.
+     */
+    @Test
+    public void onPreferenceChange_toBtDevices_shouldSetSecondBtDeviceName() {
+        ShadowBluetoothDevice shadowBluetoothDevice;
+        BluetoothDevice secondBluetoothDevice;
+        secondBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_2);
+        shadowBluetoothDevice = Shadows.shadowOf(secondBluetoothDevice);
+        shadowBluetoothDevice.setName(TEST_DEVICE_NAME_2);
+        mController.mConnectedDevices.clear();
+        mController.mConnectedDevices.add(mBluetoothDevice);
+        mController.mConnectedDevices.add(secondBluetoothDevice);
+
+        mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_2);
+
+        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_2);
+    }
+
+    /**
+     * mConnectedDevices is empty.
+     * onPreferenceChange should return false.
+     */
+    @Test
+    public void onPreferenceChange_connectedDeviceIsNull_shouldReturnFalse() {
+        mController.mConnectedDevices.clear();
+
+        assertThat(mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_1)).isFalse();
+    }
+
+    @Test
+    public void onPreferenceChange_toThisDevice_shouldSetDefaultSummary() {
+        mController.mConnectedDevices.clear();
+        mController.mConnectedDevices.add(mBluetoothDevice);
+
+        mController.onPreferenceChange(mPreference,
+                mContext.getText(R.string.media_output_default_summary));
+
+        assertThat(mPreference.getSummary()).isEqualTo(
+                mContext.getText(R.string.media_output_default_summary));
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
index 8c7faef..7fcd3d2 100644
--- a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
@@ -17,16 +17,15 @@
 package com.android.settings.sound;
 
 import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
+import static android.media.AudioSystem.DEVICE_OUT_EARPIECE;
 import static android.media.AudioSystem.DEVICE_OUT_HEARING_AID;
 import static android.media.AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -34,9 +33,10 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothManager;
 import android.content.Context;
+import android.content.Intent;
 import android.media.AudioManager;
 
-import androidx.preference.ListPreference;
+import androidx.preference.Preference;
 import androidx.preference.PreferenceManager;
 import androidx.preference.PreferenceScreen;
 
@@ -49,11 +49,13 @@
 import com.android.settingslib.bluetooth.HearingAidProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.settingslib.media.MediaOutputSliceConstants;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
@@ -80,8 +82,6 @@
     private static final String TEST_DEVICE_ADDRESS_2 = "00:B2:B2:B2:B2:B2";
     private static final String TEST_DEVICE_ADDRESS_3 = "00:C3:C3:C3:C3:C3";
     private static final String TEST_DEVICE_ADDRESS_4 = "00:D4:D4:D4:D4:D4";
-    private final static long HISYNCID1 = 10;
-    private final static long HISYNCID2 = 11;
 
     @Mock
     private LocalBluetoothManager mLocalManager;
@@ -98,7 +98,7 @@
 
     private Context mContext;
     private PreferenceScreen mScreen;
-    private ListPreference mPreference;
+    private Preference mPreference;
     private AudioManager mAudioManager;
     private ShadowAudioManager mShadowAudioManager;
     private BluetoothManager mBluetoothManager;
@@ -108,8 +108,8 @@
     private BluetoothDevice mLeftBluetoothHapDevice;
     private BluetoothDevice mRightBluetoothHapDevice;
     private LocalBluetoothManager mLocalBluetoothManager;
-    private AudioSwitchPreferenceController mController;
-    private List<BluetoothDevice> mProfileConnectedDevices;
+    private MediaOutputPreferenceController mController;
+    private List<BluetoothDevice> mProfileConnectableDevices;
     private List<BluetoothDevice> mHearingAidActiveDevices;
 
     @Before
@@ -149,8 +149,8 @@
 
         mController = new MediaOutputPreferenceController(mContext, TEST_KEY);
         mScreen = spy(new PreferenceScreen(mContext, null));
-        mPreference = new ListPreference(mContext);
-        mProfileConnectedDevices = new ArrayList<>();
+        mPreference = new Preference(mContext);
+        mProfileConnectableDevices = new ArrayList<>();
         mHearingAidActiveDevices = new ArrayList<>(2);
 
         when(mScreen.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
@@ -166,61 +166,140 @@
         ShadowBluetoothUtils.reset();
     }
 
+
     /**
-     * In normal mode, bluetooth device with HisyncId.
-     * HearingAidProfile should set active device to this device.
+     * A2DP Bluetooth device(s) are not connected nor previously connected
+     * Preference should be invisible
      */
     @Test
-    public void setActiveBluetoothDevice_btDeviceWithHisyncId_shouldSetBtDeviceActive() {
+    public void updateState_withoutConnectableBtDevice_preferenceInvisible() {
+        mShadowAudioManager.setOutputDevice(DEVICE_OUT_EARPIECE);
         mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
+        mProfileConnectableDevices.clear();
+        when(mA2dpProfile.getConnectableDevices()).thenReturn(mProfileConnectableDevices);
+        mPreference.setVisible(true);
 
-        mController.setActiveBluetoothDevice(mLeftBluetoothHapDevice);
-
-        verify(mHearingAidProfile).setActiveDevice(mLeftBluetoothHapDevice);
-        verify(mA2dpProfile, never()).setActiveDevice(mLeftBluetoothHapDevice);
+        assertThat(mPreference.isVisible()).isTrue();
+        mController.updateState(mPreference);
+        assertThat(mPreference.isVisible()).isFalse();
     }
 
     /**
-     * In normal mode, bluetooth device without HisyncId.
-     * A2dpProfile should set active device to this device.
+     * A2DP Bluetooth device(s) are connectable, no matter active or inactive
+     * Preference should be visible
      */
     @Test
-    public void setActiveBluetoothDevice_btDeviceWithoutHisyncId_shouldSetBtDeviceActive() {
+    public void updateState_withConnectableBtDevice_preferenceVisible() {
+        mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_A2DP);
         mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        mProfileConnectableDevices.clear();
+        mProfileConnectableDevices.add(mBluetoothDevice);
+        when(mA2dpProfile.getConnectableDevices()).thenReturn(mProfileConnectableDevices);
+        assertThat(mPreference.isVisible()).isFalse();
 
-        mController.setActiveBluetoothDevice(mBluetoothDevice);
+        // Without Active Bluetooth Device
+        mController.updateState(mPreference);
+        assertThat(mPreference.isVisible()).isTrue();
 
-        verify(mA2dpProfile).setActiveDevice(mBluetoothDevice);
-        verify(mHearingAidProfile, never()).setActiveDevice(mBluetoothDevice);
+        // With Active Bluetooth Device
+        when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
+        mController.updateState(mPreference);
+        assertThat(mPreference.isVisible()).isTrue();
     }
 
     /**
-     * In normal mode, set active device to "this device".
-     * A2dpProfile should set to null.
-     * HearingAidProfile should set to null.
+     * A2DP Bluetooth device(s) are connectable, but no device is set as activated
+     * Preference summary should be "This device"
      */
     @Test
-    public void setActiveBluetoothDevice_setNull_shouldSetNullToBothProfiles() {
+    public void updateState_withConnectableBtDevice_withoutActiveBtDevice_setDefaultSummary() {
+        mShadowAudioManager.setOutputDevice(DEVICE_OUT_EARPIECE);
         mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        mProfileConnectableDevices.clear();
+        mProfileConnectableDevices.add(mBluetoothDevice);
+        mProfileConnectableDevices.add(mSecondBluetoothDevice);
+        when(mA2dpProfile.getConnectableDevices()).thenReturn(mProfileConnectableDevices);
+        when(mA2dpProfile.getActiveDevice()).thenReturn(null);
 
-        mController.setActiveBluetoothDevice(null);
-
-        verify(mA2dpProfile).setActiveDevice(null);
-        verify(mHearingAidProfile).setActiveDevice(null);
+        assertThat(mPreference.getSummary()).isNull();
+        mController.updateState(mPreference);
+        assertThat(mPreference.getSummary()).isEqualTo(
+                mContext.getText(R.string.media_output_default_summary));
     }
 
     /**
-     * During a call
-     * A2dpProfile should not set active device.
+     * A2DP Bluetooth device(s) are connected and active
+     * Preference summary should be device's name
      */
     @Test
-    public void setActiveBluetoothDevice_duringACall_shouldNotSetActiveDeviceToA2dpProfile() {
-        mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
+    public void updateState_withActiveBtDevice_setActivatedDeviceName() {
+        mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_A2DP);
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        mProfileConnectableDevices.clear();
+        mProfileConnectableDevices.add(mBluetoothDevice);
+        mProfileConnectableDevices.add(mSecondBluetoothDevice);
+        when(mA2dpProfile.getConnectableDevices()).thenReturn(mProfileConnectableDevices);
+        when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
 
-        mController.setActiveBluetoothDevice(mBluetoothDevice);
+        assertThat(mPreference.getSummary()).isNull();
+        mController.updateState(mPreference);
+        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_1);
+    }
 
-        verify(mA2dpProfile, times(0)).setActiveDevice(any(BluetoothDevice.class));
+
+    /**
+     * Hearing Aid device(s) are connectable, no matter active or inactive
+     * Preference should be visible
+     */
+    @Test
+    public void updateState_withConnectableHADevice_preferenceVisible() {
+        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        mHearingAidActiveDevices.clear();
+        mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
+        when(mHearingAidProfile.getConnectableDevices()).thenReturn(mHearingAidActiveDevices);
+        assertThat(mPreference.isVisible()).isFalse();
+
+        // Without Active Hearing Aid Device
+        mController.updateState(mPreference);
+        assertThat(mPreference.isVisible()).isTrue();
+
+        // With Active Hearing Aid Device
+        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
+        mController.updateState(mPreference);
+        assertThat(mPreference.isVisible()).isTrue();
+    }
+
+    /**
+     * Hearing Aid device(s) are connected and active
+     * Preference summary should be device's name
+     */
+    @Test
+    public void updateState_withActiveHADevice_setActivatedDeviceName() {
+        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        mHearingAidActiveDevices.clear();
+        mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
+        when(mHearingAidProfile.getConnectableDevices()).thenReturn(mHearingAidActiveDevices);
+        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
+
+        assertThat(mPreference.getSummary()).isNull();
+        mController.updateState(mPreference);
+        assertThat(mPreference.getSummary()).isEqualTo(TEST_HAP_DEVICE_NAME_1);
+
+    }
+
+    @Test
+    public void click_launch_outputSwitcherSlice() {
+        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        mController.handlePreferenceTreeClick(mPreference);
+        verify(mContext, never()).startActivity(intentCaptor.capture());
+
+        mPreference.setKey(TEST_KEY);
+        mController.handlePreferenceTreeClick(mPreference);
+        verify(mContext).startActivity(intentCaptor.capture());
+        assertThat(intentCaptor.getValue().getAction())
+                .isEqualTo(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT);
     }
 
     /**
@@ -254,24 +333,6 @@
     }
 
     /**
-     * No available A2dp BT devices:
-     * Preference should be invisible
-     * Preference summary should be "This device"
-     */
-    @Test
-    public void updateState_noAvailableA2dpBtDevices_shouldDisableAndSetDefaultSummary() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        List<BluetoothDevice> emptyDeviceList = new ArrayList<>();
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(emptyDeviceList);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isFalse();
-        String defaultString = mContext.getString(R.string.media_output_default_summary);
-        assertThat(mPreference.getSummary()).isEqualTo(defaultString);
-    }
-
-    /**
      * Media stream is captured by something else (cast device):
      * Preference should be invisible
      * Preference summary should be "unavailable"
@@ -287,235 +348,6 @@
         assertThat(mPreference.getSummary()).isEqualTo(defaultString);
     }
 
-    /**
-     * One A2DP Bluetooth device is available and active.
-     * Preference should be visible
-     * Preference summary should be the activated device name
-     */
-    @Test
-    public void updateState_oneA2dpBtDeviceAreAvailable_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_A2DP);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_1);
-    }
-
-    /**
-     * More than one A2DP Bluetooth devices are available, and second device is active.
-     * Preference should be visible
-     * Preference summary should be the activated device name
-     */
-    @Test
-    public void updateState_moreThanOneA2DpBtDevicesAreAvailable_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_A2DP);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        mProfileConnectedDevices.add(mSecondBluetoothDevice);
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mA2dpProfile.getActiveDevice()).thenReturn(mSecondBluetoothDevice);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_2);
-    }
-
-    /**
-     * A2DP Bluetooth device(s) are available, but wired headset is plugged in and activated
-     * Preference should be visible
-     * Preference summary should be "This device"
-     */
-    @Test
-    public void updateState_a2dpDevicesAvailableWiredHeadsetIsActivated_shouldSetDefaultSummary() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(null);
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mA2dpProfile.getActiveDevice()).thenReturn(null);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(
-                mContext.getString(R.string.media_output_default_summary));
-    }
-
-
-    /**
-     * A2DP Bluetooth device(s) are available, but current device speaker is activated
-     * Preference should be visible
-     * Preference summary should be "This device"
-     */
-    @Test
-    public void updateState_a2dpDevicesAvailableCurrentDeviceActivated_shouldSetDefaultSummary() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mA2dpProfile.getActiveDevice()).thenReturn(null);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(
-                mContext.getString(R.string.media_output_default_summary));
-    }
-
-    /**
-     * One hearing aid profile Bluetooth device is available and active.
-     * Preference should be visible
-     * Preference summary should be the activated device name
-     */
-    @Test
-    public void updateState_oneHapBtDeviceAreAvailable_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
-        mHearingAidActiveDevices.clear();
-        mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
-        when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
-        when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(mLeftBluetoothHapDevice.getName());
-    }
-
-    /**
-     * More than one hearing aid profile Bluetooth devices are available, and second
-     * device is active.
-     * Preference should be visible
-     * Preference summary should be the activated device name
-     */
-    @Test
-    public void updateState_moreThanOneHapBtDevicesAreAvailable_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
-        mProfileConnectedDevices.add(mRightBluetoothHapDevice);
-        mHearingAidActiveDevices.clear();
-        mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
-        when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
-        when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
-        when(mHearingAidProfile.getHiSyncId(mRightBluetoothHapDevice)).thenReturn(HISYNCID2);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(mRightBluetoothHapDevice.getName());
-    }
-
-    /**
-     * Both hearing aid profile and A2dp Bluetooth devices are available, and two hearing aid
-     * profile devices with same HisyncId are active. Both of HAP device are active,
-     * "left" side HAP device is added first.
-     * Preference should be visible
-     * Preference summary should be the activated device name
-     * ConnectedDevice should not contain second HAP device with same HisyncId
-     */
-    @Test
-    public void updateState_hapBtDeviceWithSameId_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        //with same HisyncId, first one will remain in UI.
-        mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
-        mProfileConnectedDevices.add(mRightBluetoothHapDevice);
-        mHearingAidActiveDevices.clear();
-        mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
-        mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
-        when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
-        when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
-        when(mHearingAidProfile.getHiSyncId(mRightBluetoothHapDevice)).thenReturn(HISYNCID1);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(mLeftBluetoothHapDevice.getName());
-        assertThat(mController.mConnectedDevices.contains(mLeftBluetoothHapDevice)).isTrue();
-        assertThat(mController.mConnectedDevices.contains(mRightBluetoothHapDevice)).isFalse();
-    }
-
-    /**
-     * Both hearing aid profile and A2dp Bluetooth devices are available, and two hearing aid
-     * profile devices with same HisyncId. Both of HAP device are active,
-     * "right" side HAP device is added first.
-     * Preference should be visible
-     * Preference summary should be the activated device name
-     * ConnectedDevice should not contain second HAP device with same HisyncId
-     */
-    @Test
-    public void updateState_hapBtDeviceWithSameIdButDifferentOrder_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        //with same HisyncId, first one will remain in UI.
-        mProfileConnectedDevices.add(mRightBluetoothHapDevice);
-        mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
-        mHearingAidActiveDevices.clear();
-        mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
-        mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
-        when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
-        when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
-        when(mHearingAidProfile.getHiSyncId(mRightBluetoothHapDevice)).thenReturn(HISYNCID1);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(mRightBluetoothHapDevice.getName());
-        assertThat(mController.mConnectedDevices.contains(mRightBluetoothHapDevice)).isTrue();
-        assertThat(mController.mConnectedDevices.contains(mLeftBluetoothHapDevice)).isFalse();
-    }
-
-    /**
-     * Both hearing aid profile and A2dp Bluetooth devices are available, and two hearing aid
-     * profile devices with different HisyncId. One of HAP device is active.
-     * Preference should be visible
-     * Preference summary should be the activated device name
-     * ConnectedDevice should contain both HAP device with different HisyncId
-     */
-    @Test
-    public void updateState_hapBtDeviceWithDifferentId_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
-        mProfileConnectedDevices.add(mRightBluetoothHapDevice);
-        mHearingAidActiveDevices.clear();
-        mHearingAidActiveDevices.add(null);
-        mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
-        when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
-        when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
-        when(mHearingAidProfile.getHiSyncId(mRightBluetoothHapDevice)).thenReturn(HISYNCID2);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(mRightBluetoothHapDevice.getName());
-        assertThat(mController.mConnectedDevices).containsExactly(mBluetoothDevice,
-                mLeftBluetoothHapDevice, mRightBluetoothHapDevice);
-    }
-
     @Test
     public void findActiveDevice_onlyA2dpDeviceActive_returnA2dpDevice() {
         when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(null);
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDisclaimerItemFactory.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDisclaimerItemFactory.java
new file mode 100644
index 0000000..c50d4f1
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDisclaimerItemFactory.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.testutils.shadow;
+
+import android.content.Context;
+
+import com.android.settings.wifi.calling.DisclaimerItemFactory;
+import com.android.settings.wifi.calling.DisclaimerItem;
+
+import java.util.List;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+@Implements(DisclaimerItemFactory.class)
+public final class ShadowDisclaimerItemFactory {
+    private static List<DisclaimerItem> sMockDisclaimerItemList;
+
+    public static void setDisclaimerItemList(List<DisclaimerItem> list) {
+        sMockDisclaimerItemList = list;
+    }
+
+    @Implementation
+    public static List<DisclaimerItem> create(Context context, int subId) {
+        return sMockDisclaimerItemList;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/DisclaimerItemListAdapterTest.java b/tests/robotests/src/com/android/settings/wifi/calling/DisclaimerItemListAdapterTest.java
new file mode 100644
index 0000000..4cfc9ba
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/calling/DisclaimerItemListAdapterTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.calling;
+
+import static com.android.settings.wifi.calling.DisclaimerItemListAdapter
+        .DisclaimerItemViewHolder.ID_DISCLAIMER_ITEM_TITLE;
+import static com.android.settings.wifi.calling.DisclaimerItemListAdapter
+        .DisclaimerItemViewHolder.ID_DISCLAIMER_ITEM_DESCRIPTION;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.settings.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+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;
+
+@RunWith(RobolectricTestRunner.class)
+public class DisclaimerItemListAdapterTest {
+
+    private static final int ITEM_POSITION = 0;
+    private static final int DISCLAIMER_TITLE_STRING_ID = 0;
+    private static final int DISCLAIMER_MESSAGE_STRING_ID = 1;
+
+    @Mock
+    private LayoutInflater mLayoutInflater;
+    @Mock
+    private TextView mTestView;
+    @Mock
+    private TextView mDescView;
+    @Mock
+    private View mView;
+    @Mock
+    private ViewGroup mViewGroup;
+    @Mock
+    private Context mContext;
+
+    private MockDisclaimerItem mDisclaimerItem;
+    private DisclaimerItemListAdapter mDisclaimerItemListAdapter;
+    private List<DisclaimerItem> mDisclaimerItemList = new ArrayList<>();
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mDisclaimerItem = spy(new MockDisclaimerItem(mContext, 0 /* subId */));
+        mDisclaimerItemList.add(mDisclaimerItem);
+
+        when(mLayoutInflater.inflate(anyInt(), anyObject(), anyBoolean())).thenReturn(mView);
+        when(mViewGroup.getContext()).thenReturn(mContext);
+        when(mViewGroup.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).thenReturn(
+                mLayoutInflater);
+        when(mView.findViewById(ID_DISCLAIMER_ITEM_TITLE)).thenReturn(mTestView);
+        when(mView.findViewById(ID_DISCLAIMER_ITEM_DESCRIPTION)).thenReturn(mDescView);
+    }
+
+    @Test
+    public void onBindViewHolder_haveItem_shouldSetText() {
+        final DisclaimerItemListAdapter.DisclaimerItemViewHolder viewHolder =
+                new DisclaimerItemListAdapter.DisclaimerItemViewHolder(mView);
+
+        mDisclaimerItemListAdapter = new DisclaimerItemListAdapter(mDisclaimerItemList);
+        mDisclaimerItemListAdapter.onCreateViewHolder(mViewGroup, 0 /* viewType */);
+        mDisclaimerItemListAdapter.onBindViewHolder(viewHolder, ITEM_POSITION);
+
+        // Check the text is set when the DisclaimerItem exists.
+        verify(viewHolder.titleView).setText(DISCLAIMER_TITLE_STRING_ID);
+        verify(viewHolder.descriptionView).setText(DISCLAIMER_MESSAGE_STRING_ID);
+    }
+
+    private class MockDisclaimerItem extends DisclaimerItem {
+        MockDisclaimerItem(Context context, int subId) {
+            super(context, subId);
+        }
+
+        @Override
+        protected int getTitleId() {
+            return DISCLAIMER_TITLE_STRING_ID;
+        }
+
+        @Override
+        protected int getMessageId() {
+            return DISCLAIMER_MESSAGE_STRING_ID;
+        }
+
+        @Override
+        protected String getName() {
+            return "MockDisclaimerItem";
+        }
+
+        @Override
+        protected String getPrefKey() {
+            return "mock_pref_key";
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/ListWithEntrySummaryPreferenceTest.java b/tests/robotests/src/com/android/settings/wifi/calling/ListWithEntrySummaryPreferenceTest.java
new file mode 100644
index 0000000..307c0ac
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/calling/ListWithEntrySummaryPreferenceTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.calling;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.Parcelable;
+import android.widget.ListAdapter;
+import android.widget.TextView;
+
+import androidx.appcompat.app.AlertDialog;
+
+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 ListWithEntrySummaryPreferenceTest {
+
+    private Context mContext;
+    private ListWithEntrySummaryPreference mPreference;
+
+    private CharSequence[] mDefaultEntries =
+            {"default_entry1", "default_entry2", "default_entry3"};
+    private CharSequence[] mDefaultEntryValues = {"0", "1", "2"};
+    private CharSequence[] mDefaultEntrySummaries =
+            {"default_summary1", "default_summary2", "default_summary3"};
+
+    private CharSequence[] mCustomEntries = {"custom_entry1", "custom_entry2"};
+    private CharSequence[] mCustomEntryValues = {"0", "1"};
+    private CharSequence[] mCustomEntrySummaries = {"custom_summary1", "custom_summary2"};
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mContext.setTheme(R.style.Theme_Settings_Home);
+        mPreference = new ListWithEntrySummaryPreference(mContext, null);
+        mPreference.setEntries(mDefaultEntries);
+        mPreference.setEntryValues(mDefaultEntryValues);
+        mPreference.setEntrySummaries(mDefaultEntrySummaries);
+    }
+
+    @Test
+    public void initialize_defaultEntries_shouldDisplayDefalutEntries() {
+        AlertDialog dialog = showDialog(mPreference);
+        ListAdapter adapter = dialog.getListView().getAdapter();
+
+        int len = mDefaultEntries.length;
+        assertThat(adapter.getCount()).isEqualTo(len);
+        for (int i = 0; i < len; i++) {
+            TextView title = adapter.getView(i, null, null).findViewById(R.id.title);
+            TextView summary = adapter.getView(i, null, null).findViewById(R.id.summary);
+            assertThat(title.getText()).isEqualTo(mDefaultEntries[i]);
+            assertThat(summary.getText()).isEqualTo(mDefaultEntrySummaries[i]);
+        }
+    }
+
+    @Test
+    public void setEntries_customEntries_shouldUpdateEntries() {
+        mPreference.setEntries(mCustomEntries);
+        mPreference.setEntryValues(mCustomEntryValues);
+        mPreference.setEntrySummaries(mCustomEntrySummaries);
+
+        AlertDialog dialog = showDialog(mPreference);
+        ListAdapter adapter = dialog.getListView().getAdapter();
+
+        int len = mCustomEntries.length;
+        assertThat(adapter.getCount()).isEqualTo(len);
+        for (int i = 0; i < len; i++) {
+            TextView title = adapter.getView(i, null, null).findViewById(R.id.title);
+            TextView summary = adapter.getView(i, null, null).findViewById(R.id.summary);
+            assertThat(title.getText()).isEqualTo(mCustomEntries[i]);
+            assertThat(summary.getText()).isEqualTo(mCustomEntrySummaries[i]);
+        }
+    }
+
+    @Test
+    public void onSaveAndRestoreInstanceState_resumePreference_shouldNotChangeEntries() {
+        setEntries_customEntries_shouldUpdateEntries();
+
+        final Parcelable parcelable = mPreference.onSaveInstanceState();
+        ListWithEntrySummaryPreference preference
+                = new ListWithEntrySummaryPreference(mContext, null);
+        preference.setEntries(mDefaultEntries);
+        preference.setEntryValues(mDefaultEntryValues);
+        preference.setEntrySummaries(mDefaultEntrySummaries);
+        preference.onRestoreInstanceState(parcelable);
+
+        AlertDialog dialog = showDialog(preference);
+        ListAdapter adapter = dialog.getListView().getAdapter();
+
+        int len = mCustomEntries.length;
+        assertThat(adapter.getCount()).isEqualTo(len);
+        for (int i = 0; i < len; i++) {
+            TextView title = adapter.getView(i, null, null).findViewById(R.id.title);
+            TextView summary = adapter.getView(i, null, null).findViewById(R.id.summary);
+            assertThat(title.getText()).isEqualTo(mCustomEntries[i]);
+            assertThat(summary.getText()).isEqualTo(mCustomEntrySummaries[i]);
+        }
+    }
+
+    private AlertDialog showDialog(ListWithEntrySummaryPreference preference) {
+        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+        preference.onPrepareDialogBuilder(builder, null);
+        return builder.show();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingDisclaimerFragmentTest.java b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingDisclaimerFragmentTest.java
new file mode 100644
index 0000000..6c221e7
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingDisclaimerFragmentTest.java
@@ -0,0 +1,180 @@
+/*
+ * 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.calling;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
+
+import com.android.settings.R;
+import com.android.settings.testutils.shadow.ShadowDisclaimerItemFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = ShadowDisclaimerItemFactory.class)
+public class WifiCallingDisclaimerFragmentTest {
+
+    @Mock
+    private Activity mActivity;
+    @Mock
+    private DisclaimerItem mDisclaimerItem;
+    @Mock
+    private LayoutInflater mLayoutInflater;
+    @Mock
+    private View mView;
+    @Mock
+    private ViewGroup mViewGroup;
+    @Mock
+    private Button mAgreeButton;
+    @Mock
+    private Button mDisagreeButton;
+    @Mock
+    private RecyclerView mRecyclerView;
+
+    @Captor
+    ArgumentCaptor<OnClickListener> mOnClickListenerCaptor;
+    @Captor
+    ArgumentCaptor<OnScrollListener> mOnScrollListenerCaptor;
+
+    private WifiCallingDisclaimerFragment mFragment;
+    private List<DisclaimerItem> mDisclaimerItemList = new ArrayList<>();
+    private List<DisclaimerItem> mEmptyDisclaimerItemList = new ArrayList<>();
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mActivity = Robolectric.setupActivity(Activity.class);
+        mFragment = spy(new WifiCallingDisclaimerFragment());
+
+        doReturn(mActivity).when(mFragment).getActivity();
+
+        when(mLayoutInflater.inflate(anyInt(), anyObject(), anyBoolean())).thenReturn(mView);
+        when(mView.findViewById(R.id.agree_button)).thenReturn(mAgreeButton);
+        when(mView.findViewById(R.id.disagree_button)).thenReturn(mDisagreeButton);
+        when(mView.findViewById(R.id.disclaimer_item_list)).thenReturn(mRecyclerView);
+        when(mView.getId()).thenReturn(R.id.agree_button);
+
+        mOnScrollListenerCaptor = ArgumentCaptor.forClass(OnScrollListener.class);
+        doNothing().when(mRecyclerView).addOnScrollListener(mOnScrollListenerCaptor.capture());
+        mOnClickListenerCaptor = ArgumentCaptor.forClass(OnClickListener.class);
+        doNothing().when(mAgreeButton).setOnClickListener(mOnClickListenerCaptor.capture());
+
+        mDisclaimerItemList.add(mDisclaimerItem);
+    }
+
+    @Test
+    public void onCreate_notHaveItem_shouldFinishFragment() {
+        ShadowDisclaimerItemFactory.setDisclaimerItemList(mEmptyDisclaimerItemList);
+
+        mFragment.onCreate(null /* savedInstanceState */);
+
+        // Check the fragment is finished when the DisclaimerItemList is empty.
+        verify(mFragment).finish(Activity.RESULT_OK);
+    }
+
+    @Test
+    public void onCreate_haveItem_shouldNotFinishFragment() {
+        ShadowDisclaimerItemFactory.setDisclaimerItemList(mDisclaimerItemList);
+
+        mFragment.onCreate(null /* savedInstanceState */);
+
+        // Check the fragment is not finished when the DisclaimerItemList is not empty.
+        verify(mFragment, never()).finish(Activity.RESULT_OK);
+    }
+
+    @Test
+    public void onScrolled_canNotScroll_shouldEnableAgreeButton() {
+        ShadowDisclaimerItemFactory.setDisclaimerItemList(mDisclaimerItemList);
+
+        when(mRecyclerView.canScrollVertically(1)).thenReturn(false);
+
+        mFragment.onCreate(null /* savedInstanceState */);
+        mFragment.onCreateView(mLayoutInflater, mViewGroup, null /* savedInstanceState */);
+
+        mOnScrollListenerCaptor.getValue().onScrolled(mRecyclerView, 0, 0);
+
+        // Check the agreeButton is enabled when the view is scrolled to the bottom end.
+        verify(mAgreeButton).setEnabled(true);
+        // Check the OnScrollListener is removed when the view is scrolled to the bottom end.
+        verify(mRecyclerView).removeOnScrollListener(any());
+    }
+
+    @Test
+    public void onScrolled_canScroll_shouldNotEnableAgreeButton() {
+        ShadowDisclaimerItemFactory.setDisclaimerItemList(mDisclaimerItemList);
+
+        when(mRecyclerView.canScrollVertically(1)).thenReturn(true);
+
+        mFragment.onCreate(null /* savedInstanceState */);
+        mFragment.onCreateView(mLayoutInflater, mViewGroup, null /* savedInstanceState */);
+
+        mOnScrollListenerCaptor.getValue().onScrolled(mRecyclerView, 0, 0);
+
+        // Check the agreeButton is not enabled when the view is not scrolled to the bottom end.
+        verify(mAgreeButton, never()).setEnabled(anyBoolean());
+        // Check the OnScrollListener is not removed when the view is not scrolled to
+        // the bottom end.
+        verify(mRecyclerView, never()).removeOnScrollListener(any());
+    }
+
+    @Test
+    public void onClick_agreeButton_shouldFinishFragment() {
+        ShadowDisclaimerItemFactory.setDisclaimerItemList(mDisclaimerItemList);
+
+        mFragment.onCreate(null /* savedInstanceState */);
+        mFragment.onCreateView(mLayoutInflater, mViewGroup, null /* savedInstanceState */);
+
+        mOnClickListenerCaptor.getValue().onClick(mAgreeButton);
+
+        // Check the onAgreed callback is called when "CONTINUE" button is clicked.
+        verify(mDisclaimerItem).onAgreed();
+        // Check the WFC disclaimer fragment is finished when "CONTINUE" button is clicked.
+        verify(mFragment).finish(Activity.RESULT_OK);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
index 39de254..ae88231 100644
--- a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
@@ -16,11 +16,14 @@
 
 package com.android.settings.wifi.calling;
 
+import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT;
 import static com.google.common.truth.Truth.assertThat;
 
+import static junit.framework.Assert.assertEquals;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
@@ -31,6 +34,8 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.Activity;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
@@ -41,20 +46,22 @@
 import android.view.View;
 import android.widget.TextView;
 
-import androidx.preference.ListPreference;
+import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
 import com.android.ims.ImsConfig;
-import com.android.ims.ImsException;
 import com.android.ims.ImsManager;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.shadow.SettingsShadowResources;
 import com.android.settings.widget.SwitchBar;
 import com.android.settings.widget.ToggleSwitch;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
@@ -65,6 +72,8 @@
 public class WifiCallingSettingsForSubTest {
     private static final String BUTTON_WFC_MODE = "wifi_calling_mode";
     private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode";
+    private static final String TEST_EMERGENCY_ADDRESS_CARRIER_APP =
+            "com.android.settings/.wifi.calling.TestEmergencyAddressCarrierApp";
 
     private TestFragment mFragment;
     private Context mContext;
@@ -72,6 +81,7 @@
     private final PersistableBundle mBundle = new PersistableBundle();
 
     @Mock private static CarrierConfigManager sCarrierConfigManager;
+    @Mock private CarrierConfigManager mMockConfigManager;
     @Mock private ImsManager mImsManager;
     @Mock private TelephonyManager mTelephonyManager;
     @Mock private PreferenceScreen mPreferenceScreen;
@@ -80,11 +90,12 @@
     @Mock private ToggleSwitch mToggleSwitch;
     @Mock private View mView;
     @Mock private ImsConfig mImsConfig;
-    @Mock private ListPreference mButtonWfcMode;
-    @Mock private ListPreference mButtonWfcRoamingMode;
+    @Mock private ListWithEntrySummaryPreference mButtonWfcMode;
+    @Mock private ListWithEntrySummaryPreference mButtonWfcRoamingMode;
+    @Mock private Preference mUpdateAddress;
 
     @Before
-    public void setUp() throws NoSuchFieldException, ImsException {
+    public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
         mContext = RuntimeEnvironment.application;
@@ -100,7 +111,7 @@
         final Bundle bundle = new Bundle();
         when(mFragment.getArguments()).thenReturn(bundle);
         doNothing().when(mFragment).addPreferencesFromResource(anyInt());
-        doReturn(mock(ListPreference.class)).when(mFragment).findPreference(any());
+        doReturn(mock(ListWithEntrySummaryPreference.class)).when(mFragment).findPreference(any());
         doReturn(mButtonWfcMode).when(mFragment).findPreference(BUTTON_WFC_MODE);
         doReturn(mButtonWfcRoamingMode).when(mFragment).findPreference(BUTTON_WFC_ROAMING_MODE);
         doNothing().when(mFragment).finish();
@@ -123,6 +134,11 @@
         doReturn(mBundle).when(sCarrierConfigManager).getConfigForSubId(anyInt());
         setDefaultCarrierConfigValues();
 
+        doReturn(sCarrierConfigManager).when(mActivity).getSystemService(
+                CarrierConfigManager.class);
+        doReturn(mContext.getResources()).when(mFragment).getResourcesForSubId();
+        doNothing().when(mFragment).startActivityForResult(any(Intent.class), anyInt());
+
         mFragment.onAttach(mContext);
         mFragment.onCreate(null);
         mFragment.onActivityCreated(null);
@@ -133,6 +149,9 @@
                 CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL, false);
         mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL, true);
         mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, true);
+        mBundle.putString(
+                CarrierConfigManager.KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING,
+                TEST_EMERGENCY_ADDRESS_CARRIER_APP);
     }
 
     @Test
@@ -141,7 +160,7 @@
     }
 
     @Test
-    public void onResume_provisioningAllowed_shouldNotFinish() throws ImsException {
+    public void onResume_provisioningAllowed_shouldNotFinish() {
         // Call onResume while provisioning is allowed.
         mFragment.onResume();
 
@@ -160,7 +179,7 @@
     }
 
     @Test
-    public void onResumeOnPause_provisioningCallbackRegistration() throws ImsException {
+    public void onResumeOnPause_provisioningCallbackRegistration() throws Exception {
         // Verify that provisioning callback is registered after call to onResume().
         mFragment.onResume();
         verify(mImsConfig).addConfigCallback(any(ProvisioningManager.Callback.class));
@@ -261,6 +280,61 @@
                 eq(true));
     }
 
+    @Test
+    public void onSwitchChanged_enableSetting_shouldLaunchWfcDisclaimerFragment() {
+        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+
+        mFragment.onSwitchChanged(null, true);
+
+        // Check the WFC disclaimer fragment is launched.
+        verify(mFragment).startActivityForResult(intentCaptor.capture(),
+                eq(WifiCallingSettingsForSub.REQUEST_CHECK_WFC_DISCLAIMER));
+        Intent intent = intentCaptor.getValue();
+        assertThat(intent.getStringExtra(EXTRA_SHOW_FRAGMENT))
+                .isEqualTo(WifiCallingDisclaimerFragment.class.getName());
+    }
+
+    @Test
+    public void onActivityResult_finishWfcDisclaimerFragment_shouldLaunchCarrierActivity() {
+        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+
+        // Emulate the WfcDisclaimerActivity finish.
+        mFragment.onActivityResult(WifiCallingSettingsForSub.REQUEST_CHECK_WFC_DISCLAIMER,
+                Activity.RESULT_OK, null);
+
+        // Check the WFC emergency address activity is launched.
+        verify(mFragment).startActivityForResult(intentCaptor.capture(),
+                eq(WifiCallingSettingsForSub.REQUEST_CHECK_WFC_EMERGENCY_ADDRESS));
+        Intent intent = intentCaptor.getValue();
+        assertEquals(intent.getComponent(), ComponentName.unflattenFromString(
+                TEST_EMERGENCY_ADDRESS_CARRIER_APP));
+    }
+
+    @Test
+    public void onActivityResult_finishCarrierActivity_shouldShowWfcPreference() {
+        ReflectionHelpers.setField(mFragment, "mButtonWfcMode", mButtonWfcMode);
+        ReflectionHelpers.setField(mFragment, "mButtonWfcRoamingMode", mButtonWfcRoamingMode);
+        ReflectionHelpers.setField(mFragment, "mUpdateAddress", mUpdateAddress);
+
+        mFragment.onActivityResult(WifiCallingSettingsForSub.REQUEST_CHECK_WFC_EMERGENCY_ADDRESS,
+                Activity.RESULT_OK, null);
+
+        // Check the WFC preferences is added.
+        verify(mPreferenceScreen).addPreference(mButtonWfcMode);
+        verify(mPreferenceScreen).addPreference(mButtonWfcRoamingMode);
+        verify(mPreferenceScreen).addPreference(mUpdateAddress);
+        // Check the WFC enable request.
+        verify(mImsManager).setWfcSetting(true);
+    }
+
+    @Test
+    public void onSwitchChanged_disableSetting_shouldNotLaunchWfcDisclaimerFragment() {
+        mFragment.onSwitchChanged(null, false);
+
+        // Check the WFC disclaimer fragment is not launched.
+        verify(mFragment, never()).startActivityForResult(any(Intent.class), anyInt());
+    }
+
     protected class TestFragment extends WifiCallingSettingsForSub {
         @Override
         protected Object getSystemService(final String name) {
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSliceHelperTest.java b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSliceHelperTest.java
index f9109ce..644e5e8 100644
--- a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSliceHelperTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSliceHelperTest.java
@@ -22,7 +22,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
@@ -48,7 +47,6 @@
 import com.android.ims.ImsConfig;
 import com.android.ims.ImsManager;
 import com.android.settings.R;
-import com.android.settings.slices.CustomSliceManager;
 import com.android.settings.slices.CustomSliceRegistry;
 import com.android.settings.slices.SettingsSliceProvider;
 import com.android.settings.slices.SliceBroadcastReceiver;
@@ -99,9 +97,6 @@
 
         mFeatureFactory = FakeFeatureFactory.setupForTest();
         mSlicesFeatureProvider = mFeatureFactory.getSlicesFeatureProvider();
-        CustomSliceManager manager = new CustomSliceManager(mContext);
-        when(mSlicesFeatureProvider.getCustomSliceManager(any(Context.class)))
-                .thenReturn(manager);
 
         mWfcSliceHelper = new FakeWifiCallingSliceHelper(mContext);
 
diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
index 640c426..db76722 100644
--- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
@@ -384,9 +384,9 @@
     }
 
     @Test
-    public void entityHeader_shouldHaveLabelSetToSsid() {
-        String label = "ssid";
-        when(mockAccessPoint.getSsidStr()).thenReturn(label);
+    public void entityHeader_shouldHaveLabelSetToTitle() {
+        String label = "title";
+        when(mockAccessPoint.getTitle()).thenReturn(label);
 
         displayAndResume();
 
@@ -758,7 +758,9 @@
     }
 
     @Test
-    public void forgetNetwork_Passpoint() {
+    public void forgetNetwork_v1_Passpoint() {
+        FeatureFlagPersistent.setEnabled(mContext, FeatureFlags.NETWORK_INTERNET_V2, false);
+
         mockWifiConfig.networkId = 5;
         when(mockWifiConfig.isPasspoint()).thenReturn(true);
 
@@ -776,9 +778,9 @@
 
         mockWifiConfig.networkId = 5;
         when(mockWifiConfig.isPasspoint()).thenReturn(true);
+        spyController.displayPreference(mockScreen);
         FeatureFlagPersistent.setEnabled(mContext, FeatureFlags.NETWORK_INTERNET_V2, true);
 
-        spyController.displayPreference(mockScreen);
         mForgetClickListener.getValue().onClick(null);
 
         verify(mockWifiManager, times(0)).removePasspointConfiguration(mockWifiConfig.FQDN);
diff --git a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettingsTest.java
index 6ede989..746456e 100644
--- a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettingsTest.java
@@ -82,6 +82,8 @@
 
     @Test
     public void onForget_isPasspointConfig_shouldRefreshAPList() {
+        FeatureFlagPersistent.setEnabled(RuntimeEnvironment.application,
+                FeatureFlags.NETWORK_INTERNET_V2, false);
         when(mAccessPoint.isPasspointConfig()).thenReturn(true);
         ReflectionHelpers.setField(mSettings, "mSelectedAccessPoint", mAccessPoint);
 
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 d681afe..520d988 100644
--- a/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java
@@ -36,6 +36,8 @@
 
 import com.android.settings.R;
 import com.android.settings.slices.CustomSliceRegistry;
+import com.android.settings.slices.SlicesFeatureProviderImpl;
+import com.android.settings.testutils.FakeFeatureFactory;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -52,11 +54,15 @@
     private ContentResolver mResolver;
     private WifiManager mWifiManager;
     private ContextualWifiSlice mWifiSlice;
+    private FakeFeatureFactory mFeatureFactory;
 
     @Before
     public void setUp() {
         mContext = spy(RuntimeEnvironment.application);
         mResolver = mock(ContentResolver.class);
+        mFeatureFactory = FakeFeatureFactory.setupForTest();
+        mFeatureFactory.slicesFeatureProvider = new SlicesFeatureProviderImpl();
+        mFeatureFactory.slicesFeatureProvider.newUiSession();
         doReturn(mResolver).when(mContext).getContentResolver();
         mWifiManager = mContext.getSystemService(WifiManager.class);
 
@@ -65,10 +71,28 @@
         mWifiManager.setWifiEnabled(true);
 
         mWifiSlice = new ContextualWifiSlice(mContext);
+        mWifiSlice.sPreviouslyDisplayed = false;
     }
 
     @Test
     public void getWifiSlice_hasActiveConnection_shouldReturnNull() {
+        mWifiSlice.sPreviouslyDisplayed = false;
+        final WifiConfiguration config = new WifiConfiguration();
+        config.SSID = "123";
+        mWifiManager.connect(config, null /* listener */);
+
+        final Slice wifiSlice = mWifiSlice.getSlice();
+
+        assertThat(wifiSlice).isNull();
+    }
+
+    @Test
+    public void getWifiSlice_newSession_hasActiveConnection_shouldReturnNull() {
+        // Session: use a non-active value
+        // previous displayed: yes
+        mWifiSlice.sPreviouslyDisplayed = true;
+        mWifiSlice.sActiveUiSession = ~mFeatureFactory.slicesFeatureProvider.getUiSessionToken();
+
         final WifiConfiguration config = new WifiConfiguration();
         config.SSID = "123";
         mWifiManager.connect(config, null /* listener */);
@@ -80,7 +104,8 @@
 
     @Test
     public void getWifiSlice_previousDisplayed_hasActiveConnection_shouldHaveTitleAndToggle() {
-        mWifiSlice.mPreviouslyDisplayed = true;
+        mWifiSlice.sActiveUiSession = mFeatureFactory.slicesFeatureProvider.getUiSessionToken();
+        mWifiSlice.sPreviouslyDisplayed = true;
         final WifiConfiguration config = new WifiConfiguration();
         config.SSID = "123";
         mWifiManager.connect(config, null /* listener */);
@@ -101,7 +126,8 @@
 
     @Test
     public void getWifiSlice_contextualWifiSlice_shouldReturnContextualWifiSliceUri() {
-        mWifiSlice.mPreviouslyDisplayed = true;
+        mWifiSlice.sActiveUiSession = mFeatureFactory.slicesFeatureProvider.getUiSessionToken();
+        mWifiSlice.sPreviouslyDisplayed = true;
 
         final Slice wifiSlice = mWifiSlice.getSlice();
 
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java
index d8cd878a..06716db 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java
@@ -112,36 +112,6 @@
     }
 
     @Test
-    public void testReceiver_turnOnAirplaneMode_clearPreferenceSummary() {
-        final ContentResolver cr = mock(ContentResolver.class);
-        when(mContext.getContentResolver()).thenReturn(cr);
-        Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, 1);
-        mController.displayPreference(mScreen);
-        final BroadcastReceiver receiver = ReflectionHelpers.getField(mController, "mReceiver");
-        final Intent broadcast = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-
-        receiver.onReceive(RuntimeEnvironment.application, broadcast);
-
-        assertThat(mPreference.getSummary().toString()).isEqualTo(
-                "Unavailable because airplane mode is turned on");
-    }
-
-    @Test
-    public void testReceiver_turnOffAirplaneMode_displayOffSummary() {
-        final ContentResolver cr = mock(ContentResolver.class);
-        when(mContext.getContentResolver()).thenReturn(cr);
-        Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, 0);
-        mController.displayPreference(mScreen);
-        final BroadcastReceiver receiver = ReflectionHelpers.getField(mController, "mReceiver");
-        final Intent broadcast = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-
-        receiver.onReceive(RuntimeEnvironment.application, broadcast);
-
-        assertThat(mPreference.getSummary().toString()).isEqualTo(
-                "Not sharing internet or content with other devices");
-    }
-
-    @Test
     public void testHandleWifiApStateChanged_stateEnabling_showEnablingSummary() {
         mController.handleWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLING, 0 /* reason */);
 
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceControllerTest.java
index cb58778..3d15197 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceControllerTest.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiManager;
 
 import androidx.preference.PreferenceScreen;
@@ -56,12 +57,12 @@
     private PreferenceScreen mScreen;
 
     private WifiTetherSSIDPreferenceController mController;
-    private ValidatedEditTextPreference mPreference;
+    private WifiTetherSsidPreference mPreference;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mPreference = new ValidatedEditTextPreference(RuntimeEnvironment.application);
+        mPreference = new WifiTetherSsidPreference(RuntimeEnvironment.application);
 
         when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager);
         when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
@@ -121,4 +122,28 @@
         assertThat(mController.getSSID()).isEqualTo(config.SSID);
         assertThat(mPreference.getSummary()).isEqualTo(config.SSID);
     }
+
+    @Test
+    public void displayPreference_wifiApDisabled_shouldHideQrCodeIcon() {
+        when(mWifiManager.isWifiApEnabled()).thenReturn(false);
+        final WifiConfiguration config = new WifiConfiguration();
+        config.SSID = "test_1234";
+        config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
+        when(mWifiManager.getWifiApConfiguration()).thenReturn(config);
+
+        mController.displayPreference(mScreen);
+        assertThat(mController.isQrCodeButtonAvailable()).isEqualTo(false);
+    }
+
+    @Test
+    public void displayPreference_wifiApEnabled_shouldShowQrCodeIcon() {
+        when(mWifiManager.isWifiApEnabled()).thenReturn(true);
+        final WifiConfiguration config = new WifiConfiguration();
+        config.SSID = "test_1234";
+        config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
+        when(mWifiManager.getWifiApConfiguration()).thenReturn(config);
+
+        mController.displayPreference(mScreen);
+        assertThat(mController.isQrCodeButtonAvailable()).isEqualTo(true);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSwitchBarControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSwitchBarControllerTest.java
index 1a5a228..30358da 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSwitchBarControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSwitchBarControllerTest.java
@@ -73,17 +73,7 @@
         mController = new WifiTetherSwitchBarController(mContext,
                 new SwitchBarController(mSwitchBar));
     }
-
-    @Test
-    public void constructor_airplaneModeOn_switchBarDisabled() {
-        Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_ON, 1);
-
-        new WifiTetherSwitchBarController(mContext, new SwitchBarController(mSwitchBar));
-
-        assertThat(mSwitchBar.isEnabled()).isFalse();
-    }
-
+    
     @Test
     public void startTether_fail_resetSwitchBar() {
         when(mNetworkPolicyManager.getRestrictBackground()).thenReturn(false);
diff --git a/tests/unit/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java b/tests/unit/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
index 447e2b4..653e55e 100644
--- a/tests/unit/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
+++ b/tests/unit/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
@@ -86,6 +86,7 @@
     private ContextualCard getContextualCard(Uri sliceUri) {
         return new ContextualCard.Builder()
                 .setName("test_card")
+                .setRankingScore(0.5f)
                 .setCardType(ContextualCard.CardType.SLICE)
                 .setSliceUri(sliceUri)
                 .build();
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 405ed4a..38211b3 100644
--- a/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
+++ b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
@@ -147,7 +147,7 @@
     @Test
     public void rotateScreen_shouldGetCorrectWifiNetworkConfig() {
         final WifiNetworkConfig wifiNetworkConfig = new WifiNetworkConfig("WPA", "WifiSsid",
-                "password", /* hiddenSsid */ false, /* networkId */ 0);
+                "password", /* hiddenSsid */ false, /* networkId */ 0, /* isHotspot */ true);
         final Intent intent = new Intent(Settings.ACTION_PROCESS_WIFI_EASY_CONNECT_URI);
         intent.setData(Uri.parse(VALID_WIFI_DPP_QR_CODE));
 
@@ -173,5 +173,6 @@
         assertThat(restoredWifiNetworkConfig.getPreSharedKey()).isEqualTo("password");
         assertThat(restoredWifiNetworkConfig.getHiddenSsid()).isFalse();
         assertThat(restoredWifiNetworkConfig.getNetworkId()).isEqualTo(0);
+        assertThat(restoredWifiNetworkConfig.isHotspot()).isTrue();
     }
 }