Merge "Don't show NLSes with excessively long component names" into udc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index d82fc94..dc519e9 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3073,7 +3073,8 @@
             android:name="Settings$PowerUsageSummaryActivity"
             android:label="@string/power_usage_summary_title"
             android:exported="true"
-            android:icon="@drawable/ic_homepage_battery">
+            android:icon="@drawable/ic_homepage_battery"
+            android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize">
             <intent-filter android:priority="1">
                 <action android:name="android.intent.action.POWER_USAGE_SUMMARY" />
                 <category android:name="android.intent.category.DEFAULT" />
diff --git a/color-check-baseline.xml b/color-check-baseline.xml
index 410acad..911a95b 100644
--- a/color-check-baseline.xml
+++ b/color-check-baseline.xml
@@ -21,11 +21,203 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
+        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview.xml"
+            line="38"
+            column="34"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
+        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/accessibility_gesture_navigation_three_finger_preview.xml"
+            line="38"
+            column="34"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
+        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview.xml"
+            line="39"
+            column="38"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
+        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/accessibility_gesture_navigation_three_finger_preview.xml"
+            line="39"
+            column="38"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
+        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview.xml"
+            line="52"
+            column="34"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
+        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/accessibility_gesture_navigation_three_finger_preview.xml"
+            line="52"
+            column="34"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
+        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview.xml"
+            line="53"
+            column="38"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
+        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/accessibility_gesture_navigation_three_finger_preview.xml"
+            line="53"
+            column="38"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
+        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview.xml"
+            line="66"
+            column="34"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
+        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/accessibility_gesture_navigation_three_finger_preview.xml"
+            line="66"
+            column="34"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
+        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview.xml"
+            line="67"
+            column="38"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
+        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/accessibility_gesture_navigation_three_finger_preview.xml"
+            line="67"
+            column="38"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
         errorLine1="          &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
         errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture.xml"
-            line="30"
+            file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+            line="46"
             column="36"/>
     </issue>
 
@@ -40,8 +232,8 @@
         errorLine1="          &lt;item android:offset=&quot;0&quot; android:color=&quot;#001A73E8&quot;/>"
         errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture.xml"
-            line="30"
+            file="res/drawable/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+            line="46"
             column="36"/>
     </issue>
 
@@ -56,8 +248,8 @@
         errorLine1="          &lt;item android:offset=&quot;0.69&quot; android:color=&quot;#FF669DF6&quot;/>"
         errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture.xml"
-            line="31"
+            file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+            line="47"
             column="39"/>
     </issue>
 
@@ -72,8 +264,8 @@
         errorLine1="          &lt;item android:offset=&quot;0.69&quot; android:color=&quot;#FF1A73E8&quot;/>"
         errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture.xml"
-            line="31"
+            file="res/drawable/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+            line="47"
             column="39"/>
     </issue>
 
@@ -88,8 +280,8 @@
         errorLine1="          &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
         errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture.xml"
-            line="44"
+            file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+            line="60"
             column="36"/>
     </issue>
 
@@ -104,8 +296,8 @@
         errorLine1="          &lt;item android:offset=&quot;0&quot; android:color=&quot;#001A73E8&quot;/>"
         errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture.xml"
-            line="44"
+            file="res/drawable/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+            line="60"
             column="36"/>
     </issue>
 
@@ -120,8 +312,8 @@
         errorLine1="          &lt;item android:offset=&quot;0.69&quot; android:color=&quot;#FF669DF6&quot;/>"
         errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture.xml"
-            line="45"
+            file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+            line="61"
             column="39"/>
     </issue>
 
@@ -136,8 +328,8 @@
         errorLine1="          &lt;item android:offset=&quot;0.69&quot; android:color=&quot;#FF1A73E8&quot;/>"
         errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture.xml"
-            line="45"
+            file="res/drawable/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+            line="61"
             column="39"/>
     </issue>
 
@@ -152,8 +344,8 @@
         errorLine1="          &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
         errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture_talkback.xml"
-            line="30"
+            file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+            line="74"
             column="36"/>
     </issue>
 
@@ -168,8 +360,8 @@
         errorLine1="          &lt;item android:offset=&quot;0&quot; android:color=&quot;#001A73E8&quot;/>"
         errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture_talkback.xml"
-            line="30"
+            file="res/drawable/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+            line="74"
             column="36"/>
     </issue>
 
@@ -184,8 +376,8 @@
         errorLine1="          &lt;item android:offset=&quot;0.69&quot; android:color=&quot;#FF669DF6&quot;/>"
         errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture_talkback.xml"
-            line="31"
+            file="res/drawable-night/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+            line="75"
             column="39"/>
     </issue>
 
@@ -200,8 +392,200 @@
         errorLine1="          &lt;item android:offset=&quot;0.69&quot; android:color=&quot;#FF1A73E8&quot;/>"
         errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture_talkback.xml"
-            line="31"
+            file="res/drawable/accessibility_gesture_navigation_three_finger_preview_tablet.xml"
+            line="75"
+            column="39"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
+        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable-night/accessibility_gesture_navigation_two_finger_preview.xml"
+            line="38"
+            column="34"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
+        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/accessibility_gesture_navigation_two_finger_preview.xml"
+            line="38"
+            column="34"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
+        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable-night/accessibility_gesture_navigation_two_finger_preview.xml"
+            line="39"
+            column="38"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
+        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/accessibility_gesture_navigation_two_finger_preview.xml"
+            line="39"
+            column="38"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
+        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable-night/accessibility_gesture_navigation_two_finger_preview.xml"
+            line="52"
+            column="34"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
+        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/accessibility_gesture_navigation_two_finger_preview.xml"
+            line="52"
+            column="34"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
+        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable-night/accessibility_gesture_navigation_two_finger_preview.xml"
+            line="53"
+            column="38"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
+        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/accessibility_gesture_navigation_two_finger_preview.xml"
+            line="53"
+            column="38"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="          &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
+        errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable-night/accessibility_gesture_navigation_two_finger_preview_tablet.xml"
+            line="46"
+            column="36"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="          &lt;item android:offset=&quot;0&quot; android:color=&quot;#001A73E8&quot;/>"
+        errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/accessibility_gesture_navigation_two_finger_preview_tablet.xml"
+            line="46"
+            column="36"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="          &lt;item android:offset=&quot;0.69&quot; android:color=&quot;#FF669DF6&quot;/>"
+        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable-night/accessibility_gesture_navigation_two_finger_preview_tablet.xml"
+            line="47"
+            column="39"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="          &lt;item android:offset=&quot;0.69&quot; android:color=&quot;#FF1A73E8&quot;/>"
+        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/accessibility_gesture_navigation_two_finger_preview_tablet.xml"
+            line="47"
             column="39"/>
     </issue>
 
@@ -216,8 +600,8 @@
         errorLine1="          &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
         errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture_talkback.xml"
-            line="44"
+            file="res/drawable-night/accessibility_gesture_navigation_two_finger_preview_tablet.xml"
+            line="60"
             column="36"/>
     </issue>
 
@@ -232,8 +616,8 @@
         errorLine1="          &lt;item android:offset=&quot;0&quot; android:color=&quot;#001A73E8&quot;/>"
         errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture_talkback.xml"
-            line="44"
+            file="res/drawable/accessibility_gesture_navigation_two_finger_preview_tablet.xml"
+            line="60"
             column="36"/>
     </issue>
 
@@ -248,8 +632,8 @@
         errorLine1="          &lt;item android:offset=&quot;0.69&quot; android:color=&quot;#FF669DF6&quot;/>"
         errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture_talkback.xml"
-            line="45"
+            file="res/drawable-night/accessibility_gesture_navigation_two_finger_preview_tablet.xml"
+            line="61"
             column="39"/>
     </issue>
 
@@ -264,72 +648,8 @@
         errorLine1="          &lt;item android:offset=&quot;0.69&quot; android:color=&quot;#FF1A73E8&quot;/>"
         errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture_talkback.xml"
-            line="45"
-            column="39"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="          &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
-        errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture_talkback.xml"
-            line="58"
-            column="36"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="          &lt;item android:offset=&quot;0&quot; android:color=&quot;#001A73E8&quot;/>"
-        errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture_talkback.xml"
-            line="58"
-            column="36"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="          &lt;item android:offset=&quot;0.69&quot; android:color=&quot;#FF669DF6&quot;/>"
-        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable-sw600dp-night/accessibility_shortcut_type_software_gesture_talkback.xml"
-            line="59"
-            column="39"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="          &lt;item android:offset=&quot;0.69&quot; android:color=&quot;#FF1A73E8&quot;/>"
-        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable-sw600dp/accessibility_shortcut_type_software_gesture_talkback.xml"
-            line="59"
+            file="res/drawable/accessibility_gesture_navigation_two_finger_preview_tablet.xml"
+            line="61"
             column="39"/>
     </issue>
 
@@ -4165,316 +4485,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;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine1="            android:tint=&quot;#4F8438&quot;"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="res/drawable-night/illustration_accessibility_gesture_three_finger.xml"
-            line="38"
-            column="34"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable/illustration_accessibility_gesture_three_finger.xml"
-            line="38"
-            column="34"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable-night/illustration_accessibility_gesture_three_finger.xml"
-            line="39"
-            column="38"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable/illustration_accessibility_gesture_three_finger.xml"
-            line="39"
-            column="38"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable-night/illustration_accessibility_gesture_three_finger.xml"
-            line="52"
-            column="34"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable/illustration_accessibility_gesture_three_finger.xml"
-            line="52"
-            column="34"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable-night/illustration_accessibility_gesture_three_finger.xml"
-            line="53"
-            column="38"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable/illustration_accessibility_gesture_three_finger.xml"
-            line="53"
-            column="38"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable-night/illustration_accessibility_gesture_three_finger.xml"
-            line="66"
-            column="34"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable/illustration_accessibility_gesture_three_finger.xml"
-            line="66"
-            column="34"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable-night/illustration_accessibility_gesture_three_finger.xml"
-            line="67"
-            column="38"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable/illustration_accessibility_gesture_three_finger.xml"
-            line="67"
-            column="38"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable-night/illustration_accessibility_gesture_two_finger.xml"
-            line="38"
-            column="34"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable/illustration_accessibility_gesture_two_finger.xml"
-            line="38"
-            column="34"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable-night/illustration_accessibility_gesture_two_finger.xml"
-            line="39"
-            column="38"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable/illustration_accessibility_gesture_two_finger.xml"
-            line="39"
-            column="38"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable-night/illustration_accessibility_gesture_two_finger.xml"
-            line="52"
-            column="34"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0&quot; android:color=&quot;#00669DF6&quot;/>"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable/illustration_accessibility_gesture_two_finger.xml"
-            line="52"
-            column="34"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable-night/illustration_accessibility_gesture_two_finger.xml"
-            line="53"
-            column="38"/>
-    </issue>
-
-    <issue
-        id="HardCodedColor"
-        severity="Error"
-        message="Avoid using hardcoded color"
-        category="Correctness"
-        priority="4"
-        summary="Using hardcoded color"
-        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
-        errorLine1="        &lt;item android:offset=&quot;0.695&quot; android:color=&quot;#FF669DF6&quot;/>"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable/illustration_accessibility_gesture_two_finger.xml"
-            line="53"
-            column="38"/>
+            file="res/layout/locale_dialog.xml"
+            line="36"
+            column="13"/>
     </issue>
 
     <issue
@@ -5801,7 +5817,7 @@
         errorLine2="                                          ^">
         <location
             file="res/values/styles.xml"
-            line="931"
+            line="930"
             column="43"/>
     </issue>
 
@@ -5817,7 +5833,7 @@
         errorLine2="                                          ^">
         <location
             file="res/values/styles.xml"
-            line="931"
+            line="930"
             column="43"/>
     </issue>
 
@@ -5833,7 +5849,7 @@
         errorLine2="                                                ^">
         <location
             file="res/values/styles.xml"
-            line="932"
+            line="931"
             column="49"/>
     </issue>
 
@@ -5849,7 +5865,7 @@
         errorLine2="                                                ^">
         <location
             file="res/values/styles.xml"
-            line="932"
+            line="931"
             column="49"/>
     </issue>
 
@@ -5865,7 +5881,7 @@
         errorLine2="                                                     ^">
         <location
             file="res/values/styles.xml"
-            line="933"
+            line="932"
             column="54"/>
     </issue>
 
@@ -5881,7 +5897,7 @@
         errorLine2="                                                     ^">
         <location
             file="res/values/styles.xml"
-            line="933"
+            line="932"
             column="54"/>
     </issue>
 
@@ -5897,7 +5913,7 @@
         errorLine2="                                              ^">
         <location
             file="res/values/styles.xml"
-            line="934"
+            line="933"
             column="47"/>
     </issue>
 
@@ -5913,7 +5929,7 @@
         errorLine2="                                              ^">
         <location
             file="res/values/styles.xml"
-            line="934"
+            line="933"
             column="47"/>
     </issue>
 
@@ -5929,7 +5945,7 @@
         errorLine2="                                                  ^">
         <location
             file="res/values/styles.xml"
-            line="935"
+            line="934"
             column="51"/>
     </issue>
 
@@ -5945,7 +5961,7 @@
         errorLine2="                                                  ^">
         <location
             file="res/values/styles.xml"
-            line="935"
+            line="934"
             column="51"/>
     </issue>
 
@@ -5961,7 +5977,7 @@
         errorLine2="                                                              ^">
         <location
             file="res/values/styles.xml"
-            line="936"
+            line="935"
             column="63"/>
     </issue>
 
@@ -5977,7 +5993,7 @@
         errorLine2="                                                              ^">
         <location
             file="res/values/styles.xml"
-            line="936"
+            line="935"
             column="63"/>
     </issue>
 
diff --git a/res-product/values/strings.xml b/res-product/values/strings.xml
index d149707..5b6474e 100644
--- a/res-product/values/strings.xml
+++ b/res-product/values/strings.xml
@@ -676,4 +676,8 @@
     <string name="lockpassword_confirm_your_password_details_frp" product="tablet">Your tablet was reset to factory settings. To use this tablet, enter your previous password.</string>
     <!-- An explanation text that the password needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
     <string name="lockpassword_confirm_your_password_details_frp" product="device">Your device was reset to factory settings. To use this device, enter your previous password.</string>
+    <!-- Message of incompatible charging battery tip [CHAR LIMIT=NONE] -->
+    <string name="battery_tip_incompatible_charging_message" product="default">Battery charging slowly or won\'t charge. Check if the cable and power adapter work with your phone</string>
+    <string name="battery_tip_incompatible_charging_message" product="device">Battery charging slowly or won\'t charge. Check if the cable and power adapter work with your device</string>
+    <string name="battery_tip_incompatible_charging_message" product="tablet">Battery charging slowly or won\'t charge. Check if the cable and power adapter work with your tablet</string>
 </resources>
diff --git a/res/layout/locale_dialog.xml b/res/layout/locale_dialog.xml
new file mode 100644
index 0000000..cbdb37e
--- /dev/null
+++ b/res/layout/locale_dialog.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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="wrap_content"
+    android:layout_height="wrap_content"
+    android:paddingTop="@dimen/admin_details_dialog_padding"
+    android:paddingStart="@dimen/admin_details_dialog_padding"
+    android:paddingEnd="@dimen/admin_details_dialog_padding"
+    android:paddingBottom="@dimen/admin_details_dialog_padding_bottom"
+    android:orientation="vertical">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:gravity="center_horizontal"
+        android:paddingBottom="@dimen/admin_details_dialog_title_bottom_padding">
+        <ImageView
+            android:layout_width="@dimen/admin_details_dialog_icon_size"
+            android:layout_height="@dimen/admin_details_dialog_icon_size"
+            android:scaleType="fitCenter"
+            android:src="@drawable/ic_settings_language"
+            android:tint="#4F8438"
+            android:contentDescription="@null"/>
+        <TextView
+            android:id="@+id/dialog_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="16dp"
+            android:gravity="center_horizontal"
+            android:textAppearance="@style/TextAppearance.AdminDialogTitle"/>
+    </LinearLayout>
+
+    <ScrollView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:fadeScrollbars="false">
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+            <TextView
+                android:id="@+id/dialog_msg"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:maxLength="200"
+                android:gravity="left"
+                android:autoLink="email|phone|web"
+                android:textColor="?android:attr/textColorSecondary"/>
+        </LinearLayout>
+    </ScrollView>
+</LinearLayout>
diff --git a/res/layout/panel_layout.xml b/res/layout/panel_layout.xml
index f154abc..e55c1e6 100644
--- a/res/layout/panel_layout.xml
+++ b/res/layout/panel_layout.xml
@@ -67,7 +67,7 @@
                     android:maxLines="1"
                     android:textColor="?android:attr/textColorPrimary"
                     android:textSize="24sp"
-                    android:fontFamily="sans-serif-reqular"/>
+                    android:fontFamily="@*android:string/config_headlineFontFamilyMedium"/>
 
                 <TextView
                     android:id="@+id/header_subtitle"
@@ -77,7 +77,7 @@
                     android:maxLines="1"
                     android:textColor="?android:attr/textColorSecondary"
                     android:textSize="14sp"
-                    android:fontFamily="sans-serif-reqular" />
+                    android:fontFamily="@*android:string/config_headlineFontFamilyMedium" />
             </LinearLayout>
         </LinearLayout>
 
@@ -90,7 +90,7 @@
             android:gravity="center"
             android:textColor="?android:attr/textColorPrimary"
             android:textSize="24sp"
-            android:fontFamily="sans-serif-reqular"/>
+            android:fontFamily="@*android:string/config_headlineFontFamilyMedium"/>
 
         <ProgressBar
             android:id="@+id/progress_bar"
diff --git a/res/layout/preference_contrast_level_slider.xml b/res/layout/preference_contrast_level_slider.xml
deleted file mode 100644
index 1766dd7..0000000
--- a/res/layout/preference_contrast_level_slider.xml
+++ /dev/null
@@ -1,104 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 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:minHeight="?android:attr/listPreferredItemHeightSmall"
-    android:gravity="center_vertical"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:clickable="false"
-    android:orientation="horizontal">
-
-    <include layout="@layout/settingslib_icon_frame"/>
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:paddingTop="16dp">
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content">
-            <TextView
-                android:id="@android:id/title"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:singleLine="true"
-                android:textAppearance="?android:attr/textAppearanceListItem"
-                android:textColor="?android:attr/textColorPrimary"
-                android:ellipsize="marquee"
-                android:hyphenationFrequency="normalFast"
-                android:lineBreakWordStyle="phrase"
-                android:fadingEdge="horizontal"/>
-            <LinearLayout
-                android:id="@android:id/widget_frame"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:gravity="center_vertical"
-                android:orientation="vertical"/>
-        </LinearLayout>
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layoutDirection="ltr"
-            android:orientation="vertical">
-
-            <com.android.settings.accessibility.ContrastLevelSeekBar
-                android:id="@*android:id/seekbar"
-                android:minHeight="?android:attr/listPreferredItemHeightSmall"
-                android:paddingStart="0dp"
-                android:paddingEnd="0dp"
-                android:layout_gravity="center_vertical"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-
-            <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_vertical"
-                android:orientation="horizontal">
-                <TextView
-                    android:id="@+id/left_text"
-                    android:text="@string/accessibility_contrast_level_left_label"
-                    android:textAppearance="?android:attr/textAppearanceSmall"
-                    android:textColor="?android:attr/textColorSecondary"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="1"
-                    android:maxLines="1"
-                    android:textAlignment="viewStart" />
-                <TextView
-                    android:id="@+id/right_text"
-                    android:text="@string/accessibility_contrast_level_right_label"
-                    android:textAppearance="?android:attr/textAppearanceSmall"
-                    android:textColor="?android:attr/textColorSecondary"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="1"
-                    android:maxLines="1"
-                    android:textAlignment="viewEnd" />
-
-            </LinearLayout>
-        </LinearLayout>
-    </LinearLayout>
-
-</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/zen_rule_type.xml b/res/layout/zen_rule_type.xml
index bd50273..4c1b84b 100644
--- a/res/layout/zen_rule_type.xml
+++ b/res/layout/zen_rule_type.xml
@@ -23,8 +23,8 @@
 
     <ImageView
             android:id="@+id/icon"
-            android:layout_width="@dimen/app_icon_size"
-            android:layout_height="@dimen/app_icon_size"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
             android:layout_gravity="center"/>
 
     <RelativeLayout
diff --git a/res/values/config.xml b/res/values/config.xml
index 07f6432..ef786be 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -363,6 +363,9 @@
     <!-- Whether Wi-Fi hotspot settings should be shown or not. -->
     <bool name="config_show_wifi_hotspot_settings">true</bool>
 
+    <!-- Whether Wi-Fi hotspot speed should be shown or not. -->
+    <bool name="config_show_wifi_hotspot_speed">false</bool>
+
     <!-- Whether toggle_airplane is available or not. -->
     <bool name="config_show_toggle_airplane">true</bool>
 
@@ -553,7 +556,7 @@
     <!-- Cell broacast receiver package name -->
     <string name="config_cell_broadcast_receiver_package" translatable="false">com.android.cellbroadcastreceiver.module</string>
 
-    <!-- TODO(b/174964885): These media Uri are not defined in framework yet. Replace with framework defined variables once it's available. -->
+    <!-- These media Uri are not defined in framework yet. Replace with framework defined variables once it's available. -->
     <!-- Media Uri to view images storage category. -->
     <string name="config_images_storage_category_uri" translatable="false">content://com.android.providers.media.documents/root/images_root</string>
 
@@ -695,4 +698,10 @@
 
     <!-- Whether auto data switching on secondary SIM enables cross-SIM calling on both SIMs. -->
     <bool name="config_auto_data_switch_enables_cross_sim_calling">false</bool>
+
+    <!-- Whether checking adaptive charging to define battery manager visibility. -->
+    <bool name="config_battery_manager_consider_ac">false</bool>
+
+    <!-- Whether to display Cloned Apps page in Settings (Settings > Apps > Cloned Apps).-->
+    <bool name="config_cloned_apps_page_enabled">false</bool>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 1bd0943..57e47f2 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -220,10 +220,6 @@
     <dimen name="accessibility_qs_tooltip_margin">20dp</dimen>
     <dimen name="accessibility_qs_tooltip_margin_top">27dp</dimen>
 
-    <!-- Contrast level slider -->
-    <dimen name="contrast_level_seekbar_center_marker_height">14dp</dimen>
-    <dimen name="contrast_level_seekbar_center_marker_width">1dp</dimen>
-
     <!-- Restricted icon in switch bar -->
     <dimen name="restricted_icon_margin_end">16dp</dimen>
     <!-- Restricted icon size in switch bar -->
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6a18414..4ae9e67 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -228,6 +228,11 @@
     <!-- Summary of checkbox for enabling Bluetooth LE audio [CHAR LIMIT=none]-->
     <string name="bluetooth_enable_leaudio_summary">Enables Bluetooth LE audio feature if the device supports LE audio hardware capabilities.</string>
 
+    <!-- Setting Checkbox title for enabling Bluetooth LE Audio Allow List. [CHAR LIMIT=none] -->
+    <string name="bluetooth_enable_leaudio_allow_list">Enable Bluetooth LE audio Allow List</string>
+    <!-- Summary of checkbox for enabling Bluetooth LE audio Allow List [CHAR LIMIT=none]-->
+    <string name="bluetooth_enable_leaudio_allow_list_summary">Enable Bluetooth LE audio allow list feature.</string>
+
     <!-- Title for Bluetooth device group with media capability group [CHAR LIMIT=none]-->
     <string name="connected_device_media_device_title">Media devices</string>
     <!-- Title for Bluetooth device group with media capability group [CHAR LIMIT=none]-->
@@ -372,6 +377,21 @@
     <!-- Link for Locale helper page. [CHAR LIMIT=NONE]-->
     <string name="link_locale_picker_footer_learn_more" translatable="false">https://support.google.com/android?p=per_language_app_settings</string>
 
+    <!-- Title for asking to change system locale or not. [CHAR LIMIT=50]-->
+    <string name="title_change_system_locale">Change system language to %s ?</string>
+
+    <!-- The text of the confirmation dialog showing the system locale will be changed. [CHAR LIMIT=NONE]-->
+    <string name="desc_notice_device_locale_settings_change">Your device settings and regional preferences will change.</string>
+
+    <!-- A dialog button for confirmmation of system locale change. [CHAR LIMIT=25]-->
+    <string name="button_label_confirmation_of_system_locale_change">Change</string>
+
+    <!-- Title for saying this selected locale is unavailable to use. [CHAR LIMIT=50]-->
+    <string name="title_unavailable_locale">%s not available</string>
+
+    <!-- The text of the confirmation dialog for saying this selected locale is unavailable to use. [CHAR LIMIT=NONE]-->
+    <string name="desc_unavailable_locale">This language can’t be used as a system language, but you’ve let apps and websites know you prefer this language.</string>
+
     <!-- Regional Preferences begin -->
     <!-- The title of the menu entry of regional preferences. [CHAR LIMIT=50] -->
     <string name="regional_preferences_title">Regional preferences</string>
@@ -745,6 +765,8 @@
     <string name="security_settings_fingerprint_enroll_consent_introduction_title">Allow fingerprint unlock</string>
     <!-- Introduction title shown in fingerprint enrollment to introduce the fingerprint feature, when fingerprint unlock is disabled by device admin [CHAR LIMIT=40] -->
     <string name="security_settings_fingerprint_enroll_introduction_title_unlock_disabled">Use your fingerprint</string>
+    <!-- Learn more text of footer preference for fingerprint settings [CHAR LIMIT=NONE] -->
+    <string name="security_settings_fingerprint_settings_footer_learn_more">Learn more about Fingerprint Unlock</string>
     <!-- Introduction title shown in the bottom of fingerprint enrollment dialog [CHAR LIMIT=NONE]-->
     <string name="security_settings_fingerprint_enroll_introduction_footer_title_1">You\u2019re in control</string>
     <!-- Introduction title shown in the bottom of fingerprint enrollment dialog [CHAR LIMIT=NONE]-->
@@ -1993,6 +2015,16 @@
     <string name="wifi_hotspot_maximize_compatibility_single_ap_summary">Helps other devices find this hotspot. Reduces hotspot connection speed.</string>
     <!-- Summary for the toggle to show the maximize compatibility warning message in dual AP device [CHAR LIMIT=NONE]-->
     <string name="wifi_hotspot_maximize_compatibility_dual_ap_summary">Helps other devices find this hotspot. Increases battery usage.</string>
+    <!-- Title for Wifi hotspot speed [CHAR LIMIT=NONE]-->
+    <string name="wifi_hotspot_speed_title">Speed &amp; compatibility</string>
+    <!-- Summary for Wifi hotspot speed to 2.4 GHz band [CHAR LIMIT=NONE]-->
+    <string name="wifi_hotspot_speed_2g_summary">2.4 GHz / Any device can connect</string>
+    <!-- Summary for Wifi hotspot speed to 5 GHz band [CHAR LIMIT=NONE]-->
+    <string name="wifi_hotspot_speed_5g_summary">5 GHz / Most devices can connect</string>
+    <!-- Summary for Wifi hotspot speed to 6 GHz band [CHAR LIMIT=NONE]-->
+    <string name="wifi_hotspot_speed_6g_summary">6 GHz / Few devices can connect</string>
+    <!-- Summary for Wifi hotspot speed to 6 GHz band [CHAR LIMIT=NONE]-->
+    <string name="wifi_hotspot_speed_2g_and_5g_summary">2.4 and 5 GHz / Any device can connect</string>
 
     <!-- Summary text when turning hotspot on -->
     <string name="wifi_tether_starting">Turning hotspot on\u2026</string>
@@ -4384,12 +4416,6 @@
     <string name="accessibility_disable_animations">Remove animations</string>
     <!-- Summary for the accessibility preference for disabling animations. [CHAR LIMIT=60] -->
     <string name="accessibility_disable_animations_summary">Reduce movement on the screen</string>
-    <!-- Title for the accessibility preference for the contrast level slider. [CHAR LIMIT=35] -->
-    <string name="accessibility_contrast_level_title">Contrast Level</string>
-    <!-- 'Low' text at the left of the contrast level slider. [CHAR LIMIT=20] -->
-    <string name="accessibility_contrast_level_left_label">Standard</string>
-    <!-- 'High' text at the right of the contrast level slider. [CHAR LIMIT=20] -->
-    <string name="accessibility_contrast_level_right_label">High</string>
     <!-- Title for the accessibility preference for primary mono. [CHAR LIMIT=35] -->
     <string name="accessibility_toggle_primary_mono_title">Mono audio</string>
     <!-- Summary for the accessibility preference for primary mono. [CHAR LIMIT=60] -->
@@ -5121,9 +5147,7 @@
     <!-- Charge to full button for battery defender tips [CHAR LIMIT=NONE] -->
     <string name="battery_tip_charge_to_full_button">Charge to full</string>
     <!-- Title of incompatible charging battery tip [CHAR LIMIT=NONE] -->
-    <string name="battery_tip_incompatible_charging_title">Incompatible charging setup</string>
-    <!-- Message of incompatible charging battery tip [CHAR LIMIT=NONE] -->
-    <string name="battery_tip_incompatible_charging_message">Your battery is not charging or is charging very slowly</string>
+    <string name="battery_tip_incompatible_charging_title">Issue with charging accessory</string>
     <!-- Content description for the incompatible charging battery tip button [CHAR LIMIT=NONE] -->
     <string name="battery_tip_incompatible_charging_content_description">Learn more about incompatible charging</string>
 
@@ -5273,6 +5297,9 @@
     <!-- Battery Saver: Title for sticky battery saver preference [CHAR_LIMIT=60] -->
     <string name="battery_saver_sticky_title_new">Turn off when charged</string>
 
+    <!-- Battery Saver: Title for sticky battery saver preference with percentage [CHAR_LIMIT=60] -->
+    <string name="battery_saver_sticky_title_percentage">Turn off at <xliff:g id="battery_percentage" example="80%">%1$s</xliff:g></string>
+
     <!-- Battery Saver: Description for sticky battery saver preference [CHAR_LIMIT=NONE] -->
     <string name="battery_saver_sticky_description_new">Battery Saver turns off when battery reaches <xliff:g id="battery_percentage" example="80%">%1$s</xliff:g></string>
 
@@ -6779,6 +6806,10 @@
     <string name="cloned_app_creation_summary">Creating&#8230;</string>
     <!-- Summary text after an app is cloned [CHAR LIMIT=40] -->
     <string name="cloned_app_created_summary">Cloned</string>
+    <!-- Summary text shown in toast when app is being cloned [CHAR LIMIT=40] -->
+    <string name="cloned_app_creation_toast_summary">Creating <xliff:g id="package_label">%1$s</xliff:g> clone</string>
+    <!-- Summary text shown in toast after app is successfully cloned [CHAR LIMIT=40] -->
+    <string name="cloned_app_created_toast_summary">Created <xliff:g id="package_label">%1$s</xliff:g> clone</string>
     <!-- Summary text for system preference title, showing important setting items under system setting [CHAR LIMIT=NONE]-->
     <string name="system_dashboard_summary">Languages, gestures, time, backup</string>
     <!-- Summary text for language preference title, showing important setting items under language setting [CHAR LIMIT=NONE]-->
@@ -10312,13 +10343,13 @@
     <!-- Apps > App Details > Wifi access > Description. [CHAR LIMIT=NONE] -->
     <string name="change_wifi_state_app_detail_summary">Allow this app to turn Wi-Fi on or off, scan and connect to Wi-Fi networks, add or remove networks, or start a local-only hotspot</string>
 
-    <!-- Title for NFC launch [CHAR LIMIT=35] -->
-    <string name="change_nfc_tag_apps_title">NFC launch</string>
+    <!-- Title for Launch via NFC [CHAR LIMIT=35] -->
+    <string name="change_nfc_tag_apps_title">Launch via NFC</string>
 
-    <!-- Apps > App Details > Nfc launch > Switch title. [CHAR LIMIT=NONE] -->
+    <!-- Special app access > Launch via NFC > Switch title. [CHAR LIMIT=NONE] -->
     <string name="change_nfc_tag_apps_detail_switch">Allow launch on NFC scan</string>
 
-    <!-- Apps > App Details > Nfc launch > Description. [CHAR LIMIT=NONE] -->
+    <!-- Special app access > Launch via NFC > Description. [CHAR LIMIT=NONE] -->
     <string name="change_nfc_tag_apps_detail_summary">Allow this app to launch when a NFC tag is scanned.\nIf this permission is on, the app will be available as an option whenever a tag is detected.</string>
 
     <!-- Title for media output settings -->
diff --git a/res/xml/accessibility_color_and_motion.xml b/res/xml/accessibility_color_and_motion.xml
index 72c67f9..a313526 100644
--- a/res/xml/accessibility_color_and_motion.xml
+++ b/res/xml/accessibility_color_and_motion.xml
@@ -64,11 +64,6 @@
         android:title="@string/accessibility_toggle_large_pointer_icon_title"
         settings:controller="com.android.settings.accessibility.LargePointerIconPreferenceController"/>
 
-    <com.android.settings.accessibility.ContrastLevelSeekBarPreference
-        android:key="seekbar_color_contrast"
-        android:persistent="false"
-        android:title="@string/accessibility_contrast_level_title"/>
-
     <PreferenceCategory
         android:key="experimental_category"
         android:persistent="false"
diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml
index 0f0aeff..f80fe57 100644
--- a/res/xml/configure_notification_settings.xml
+++ b/res/xml/configure_notification_settings.xml
@@ -131,14 +131,14 @@
         <Preference
             android:fragment="com.android.settings.accessibility.FlashNotificationsPreferenceFragment"
             android:key="flash_notifications_preference"
-            android:order="18"
+            android:order="19"
             android:persistent="false"
             android:title="@string/flash_notifications_title"
             settings:controller="com.android.settings.accessibility.FlashNotificationsPreferenceController" />
 
         <com.android.settingslib.RestrictedPreference
             android:key="app_and_notif_cell_broadcast_settings"
-            android:order="19"
+            android:order="20"
             android:title="@string/cell_broadcast_settings"
             settings:useAdminDisabledSummary="true">
             <intent
@@ -149,33 +149,33 @@
 
         <SwitchPreference
              android:key="silent_icons"
-             android:order="20"
+             android:order="21"
              android:title="@string/silent_notifications_status_bar"
              settings:controller="com.android.settings.notification.SilentStatusBarPreferenceController"/>
 
         <SwitchPreference
             android:key="show_snooze_options"
-            android:order="21"
+            android:order="22"
             android:title="@string/snooze_options_title"
             settings:controller="com.android.settings.notification.SnoozeNotificationPreferenceController" />
 
         <!-- Notification badging -->
         <SwitchPreference
             android:key="notification_badging"
-            android:order="22"
+            android:order="23"
             android:title="@string/notification_badging_title"
             settings:controller="com.android.settings.notification.BadgingNotificationPreferenceController"/>
 
         <!-- Pulse notification light, on devices that support it -->
         <SwitchPreference
             android:key="notification_pulse"
-            android:order="23"
+            android:order="24"
             android:title="@string/notification_pulse_title"
             settings:controller="com.android.settings.notification.PulseNotificationPreferenceController"/>
 
         <com.android.settingslib.PrimarySwitchPreference
             android:key="notification_assistant"
-            android:order="24"
+            android:order="25"
             android:title="@string/notification_assistant_title"
             android:summary="@string/notification_assistant_summary"
             settings:controller="com.android.settings.notification.NotificationAssistantPreferenceController"/>
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index 7e720c9..f3ac926 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -346,6 +346,11 @@
             android:summary="@string/bluetooth_enable_leaudio_summary" />
 
         <SwitchPreference
+            android:key="bluetooth_enable_leaudio_allow_list"
+            android:title="@string/bluetooth_enable_leaudio_allow_list"
+            android:summary="@string/bluetooth_enable_leaudio_allow_list_summary" />
+
+        <SwitchPreference
             android:key="bluetooth_disable_le_audio_hw_offload"
             android:title="@string/bluetooth_disable_le_audio_hw_offload" />
 
@@ -505,6 +510,11 @@
             android:title="@string/display_cutout_emulation"
             settings:keywords="@string/display_cutout_emulation_keywords" />
 
+        <SwitchPreference
+            android:key="transparent_navigation_bar"
+            android:title="@string/transparent_navigation_bar"
+            android:summary="@string/transparent_navigation_bar_summary" />
+
     </PreferenceCategory>
 
     <PreferenceCategory
diff --git a/res/xml/wifi_tether_settings.xml b/res/xml/wifi_tether_settings.xml
index 21f347b..1cd5f48 100644
--- a/res/xml/wifi_tether_settings.xml
+++ b/res/xml/wifi_tether_settings.xml
@@ -45,4 +45,10 @@
     <SwitchPreference
         android:key="wifi_tether_maximize_compatibility"
         android:title="@string/wifi_hotspot_maximize_compatibility"/>
+
+    <Preference
+        android:key="wifi_hotspot_speed"
+        android:title="@string/wifi_hotspot_speed_title"
+        android:summary="@string/summary_placeholder"
+        settings:isPreferenceVisible="@bool/config_show_wifi_hotspot_speed"/>
 </PreferenceScreen>
diff --git a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
index 33dab82..45923e3 100644
--- a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
@@ -66,6 +66,7 @@
     protected int mSavedCheckBoxValue = NOT_SET;
 
     protected ShortcutPreference mShortcutPreference;
+    protected Dialog mDialog;
     private AccessibilityManager.TouchExplorationStateChangeListener
             mTouchExplorationStateChangeListener;
     private AccessibilitySettingsContentObserver mSettingsContentObserver;
@@ -167,12 +168,15 @@
     @Override
     public void onResume() {
         super.onResume();
+
         final AccessibilityManager am = getPrefContext().getSystemService(
                 AccessibilityManager.class);
         am.addTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener);
         mSettingsContentObserver.register(getContentResolver());
         updateShortcutPreferenceData();
         updateShortcutPreference();
+
+        updateEditShortcutDialogIfNeeded();
     }
 
     @Override
@@ -200,31 +204,30 @@
 
     @Override
     public Dialog onCreateDialog(int dialogId) {
-        final Dialog dialog;
         switch (dialogId) {
             case DialogEnums.EDIT_SHORTCUT:
                 final int dialogType = WizardManagerHelper.isAnySetupWizard(getIntent())
                         ? AccessibilityDialogUtils.DialogType.EDIT_SHORTCUT_GENERIC_SUW :
                         AccessibilityDialogUtils.DialogType.EDIT_SHORTCUT_GENERIC;
-                dialog = AccessibilityDialogUtils.showEditShortcutDialog(
+                mDialog = AccessibilityDialogUtils.showEditShortcutDialog(
                         getPrefContext(), dialogType, getShortcutTitle(),
                         this::callOnAlertDialogCheckboxClicked);
-                setupEditShortcutDialog(dialog);
-                return dialog;
+                setupEditShortcutDialog(mDialog);
+                return mDialog;
             case DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL:
                 if (WizardManagerHelper.isAnySetupWizard(getIntent())) {
-                    dialog = AccessibilityGestureNavigationTutorial
+                    mDialog = AccessibilityGestureNavigationTutorial
                             .createAccessibilityTutorialDialogForSetupWizard(
                                     getPrefContext(), getUserShortcutTypes(),
                                     this::callOnTutorialDialogButtonClicked);
                 } else {
-                    dialog = AccessibilityGestureNavigationTutorial
+                    mDialog = AccessibilityGestureNavigationTutorial
                             .createAccessibilityTutorialDialog(
                                     getPrefContext(), getUserShortcutTypes(),
                                     this::callOnTutorialDialogButtonClicked);
                 }
-                dialog.setCanceledOnTouchOutside(false);
-                return dialog;
+                mDialog.setCanceledOnTouchOutside(false);
+                return mDialog;
             default:
                 throw new IllegalArgumentException("Unsupported dialogId " + dialogId);
         }
@@ -368,6 +371,13 @@
         getPreferenceScreen().addPreference(generalCategory);
     }
 
+    private void updateEditShortcutDialogIfNeeded() {
+        if (mDialog == null || !mDialog.isShowing()) {
+            return;
+        }
+        AccessibilityDialogUtils.updateShortcutInDialog(getContext(), mDialog);
+    }
+
     @VisibleForTesting
     void saveNonEmptyUserShortcutType(int type) {
         if (type == AccessibilityUtil.UserShortcutType.EMPTY) {
diff --git a/src/com/android/settings/accessibility/CameraFlashNotificationPreferenceController.java b/src/com/android/settings/accessibility/CameraFlashNotificationPreferenceController.java
index c630267..f19795f 100644
--- a/src/com/android/settings/accessibility/CameraFlashNotificationPreferenceController.java
+++ b/src/com/android/settings/accessibility/CameraFlashNotificationPreferenceController.java
@@ -18,7 +18,6 @@
 
 import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
 import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
 
 import android.content.Context;
 import android.provider.Settings;
@@ -45,13 +44,13 @@
     @Override
     public boolean isChecked() {
         return Settings.System.getInt(mContext.getContentResolver(),
-                SETTING_KEY_CAMERA_FLASH_NOTIFICATION, OFF) != OFF;
+                Settings.System.CAMERA_FLASH_NOTIFICATION, OFF) != OFF;
     }
 
     @Override
     public boolean setChecked(boolean isChecked) {
         return Settings.System.putInt(mContext.getContentResolver(),
-                SETTING_KEY_CAMERA_FLASH_NOTIFICATION, (isChecked ? ON : OFF));
+                Settings.System.CAMERA_FLASH_NOTIFICATION, (isChecked ? ON : OFF));
     }
 
     @Override
diff --git a/src/com/android/settings/accessibility/ContrastLevelSeekBar.java b/src/com/android/settings/accessibility/ContrastLevelSeekBar.java
deleted file mode 100644
index 8723285..0000000
--- a/src/com/android/settings/accessibility/ContrastLevelSeekBar.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2022 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 android.view.HapticFeedbackConstants.CLOCK_TICK;
-
-import static com.android.settings.Utils.isNightMode;
-import static com.android.settings.accessibility.ContrastLevelSeekBarPreference.CONTRAST_SLIDER_TICKS;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.AttributeSet;
-import android.widget.SeekBar;
-
-import com.android.settings.R;
-
-/**
- * A custom seekbar for the contrast level setting.
- *
- * Adds a center line indicator between left and right, which snaps to if close.
- * Updates the Settings.Secure.CONTRAST_LEVEL setting on progress changed.
- *
- * TODO(b/266071578): remove this class and replace this with the final UI
- */
-public class ContrastLevelSeekBar extends SeekBar {
-
-    private final Context mContext;
-    private int mLastProgress = -1;
-
-    private final Paint mMarkerPaint;
-    private final Rect mMarkerRect;
-
-    private final OnSeekBarChangeListener mProxySeekBarListener = new OnSeekBarChangeListener() {
-        @Override
-        public void onStopTrackingTouch(SeekBar seekBar) { }
-
-        @Override
-        public void onStartTrackingTouch(SeekBar seekBar) { }
-
-        @Override
-        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-            if (!fromUser || progress == mLastProgress) return;
-            seekBar.performHapticFeedback(CLOCK_TICK);
-            mLastProgress = progress;
-
-            // rescale progress from [0, 1, 2] to [0, 0.5, 1]
-            final float contrastLevel = (float) progress / CONTRAST_SLIDER_TICKS;
-
-            Settings.Secure.putFloatForUser(mContext.getContentResolver(),
-                    Settings.Secure.CONTRAST_LEVEL, contrastLevel, UserHandle.USER_CURRENT);
-        }
-    };
-
-    public ContrastLevelSeekBar(Context context, AttributeSet attrs) {
-        this(context, attrs, com.android.internal.R.attr.seekBarStyle);
-    }
-
-    public ContrastLevelSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0 /* defStyleRes */);
-    }
-
-    public ContrastLevelSeekBar(
-            Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        mContext = context;
-        Resources res = getResources();
-        mMarkerRect = new Rect(0 /* left */, 0 /* top */,
-                res.getDimensionPixelSize(R.dimen.contrast_level_seekbar_center_marker_width),
-                res.getDimensionPixelSize(R.dimen.contrast_level_seekbar_center_marker_height));
-        mMarkerPaint = new Paint();
-
-        // the might be a better colour for the markers, but this slider is temporary anyway
-        mMarkerPaint.setColor(isNightMode(context) ? Color.WHITE : Color.BLACK);
-        mMarkerPaint.setStyle(Paint.Style.FILL);
-        // Remove the progress colour
-        setProgressTintList(ColorStateList.valueOf(Color.TRANSPARENT));
-        super.setOnSeekBarChangeListener(mProxySeekBarListener);
-    }
-
-    @Override
-    public void setOnSeekBarChangeListener(OnSeekBarChangeListener listener) { }
-
-    // Note: the superclass AbsSeekBar.onDraw is synchronized.
-    @Override
-    protected synchronized void onDraw(Canvas canvas) {
-
-        // Draw a marker at the center of the seekbar
-        int seekBarCenter = (getHeight() - getPaddingBottom()) / 2;
-        float sliderWidth = getWidth() - mMarkerRect.right - getPaddingEnd();
-        canvas.save();
-        canvas.translate(sliderWidth / 2f,
-                seekBarCenter - (mMarkerRect.bottom / 2f));
-        canvas.drawRect(mMarkerRect, mMarkerPaint);
-        canvas.restore();
-        super.onDraw(canvas);
-    }
-}
diff --git a/src/com/android/settings/accessibility/ContrastLevelSeekBarPreference.java b/src/com/android/settings/accessibility/ContrastLevelSeekBarPreference.java
deleted file mode 100644
index 15795d8..0000000
--- a/src/com/android/settings/accessibility/ContrastLevelSeekBarPreference.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2022 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 android.content.Context;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.AttributeSet;
-
-import androidx.core.content.res.TypedArrayUtils;
-import androidx.preference.PreferenceViewHolder;
-
-import com.android.settings.R;
-import com.android.settings.widget.SeekBarPreference;
-
-/** A slider preference that directly controls the contrast level **/
-public class ContrastLevelSeekBarPreference extends SeekBarPreference {
-
-    /**
-     * The number of ticks of the slider (the more ticks, the more continuous the slider feels).
-     */
-    public static final int CONTRAST_SLIDER_TICKS = 2;
-
-    private final Context mContext;
-    private ContrastLevelSeekBar mSeekBar;
-
-    public ContrastLevelSeekBarPreference(Context context, AttributeSet attrs) {
-        super(context, attrs, TypedArrayUtils.getAttr(context,
-                R.attr.preferenceStyle,
-                android.R.attr.preferenceStyle));
-        mContext = context;
-        setLayoutResource(R.layout.preference_contrast_level_slider);
-    }
-
-    @Override
-    public void onBindViewHolder(PreferenceViewHolder view) {
-        super.onBindViewHolder(view);
-        mSeekBar = (ContrastLevelSeekBar) view.findViewById(
-                com.android.internal.R.id.seekbar);
-        init();
-    }
-
-    private void init() {
-        if (mSeekBar == null) {
-            return;
-        }
-        final float contrastLevel = Settings.Secure.getFloatForUser(
-                mContext.getContentResolver(), Settings.Secure.CONTRAST_LEVEL,
-                0.f /* default */, UserHandle.USER_CURRENT);
-
-        mSeekBar.setMax(CONTRAST_SLIDER_TICKS);
-
-        // Rescale contrast from [0, 0.5, 1] to [0, 1, 2]
-        int progress = Math.max(0, Math.round(contrastLevel * CONTRAST_SLIDER_TICKS));
-
-        mSeekBar.setProgress(progress);
-        mSeekBar.setEnabled(isEnabled());
-    }
-}
diff --git a/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceController.java b/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceController.java
index 8774043..5a16a30 100644
--- a/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceController.java
+++ b/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceController.java
@@ -19,8 +19,6 @@
 
 import static com.android.settings.accessibility.FlashNotificationsUtil.ACTION_FLASH_NOTIFICATION_START_PREVIEW;
 import static com.android.settings.accessibility.FlashNotificationsUtil.EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
 import static com.android.settings.accessibility.FlashNotificationsUtil.TYPE_SHORT_PREVIEW;
 
 import android.content.ContentResolver;
@@ -95,10 +93,10 @@
             @NonNull Lifecycle.Event event) {
         if (event == Lifecycle.Event.ON_RESUME) {
             mContentResolver.registerContentObserver(
-                    Settings.System.getUriFor(SETTING_KEY_CAMERA_FLASH_NOTIFICATION),
+                    Settings.System.getUriFor(Settings.System.CAMERA_FLASH_NOTIFICATION),
                     /* notifyForDescendants= */ false, mContentObserver);
             mContentResolver.registerContentObserver(
-                    Settings.System.getUriFor(SETTING_KEY_SCREEN_FLASH_NOTIFICATION),
+                    Settings.System.getUriFor(Settings.System.SCREEN_FLASH_NOTIFICATION),
                     /* notifyForDescendants= */ false, mContentObserver);
         } else if (event == Lifecycle.Event.ON_PAUSE) {
             mContentResolver.unregisterContentObserver(mContentObserver);
diff --git a/src/com/android/settings/accessibility/FlashNotificationsUtil.java b/src/com/android/settings/accessibility/FlashNotificationsUtil.java
index 429936e..544f835 100644
--- a/src/com/android/settings/accessibility/FlashNotificationsUtil.java
+++ b/src/com/android/settings/accessibility/FlashNotificationsUtil.java
@@ -16,8 +16,6 @@
 
 package com.android.settings.accessibility;
 
-import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
-
 import android.content.Context;
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraCharacteristics;
@@ -43,19 +41,10 @@
     static final String EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE =
             "com.android.internal.intent.extra.FLASH_NOTIFICATION_PREVIEW_TYPE";
 
-    static final String SETTING_KEY_CAMERA_FLASH_NOTIFICATION =
-            "camera_flash_notification";
-    static final String SETTING_KEY_SCREEN_FLASH_NOTIFICATION =
-            "screen_flash_notification";
-    static final String SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR =
-            "screen_flash_notification_color_global";
-
     static final int TYPE_SHORT_PREVIEW = 0;
     static final int TYPE_LONG_PREVIEW = 1;
 
-    static final int DEFAULT_SCREEN_FLASH_COLOR =
-            ScreenFlashNotificationColor.YELLOW.mColorInt;
-
+    static final int DEFAULT_SCREEN_FLASH_COLOR = ScreenFlashNotificationColor.YELLOW.mColorInt;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({
@@ -128,9 +117,9 @@
 
         final boolean isTorchAvailable = FlashNotificationsUtil.isTorchAvailable(context);
         final boolean isCameraFlashEnabled = Settings.System.getInt(context.getContentResolver(),
-                SETTING_KEY_CAMERA_FLASH_NOTIFICATION, State.OFF) != State.OFF;
+                Settings.System.CAMERA_FLASH_NOTIFICATION, State.OFF) != State.OFF;
         final boolean isScreenFlashEnabled = Settings.System.getInt(context.getContentResolver(),
-                SETTING_KEY_SCREEN_FLASH_NOTIFICATION, State.OFF) != State.OFF;
+                Settings.System.SCREEN_FLASH_NOTIFICATION, State.OFF) != State.OFF;
 
         return ((isTorchAvailable && isCameraFlashEnabled) ? State.CAMERA : State.OFF)
                 | (isScreenFlashEnabled ? State.SCREEN : State.OFF);
diff --git a/src/com/android/settings/accessibility/FontSizeData.java b/src/com/android/settings/accessibility/FontSizeData.java
index 88aa1aa..1226d25 100644
--- a/src/com/android/settings/accessibility/FontSizeData.java
+++ b/src/com/android/settings/accessibility/FontSizeData.java
@@ -16,6 +16,9 @@
 
 package com.android.settings.accessibility;
 
+import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
+import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
+
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.Resources;
@@ -50,6 +53,12 @@
     @Override
     void commit(int currentProgress) {
         final ContentResolver resolver = getContext().getContentResolver();
+        if (Settings.Secure.getInt(resolver,
+                Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
+                /* def= */ OFF) != ON) {
+            Settings.Secure.putInt(resolver,
+                    Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED, ON);
+        }
         Settings.System.putFloat(resolver, Settings.System.FONT_SCALE,
                 getValues().get(currentProgress));
     }
diff --git a/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceController.java b/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceController.java
index 546ae19..2b96dcf 100644
--- a/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceController.java
+++ b/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceController.java
@@ -19,8 +19,6 @@
 import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
 import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
 import static com.android.settings.accessibility.FlashNotificationsUtil.DEFAULT_SCREEN_FLASH_COLOR;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR;
 
 import android.content.Context;
 import android.graphics.Color;
@@ -59,7 +57,7 @@
     @Override
     public boolean isChecked() {
         return Settings.System.getInt(mContext.getContentResolver(),
-                SETTING_KEY_SCREEN_FLASH_NOTIFICATION, OFF) != OFF;
+                Settings.System.SCREEN_FLASH_NOTIFICATION, OFF) != OFF;
     }
 
     @Override
@@ -67,7 +65,7 @@
         if (isChecked) checkAndSetInitialColor();
 
         return Settings.System.putInt(mContext.getContentResolver(),
-                SETTING_KEY_SCREEN_FLASH_NOTIFICATION, (isChecked ? ON : OFF));
+                Settings.System.SCREEN_FLASH_NOTIFICATION, (isChecked ? ON : OFF));
     }
 
     @Override
@@ -79,7 +77,8 @@
     public CharSequence getSummary() {
         return FlashNotificationsUtil.getColorDescriptionText(mContext,
                 Settings.System.getInt(mContext.getContentResolver(),
-                        SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, DEFAULT_SCREEN_FLASH_COLOR));
+                        Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR,
+                        DEFAULT_SCREEN_FLASH_COLOR));
     }
 
     @Override
@@ -94,12 +93,12 @@
         if (getPreferenceKey().equals(preference.getKey()) && mParentFragment != null) {
 
             final int initialColor = Settings.System.getInt(mContext.getContentResolver(),
-                    SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR,
+                    Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR,
                     DEFAULT_SCREEN_FLASH_COLOR);
 
             final Consumer<Integer> consumer = color -> {
                 Settings.System.putInt(mContext.getContentResolver(),
-                        SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, color);
+                        Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, color);
                 refreshColorSummary();
             };
 
@@ -115,10 +114,10 @@
 
     private void checkAndSetInitialColor() {
         if (Settings.System.getInt(mContext.getContentResolver(),
-                SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, Color.TRANSPARENT)
+                Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, Color.TRANSPARENT)
                 == Color.TRANSPARENT) {
             Settings.System.putInt(mContext.getContentResolver(),
-                    SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, DEFAULT_SCREEN_FLASH_COLOR);
+                    Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, DEFAULT_SCREEN_FLASH_COLOR);
         }
     }
 
diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
index 22c57b7..e362e0d 100644
--- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
@@ -120,7 +120,6 @@
     private AccessibilityQuickSettingsTooltipWindow mTooltipWindow;
     private boolean mNeedsQSTooltipReshow = false;
     private int mNeedsQSTooltipType = QuickSettingsTooltipType.GUIDE_TO_EDIT;
-    private boolean mSavedAccessibilityFloatingMenuEnabled;
     private ImageView mImageGetterCacheView;
     protected final Html.ImageGetter mImageGetter = (String str) -> {
         if (str != null && str.startsWith(IMG_PREFIX)) {
@@ -276,8 +275,6 @@
                 AccessibilityManager.class);
         am.removeTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener);
         mSettingsContentObserver.unregister(getContentResolver());
-        mSavedAccessibilityFloatingMenuEnabled = AccessibilityUtil.isFloatingMenuEnabled(
-                getContext());
         super.onPause();
     }
 
diff --git a/src/com/android/settings/applications/ClonedAppsPreferenceController.java b/src/com/android/settings/applications/ClonedAppsPreferenceController.java
index 2b6ab5d..fd6bfe0 100644
--- a/src/com/android/settings/applications/ClonedAppsPreferenceController.java
+++ b/src/com/android/settings/applications/ClonedAppsPreferenceController.java
@@ -56,7 +56,9 @@
     @Override
     public int getAvailabilityStatus() {
         return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_APP_CLONING,
-                PROPERTY_CLONED_APPS_ENABLED, false) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+                PROPERTY_CLONED_APPS_ENABLED, false)
+                && mContext.getResources().getBoolean(R.bool.config_cloned_apps_page_enabled)
+                ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
     }
 
     @Override
diff --git a/src/com/android/settings/applications/ProcessStatsUi.java b/src/com/android/settings/applications/ProcessStatsUi.java
index f49d638..ab334a8 100644
--- a/src/com/android/settings/applications/ProcessStatsUi.java
+++ b/src/com/android/settings/applications/ProcessStatsUi.java
@@ -137,11 +137,6 @@
             ProcessStats.STATE_TOP
     };
 
-    public static final int[] CACHED_PROC_STATES = new int[] {
-            ProcessStats.STATE_CACHED_ACTIVITY, ProcessStats.STATE_CACHED_ACTIVITY_CLIENT,
-            ProcessStats.STATE_CACHED_EMPTY
-    };
-
     public static String makeDuration(long time) {
         StringBuilder sb = new StringBuilder(32);
         TimeUtils.formatDuration(time, sb);
diff --git a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
index 0bccfe2..f8c1f64 100644
--- a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
+++ b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
@@ -25,14 +25,11 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
 import android.credentials.CredentialManager;
-import android.credentials.ListEnabledProvidersException;
-import android.credentials.ListEnabledProvidersResponse;
+import android.credentials.CredentialProviderInfo;
 import android.credentials.SetEnabledProvidersException;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.os.CancellationSignal;
 import android.os.OutcomeReceiver;
 import android.os.UserHandle;
 import android.util.IconDrawableFactory;
@@ -71,10 +68,9 @@
 
     private final PackageManager mPm;
     private final IconDrawableFactory mIconFactory;
-    private final List<ServiceInfo> mServices;
+    private final List<CredentialProviderInfo> mServices;
     private final Set<String> mEnabledPackageNames;
     private final @Nullable CredentialManager mCredentialManager;
-    private final CancellationSignal mCancellationSignal = new CancellationSignal();
     private final Executor mExecutor;
     private final Map<String, SwitchPreference> mPrefs = new HashMap<>(); // key is package name
 
@@ -132,42 +128,20 @@
                 lifecycleOwner,
                 mCredentialManager.getCredentialProviderServices(
                         getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY));
-
-        mCredentialManager.listEnabledProviders(
-                mCancellationSignal,
-                mExecutor,
-                new OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException>() {
-                    @Override
-                    public void onResult(ListEnabledProvidersResponse result) {
-                        Set<String> enabledPackages = new HashSet<>();
-                        for (String flattenedComponentName : result.getProviderComponentNames()) {
-                            ComponentName cn =
-                                    ComponentName.unflattenFromString(flattenedComponentName);
-                            if (cn != null) {
-                                enabledPackages.add(cn.getPackageName());
-                            }
-                        }
-
-                        setEnabledPackageNames(enabledPackages);
-                    }
-
-                    @Override
-                    public void onError(ListEnabledProvidersException e) {
-                        Log.e(TAG, "listEnabledProviders error: " + e.toString());
-                    }
-                });
     }
 
     @VisibleForTesting
-    void setAvailableServices(LifecycleOwner lifecycleOwner, List<ServiceInfo> availableServices) {
+    void setAvailableServices(
+            LifecycleOwner lifecycleOwner, List<CredentialProviderInfo> availableServices) {
         mServices.clear();
         mServices.addAll(availableServices);
-    }
 
-    @VisibleForTesting
-    void setEnabledPackageNames(Set<String> enabledPackages) {
         mEnabledPackageNames.clear();
-        mEnabledPackageNames.addAll(enabledPackages);
+        for (CredentialProviderInfo cpi : availableServices) {
+            if (cpi.isEnabled()) {
+                mEnabledPackageNames.add(cpi.getServiceInfo().packageName);
+            }
+        }
 
         for (String packageName : mPrefs.keySet()) {
             mPrefs.get(packageName).setChecked(mEnabledPackageNames.contains(packageName));
@@ -189,22 +163,22 @@
         PreferenceGroup group = screen.findPreference(getPreferenceKey());
         Context context = screen.getContext();
 
-        for (ServiceInfo serviceInfo : mServices) {
-            CharSequence title = "";
-            if (serviceInfo.nonLocalizedLabel != null) {
-                title = serviceInfo.loadLabel(mPm);
-            }
-
-            group.addPreference(
-                    addProviderPreference(
-                            context,
-                            title,
-                            mIconFactory.getBadgedIcon(
-                                    serviceInfo, serviceInfo.applicationInfo, getUser()),
-                            serviceInfo.packageName));
+        for (CredentialProviderInfo service : mServices) {
+            group.addPreference(createPreference(context, service));
         }
     }
 
+    /** Creates a preference object based on the provider info. */
+    @VisibleForTesting
+    public SwitchPreference createPreference(Context context, CredentialProviderInfo service) {
+        CharSequence label = service.getLabel(context);
+        return addProviderPreference(
+                context,
+                label == null ? "" : label,
+                service.getServiceIcon(mContext),
+                service.getServiceInfo().packageName);
+    }
+
     /**
      * Enables the package name as an enabled credential manager provider.
      *
@@ -246,9 +220,10 @@
     public List<String> getEnabledSettings() {
         // Get all the component names that match the enabled package names.
         List<String> enabledServices = new ArrayList<>();
-        for (ServiceInfo service : mServices) {
-            if (mEnabledPackageNames.contains(service.packageName)) {
-                enabledServices.add(service.getComponentName().flattenToString());
+        for (CredentialProviderInfo service : mServices) {
+            ComponentName cn = service.getServiceInfo().getComponentName();
+            if (mEnabledPackageNames.contains(service.getServiceInfo().packageName)) {
+                enabledServices.add(cn.flattenToString());
             }
         }
 
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
index fcf4a60..9b1b30a 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@@ -769,7 +769,10 @@
         }
     }
 
-    private void configureEnrollmentStage(@RawRes int lottie) {
+    @VisibleForTesting void configureEnrollmentStage(@RawRes int lottie) {
+        if (!mCanAssumeSfps) {
+            setDescriptionText("");
+        }
         LottieCompositionFactory.fromRawRes(this, lottie)
                 .addListener((c) -> {
                     mIllustrationLottie.setComposition(c);
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index f2ed120..fd320d9 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -450,6 +450,10 @@
                 column2.mTitle = getText(
                         R.string.security_fingerprint_disclaimer_lockscreen_disabled_2
                 );
+                if (isSfps()) {
+                    column2.mLearnMoreOverrideText = getText(
+                            R.string.security_settings_fingerprint_settings_footer_learn_more);
+                }
                 column2.mLearnMoreClickListener = learnMoreClickListener;
                 mFooterColumns.add(column2);
             } else {
@@ -458,6 +462,10 @@
                         R.string.security_settings_fingerprint_enroll_introduction_v3_message,
                         DeviceHelper.getDeviceName(getActivity()));
                 column.mLearnMoreClickListener = learnMoreClickListener;
+                if (isSfps()) {
+                    column.mLearnMoreOverrideText = getText(
+                            R.string.security_settings_fingerprint_settings_footer_learn_more);
+                }
                 mFooterColumns.add(column);
             }
         }
diff --git a/src/com/android/settings/biometrics2/data/repository/AccessibilityRepository.java b/src/com/android/settings/biometrics2/data/repository/AccessibilityRepository.java
deleted file mode 100644
index 20d7f1f..0000000
--- a/src/com/android/settings/biometrics2/data/repository/AccessibilityRepository.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2023 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.biometrics2.data.repository;
-
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-
-import androidx.annotation.NonNull;
-
-/**
- * This repository is used to call all APIs in {@link AccessibilityManager}
- */
-public class AccessibilityRepository {
-
-    private final AccessibilityManager mAccessibilityManager;
-
-    public AccessibilityRepository(AccessibilityManager accessibilityManager) {
-        mAccessibilityManager = accessibilityManager;
-    }
-
-    /**
-     * Requests interruption of the accessibility feedback from all accessibility services.
-     */
-    public void interrupt() {
-        mAccessibilityManager.interrupt();
-    }
-
-    /**
-     * Returns if the {@link AccessibilityManager} is enabled.
-     *
-     * @return True if this {@link AccessibilityManager} is enabled, false otherwise.
-     */
-    public boolean isEnabled() {
-        return mAccessibilityManager.isEnabled();
-    }
-
-    /**
-     * Sends an {@link AccessibilityEvent}.
-     *
-     * @param event The event to send.
-     *
-     * @throws IllegalStateException if accessibility is not enabled.
-     *
-     * <strong>Note:</strong> The preferred mechanism for sending custom accessibility
-     * events is through calling
-     * {@link android.view.ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)}
-     * instead of this method to allow predecessors to augment/filter events sent by
-     * their descendants.
-     */
-    public void sendAccessibilityEvent(@NonNull AccessibilityEvent event) {
-        mAccessibilityManager.sendAccessibilityEvent(event);
-    }
-
-    /**
-     * Returns if the touch exploration in the system is enabled.
-     *
-     * @return True if touch exploration is enabled, false otherwise.
-     */
-    public boolean isTouchExplorationEnabled() {
-        return mAccessibilityManager.isTouchExplorationEnabled();
-    }
-}
diff --git a/src/com/android/settings/biometrics2/data/repository/VibratorRepository.java b/src/com/android/settings/biometrics2/data/repository/VibratorRepository.java
deleted file mode 100644
index cccafff..0000000
--- a/src/com/android/settings/biometrics2/data/repository/VibratorRepository.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2023 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.biometrics2.data.repository;
-
-import android.annotation.NonNull;
-import android.os.VibrationAttributes;
-import android.os.VibrationEffect;
-import android.os.Vibrator;
-
-/**
- * This repository is used to call all APIs in {@link Vibrator}
- */
-public class VibratorRepository {
-
-    private final Vibrator mVibrator;
-
-    public VibratorRepository(Vibrator vibrator) {
-        mVibrator = vibrator;
-    }
-
-    /**
-     * Like {@link #vibrate(VibrationEffect, VibrationAttributes)}, but allows the
-     * caller to specify the vibration is owned by someone else and set a reason for vibration.
-     */
-    public void vibrate(int uid, String opPkg, @NonNull VibrationEffect vibe,
-            String reason, @NonNull VibrationAttributes attributes) {
-        mVibrator.vibrate(uid, opPkg, vibe, reason, attributes);
-    }
-}
diff --git a/src/com/android/settings/biometrics2/factory/BiometricsRepositoryProvider.java b/src/com/android/settings/biometrics2/factory/BiometricsRepositoryProvider.java
index 8e17ba4..fdc5745 100644
--- a/src/com/android/settings/biometrics2/factory/BiometricsRepositoryProvider.java
+++ b/src/com/android/settings/biometrics2/factory/BiometricsRepositoryProvider.java
@@ -21,9 +21,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import com.android.settings.biometrics2.data.repository.AccessibilityRepository;
 import com.android.settings.biometrics2.data.repository.FingerprintRepository;
-import com.android.settings.biometrics2.data.repository.VibratorRepository;
 
 /**
  * Interface for BiometricsRepositoryProvider
@@ -35,16 +33,4 @@
      */
     @Nullable
     FingerprintRepository getFingerprintRepository(@NonNull Application application);
-
-    /**
-     * Get VibtatorRepository
-     */
-    @Nullable
-    VibratorRepository getVibratorRepository(@NonNull Application application);
-
-    /**
-     * Get AccessibilityRepository
-     */
-    @Nullable
-    AccessibilityRepository getAccessibilityRepository(@NonNull Application application);
 }
diff --git a/src/com/android/settings/biometrics2/factory/BiometricsRepositoryProviderImpl.java b/src/com/android/settings/biometrics2/factory/BiometricsRepositoryProviderImpl.java
index 7b1fe16..22409c8 100644
--- a/src/com/android/settings/biometrics2/factory/BiometricsRepositoryProviderImpl.java
+++ b/src/com/android/settings/biometrics2/factory/BiometricsRepositoryProviderImpl.java
@@ -18,16 +18,12 @@
 
 import android.app.Application;
 import android.hardware.fingerprint.FingerprintManager;
-import android.os.Vibrator;
-import android.view.accessibility.AccessibilityManager;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.settings.Utils;
-import com.android.settings.biometrics2.data.repository.AccessibilityRepository;
 import com.android.settings.biometrics2.data.repository.FingerprintRepository;
-import com.android.settings.biometrics2.data.repository.VibratorRepository;
 
 /**
  * Implementation for BiometricsRepositoryProvider
@@ -35,8 +31,6 @@
 public class BiometricsRepositoryProviderImpl implements BiometricsRepositoryProvider {
 
     private static volatile FingerprintRepository sFingerprintRepository;
-    private static volatile VibratorRepository sVibratorRepository;
-    private static volatile AccessibilityRepository sAccessibilityRepository;
 
     /**
      * Get FingerprintRepository
@@ -58,49 +52,4 @@
         }
         return sFingerprintRepository;
     }
-
-    /**
-     * Get VibratorRepository
-     */
-    @Nullable
-    @Override
-    public VibratorRepository getVibratorRepository(@NonNull Application application) {
-
-        final Vibrator vibrator = application.getSystemService(Vibrator.class);
-        if (vibrator == null) {
-            return null;
-        }
-
-        if (sVibratorRepository == null) {
-            synchronized (VibratorRepository.class) {
-                if (sVibratorRepository == null) {
-                    sVibratorRepository = new VibratorRepository(vibrator);
-                }
-            }
-        }
-        return sVibratorRepository;
-    }
-
-    /**
-     * Get AccessibilityRepository
-     */
-    @Nullable
-    @Override
-    public AccessibilityRepository getAccessibilityRepository(@NonNull Application application) {
-
-        final AccessibilityManager accessibilityManager = application.getSystemService(
-                AccessibilityManager.class);
-        if (accessibilityManager == null) {
-            return null;
-        }
-
-        if (sAccessibilityRepository == null) {
-            synchronized (AccessibilityRepository.class) {
-                if (sAccessibilityRepository == null) {
-                    sAccessibilityRepository = new AccessibilityRepository(accessibilityManager);
-                }
-            }
-        }
-        return sAccessibilityRepository;
-    }
 }
diff --git a/src/com/android/settings/biometrics2/factory/BiometricsViewModelFactory.java b/src/com/android/settings/biometrics2/factory/BiometricsViewModelFactory.java
index 970ed02..dd5b673 100644
--- a/src/com/android/settings/biometrics2/factory/BiometricsViewModelFactory.java
+++ b/src/com/android/settings/biometrics2/factory/BiometricsViewModelFactory.java
@@ -27,9 +27,7 @@
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.settings.biometrics.fingerprint.FingerprintUpdater;
-import com.android.settings.biometrics2.data.repository.AccessibilityRepository;
 import com.android.settings.biometrics2.data.repository.FingerprintRepository;
-import com.android.settings.biometrics2.data.repository.VibratorRepository;
 import com.android.settings.biometrics2.ui.model.EnrollmentRequest;
 import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel;
 import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.ChallengeGenerator;
@@ -115,12 +113,9 @@
             final Integer userId = extras.get(USER_ID_KEY);
             final FingerprintRepository fingerprint = provider.getFingerprintRepository(
                     application);
-            final AccessibilityRepository accessibility = provider.getAccessibilityRepository(
-                    application);
-            final VibratorRepository vibrator = provider.getVibratorRepository(application);
-            if (fingerprint != null && accessibility != null && vibrator != null) {
-                return (T) new FingerprintEnrollEnrollingViewModel(application, userId, fingerprint,
-                        accessibility, vibrator);
+            if (fingerprint != null) {
+                return (T) new FingerprintEnrollEnrollingViewModel(application, userId,
+                        fingerprint);
             }
         } else if (modelClass.isAssignableFrom(FingerprintEnrollFinishViewModel.class)) {
             final Integer userId = extras.get(USER_ID_KEY);
diff --git a/src/com/android/settings/biometrics2/ui/model/CredentialModel.java b/src/com/android/settings/biometrics2/ui/model/CredentialModel.java
index a6e8b6e..caff80a 100644
--- a/src/com/android/settings/biometrics2/ui/model/CredentialModel.java
+++ b/src/com/android/settings/biometrics2/ui/model/CredentialModel.java
@@ -17,7 +17,6 @@
 package com.android.settings.biometrics2.ui.model;
 
 import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_CHALLENGE;
-import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_SENSOR_ID;
 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN;
 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE;
 
@@ -34,10 +33,9 @@
 /**
  * Secret credential data including
  * 1. userId
- * 2. sensorId
- * 3. challenge
- * 4. token
- * 5. gkPwHandle
+ * 2. challenge
+ * 3. token
+ * 4. gkPwHandle
  */
 public final class CredentialModel {
 
@@ -53,22 +51,12 @@
     @VisibleForTesting
     public static final long INVALID_GK_PW_HANDLE = 0L;
 
-    /**
-     * Default value for a invalid sensor id
-     */
-    @VisibleForTesting
-    public static final int INVALID_SENSOR_ID = -1;
-
     private final Clock mClock;
 
     private final long mInitMillis;
 
     private final int mUserId;
 
-    private int mSensorId;
-    @Nullable
-    private Long mUpdateSensorIdMillis = null;
-
     private long mChallenge;
     @Nullable
     private Long mUpdateChallengeMillis = null;
@@ -87,7 +75,6 @@
             bundle = new Bundle();
         }
         mUserId = bundle.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId());
-        mSensorId = bundle.getInt(EXTRA_KEY_SENSOR_ID, INVALID_SENSOR_ID);
         mChallenge = bundle.getLong(EXTRA_KEY_CHALLENGE, INVALID_CHALLENGE);
         mToken = bundle.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN);
         mGkPwHandle = bundle.getLong(EXTRA_KEY_GK_PW_HANDLE, INVALID_GK_PW_HANDLE);
@@ -102,7 +89,6 @@
     public Bundle getBundle() {
         final Bundle bundle = new Bundle();
         bundle.putInt(Intent.EXTRA_USER_ID, mUserId);
-        bundle.putInt(EXTRA_KEY_SENSOR_ID, mSensorId);
         bundle.putLong(EXTRA_KEY_CHALLENGE, mChallenge);
         bundle.putByteArray(EXTRA_KEY_CHALLENGE_TOKEN, mToken);
         bundle.putLong(EXTRA_KEY_GK_PW_HANDLE, mGkPwHandle);
@@ -191,21 +177,6 @@
     }
 
     /**
-     * Get sensor id
-     */
-    public int getSensorId() {
-        return mSensorId;
-    }
-
-    /**
-     * Set sensor id
-     */
-    public void setSensorId(int value) {
-        mUpdateSensorIdMillis = mClock.millis();
-        mSensorId = value;
-    }
-
-    /**
      * Returns a string representation of the object
      */
     @Override
@@ -221,7 +192,6 @@
                 + ", updateMillis:" + mUpdateTokenMillis + "}"
                 + ", gkPwHandle:{len:" + gkPwHandleLen + ", isValid:" + isValidGkPwHandle()
                 + ", clearMillis:" + mClearGkPwHandleMillis + "}"
-                + ", mSensorId:{id:" + mSensorId + ", updateMillis:" + mUpdateSensorIdMillis + "}"
                 + " }";
     }
 }
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.java
index 8e022e0..8a4ed63 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.java
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.java
@@ -418,7 +418,7 @@
 
     private void showIconTouchDialog() {
         mIconTouchCount = 0;
-        mEnrollingViewModel.onIconTouchDialogShow();
+        mEnrollingViewModel.showIconTouchDialog();
     }
 
     private final Runnable mShowDialogRunnable = () -> showIconTouchDialog();
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.java
index ab772e3..720857c 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.java
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.java
@@ -540,8 +540,7 @@
 
     private void showIconTouchDialog() {
         mIconTouchCount = 0;
-        //TODO EnrollingActivity should observe live data and add dialog fragment
-        mEnrollingViewModel.onIconTouchDialogShow();
+        mEnrollingViewModel.showIconTouchDialog();
     }
 
     private final Runnable mShowDialogRunnable = () -> showIconTouchDialog();
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java
index ff43e8b..7f69b91 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java
@@ -30,8 +30,8 @@
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG;
-import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SKIP;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FingerprintEnrollEnrollingAction;
@@ -503,7 +503,7 @@
                 startFinishFragment();
                 break;
             }
-            case FINGERPRINT_ENROLL_ENROLLING_ACTION_SKIP: {
+            case FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP: {
                 onSetActivityResult(new ActivityResult(BiometricEnrollBase.RESULT_SKIP, null));
                 break;
             }
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModel.java
index 2b7b3b7..7e48f82 100644
--- a/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModel.java
+++ b/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModel.java
@@ -19,9 +19,7 @@
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
 
 import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_CHALLENGE;
-import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_SENSOR_ID;
 import static com.android.settings.biometrics2.ui.model.CredentialModel.INVALID_GK_PW_HANDLE;
-import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN;
 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE;
 
 import android.annotation.IntDef;
@@ -268,7 +266,6 @@
         mChallengeGenerator.setCallback((sensorId, userId, challenge) -> {
             try {
                 final byte[] newToken = requestGatekeeperHat(gkPwHandle, challenge, userId);
-                mCredentialModel.setSensorId(sensorId);
                 mCredentialModel.setChallenge(challenge);
                 mCredentialModel.setToken(newToken);
             } catch (IllegalStateException e) {
@@ -355,26 +352,6 @@
     }
 
     /**
-     * Get Credential intent extra which will be used to launch next activity.
-     */
-    @NonNull
-    public Bundle createCredentialIntentExtra() {
-        final Bundle retBundle = new Bundle();
-        if (mCredentialModel.isValidGkPwHandle()) {
-            retBundle.putLong(EXTRA_KEY_GK_PW_HANDLE, mCredentialModel.getGkPwHandle());
-        }
-        if (mCredentialModel.isValidToken()) {
-            retBundle.putByteArray(EXTRA_KEY_CHALLENGE_TOKEN, mCredentialModel.getToken());
-        }
-        if (mCredentialModel.isValidUserId()) {
-            retBundle.putInt(Intent.EXTRA_USER_ID, mCredentialModel.getUserId());
-        }
-        retBundle.putLong(EXTRA_KEY_CHALLENGE, mCredentialModel.getChallenge());
-        retBundle.putInt(EXTRA_KEY_SENSOR_ID, mCredentialModel.getSensorId());
-        return retBundle;
-    }
-
-    /**
      * Create Intent for choosing lock
      */
     @NonNull
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java
index 194bc1e..025c58b 100644
--- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java
+++ b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java
@@ -21,6 +21,7 @@
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
 import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
+import android.os.Vibrator;
 import android.util.Log;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -31,9 +32,7 @@
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MutableLiveData;
 
-import com.android.settings.biometrics2.data.repository.AccessibilityRepository;
 import com.android.settings.biometrics2.data.repository.FingerprintRepository;
-import com.android.settings.biometrics2.data.repository.VibratorRepository;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -52,24 +51,24 @@
             VibrationAttributes.createForUsage(VibrationAttributes.USAGE_ACCESSIBILITY);
 
     /**
-     * Enrolling skipped
-     */
-    public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_SKIP = 0;
-
-    /**
      * Enrolling finished
      */
-    public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE = 1;
+    public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE = 0;
 
     /**
      * Icon touch dialog show
      */
-    public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG = 2;
+    public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG = 1;
 
     /**
      * Icon touch dialog dismiss
      */
-    public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG = 3;
+    public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG = 2;
+
+    /**
+     * Has got latest cancelled event due to user skip
+     */
+    public static final int FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP = 3;
 
     /**
      * Has got latest cancelled event due to back key
@@ -77,10 +76,10 @@
     public static final int FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED = 4;
 
     @IntDef(prefix = { "FINGERPRINT_ENROLL_ENROLLING_ACTION_" }, value = {
-            FINGERPRINT_ENROLL_ENROLLING_ACTION_SKIP,
             FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE,
             FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG,
             FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG,
+            FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP,
             FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -112,25 +111,22 @@
     private final int mUserId;
     private boolean mOnBackPressed;
     private boolean mOnSkipPressed;
-    private final FingerprintRepository mFingerprintRepository;
-    private final AccessibilityRepository mAccessibilityRepository;
-    private final VibratorRepository mVibratorRepository;
+    @NonNull private final FingerprintRepository mFingerprintRepository;
+    private final AccessibilityManager mAccessibilityManager;
+    private final Vibrator mVibrator;
 
     private final MutableLiveData<Integer> mActionLiveData = new MutableLiveData<>();
     private final MutableLiveData<Integer> mIconTouchDialogLiveData = new MutableLiveData<>();
     private final MutableLiveData<ErrorDialogData> mErrorDialogLiveData = new MutableLiveData<>();
     private final MutableLiveData<Integer> mErrorDialogActionLiveData = new MutableLiveData<>();
 
-    public FingerprintEnrollEnrollingViewModel(Application application,
-            int userId,
-            FingerprintRepository fingerprintRepository,
-            AccessibilityRepository accessibilityRepository,
-            VibratorRepository vibratorRepository) {
+    public FingerprintEnrollEnrollingViewModel(@NonNull Application application,
+            int userId, @NonNull FingerprintRepository fingerprintRepository) {
         super(application);
         mUserId = userId;
         mFingerprintRepository = fingerprintRepository;
-        mAccessibilityRepository = accessibilityRepository;
-        mVibratorRepository = vibratorRepository;
+        mAccessibilityManager = application.getSystemService(AccessibilityManager.class);
+        mVibrator = application.getSystemService(Vibrator.class);
     }
 
     /**
@@ -184,7 +180,7 @@
      * Enrolling is cacelled because user clicks skip
      */
     public void onCancelledDueToOnSkipPressed() {
-        final int action = FINGERPRINT_ENROLL_ENROLLING_ACTION_SKIP;
+        final int action = FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP;
         if (DEBUG) {
             Log.d(TAG, "onSkipButtonClick, post action " + action);
         }
@@ -229,12 +225,12 @@
     /**
      * Icon touch dialog show
      */
-    public void onIconTouchDialogShow() {
+    public void showIconTouchDialog() {
         final int action = FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG;
         if (DEBUG) {
             Log.d(TAG, "onIconTouchDialogShow, post action " + action);
         }
-        mIconTouchDialogLiveData.postValue(action);
+        mActionLiveData.postValue(action);
     }
 
     /**
@@ -245,7 +241,7 @@
         if (DEBUG) {
             Log.d(TAG, "onIconTouchDialogDismiss, post action " + action);
         }
-        mIconTouchDialogLiveData.postValue(action);
+        mActionLiveData.postValue(action);
     }
 
     /**
@@ -266,7 +262,7 @@
      * Requests interruption of the accessibility feedback from all accessibility services.
      */
     public void clearTalkback() {
-        mAccessibilityRepository.interrupt();
+        mAccessibilityManager.interrupt();
     }
 
     /**
@@ -275,7 +271,7 @@
      * @return True if this {@link AccessibilityManager} is enabled, false otherwise.
      */
     public boolean isAccessibilityEnabled() {
-        return mAccessibilityRepository.isEnabled();
+        return mAccessibilityManager.isEnabled();
     }
 
     /**
@@ -287,7 +283,7 @@
         e.setClassName(getClass().getName());
         e.setPackageName(getApplication().getPackageName());
         e.getText().add(announcement);
-        mAccessibilityRepository.sendAccessibilityEvent(e);
+        mAccessibilityManager.sendAccessibilityEvent(e);
     }
 
      /**
@@ -296,7 +292,7 @@
      * @return True if touch exploration is enabled, false otherwise.
      */
     public boolean isTouchExplorationEnabled() {
-        return mAccessibilityRepository.isTouchExplorationEnabled();
+        return mAccessibilityManager.isTouchExplorationEnabled();
     }
 
     /**
@@ -304,7 +300,7 @@
      * caller to specify the vibration is owned by someone else and set a reason for vibration.
      */
     public void vibrateError(String reason) {
-        mVibratorRepository.vibrate(mUserId, getApplication().getOpPackageName(),
+        mVibrator.vibrate(mUserId, getApplication().getOpPackageName(),
                 VIBRATE_EFFECT_ERROR, reason, FINGERPRINT_ENROLLING_SONFICATION_ATTRIBUTES);
     }
 
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java
index 2a918f5..b1b420d 100644
--- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java
+++ b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java
@@ -58,7 +58,6 @@
     private final MutableLiveData<Boolean> mAcquireLiveData = new MutableLiveData<>();
     private final MutableLiveData<Integer> mPointerDownLiveData = new MutableLiveData<>();
     private final MutableLiveData<Integer> mPointerUpLiveData = new MutableLiveData<>();
-    private final MutableLiveData<Boolean> mDoneLiveData = new MutableLiveData<>(false);
 
     private byte[] mToken = null;
     private final int mUserId;
@@ -78,11 +77,6 @@
                         + ", post progress as " + progress);
             }
             mProgressLiveData.postValue(progress);
-
-            final Boolean done = remaining == 0;
-            if (!done.equals(mDoneLiveData.getValue())) {
-                mDoneLiveData.postValue(done);
-            }
         }
 
         @Override
@@ -143,7 +137,6 @@
      * clear progress
      */
     public void clearProgressLiveData() {
-        mDoneLiveData.setValue(false);
         mProgressLiveData.setValue(new EnrollmentProgress(INITIAL_STEPS, INITIAL_REMAINING));
         mHelpMessageLiveData.setValue(null);
         mErrorMessageLiveData.setValue(null);
@@ -180,10 +173,6 @@
         return mPointerUpLiveData;
     }
 
-    public LiveData<Boolean> getDoneLiveData() {
-        return mDoneLiveData;
-    }
-
     /**
      * Starts enrollment and return latest isEnrolling() result
      */
@@ -202,7 +191,6 @@
 
         // Clear data
         mProgressLiveData.setValue(new EnrollmentProgress(INITIAL_STEPS, INITIAL_REMAINING));
-        mDoneLiveData.setValue(false);
         mHelpMessageLiveData.setValue(null);
         mErrorMessageLiveData.setValue(null);
 
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModel.java
index 4f07ae6..3c779c9 100644
--- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModel.java
+++ b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModel.java
@@ -179,10 +179,6 @@
         return mFingerprintRepository.canAssumeSfps();
     }
 
-    public boolean isNewFingerprintAdded() {
-        return mIsNewFingerprintAdded;
-    }
-
     /**
      * Sets mIsNewFingerprintAdded to true
      */
diff --git a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
index 919d179..07e9633 100644
--- a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
+++ b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
@@ -191,23 +191,7 @@
             final BluetoothDevice device = mCachedDevice.getDevice();
             final String deviceType = BluetoothUtils.getStringMetaData(device,
                     BluetoothDevice.METADATA_DEVICE_TYPE);
-            if (TextUtils.equals(deviceType, BluetoothDevice.DEVICE_TYPE_WATCH)
-                    || TextUtils.equals(deviceType, BluetoothDevice.DEVICE_TYPE_DEFAULT)
-                    || TextUtils.equals(deviceType, BluetoothDevice.DEVICE_TYPE_STYLUS)) {
-                mLayoutPreference.findViewById(R.id.layout_left).setVisibility(View.GONE);
-                mLayoutPreference.findViewById(R.id.layout_right).setVisibility(View.GONE);
-
-                summary.setText(mCachedDevice.getConnectionSummary(
-                        BluetoothUtils.getIntMetaData(device, BluetoothDevice.METADATA_MAIN_BATTERY)
-                                != BluetoothUtils.META_INT_ERROR));
-                updateSubLayout(mLayoutPreference.findViewById(R.id.layout_middle),
-                        BluetoothDevice.METADATA_MAIN_ICON,
-                        BluetoothDevice.METADATA_MAIN_BATTERY,
-                        BluetoothDevice.METADATA_MAIN_LOW_BATTERY_THRESHOLD,
-                        BluetoothDevice.METADATA_MAIN_CHARGING,
-                        /* titleResId */ 0,
-                        MAIN_DEVICE_ID);
-            } else if (TextUtils.equals(deviceType,
+            if (TextUtils.equals(deviceType,
                     BluetoothDevice.DEVICE_TYPE_UNTETHERED_HEADSET)
                     || BluetoothUtils.getBooleanMetaData(device,
                     BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) {
@@ -237,6 +221,20 @@
                         RIGHT_DEVICE_ID);
 
                 showBothDevicesBatteryPredictionIfNecessary();
+            } else {
+                mLayoutPreference.findViewById(R.id.layout_left).setVisibility(View.GONE);
+                mLayoutPreference.findViewById(R.id.layout_right).setVisibility(View.GONE);
+
+                summary.setText(mCachedDevice.getConnectionSummary(
+                        BluetoothUtils.getIntMetaData(device, BluetoothDevice.METADATA_MAIN_BATTERY)
+                                != BluetoothUtils.META_INT_ERROR));
+                updateSubLayout(mLayoutPreference.findViewById(R.id.layout_middle),
+                        BluetoothDevice.METADATA_MAIN_ICON,
+                        BluetoothDevice.METADATA_MAIN_BATTERY,
+                        BluetoothDevice.METADATA_MAIN_LOW_BATTERY_THRESHOLD,
+                        BluetoothDevice.METADATA_MAIN_CHARGING,
+                        /* titleResId */ 0,
+                        MAIN_DEVICE_ID);
             }
         }
     }
diff --git a/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java b/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java
index 46ef3fb..da6e178 100644
--- a/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java
+++ b/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java
@@ -22,7 +22,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
-import android.os.SystemClock;
 import android.util.Log;
 import android.view.InputDevice;
 
@@ -57,11 +56,11 @@
     private final InputManager mInputManager;
     private final MetricsFeatureProvider mMetricsFeatureProvider;
 
-    private long mLastUsiSeenTime = 0;
     private Context mContext;
 
     @VisibleForTesting
     Integer mLastDetectedUsiId;
+    BatteryState mLastBatteryState;
 
     @VisibleForTesting
     Preference mUsiPreference;
@@ -75,7 +74,6 @@
         mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
         mContext = context;
         mInputManager = context.getSystemService(InputManager.class);
-
     }
 
     /**
@@ -132,13 +130,8 @@
     @Override
     public void onBatteryStateChanged(int deviceId, long eventTimeMillis,
             @NonNull BatteryState batteryState) {
-        if (batteryState.isPresent()) {
-            mLastUsiSeenTime = eventTimeMillis;
-            mLastDetectedUsiId = deviceId;
-        } else {
-            mLastUsiSeenTime = -1;
-            mLastDetectedUsiId = null;
-        }
+        mLastBatteryState = batteryState;
+        mLastDetectedUsiId = deviceId;
         forceUpdate();
     }
 
@@ -184,7 +177,7 @@
     }
 
     private boolean shouldShowUsiPreference() {
-        return isUsiConnectionValid() && !hasConnectedBluetoothStylusDevice();
+        return isUsiBatteryValid() && !hasConnectedBluetoothStylusDevice();
     }
 
     @VisibleForTesting
@@ -206,11 +199,9 @@
     }
 
     @VisibleForTesting
-    boolean isUsiConnectionValid() {
-        // battery listener uses uptimeMillis as its eventTime
-        long currentTime = SystemClock.uptimeMillis();
-        long usiValidityDuration = 60 * 60 * 1000; // 1 hour
-        return mLastUsiSeenTime > 0 && currentTime - usiValidityDuration <= mLastUsiSeenTime;
+    boolean isUsiBatteryValid() {
+        return mLastBatteryState != null
+                && mLastBatteryState.isPresent() && mLastBatteryState.getCapacity() > 0f;
     }
 
     private void launchDeviceDetails() {
diff --git a/src/com/android/settings/datausage/lib/DataUsageLib.java b/src/com/android/settings/datausage/lib/DataUsageLib.java
index 1ca5eff..b3f7e79 100644
--- a/src/com/android/settings/datausage/lib/DataUsageLib.java
+++ b/src/com/android/settings/datausage/lib/DataUsageLib.java
@@ -22,12 +22,14 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.util.ArraySet;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
 
 import com.android.internal.util.ArrayUtils;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
 
@@ -76,16 +78,21 @@
     }
 
     private static NetworkTemplate normalizeMobileTemplate(
-            @NonNull NetworkTemplate template, @NonNull String[] mergedSet) {
+            @NonNull NetworkTemplate template, @NonNull String[] merged) {
         if (template.getSubscriberIds().isEmpty()) return template;
         // The input template should have at most 1 subscriberId.
         final String subscriberId = template.getSubscriberIds().iterator().next();
-
-        if (Set.of(mergedSet).contains(subscriberId)) {
+        // In some rare cases (e.g. b/243015487), merged subscriberId list might contain
+        // duplicated items. Deduplication for better error handling.
+        final ArraySet mergedSet = new ArraySet(merged);
+        if (mergedSet.size() != merged.length) {
+            Log.wtf(TAG, "Duplicated merged list detected: " + Arrays.toString(merged));
+        }
+        if (mergedSet.contains(subscriberId)) {
             // Requested template subscriber is part of the merge group; return
             // a template that matches all merged subscribers.
             return new NetworkTemplate.Builder(template.getMatchRule())
-                    .setSubscriberIds(Set.of(mergedSet))
+                    .setSubscriberIds(mergedSet)
                     .setMeteredness(template.getMeteredness()).build();
         }
 
diff --git a/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java b/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java
index d567466..a50ce4c 100644
--- a/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java
+++ b/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java
@@ -77,7 +77,7 @@
         boolean isLocationEnabled =
                 timeZoneCapabilitiesAndConfig.getCapabilities().isUseLocationEnabled();
         if (isChecked && !isLocationEnabled) {
-            new LocationToggleDisabledDialogFragment(mContext)
+            new LocationToggleDisabledDialogFragment()
                     .show(mFragment.getFragmentManager(), TAG);
             // Toggle status is not updated.
             return false;
diff --git a/src/com/android/settings/datetime/LocationToggleDisabledDialogFragment.java b/src/com/android/settings/datetime/LocationToggleDisabledDialogFragment.java
index 61d46c6..046a659 100644
--- a/src/com/android/settings/datetime/LocationToggleDisabledDialogFragment.java
+++ b/src/com/android/settings/datetime/LocationToggleDisabledDialogFragment.java
@@ -19,7 +19,6 @@
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.settings.SettingsEnums;
-import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.provider.Settings;
@@ -32,11 +31,7 @@
  */
 public class LocationToggleDisabledDialogFragment extends InstrumentedDialogFragment {
 
-    private final Context mContext;
-
-    public LocationToggleDisabledDialogFragment(Context context) {
-        mContext = context;
-    }
+    public LocationToggleDisabledDialogFragment() {}
 
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
@@ -48,7 +43,7 @@
                         R.string.location_time_zone_detection_location_is_off_dialog_ok_button,
                         (dialog, which) -> {
                             Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
-                            mContext.startActivity(intent);
+                            getContext().startActivity(intent);
                         })
                 .setNegativeButton(
                         R.string.location_time_zone_detection_location_is_off_dialog_cancel_button,
diff --git a/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceController.java b/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceController.java
new file mode 100644
index 0000000..23506b3
--- /dev/null
+++ b/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceController.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothStatusCodes;
+import android.content.Context;
+import android.os.SystemProperties;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+/**
+ * Preference controller to control Bluetooth LE audio feature
+ */
+public class BluetoothLeAudioAllowListPreferenceController
+        extends DeveloperOptionsPreferenceController
+        implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+
+    private static final String PREFERENCE_KEY = "bluetooth_enable_leaudio_allow_list";
+
+    private static final String LE_AUDIO_ALLOW_LIST_SWITCH_SUPPORT_PROPERTY =
+            "ro.bluetooth.leaudio_allow_list.supported";
+    @VisibleForTesting
+    static final String LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY =
+            "persist.bluetooth.leaudio.enable_allow_list";
+
+    private static final String LE_AUDIO_DYNAMIC_SWITCH_PROPERTY =
+            "ro.bluetooth.leaudio_switcher.supported";
+    @VisibleForTesting
+    static final String LE_AUDIO_DYNAMIC_ENABLED_PROPERTY =
+            "persist.bluetooth.leaudio_switcher.enabled";
+
+    @VisibleForTesting
+    BluetoothAdapter mBluetoothAdapter;
+
+    private final DevelopmentSettingsDashboardFragment mFragment;
+
+    @VisibleForTesting
+    boolean mChanged = false;
+
+    public BluetoothLeAudioAllowListPreferenceController(Context context,
+            DevelopmentSettingsDashboardFragment fragment) {
+        super(context);
+        mFragment = fragment;
+        mBluetoothAdapter = context.getSystemService(BluetoothManager.class).getAdapter();
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return PREFERENCE_KEY;
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        BluetoothRebootDialog.show(mFragment);
+        mChanged = true;
+        return false;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        if (mBluetoothAdapter == null) {
+            return;
+        }
+
+        int leAudioSupportedState = mBluetoothAdapter.isLeAudioSupported();
+        boolean leAudioEnabled = false;
+
+        if ((leAudioSupportedState == BluetoothStatusCodes.FEATURE_SUPPORTED)
+                || (leAudioSupportedState == BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED
+                && SystemProperties.getBoolean(LE_AUDIO_DYNAMIC_SWITCH_PROPERTY, false)
+                && SystemProperties.getBoolean(LE_AUDIO_DYNAMIC_ENABLED_PROPERTY, false))) {
+            leAudioEnabled = true;
+        }
+
+        final boolean leAudioAllowListSupport =
+                SystemProperties.getBoolean(LE_AUDIO_ALLOW_LIST_SWITCH_SUPPORT_PROPERTY, false);
+
+        if (leAudioEnabled && leAudioAllowListSupport) {
+            final boolean leAudioAllowListEnabled =
+                    SystemProperties.getBoolean(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false);
+            ((SwitchPreference) mPreference).setChecked(leAudioAllowListEnabled);
+        } else {
+            mPreference.setEnabled(false);
+            ((SwitchPreference) mPreference).setChecked(false);
+        }
+    }
+
+    /**
+     * Called when the RebootDialog confirm is clicked.
+     */
+    public void onRebootDialogConfirmed() {
+        if (!mChanged) {
+            return;
+        }
+
+        final boolean leAudioAllowListEnabled =
+                SystemProperties.getBoolean(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false);
+        SystemProperties.set(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY,
+                Boolean.toString(!leAudioAllowListEnabled));
+    }
+
+    /**
+     * Called when the RebootDialog cancel is clicked.
+     */
+    public void onRebootDialogCanceled() {
+        mChanged = false;
+    }
+}
diff --git a/src/com/android/settings/development/BluetoothLeAudioPreferenceController.java b/src/com/android/settings/development/BluetoothLeAudioPreferenceController.java
index 00d0dd2..867bc2a 100644
--- a/src/com/android/settings/development/BluetoothLeAudioPreferenceController.java
+++ b/src/com/android/settings/development/BluetoothLeAudioPreferenceController.java
@@ -77,17 +77,19 @@
             return;
         }
 
-        final boolean leAudioEnabled =
-                (mBluetoothAdapter.isLeAudioSupported() == BluetoothStatusCodes.FEATURE_SUPPORTED);
-        ((SwitchPreference) mPreference).setChecked(leAudioEnabled);
-
         final boolean leAudioSwitchSupported =
                 SystemProperties.getBoolean(LE_AUDIO_DYNAMIC_SWITCH_PROPERTY, false);
-        if (!leAudioSwitchSupported) {
+
+        final int isLeAudioSupportedStatus = mBluetoothAdapter.isLeAudioSupported();
+        final boolean leAudioEnabled =
+                (isLeAudioSupportedStatus == BluetoothStatusCodes.FEATURE_SUPPORTED);
+
+        ((SwitchPreference) mPreference).setChecked(leAudioEnabled);
+
+        // Disable option if Bluetooth is disabled or if switch is not supported
+        if (isLeAudioSupportedStatus == BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED
+                || !leAudioSwitchSupported) {
             mPreference.setEnabled(false);
-        } else {
-            SystemProperties.set(LE_AUDIO_DYNAMIC_ENABLED_PROPERTY,
-                    Boolean.toString(leAudioEnabled));
         }
     }
 
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index c732c0a..3180a79 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -389,6 +389,11 @@
                 getDevelopmentOptionsController(
                         BluetoothLeAudioPreferenceController.class);
         leAudioFeatureController.onRebootDialogConfirmed();
+
+        final BluetoothLeAudioAllowListPreferenceController leAudioAllowListController =
+                getDevelopmentOptionsController(
+                    BluetoothLeAudioAllowListPreferenceController.class);
+        leAudioAllowListController.onRebootDialogConfirmed();
     }
 
     @Override
@@ -406,6 +411,11 @@
                 getDevelopmentOptionsController(
                         BluetoothLeAudioPreferenceController.class);
         leAudioFeatureController.onRebootDialogCanceled();
+
+        final BluetoothLeAudioAllowListPreferenceController leAudioAllowListController =
+                getDevelopmentOptionsController(
+                    BluetoothLeAudioAllowListPreferenceController.class);
+        leAudioAllowListController.onRebootDialogCanceled();
     }
 
     @Override
@@ -602,6 +612,7 @@
         controllers.add(new BluetoothAvrcpVersionPreferenceController(context));
         controllers.add(new BluetoothMapVersionPreferenceController(context));
         controllers.add(new BluetoothLeAudioPreferenceController(context, fragment));
+        controllers.add(new BluetoothLeAudioAllowListPreferenceController(context, fragment));
         controllers.add(new BluetoothA2dpHwOffloadPreferenceController(context, fragment));
         controllers.add(new BluetoothLeAudioHwOffloadPreferenceController(context, fragment));
         controllers.add(new BluetoothMaxConnectedAudioDevicesPreferenceController(context));
@@ -616,6 +627,7 @@
         controllers.add(new RtlLayoutPreferenceController(context));
         controllers.add(new WindowAnimationScalePreferenceController(context));
         controllers.add(new EmulateDisplayCutoutPreferenceController(context));
+        controllers.add(new TransparentNavigationBarPreferenceController(context));
         controllers.add(new TransitionAnimationScalePreferenceController(context));
         controllers.add(new AnimatorDurationScalePreferenceController(context));
         controllers.add(new SecondaryDisplayPreferenceController(context));
diff --git a/src/com/android/settings/development/TransparentNavigationBarPreferenceController.java b/src/com/android/settings/development/TransparentNavigationBarPreferenceController.java
new file mode 100644
index 0000000..d1f54b5
--- /dev/null
+++ b/src/com/android/settings/development/TransparentNavigationBarPreferenceController.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+import static android.os.UserHandle.USER_CURRENT;
+
+import android.content.Context;
+import android.content.om.IOverlayManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+public class TransparentNavigationBarPreferenceController
+        extends DeveloperOptionsPreferenceController
+        implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+
+    private static final String TRANSPARENT_NAVIGATION_BAR_KEY =
+            "transparent_navigation_bar";
+
+    private static final String OVERLAY_PACKAGE_NAME =
+            "com.android.internal.systemui.navbar.transparent";
+
+    private final IOverlayManager mOverlayManager;
+
+    public TransparentNavigationBarPreferenceController(Context context) {
+        super(context);
+        mOverlayManager = IOverlayManager.Stub.asInterface(
+                ServiceManager.getService(Context.OVERLAY_SERVICE));
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return TRANSPARENT_NAVIGATION_BAR_KEY;
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        setEnabled((boolean) newValue);
+        return true;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        ((SwitchPreference) mPreference).setChecked(isEnabled());
+    }
+
+    @Override
+    protected void onDeveloperOptionsSwitchDisabled() {
+        super.onDeveloperOptionsSwitchDisabled();
+        ((SwitchPreference) mPreference).setChecked(false);
+        final boolean enabled = isEnabled();
+        if (!enabled) {
+            setEnabled(false);
+        }
+    }
+
+    @VisibleForTesting
+    protected boolean isEnabled() {
+        return mContext.getResources().getBoolean(R.bool.config_navBarDefaultTransparent);
+    }
+
+    @VisibleForTesting
+    protected void setEnabled(boolean enabled) {
+        try {
+            mOverlayManager.setEnabled(OVERLAY_PACKAGE_NAME, enabled, USER_CURRENT);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
index ecc4ea0..81a15ca 100644
--- a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
@@ -116,12 +116,21 @@
             return;
         }
         final String action = intent.getAction();
+        Log.d(TAG, "updateBatteryStatus: action=" + action);
         if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
             final String batteryLevel = Utils.getBatteryPercentage(intent);
             final String batteryStatus =
                     Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false);
             final int batteryHealth = intent.getIntExtra(
                     BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN);
+            Log.d(
+                    TAG,
+                    "Battery changed: level="
+                            + batteryLevel
+                            + ", status="
+                            + batteryStatus
+                            + ", health="
+                            + batteryHealth);
             if (!Utils.isBatteryPresent(intent)) {
                 Log.w(TAG, "Problem reading the battery meter.");
                 mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_NOT_PRESENT);
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index b6858fc..ac72ced 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -26,6 +26,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.settingslib.fuelgauge.Estimate;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
@@ -83,7 +84,7 @@
 
     @Override
     public List<String> getSystemAppsAllowlist() {
-        return null;
+        return new ArrayList<>();
     }
 
     @Override
diff --git a/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java b/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java
index 7f314d1..5bec7bd 100644
--- a/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java
@@ -18,6 +18,7 @@
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.Preference;
@@ -34,6 +35,8 @@
 public class TopLevelBatteryPreferenceController extends BasePreferenceController implements
         LifecycleObserver, OnStart, OnStop, BatteryPreferenceController {
 
+    private static final String TAG = "TopLvBatteryPrefControl";
+
     @VisibleForTesting
     protected boolean mIsBatteryPresent = true;
     @VisibleForTesting
@@ -47,6 +50,7 @@
         super(context, preferenceKey);
         mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(mContext);
         mBatteryBroadcastReceiver.setBatteryChangedListener(type -> {
+            Log.d(TAG, "onBatteryChanged: type=" + type);
             if (type == BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_NOT_PRESENT) {
                 mIsBatteryPresent = false;
             }
@@ -101,6 +105,8 @@
             return null;
         }
 
+        Log.d(TAG, "getDashboardLabel: batteryStatusUpdate=" + batteryStatusUpdate);
+
         if (batteryStatusUpdate) {
             setSummaryAsync(info);
         }
@@ -137,6 +143,7 @@
     /**
      * Callback which receives text for the label.
      */
+    @Override
     public void updateBatteryStatus(String label, BatteryInfo info) {
         mBatteryStatusLabel = label; // Null if adaptive charging is not active
 
diff --git a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceController.java b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceController.java
index ee3f54f..274817e 100644
--- a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceController.java
@@ -118,7 +118,7 @@
     @Override
     public boolean setChecked(boolean stateOn) {
         return BatterySaverUtils.setPowerSaveMode(mContext, stateOn,
-                true /* needFirstTimeWarning */);
+                false /* needFirstTimeWarning */);
     }
 
     @Override
diff --git a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverStickyPreferenceController.java b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverStickyPreferenceController.java
index d11fe8a..f06083a 100644
--- a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverStickyPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverStickyPreferenceController.java
@@ -14,6 +14,7 @@
 
 public class BatterySaverStickyPreferenceController extends TogglePreferenceController implements
         PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
+    private static final int DEFAULT_STICKY_SHUTOFF_LEVEL = 90;
 
     private Context mContext;
 
@@ -39,10 +40,13 @@
     @Override
     protected void refreshSummary(Preference preference) {
         super.refreshSummary(preference);
-        final int stickyShutoffLevel = Settings.Global.getInt(
-            mContext.getContentResolver(), Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 90);
+        final int stickyShutoffLevel = Settings.Global.getInt(mContext.getContentResolver(),
+                Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, DEFAULT_STICKY_SHUTOFF_LEVEL);
+        final String formatPercentage = Utils.formatPercentage(stickyShutoffLevel);
+        preference.setTitle(mContext.getString(R.string.battery_saver_sticky_title_percentage,
+                formatPercentage));
         preference.setSummary(mContext.getString(R.string.battery_saver_sticky_description_new,
-                Utils.formatPercentage(stickyShutoffLevel)));
+                formatPercentage));
     }
 
     @Override
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java b/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java
index 1c4c67c..a6575a5 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java
@@ -50,7 +50,13 @@
 
     @Override
     public int getAvailabilityStatus() {
-        return mPowerUsageFeatureProvider.isBatteryManagerSupported()
+        if (!mPowerUsageFeatureProvider.isBatteryManagerSupported()) {
+            return UNSUPPORTED_ON_DEVICE;
+        }
+        if (!mContext.getResources().getBoolean(R.bool.config_battery_manager_consider_ac)) {
+            return AVAILABLE_UNSEARCHABLE;
+        }
+        return mPowerUsageFeatureProvider.isAdaptiveChargingSupported()
                 ? AVAILABLE_UNSEARCHABLE : UNSUPPORTED_ON_DEVICE;
     }
 
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java
index 7ce6b14..8a8cc5c 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java
@@ -48,7 +48,7 @@
 
     @Override
     public int getIconId() {
-        return R.drawable.ic_battery_charging;
+        return R.drawable.ic_battery_alert_24dp;
     }
 
     @Override
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java
index c5dfb0d..37eddf3 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java
@@ -42,7 +42,8 @@
             final Context context,
             final @NonNull List<BatteryDiffEntry> appDiffEntries,
             final @NonNull List<BatteryDiffEntry> systemDiffEntries,
-            final Set<String> systemAppsSet,
+            final @NonNull Set<String> systemAppsPackageNames,
+            final @NonNull Set<Integer> systemAppsUids,
             final boolean isAccumulated) {
         mAppEntries = appDiffEntries;
         mSystemEntries = systemDiffEntries;
@@ -51,7 +52,8 @@
             final PowerUsageFeatureProvider featureProvider =
                     FeatureFactory.getFactory(context).getPowerUsageFeatureProvider(context);
             purgeBatteryDiffData(featureProvider);
-            combineBatteryDiffEntry(context, featureProvider, systemAppsSet);
+            combineBatteryDiffEntry(
+                    context, featureProvider, systemAppsPackageNames, systemAppsUids);
         }
 
         processAndSortEntries(mAppEntries);
@@ -73,9 +75,13 @@
     }
 
     /** Combines into SystemAppsBatteryDiffEntry and OthersBatteryDiffEntry. */
-    private void combineBatteryDiffEntry(final Context context,
-            final PowerUsageFeatureProvider featureProvider, final Set<String> systemAppsSet) {
-        combineIntoSystemApps(context, featureProvider, systemAppsSet, mAppEntries);
+    private void combineBatteryDiffEntry(
+            final Context context,
+            final PowerUsageFeatureProvider featureProvider,
+            final @NonNull Set<String> systemAppsPackageNames,
+            final @NonNull Set<Integer> systemAppsUids) {
+        combineIntoSystemApps(
+                context, featureProvider, systemAppsPackageNames, systemAppsUids, mAppEntries);
         combineSystemItemsIntoOthers(context, featureProvider, mSystemEntries);
     }
 
@@ -113,14 +119,16 @@
     private static void combineIntoSystemApps(
             final Context context,
             final PowerUsageFeatureProvider featureProvider,
-            final Set<String> systemAppsSet,
-            final List<BatteryDiffEntry> appEntries) {
+            final @NonNull Set<String> systemAppsPackageNames,
+            final @NonNull Set<Integer> systemAppsUids,
+            final @NonNull List<BatteryDiffEntry> appEntries) {
         final List<String> systemAppsAllowlist = featureProvider.getSystemAppsAllowlist();
         BatteryDiffEntry.SystemAppsBatteryDiffEntry systemAppsDiffEntry = null;
         final Iterator<BatteryDiffEntry> appListIterator = appEntries.iterator();
         while (appListIterator.hasNext()) {
             final BatteryDiffEntry batteryDiffEntry = appListIterator.next();
-            if (needsCombineInSystemApp(batteryDiffEntry, systemAppsAllowlist, systemAppsSet)) {
+            if (needsCombineInSystemApp(batteryDiffEntry, systemAppsAllowlist,
+                    systemAppsPackageNames, systemAppsUids)) {
                 if (systemAppsDiffEntry == null) {
                     systemAppsDiffEntry = new BatteryDiffEntry.SystemAppsBatteryDiffEntry(context);
                 }
@@ -168,8 +176,11 @@
     }
 
     @VisibleForTesting
-    static boolean needsCombineInSystemApp(final BatteryDiffEntry batteryDiffEntry,
-            final List<String> systemAppsAllowlist, final Set<String> systemAppsSet) {
+    static boolean needsCombineInSystemApp(
+            final BatteryDiffEntry batteryDiffEntry,
+            final @NonNull List<String> systemAppsAllowlist,
+            final @NonNull Set<String> systemAppsPackageNames,
+            final @NonNull Set<Integer> systemAppsUids) {
         if (batteryDiffEntry.mBatteryHistEntry.mIsHidden) {
             return true;
         }
@@ -179,11 +190,12 @@
             return false;
         }
 
-        if (systemAppsAllowlist != null && systemAppsAllowlist.contains(packageName)) {
+        if (systemAppsAllowlist.contains(packageName)) {
             return true;
         }
 
-        return systemAppsSet != null && systemAppsSet.contains(packageName);
+        int uid = (int) batteryDiffEntry.mBatteryHistEntry.mUid;
+        return systemAppsPackageNames.contains(packageName) || systemAppsUids.contains(uid);
     }
 
     /**
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java
index 4506922..1f25ae0 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java
@@ -33,6 +33,7 @@
 
 import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -77,10 +78,8 @@
     private List<BatteryLevelData.PeriodBatteryLevelData> mHourlyBatteryLevelsPerDay;
     private Map<Long, Map<String, BatteryHistEntry>> mBatteryHistoryMap;
 
-    // The start timestamp of battery level data. As we don't know when is the full charge cycle
-    // start time when loading app usage data, this value is used as the start time of querying app
-    // usage data.
-    private long mStartTimestampOfLevelData;
+    // Raw start timestamp with round to the nearest hour.
+    private long mRawStartTimestamp;
 
     private boolean mIsCurrentBatteryHistoryLoaded = false;
     private boolean mIsCurrentAppUsageLoaded = false;
@@ -105,6 +104,7 @@
     DataProcessManager(
             Context context,
             Handler handler,
+            final long rawStartTimestamp,
             @NonNull final DataProcessor.UsageMapAsyncResponse callbackFunction,
             @NonNull final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
             @NonNull final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
@@ -114,7 +114,7 @@
         mCallbackFunction = callbackFunction;
         mHourlyBatteryLevelsPerDay = hourlyBatteryLevelsPerDay;
         mBatteryHistoryMap = batteryHistoryMap;
-        mStartTimestampOfLevelData = getStartTimestampOfBatteryLevelData();
+        mRawStartTimestamp = rawStartTimestamp;
     }
 
     /**
@@ -154,21 +154,6 @@
     }
 
     @VisibleForTesting
-    long getStartTimestampOfBatteryLevelData() {
-        for (int dailyIndex = 0; dailyIndex < mHourlyBatteryLevelsPerDay.size(); dailyIndex++) {
-            if (mHourlyBatteryLevelsPerDay.get(dailyIndex) == null) {
-                continue;
-            }
-            final List<Long> timestamps =
-                    mHourlyBatteryLevelsPerDay.get(dailyIndex).getTimestamps();
-            if (timestamps.size() > 0) {
-                return timestamps.get(0);
-            }
-        }
-        return 0;
-    }
-
-    @VisibleForTesting
     List<AppUsageEvent> getAppUsageEventList() {
         return mAppUsageEventList;
     }
@@ -251,7 +236,7 @@
                 final int workProfileUserId = getWorkProfileUserId();
                 final UsageEvents usageEventsForCurrentUser =
                         DataProcessor.getAppUsageEventsForUser(
-                                mContext, currentUserId, mStartTimestampOfLevelData);
+                                mContext, currentUserId, mRawStartTimestamp);
                 // If fail to load usage events for current user, return null directly and screen-on
                 // time will not be shown in the UI.
                 if (usageEventsForCurrentUser == null) {
@@ -262,7 +247,7 @@
                 if (workProfileUserId != Integer.MIN_VALUE) {
                     usageEventsForWorkProfile =
                             DataProcessor.getAppUsageEventsForUser(
-                                    mContext, workProfileUserId, mStartTimestampOfLevelData);
+                                    mContext, workProfileUserId, mRawStartTimestamp);
                 } else {
                     Log.d(TAG, "there is no work profile");
                 }
@@ -309,7 +294,7 @@
                 final List<AppUsageEvent> appUsageEventList =
                         DatabaseUtils.getAppUsageEventForUsers(
                                 mContext, Calendar.getInstance(), getCurrentUserIds(),
-                                mStartTimestampOfLevelData);
+                                mRawStartTimestamp);
                 Log.d(TAG, String.format("execute loadDatabaseAppUsageList size=%d in %d/ms",
                         appUsageEventList.size(), (System.currentTimeMillis() - startTime)));
                 return appUsageEventList;
@@ -376,7 +361,7 @@
         // Generates the indexed AppUsagePeriod list data for each corresponding time slot for
         // further use.
         mAppUsagePeriodMap = DataProcessor.generateAppUsagePeriodMap(
-                mHourlyBatteryLevelsPerDay, mAppUsageEventList);
+                mRawStartTimestamp, mHourlyBatteryLevelsPerDay, mAppUsageEventList);
     }
 
     private void tryToGenerateFinalDataAndApplyCallback() {
@@ -489,10 +474,12 @@
             return null;
         }
 
+        final long rawStartTimestamp = Collections.min(batteryHistoryMap.keySet());
         // Start the async task to compute diff usage data and load labels and icons.
         new DataProcessManager(
                 context,
                 handler,
+                rawStartTimestamp,
                 asyncResponseDelegate,
                 batteryLevelData.getHourlyBatteryLevelsPerDay(),
                 processedBatteryHistoryMap).start();
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
index 2a926d0..338cb11 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -61,7 +61,6 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -84,7 +83,8 @@
     private static final float TOTAL_HOURLY_TIME_THRESHOLD = DateUtils.HOUR_IN_MILLIS * 2;
     private static final long MIN_TIME_SLOT = DateUtils.HOUR_IN_MILLIS * 2;
     private static final String MEDIASERVER_PACKAGE_NAME = "mediaserver";
-    private static final Map<String, BatteryHistEntry> EMPTY_BATTERY_MAP = new HashMap<>();
+    private static final String ANDROID_CORE_APPS_SHARED_USER_ID = "android.uid.shared";
+    private static final Map<String, BatteryHistEntry> EMPTY_BATTERY_MAP = new ArrayMap<>();
     private static final BatteryHistEntry EMPTY_BATTERY_HIST_ENTRY =
             new BatteryHistEntry(new ContentValues());
 
@@ -102,7 +102,7 @@
     static long sTestCurrentTimeMillis = 0;
 
     @VisibleForTesting
-    static Set<String> sTestSystemAppsSet;
+    static Set<String> sTestSystemAppsPackageNames;
 
     @VisibleForTesting
     static IUsageStatsManager sUsageStatsManager =
@@ -185,7 +185,7 @@
         if (context == null) {
             return null;
         }
-        final Map<Long, UsageEvents> resultMap = new HashMap();
+        final Map<Long, UsageEvents> resultMap = new ArrayMap();
         final UserManager userManager = context.getSystemService(UserManager.class);
         if (userManager == null) {
             return null;
@@ -265,8 +265,9 @@
     @Nullable
     public static Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
             generateAppUsagePeriodMap(
-            final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
-            final List<AppUsageEvent> appUsageEventList) {
+                    final long rawStartTimestamp,
+                    final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
+                    final List<AppUsageEvent> appUsageEventList) {
         if (appUsageEventList.isEmpty()) {
             Log.w(TAG, "appUsageEventList is empty");
             return null;
@@ -275,12 +276,12 @@
         // distribution.
         Collections.sort(appUsageEventList, TIMESTAMP_COMPARATOR);
         final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>> resultMap =
-                new HashMap<>();
+                new ArrayMap<>();
 
         final long dailySize = hourlyBatteryLevelsPerDay.size();
         for (int dailyIndex = 0; dailyIndex < hourlyBatteryLevelsPerDay.size(); dailyIndex++) {
             final Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>> dailyMap =
-                    new HashMap<>();
+                    new ArrayMap<>();
             resultMap.put(dailyIndex, dailyMap);
             if (hourlyBatteryLevelsPerDay.get(dailyIndex) == null) {
                 continue;
@@ -288,8 +289,12 @@
             final List<Long> timestamps = hourlyBatteryLevelsPerDay.get(dailyIndex).getTimestamps();
             final long hourlySize = timestamps.size() - 1;
             for (int hourlyIndex = 0; hourlyIndex < timestamps.size() - 1; hourlyIndex++) {
-                // The start and end timestamps of this slot should be the adjacent timestamps.
-                final long startTimestamp = timestamps.get(hourlyIndex);
+                // The start slot timestape is the near hour timestamp instead of the last full
+                // charge time. So use rawStartTimestamp instead of reading the timestamp from
+                // hourlyBatteryLevelsPerDay here.
+                final long startTimestamp =
+                        dailyIndex == 0 && hourlyIndex == 0 && !sDebug
+                                ? rawStartTimestamp : timestamps.get(hourlyIndex);
                 // The final slot is to show the data from last even hour until now but the
                 // timestamp in hourlyBatteryLevelsPerDay is not the real value. So use current
                 // timestamp instead of reading the timestamp from hourlyBatteryLevelsPerDay here.
@@ -386,7 +391,7 @@
         if (appUsagePeriodMap == null) {
             return null;
         }
-        final Map<Integer, Map<Integer, Long>> deviceScreenOnTime = new HashMap<>();
+        final Map<Integer, Map<Integer, Long>> deviceScreenOnTime = new ArrayMap<>();
         insertHourlyDeviceScreenOnTime(appUsagePeriodMap, deviceScreenOnTime);
         insertDailyDeviceScreenOnTime(appUsagePeriodMap, deviceScreenOnTime);
         insertAllDeviceScreenOnTime(deviceScreenOnTime);
@@ -428,7 +433,7 @@
             final Context context) {
         final List<BatteryHistEntry> batteryHistEntryList =
                 getBatteryHistListFromFromStatsService(context);
-        return batteryHistEntryList == null ? new HashMap<>()
+        return batteryHistEntryList == null ? new ArrayMap<>()
                 : batteryHistEntryList.stream().collect(Collectors.toMap(e -> e.getKey(), e -> e));
     }
 
@@ -436,14 +441,14 @@
      * @return Returns the processed history map which has interpolated to every hour data.
      * The start and end timestamp must be the even hours.
      * The keys of processed history map should contain every hour between the start and end
-     * timestamp. If there's no data in some key, the value will be the empty hashmap.
+     * timestamp. If there's no data in some key, the value will be the empty map.
      */
     static Map<Long, Map<String, BatteryHistEntry>> getHistoryMapWithExpectedTimestamps(
             Context context,
             final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
         final long startTime = System.currentTimeMillis();
         final List<Long> rawTimestampList = new ArrayList<>(batteryHistoryMap.keySet());
-        final Map<Long, Map<String, BatteryHistEntry>> resultMap = new HashMap();
+        final Map<Long, Map<String, BatteryHistEntry>> resultMap = new ArrayMap();
         if (rawTimestampList.isEmpty()) {
             Log.d(TAG, "empty batteryHistoryMap in getHistoryMapWithExpectedTimestamps()");
             return resultMap;
@@ -636,11 +641,12 @@
         if (batteryHistoryMap.isEmpty()) {
             return null;
         }
-        final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new HashMap<>();
-        final Set<String> systemAppsSet = getSystemAppsSet(context);
+        final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new ArrayMap<>();
+        final Set<String> systemAppsPackageNames = getSystemAppsPackageNames(context);
+        final Set<Integer> systemAppsUids = getSystemAppsUids(context);
         // Insert diff data from [0][0] to [maxDailyIndex][maxHourlyIndex].
-        insertHourlyUsageDiffData(context, systemAppsSet, hourlyBatteryLevelsPerDay,
-                batteryHistoryMap, appUsagePeriodMap, resultMap);
+        insertHourlyUsageDiffData(context, systemAppsPackageNames, systemAppsUids,
+                hourlyBatteryLevelsPerDay, batteryHistoryMap, appUsagePeriodMap, resultMap);
         // Insert diff data from [0][SELECTED_INDEX_ALL] to [maxDailyIndex][SELECTED_INDEX_ALL].
         insertDailyUsageDiffData(context, hourlyBatteryLevelsPerDay, resultMap);
         // Insert diff data [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL].
@@ -699,9 +705,10 @@
             return null;
         }
 
-        final Set<String> systemAppsSet = getSystemAppsSet(context);
-        return new BatteryDiffData(
-                context, appEntries, systemEntries, systemAppsSet, /* isAccumulated= */ false);
+        final Set<String> systemAppsPackageNames = getSystemAppsPackageNames(context);
+        final Set<Integer> systemAppsUids = getSystemAppsUids(context);
+        return new BatteryDiffData(context, appEntries, systemEntries,
+                systemAppsPackageNames, systemAppsUids, /* isAccumulated= */ false);
     }
 
     /**
@@ -738,7 +745,7 @@
             return null;
         }
 
-        final Map<Long, Map<String, List<AppUsagePeriod>>> allUsagePeriods = new HashMap<>();
+        final Map<Long, Map<String, List<AppUsagePeriod>>> allUsagePeriods = new ArrayMap<>();
 
         for (int i = 0; i < usageEventsByInstanceId.size(); i++) {
             // The usage periods for an instance are determined by the usage events with its
@@ -850,8 +857,8 @@
      */
     static Map<Integer, Map<Integer, BatteryDiffData>> getBatteryUsageMapFromStatsService(
             final Context context) {
-        final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new HashMap<>();
-        final Map<Integer, BatteryDiffData> allUsageMap = new HashMap<>();
+        final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new ArrayMap<>();
+        final Map<Integer, BatteryDiffData> allUsageMap = new ArrayMap<>();
         // Always construct the map whether the value is null or not.
         allUsageMap.put(SELECTED_INDEX_ALL,
                 generateBatteryDiffData(context, getBatteryHistListFromFromStatsService(context)));
@@ -932,7 +939,7 @@
             final List<AppUsagePeriod> usagePeriodList,
             final long userId,
             final String packageName) {
-        usagePeriodMap.computeIfAbsent(userId, key -> new HashMap<>());
+        usagePeriodMap.computeIfAbsent(userId, key -> new ArrayMap<>());
         final Map<String, List<AppUsagePeriod>> packageNameMap = usagePeriodMap.get(userId);
         packageNameMap.computeIfAbsent(packageName, key -> new ArrayList<>());
         packageNameMap.get(packageName).addAll(usagePeriodList);
@@ -963,7 +970,7 @@
         for (final int dailyIndex : appUsagePeriodMap.keySet()) {
             final Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>> dailyAppUsageMap =
                     appUsagePeriodMap.get(dailyIndex);
-            final Map<Integer, Long> dailyScreenOnTime = new HashMap<>();
+            final Map<Integer, Long> dailyScreenOnTime = new ArrayMap<>();
             resultMap.put(dailyIndex, dailyScreenOnTime);
             if (dailyAppUsageMap == null) {
                 continue;
@@ -1004,7 +1011,7 @@
         for (final int dailyIndex : appUsagePeriodMap.keySet()) {
             Map<Integer, Long> dailyResultMap = resultMap.get(dailyIndex);
             if (dailyResultMap == null) {
-                dailyResultMap = new HashMap<>();
+                dailyResultMap = new ArrayMap<>();
                 resultMap.put(dailyIndex, dailyResultMap);
             }
             dailyResultMap.put(
@@ -1015,10 +1022,10 @@
 
     private static void insertAllDeviceScreenOnTime(
             final Map<Integer, Map<Integer, Long>> resultMap) {
-        final Map<Integer, Long> dailyAllMap = new HashMap<>();
+        final Map<Integer, Long> dailyAllMap = new ArrayMap<>();
         resultMap.keySet().forEach(
                 key -> dailyAllMap.put(key, resultMap.get(key).get(SELECTED_INDEX_ALL)));
-        final Map<Integer, Long> allUsageMap = new HashMap<>();
+        final Map<Integer, Long> allUsageMap = new ArrayMap<>();
         allUsageMap.put(SELECTED_INDEX_ALL, getAccumulatedScreenOnTime(dailyAllMap));
         resultMap.put(SELECTED_INDEX_ALL, allUsageMap);
     }
@@ -1168,7 +1175,7 @@
         // Case 1: upper timestamp is zero since scheduler is delayed!
         if (upperTimestamp == 0) {
             log(context, "job scheduler is delayed", currentSlot, null);
-            resultMap.put(currentSlot, new HashMap<>());
+            resultMap.put(currentSlot, new ArrayMap<>());
             return;
         }
         // Case 2: upper timestamp is closed to the current timestamp.
@@ -1181,7 +1188,7 @@
         // Case 3: lower timestamp is zero before starting to collect data.
         if (lowerTimestamp == 0) {
             log(context, "no lower timestamp slot data", currentSlot, null);
-            resultMap.put(currentSlot, new HashMap<>());
+            resultMap.put(currentSlot, new ArrayMap<>());
             return;
         }
         interpolateHistoryForSlot(context,
@@ -1217,12 +1224,12 @@
                 resultMap.put(currentSlot, upperEntryDataMap);
             } else {
                 log(context, "in the different booting section", currentSlot, null);
-                resultMap.put(currentSlot, new HashMap<>());
+                resultMap.put(currentSlot, new ArrayMap<>());
             }
             return;
         }
         log(context, "apply interpolation arithmetic", currentSlot, null);
-        final Map<String, BatteryHistEntry> newHistEntryMap = new HashMap<>();
+        final Map<String, BatteryHistEntry> newHistEntryMap = new ArrayMap<>();
         final double timestampLength = upperTimestamp - lowerTimestamp;
         final double timestampDiff = currentSlot - lowerTimestamp;
         // Applies interpolation arithmetic for each BatteryHistEntry.
@@ -1369,7 +1376,8 @@
 
     private static void insertHourlyUsageDiffData(
             Context context,
-            final Set<String> systemAppsSet,
+            final Set<String> systemAppsPackageNames,
+            final Set<Integer> systemAppsUids,
             final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
             final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
             final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
@@ -1385,7 +1393,7 @@
         //     Math.abs(timestamp[i+1] data - timestamp[i] data);
         // since we want to aggregate every two hours data into a single time slot.
         for (int dailyIndex = 0; dailyIndex < hourlyBatteryLevelsPerDay.size(); dailyIndex++) {
-            final Map<Integer, BatteryDiffData> dailyDiffMap = new HashMap<>();
+            final Map<Integer, BatteryDiffData> dailyDiffMap = new ArrayMap<>();
             resultMap.put(dailyIndex, dailyDiffMap);
             if (hourlyBatteryLevelsPerDay.get(dailyIndex) == null) {
                 continue;
@@ -1399,7 +1407,8 @@
                                 workProfileUserId,
                                 hourlyIndex,
                                 timestamps,
-                                systemAppsSet,
+                                systemAppsPackageNames,
+                                systemAppsUids,
                                 appUsagePeriodMap == null
                                         || appUsagePeriodMap.get(dailyIndex) == null
                                         ? null
@@ -1417,7 +1426,7 @@
         for (int index = 0; index < hourlyBatteryLevelsPerDay.size(); index++) {
             Map<Integer, BatteryDiffData> dailyUsageMap = resultMap.get(index);
             if (dailyUsageMap == null) {
-                dailyUsageMap = new HashMap<>();
+                dailyUsageMap = new ArrayMap<>();
                 resultMap.put(index, dailyUsageMap);
             }
             dailyUsageMap.put(
@@ -1432,7 +1441,7 @@
         final List<BatteryDiffData> diffDataList = new ArrayList<>();
         resultMap.keySet().forEach(
                 key -> diffDataList.add(resultMap.get(key).get(SELECTED_INDEX_ALL)));
-        final Map<Integer, BatteryDiffData> allUsageMap = new HashMap<>();
+        final Map<Integer, BatteryDiffData> allUsageMap = new ArrayMap<>();
         allUsageMap.put(SELECTED_INDEX_ALL, getAccumulatedUsageDiffData(context, diffDataList));
         resultMap.put(SELECTED_INDEX_ALL, allUsageMap);
     }
@@ -1444,7 +1453,8 @@
             final int workProfileUserId,
             final int currentIndex,
             final List<Long> timestamps,
-            final Set<String> systemAppsSet,
+            final Set<String> systemAppsPackageNames,
+            final Set<Integer> systemAppsUids,
             final Map<Long, Map<String, List<AppUsagePeriod>>> appUsageMap,
             final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
         final List<BatteryDiffEntry> appEntries = new ArrayList<>();
@@ -1598,8 +1608,8 @@
             return null;
         }
 
-        return new BatteryDiffData(
-                context, appEntries, systemEntries, systemAppsSet, /* isAccumulated= */ false);
+        return new BatteryDiffData(context, appEntries, systemEntries,
+                systemAppsPackageNames, systemAppsUids, /* isAccumulated= */ false);
     }
 
     private static long getScreenOnTime(@Nullable final List<AppUsagePeriod> appUsagePeriodList) {
@@ -1657,7 +1667,7 @@
     @Nullable
     private static BatteryDiffData getAccumulatedUsageDiffData(
             final Context context, final Collection<BatteryDiffData> diffEntryListData) {
-        final Map<String, BatteryDiffEntry> diffEntryMap = new HashMap<>();
+        final Map<String, BatteryDiffEntry> diffEntryMap = new ArrayMap<>();
         final List<BatteryDiffEntry> appEntries = new ArrayList<>();
         final List<BatteryDiffEntry> systemEntries = new ArrayList<>();
 
@@ -1683,7 +1693,8 @@
         }
 
         return diffEntryList.isEmpty() ? null : new BatteryDiffData(context, appEntries,
-                systemEntries, /* systemAppsSet= */ null, /* isAccumulated= */ true);
+                systemEntries, /* systemAppsPackageNames= */ new ArraySet<>(),
+                /* systemAppsUids= */ new ArraySet<>(), /* isAccumulated= */ true);
     }
 
     private static void computeUsageDiffDataPerEntry(
@@ -1899,11 +1910,22 @@
         return null;
     }
 
-    private static Set<String> getSystemAppsSet(Context context) {
-        return sTestSystemAppsSet != null ? sTestSystemAppsSet
+    private static Set<String> getSystemAppsPackageNames(Context context) {
+        return sTestSystemAppsPackageNames != null ? sTestSystemAppsPackageNames
                 : AppListRepositoryUtil.getSystemPackageNames(context, context.getUserId(), false);
     }
 
+    private static Set<Integer> getSystemAppsUids(Context context) {
+        Set<Integer> result = new ArraySet<>();
+        try {
+            result.add(context.getPackageManager().getUidForSharedUser(
+                    ANDROID_CORE_APPS_SHARED_USER_ID));
+        } catch (PackageManager.NameNotFoundException e) {
+            // No Android Core Apps
+        }
+        return result;
+    }
+
     private static long getCurrentTimeMillis() {
         return sTestCurrentTimeMillis > 0 ? sTestCurrentTimeMillis : System.currentTimeMillis();
     }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
index 2b330cc..655114f 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
@@ -139,13 +139,13 @@
             Context context,
             final Calendar calendar,
             final List<Integer> userIds,
-            final long startTimestampOfLevelData) {
+            final long rawStartTimestamp) {
         final long startTime = System.currentTimeMillis();
         final long sixDaysAgoTimestamp = getTimestampSixDaysAgo(calendar);
         // Query a longer time period and then trim to the original time period in order to make
         // sure the app usage calculation near the boundaries is correct.
         final long queryTimestamp =
-                Math.max(startTimestampOfLevelData, sixDaysAgoTimestamp) - USAGE_QUERY_BUFFER_HOURS;
+                Math.max(rawStartTimestamp, sixDaysAgoTimestamp) - USAGE_QUERY_BUFFER_HOURS;
         Log.d(TAG, "sixDayAgoTimestamp: " + sixDaysAgoTimestamp);
         final String queryUserIdString = userIds.stream()
                 .map(userId -> String.valueOf(userId))
diff --git a/src/com/android/settings/inputmethod/KeyboardLayoutDialogFragment.java b/src/com/android/settings/inputmethod/KeyboardLayoutDialogFragment.java
index f91c9d8..94f0757 100644
--- a/src/com/android/settings/inputmethod/KeyboardLayoutDialogFragment.java
+++ b/src/com/android/settings/inputmethod/KeyboardLayoutDialogFragment.java
@@ -308,6 +308,12 @@
         public Keyboards loadInBackground() {
             Keyboards keyboards = new Keyboards();
             InputManager im = (InputManager)getContext().getSystemService(Context.INPUT_SERVICE);
+            if (mInputDeviceIdentifier == null || NewKeyboardSettingsUtils.getInputDevice(
+                    im, mInputDeviceIdentifier) == null) {
+                keyboards.keyboardLayouts.add(null); // default layout
+                keyboards.current = 0;
+                return keyboards;
+            }
             String[] keyboardLayoutDescriptors = im.getEnabledKeyboardLayoutsForInputDevice(
                     mInputDeviceIdentifier);
             for (String keyboardLayoutDescriptor : keyboardLayoutDescriptors) {
diff --git a/src/com/android/settings/inputmethod/KeyboardLayoutPickerController.java b/src/com/android/settings/inputmethod/KeyboardLayoutPickerController.java
index c6a0d75..10cd4a2 100644
--- a/src/com/android/settings/inputmethod/KeyboardLayoutPickerController.java
+++ b/src/com/android/settings/inputmethod/KeyboardLayoutPickerController.java
@@ -21,7 +21,6 @@
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
 import android.hardware.input.KeyboardLayout;
-import android.view.InputDevice;
 
 import androidx.fragment.app.Fragment;
 import androidx.preference.Preference;
@@ -37,7 +36,6 @@
 import java.util.HashMap;
 import java.util.Map;
 
-
 public class KeyboardLayoutPickerController extends BasePreferenceController implements
         InputManager.InputDeviceListener, LifecycleObserver, OnStart, OnStop {
 
@@ -68,15 +66,12 @@
     @Override
     public void onStart() {
         mIm.registerInputDeviceListener(this, null);
-
-        final InputDevice inputDevice =
-                mIm.getInputDeviceByDescriptor(mInputDeviceIdentifier.getDescriptor());
-        if (inputDevice == null) {
-            mParent.getActivity().finish();
+        if (mInputDeviceIdentifier == null
+                || NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier) == null) {
             return;
         }
-        mInputDeviceId = inputDevice.getId();
-
+        mInputDeviceId =
+                NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier).getId();
         updateCheckedState();
     }
 
@@ -150,6 +145,9 @@
     }
 
     private void createPreferenceHierarchy() {
+        if (mKeyboardLayouts == null) {
+            return;
+        }
         for (KeyboardLayout layout : mKeyboardLayouts) {
             final SwitchPreference pref = new SwitchPreference(mScreen.getContext());
             pref.setTitle(layout.getLabel());
diff --git a/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment.java b/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment.java
index a13ebc0..8abde7e 100644
--- a/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment.java
+++ b/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment.java
@@ -19,11 +19,11 @@
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.hardware.input.InputDeviceIdentifier;
+import android.hardware.input.InputManager;
 
 import com.android.settings.R;
 import com.android.settings.dashboard.DashboardFragment;
 
-
 public class KeyboardLayoutPickerFragment extends DashboardFragment {
 
     private static final String TAG = "KeyboardLayoutPicker";
@@ -45,10 +45,10 @@
 
         final InputDeviceIdentifier inputDeviceIdentifier = getActivity().getIntent().
                 getParcelableExtra(EXTRA_INPUT_DEVICE_IDENTIFIER);
-        if (inputDeviceIdentifier == null) {
-            getActivity().finish();
+        final InputManager im = context.getSystemService(InputManager.class);
+        if (NewKeyboardSettingsUtils.getInputDevice(im, inputDeviceIdentifier) == null) {
+            return;
         }
-
         use(KeyboardLayoutPickerController.class).initialize(this /*parent*/,
                 inputDeviceIdentifier);
     }
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java
index 9311c97..2db3382 100644
--- a/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java
@@ -68,6 +68,9 @@
     }
 
     private void updateCheckedState() {
+        if (NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier) == null) {
+            return;
+        }
         PreferenceScreen preferenceScreen = getPreferenceScreen();
         preferenceScreen.removeAll();
         List<InputMethodInfo> infoList = mImm.getEnabledInputMethodListAsUser(mUserId);
@@ -174,8 +177,8 @@
     public void onStart() {
         super.onStart();
         mIm.registerInputDeviceListener(this, null);
-        final InputDevice inputDevice =
-                mIm.getInputDeviceByDescriptor(mInputDeviceIdentifier.getDescriptor());
+        InputDevice inputDevice =
+                NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier);
         if (inputDevice == null) {
             getActivity().finish();
             return;
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java
index bb452f7..605095f 100644
--- a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java
@@ -19,6 +19,7 @@
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.hardware.input.InputDeviceIdentifier;
+import android.hardware.input.InputManager;
 import android.os.Bundle;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
@@ -33,25 +34,24 @@
     @Override
     public void onAttach(Context context) {
         super.onAttach(context);
-
+        InputManager inputManager = getContext().getSystemService(InputManager.class);
         Bundle arguments = getArguments();
         final String title = arguments.getString(NewKeyboardSettingsUtils.EXTRA_TITLE);
         final String layout = arguments.getString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_LAYOUT);
         final int userId = arguments.getInt(NewKeyboardSettingsUtils.EXTRA_USER_ID);
-        final InputDeviceIdentifier inputDeviceIdentifier =
+        final InputDeviceIdentifier identifier =
                 arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER);
         final InputMethodInfo inputMethodInfo =
                 arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_INFO);
         final InputMethodSubtype inputMethodSubtype =
                 arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_SUBTYPE);
-
-
-        if (inputDeviceIdentifier == null) {
-            getActivity().finish();
+        if (identifier == null
+                || NewKeyboardSettingsUtils.getInputDevice(inputManager, identifier) == null) {
+            return;
         }
         getActivity().setTitle(title);
         use(NewKeyboardLayoutPickerController.class).initialize(this /*parent*/, userId,
-                inputDeviceIdentifier, inputMethodInfo, inputMethodSubtype, layout);
+                identifier, inputMethodInfo, inputMethodSubtype, layout);
     }
 
     @Override
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
index eb0a7aa..893ad4c 100644
--- a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
@@ -20,7 +20,6 @@
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
 import android.hardware.input.KeyboardLayout;
-import android.view.InputDevice;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
 
@@ -75,13 +74,12 @@
     @Override
     public void onStart() {
         mIm.registerInputDeviceListener(this, null);
-        final InputDevice inputDevice =
-                mIm.getInputDeviceByDescriptor(mInputDeviceIdentifier.getDescriptor());
-        if (inputDevice == null) {
-            mParent.getActivity().finish();
+        if (mInputDeviceIdentifier == null
+                || NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier) == null) {
             return;
         }
-        mInputDeviceId = inputDevice.getId();
+        mInputDeviceId =
+                NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier).getId();
     }
 
     @Override
@@ -138,6 +136,9 @@
     }
 
     private void createPreferenceHierarchy() {
+        if (mKeyboardLayouts == null) {
+            return;
+        }
         for (KeyboardLayout layout : mKeyboardLayouts) {
             final KeyboardLayoutPreference pref;
             if (mLayout.equals(layout.getLabel())) {
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java
index 169b84b..88cacd2 100644
--- a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java
@@ -27,13 +27,11 @@
 
 public class NewKeyboardLayoutPickerFragment extends Fragment {
 
-    private ViewGroup mFragmentView;
-
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
 
-        mFragmentView = (ViewGroup) inflater.inflate(
+        ViewGroup fragmentView = (ViewGroup) inflater.inflate(
                 R.layout.keyboard_layout_picker, container, false);
         getActivity().getSupportFragmentManager()
                 .beginTransaction()
@@ -47,6 +45,6 @@
                 .replace(R.id.keyboard_layouts, fragment)
                 .commit();
 
-        return mFragmentView;
+        return fragmentView;
     }
 }
diff --git a/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java b/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java
index 0bd938e..dda5500 100644
--- a/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java
+++ b/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java
@@ -17,6 +17,8 @@
 package com.android.settings.inputmethod;
 
 import android.content.Context;
+import android.hardware.input.InputDeviceIdentifier;
+import android.hardware.input.InputManager;
 import android.view.InputDevice;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
@@ -102,4 +104,8 @@
             return mInputMethodSubtype;
         }
     }
+
+    static InputDevice getInputDevice(InputManager im, InputDeviceIdentifier identifier) {
+        return im.getInputDeviceByDescriptor(identifier.getDescriptor());
+    }
 }
diff --git a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
index 20a634e..e9dba57 100644
--- a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
+++ b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
@@ -160,6 +160,10 @@
         final Context context = getContext();
         ThreadUtils.postOnBackgroundThread(() -> {
             final List<HardKeyboardDeviceInfo> newHardKeyboards = getHardKeyboards(context);
+            if (newHardKeyboards.isEmpty()) {
+                getActivity().finish();
+                return;
+            }
             ThreadUtils.postOnMainThread(() -> updateHardKeyboards(newHardKeyboards));
         });
     }
diff --git a/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceController.java b/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceController.java
index 367ea80..3dcae09 100644
--- a/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceController.java
+++ b/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceController.java
@@ -22,6 +22,7 @@
 
 import androidx.preference.Preference;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.inputmethod.PhysicalKeyboardFragment.HardKeyboardDeviceInfo;
@@ -34,7 +35,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-
 public class PhysicalKeyboardPreferenceController extends AbstractPreferenceController
         implements PreferenceControllerMixin, LifecycleObserver, OnResume, OnPause,
         InputManager.InputDeviceListener {
@@ -54,13 +54,14 @@
 
     @Override
     public boolean isAvailable() {
-        return mContext.getResources().getBoolean(R.bool.config_show_physical_keyboard_pref);
+        return !getKeyboards().isEmpty()
+                && mContext.getResources().getBoolean(R.bool.config_show_physical_keyboard_pref);
     }
 
     @Override
     public void updateState(Preference preference) {
         mPreference = preference;
-        updateSummary();
+        updateEntry();
     }
 
     @Override
@@ -80,33 +81,42 @@
 
     @Override
     public void onInputDeviceAdded(int deviceId) {
-        updateSummary();
+        updateEntry();
     }
 
     @Override
     public void onInputDeviceRemoved(int deviceId) {
-        updateSummary();
+        updateEntry();
     }
 
     @Override
     public void onInputDeviceChanged(int deviceId) {
-        updateSummary();
+        updateEntry();
     }
 
-    private void updateSummary() {
+    private void updateEntry() {
         if (mPreference == null) {
             return;
         }
-        final List<HardKeyboardDeviceInfo> keyboards =
-                PhysicalKeyboardFragment.getHardKeyboards(mContext);
+        List<HardKeyboardDeviceInfo> keyboards = getKeyboards();
         if (keyboards.isEmpty()) {
-            mPreference.setSummary(R.string.keyboard_disconnected);
+            mPreference.setVisible(false);
             return;
         }
-        final List<String> summaries = new ArrayList<>();
+        updateSummary(keyboards);
+    }
+
+    private void updateSummary(List<HardKeyboardDeviceInfo> keyboards) {
+        mPreference.setVisible(true);
+        List<String> summaries = new ArrayList<>();
         for (HardKeyboardDeviceInfo info : keyboards) {
             summaries.add(info.mDeviceName);
         }
         mPreference.setSummary(ListFormatter.getInstance().format(summaries));
     }
+
+    @VisibleForTesting
+    List<HardKeyboardDeviceInfo> getKeyboards() {
+        return PhysicalKeyboardFragment.getHardKeyboards(mContext);
+    }
 }
diff --git a/src/com/android/settings/localepicker/LocaleDialogFragment.java b/src/com/android/settings/localepicker/LocaleDialogFragment.java
new file mode 100644
index 0000000..63fc179
--- /dev/null
+++ b/src/com/android/settings/localepicker/LocaleDialogFragment.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2023 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.localepicker;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.os.ResultReceiver;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.FragmentManager;
+
+import com.android.internal.app.LocaleStore;
+import com.android.settings.R;
+import com.android.settings.RestrictedSettingsFragment;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+/**
+ * Create a dialog for system locale events.
+ */
+public class LocaleDialogFragment extends InstrumentedDialogFragment {
+    private static final String TAG = LocaleDialogFragment.class.getSimpleName();
+
+    static final int DIALOG_CONFIRM_SYSTEM_DEFAULT = 0;
+    static final int DIALOG_NOT_AVAILABLE_LOCALE = 1;
+
+    static final String ARG_DIALOG_TYPE = "arg_dialog_type";
+    static final String ARG_TARGET_LOCALE = "arg_target_locale";
+    static final String ARG_RESULT_RECEIVER = "arg_result_receiver";
+
+    /**
+     * Show dialog
+     */
+    public static void show(
+            @NonNull RestrictedSettingsFragment fragment,
+            int dialogType,
+            LocaleStore.LocaleInfo localeInfo) {
+        show(fragment, dialogType, localeInfo, null);
+    }
+
+    /**
+     * Show dialog
+     */
+    public static void show(
+            @NonNull RestrictedSettingsFragment fragment,
+            int dialogType,
+            LocaleStore.LocaleInfo localeInfo,
+            ResultReceiver resultReceiver) {
+        FragmentManager manager = fragment.getChildFragmentManager();
+        Bundle args = new Bundle();
+        args.putInt(ARG_DIALOG_TYPE, dialogType);
+        args.putSerializable(ARG_TARGET_LOCALE, localeInfo);
+        args.putParcelable(ARG_RESULT_RECEIVER, resultReceiver);
+
+        LocaleDialogFragment localeDialogFragment = new LocaleDialogFragment();
+        localeDialogFragment.setArguments(args);
+        localeDialogFragment.show(manager, TAG);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        int dialogType = getArguments().getInt(ARG_DIALOG_TYPE);
+        switch (dialogType) {
+            case DIALOG_CONFIRM_SYSTEM_DEFAULT:
+                return SettingsEnums.DIALOG_SYSTEM_LOCALE_CHANGE;
+            case DIALOG_NOT_AVAILABLE_LOCALE:
+                return SettingsEnums.DIALOG_SYSTEM_LOCALE_UNAVAILABLE;
+            default:
+                return SettingsEnums.DIALOG_SYSTEM_LOCALE_CHANGE;
+        }
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        LocaleDialogController controller = new LocaleDialogController(this);
+        LocaleDialogController.DialogContent dialogContent = controller.getDialogContent();
+        ViewGroup viewGroup = (ViewGroup) LayoutInflater.from(getContext()).inflate(
+                R.layout.locale_dialog, null);
+        setDialogTitle(viewGroup, dialogContent.mTitle);
+        setDialogMessage(viewGroup, dialogContent.mMessage);
+        AlertDialog.Builder builder = new AlertDialog.Builder(getContext())
+                .setView(viewGroup);
+        if (!dialogContent.mPositiveButton.isEmpty()) {
+            builder.setPositiveButton(dialogContent.mPositiveButton, controller);
+        }
+        if (!dialogContent.mNegativeButton.isEmpty()) {
+            builder.setNegativeButton(dialogContent.mNegativeButton, controller);
+        }
+        return builder.create();
+    }
+
+    private static void setDialogTitle(View root, String content) {
+        TextView titleView = root.findViewById(R.id.dialog_title);
+        if (titleView == null) {
+            return;
+        }
+        titleView.setText(content);
+    }
+
+    private static void setDialogMessage(View root, String content) {
+        TextView textView = root.findViewById(R.id.dialog_msg);
+        if (textView == null) {
+            return;
+        }
+        textView.setText(content);
+    }
+
+    static class LocaleDialogController implements DialogInterface.OnClickListener {
+        private final Context mContext;
+        private final int mDialogType;
+        private final LocaleStore.LocaleInfo mLocaleInfo;
+        private final ResultReceiver mResultReceiver;
+
+        LocaleDialogController(
+                @NonNull Context context, @NonNull LocaleDialogFragment dialogFragment) {
+            mContext = context;
+            Bundle arguments = dialogFragment.getArguments();
+            mDialogType = arguments.getInt(ARG_DIALOG_TYPE);
+            mLocaleInfo = (LocaleStore.LocaleInfo) arguments.getSerializable(
+                    ARG_TARGET_LOCALE);
+            mResultReceiver = (ResultReceiver) arguments.getParcelable(ARG_RESULT_RECEIVER);
+        }
+
+        LocaleDialogController(@NonNull LocaleDialogFragment dialogFragment) {
+            this(dialogFragment.getContext(), dialogFragment);
+        }
+
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            if (mResultReceiver != null && mDialogType == DIALOG_CONFIRM_SYSTEM_DEFAULT) {
+                Bundle bundle = new Bundle();
+                bundle.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT);
+                if (which == DialogInterface.BUTTON_POSITIVE) {
+                    mResultReceiver.send(Activity.RESULT_OK, bundle);
+                } else if (which == DialogInterface.BUTTON_NEGATIVE) {
+                    mResultReceiver.send(Activity.RESULT_CANCELED, bundle);
+                }
+            }
+        }
+
+        @VisibleForTesting
+        DialogContent getDialogContent() {
+            DialogContent
+                    dialogContent = new DialogContent();
+            switch (mDialogType) {
+                case DIALOG_CONFIRM_SYSTEM_DEFAULT:
+                    dialogContent.mTitle = String.format(mContext.getString(
+                            R.string.title_change_system_locale), mLocaleInfo.getFullNameNative());
+                    dialogContent.mMessage = mContext.getString(
+                            R.string.desc_notice_device_locale_settings_change);
+                    dialogContent.mPositiveButton = mContext.getString(
+                            R.string.button_label_confirmation_of_system_locale_change);
+                    dialogContent.mNegativeButton = mContext.getString(R.string.cancel);
+                    break;
+                case DIALOG_NOT_AVAILABLE_LOCALE:
+                    dialogContent.mTitle = String.format(mContext.getString(
+                            R.string.title_unavailable_locale), mLocaleInfo.getFullNameNative());
+                    dialogContent.mMessage = mContext.getString(R.string.desc_unavailable_locale);
+                    dialogContent.mPositiveButton = mContext.getString(R.string.okay);
+                    break;
+                default:
+                    break;
+            }
+            return dialogContent;
+        }
+
+        @VisibleForTesting
+        static class DialogContent {
+            String mTitle = "";
+            String mMessage = "";
+            String mPositiveButton = "";
+            String mNegativeButton = "";
+        }
+    }
+}
diff --git a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
index b3c2e30..bece414 100644
--- a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
+++ b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
@@ -16,10 +16,14 @@
 
 package com.android.settings.localepicker;
 
+import android.app.Activity;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.LocaleList;
+import android.os.Looper;
+import android.os.ResultReceiver;
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.LayoutInflater;
@@ -49,9 +53,11 @@
     private static final String TAG = "LocaleDragAndDropAdapter";
     private static final String CFGKEY_SELECTED_LOCALES = "selectedLocales";
     private final Context mContext;
-    private final List<LocaleStore.LocaleInfo> mFeedItemList;
+    private List<LocaleStore.LocaleInfo> mFeedItemList;
+    private List<LocaleStore.LocaleInfo> mCacheItemList;
     private final ItemTouchHelper mItemTouchHelper;
     private RecyclerView mParentView = null;
+    private LocaleListEditor mParent;
     private boolean mRemoveMode = false;
     private boolean mDragEnabled = true;
     private NumberFormat mNumberFormatter = NumberFormat.getNumberInstance();
@@ -81,12 +87,15 @@
         }
     }
 
-    public LocaleDragAndDropAdapter(Context context, List<LocaleStore.LocaleInfo> feedItemList) {
+    LocaleDragAndDropAdapter(LocaleListEditor parent,
+            List<LocaleStore.LocaleInfo> feedItemList) {
         mFeedItemList = feedItemList;
-        mContext = context;
+        mParent = parent;
+        mCacheItemList = new ArrayList<>(feedItemList);
+        mContext = parent.getContext();
 
         final float dragElevation = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8,
-                context.getResources().getDisplayMetrics());
+                mContext.getResources().getDisplayMetrics());
 
         mItemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(
                 ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0 /* no swipe */) {
@@ -168,13 +177,13 @@
         checkbox.setOnCheckedChangeListener(null);
         checkbox.setChecked(mRemoveMode ? feedItem.getChecked() : false);
         checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
-                    @Override
-                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-                        LocaleStore.LocaleInfo feedItem =
-                                (LocaleStore.LocaleInfo) dragCell.getTag();
-                        feedItem.setChecked(isChecked);
-                    }
-                });
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                LocaleStore.LocaleInfo feedItem =
+                        (LocaleStore.LocaleInfo) dragCell.getTag();
+                feedItem.setChecked(isChecked);
+            }
+        });
     }
 
     @Override
@@ -308,6 +317,42 @@
         });
     }
 
+    public void doTheUpdateWithMovingLocaleItem() {
+        LocaleStore.LocaleInfo localeInfo = mFeedItemList.get(0);
+        if (!localeInfo.getLocale().equals(LocalePicker.getLocales().get(0))) {
+            LocaleDialogFragment.show(mParent,
+                    LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT,
+                    localeInfo,
+                    new ResultReceiver(new Handler(Looper.getMainLooper())) {
+                        @Override
+                        protected void onReceiveResult(int resultCode, Bundle resultData) {
+                            super.onReceiveResult(resultCode, resultData);
+                            int type = resultData.getInt(LocaleDialogFragment.ARG_DIALOG_TYPE);
+                            if (type == LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT) {
+                                if (resultCode == Activity.RESULT_OK) {
+                                    doTheUpdate();
+                                    if (!localeInfo.isTranslated()) {
+                                        LocaleDialogFragment.show(mParent,
+                                                        LocaleDialogFragment
+                                                                .DIALOG_NOT_AVAILABLE_LOCALE,
+                                                        localeInfo);
+                                    }
+                                } else {
+                                    if (!localeInfo.getLocale()
+                                            .equals(mCacheItemList.get(0).getLocale())) {
+                                        mFeedItemList = new ArrayList<>(mCacheItemList);
+                                        notifyDataSetChanged();
+                                    }
+                                }
+                                mCacheItemList = new ArrayList<>(mFeedItemList);
+                            }
+                        }
+                    });
+        } else {
+            doTheUpdate();
+        }
+    }
+
     private void setDragEnabled(boolean enabled) {
         mDragEnabled = enabled;
     }
@@ -315,6 +360,7 @@
     /**
      * Saves the list of checked locales to preserve status when the list is destroyed.
      * (for instance when the device is rotated)
+     *
      * @param outInstanceState Bundle in which to place the saved state
      */
     public void saveState(Bundle outInstanceState) {
@@ -332,6 +378,7 @@
     /**
      * Restores the list of checked locales to preserve status when the list is recreated.
      * (for instance when the device is rotated)
+     *
      * @param savedInstanceState Bundle with the data saved by {@link #saveState(Bundle)}
      */
     public void restoreState(Bundle savedInstanceState) {
diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java
index 89efe53..bdb9295 100644
--- a/src/com/android/settings/localepicker/LocaleListEditor.java
+++ b/src/com/android/settings/localepicker/LocaleListEditor.java
@@ -105,7 +105,7 @@
 
         LocaleStore.fillCache(this.getContext());
         final List<LocaleStore.LocaleInfo> feedsList = getUserLocaleList();
-        mAdapter = new LocaleDragAndDropAdapter(this.getContext(), feedsList);
+        mAdapter = new LocaleDragAndDropAdapter(this, feedsList);
     }
 
     @Override
diff --git a/src/com/android/settings/localepicker/LocaleRecyclerView.java b/src/com/android/settings/localepicker/LocaleRecyclerView.java
index d32a735..5d469bf 100644
--- a/src/com/android/settings/localepicker/LocaleRecyclerView.java
+++ b/src/com/android/settings/localepicker/LocaleRecyclerView.java
@@ -40,7 +40,7 @@
         if (e.getAction() == MotionEvent.ACTION_UP || e.getAction() == MotionEvent.ACTION_CANCEL) {
             LocaleDragAndDropAdapter adapter = (LocaleDragAndDropAdapter) this.getAdapter();
             if (adapter != null) {
-                adapter.doTheUpdate();
+                adapter.doTheUpdateWithMovingLocaleItem();
             }
         }
         return super.onTouchEvent(e);
diff --git a/src/com/android/settings/network/EthernetTetherPreferenceController.java b/src/com/android/settings/network/EthernetTetherPreferenceController.java
index 17b4b02..2fd92f3 100644
--- a/src/com/android/settings/network/EthernetTetherPreferenceController.java
+++ b/src/com/android/settings/network/EthernetTetherPreferenceController.java
@@ -26,6 +26,7 @@
 import androidx.lifecycle.OnLifecycleEvent;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.Utils;
 import com.android.settingslib.utils.ThreadUtils;
 
 import java.util.HashSet;
@@ -50,7 +51,7 @@
     @OnLifecycleEvent(Lifecycle.Event.ON_START)
     public void onStart() {
         mEthernetListener = (iface, state, role, configuration) -> {
-            if (state == EthernetManager.STATE_LINK_UP) {
+            if (state != EthernetManager.STATE_ABSENT) {
                 mAvailableInterfaces.add(iface);
             } else {
                 mAvailableInterfaces.remove(iface);
@@ -87,7 +88,7 @@
 
     @Override
     public boolean shouldShow() {
-        return mEthernetManager != null;
+        return mEthernetManager != null && !Utils.isMonkeyRunning();
     }
 
     @Override
diff --git a/src/com/android/settings/network/MobileNetworkRepository.java b/src/com/android/settings/network/MobileNetworkRepository.java
index e483a4d..f07a3b7 100644
--- a/src/com/android/settings/network/MobileNetworkRepository.java
+++ b/src/com/android/settings/network/MobileNetworkRepository.java
@@ -179,7 +179,7 @@
     }
 
     private void addRegisterBySubId(int subId) {
-        if (!mTelephonyCallbackMap.containsKey(subId)) {
+        if (!mTelephonyCallbackMap.containsKey(subId) || !mTelephonyManagerMap.containsKey(subId)) {
             PhoneCallStateTelephonyCallback
                     telephonyCallback = new PhoneCallStateTelephonyCallback();
             mTelephonyManager.registerTelephonyCallback(mContext.getMainExecutor(),
@@ -435,8 +435,6 @@
             getUiccInfoBySubscriptionInfo(uiccSlotInfos, subInfo);
             SubscriptionInfo firstRemovableSubInfo = SubscriptionUtil.getFirstRemovableSubscription(
                     context);
-            SubscriptionInfo subscriptionOrDefault = SubscriptionUtil.getSubscriptionOrDefault(
-                    context, mSubId);
             if(DEBUG){
                 Log.d(TAG, "convert subscriptionInfo to entity for subId = " + mSubId);
             }
@@ -455,8 +453,7 @@
                     firstRemovableSubInfo == null ? false
                             : firstRemovableSubInfo.getSubscriptionId() == mSubId,
                     String.valueOf(SubscriptionUtil.getDefaultSimConfig(context, mSubId)),
-                    subscriptionOrDefault == null ? false
-                            : subscriptionOrDefault.getSubscriptionId() == mSubId,
+                    SubscriptionUtil.isDefaultSubscription(context, mSubId),
                     mSubscriptionManager.isValidSubscriptionId(mSubId),
                     mSubscriptionManager.isUsableSubscriptionId(mSubId),
                     mSubscriptionManager.isActiveSubscriptionId(mSubId),
@@ -540,11 +537,11 @@
                 SubscriptionUtil.getSelectableSubscriptionInfoList(mContext));
     }
 
-    private void insertAvailableSubInfoToEntity(List<SubscriptionInfo> availableInfoList) {
+    private void insertAvailableSubInfoToEntity(List<SubscriptionInfo> inputAvailableInfoList) {
         sExecutor.execute(() -> {
             SubscriptionInfoEntity[] availableInfoArray = mAvailableSubInfoEntityList.toArray(
                     new SubscriptionInfoEntity[0]);
-            if ((availableInfoList == null || availableInfoList.size() == 0)
+            if ((inputAvailableInfoList == null || inputAvailableInfoList.size() == 0)
                     && mAvailableSubInfoEntityList.size() != 0) {
                 if (DEBUG) {
                     Log.d(TAG, "availableSudInfoList from framework is empty, remove all subs");
@@ -554,11 +551,12 @@
                     deleteAllInfoBySubId(info.subId);
                 }
 
-            } else if (availableInfoList != null) {
-                SubscriptionInfo[] infoArray = availableInfoList.toArray(new SubscriptionInfo[0]);
+            } else if (inputAvailableInfoList != null) {
+                SubscriptionInfo[] inputAvailableInfoArray = inputAvailableInfoList.toArray(
+                        new SubscriptionInfo[0]);
                 // Remove the redundant subInfo
-                if (availableInfoList.size() <= mAvailableSubInfoEntityList.size()) {
-                    for (SubscriptionInfo subInfo : infoArray) {
+                if (inputAvailableInfoList.size() <= mAvailableSubInfoEntityList.size()) {
+                    for (SubscriptionInfo subInfo : inputAvailableInfoArray) {
                         int subId = subInfo.getSubscriptionId();
                         if (mSubscriptionInfoMap.containsKey(subId)) {
                             mSubscriptionInfoMap.remove(subId);
@@ -571,11 +569,20 @@
                                 deleteAllInfoBySubId(String.valueOf(key));
                             }
                         }
+                    } else if (inputAvailableInfoList.size() < mAvailableSubInfoEntityList.size()) {
+                        // Check the subInfo between the new list from framework and old list in
+                        // the database, if the subInfo is not existed in the new list, delete it
+                        // from the database.
+                        for (SubscriptionInfoEntity info : availableInfoArray) {
+                            if (sCacheSubscriptionInfoEntityMap.containsKey(info.subId)) {
+                                deleteAllInfoBySubId(info.subId);
+                            }
+                        }
                     }
                 }
 
                 // Insert all new available subInfo to database.
-                for (SubscriptionInfo subInfo : infoArray) {
+                for (SubscriptionInfo subInfo : inputAvailableInfoArray) {
                     if (DEBUG) {
                         Log.d(TAG, "insert subInfo to subInfoEntity, subInfo = " + subInfo);
                     }
diff --git a/src/com/android/settings/network/NetworkProviderCallsSmsController.java b/src/com/android/settings/network/NetworkProviderCallsSmsController.java
index 4ad0470..ced2b8a 100644
--- a/src/com/android/settings/network/NetworkProviderCallsSmsController.java
+++ b/src/com/android/settings/network/NetworkProviderCallsSmsController.java
@@ -101,7 +101,9 @@
             return setSummaryResId(R.string.calls_sms_no_sim);
         } else {
             final StringBuilder summary = new StringBuilder();
-            for (SubscriptionInfoEntity subInfo : list) {
+            SubscriptionInfoEntity[] entityArray = list.toArray(
+                    new SubscriptionInfoEntity[0]);
+            for (SubscriptionInfoEntity subInfo : entityArray) {
                 int subsSize = list.size();
                 int subId = Integer.parseInt(subInfo.subId);
                 final CharSequence displayName = subInfo.uniqueName;
@@ -125,7 +127,7 @@
                             .append(")");
                 }
                 // Do not add ", " for the last subscription.
-                if (!subInfo.equals(list.get(list.size() - 1))) {
+                if (list.size() > 0 && !subInfo.equals(list.get(list.size() - 1))) {
                     summary.append(", ");
                 }
 
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
index a562990..9c4ac03 100644
--- a/src/com/android/settings/network/SubscriptionUtil.java
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -50,6 +50,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.function.Function;
@@ -560,7 +561,8 @@
         if (TextUtils.isEmpty(rawPhoneNumber)) {
             return null;
         }
-        String countryIso = MccTable.countryCodeForMcc(subscriptionInfo.getMccString());
+        String countryIso = MccTable.countryCodeForMcc(subscriptionInfo.getMccString())
+                .toUpperCase(Locale.ROOT);
         return PhoneNumberUtils.formatNumber(rawPhoneNumber, countryIso);
     }
 
@@ -686,6 +688,12 @@
                         .findFirst().orElse(null);
     }
 
+    public static boolean isDefaultSubscription(Context context, int subId) {
+        SubscriptionAnnotation subInfo = getDefaultSubscriptionSelection(
+                new SelectableSubscriptions(context, true).call());
+        return subInfo != null && subInfo.getSubscriptionId() == subId;
+    }
+
     public static SubscriptionInfo getSubscriptionOrDefault(Context context, int subscriptionId) {
         return getSubscription(context, subscriptionId,
                 (subscriptionId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) ? null : (
diff --git a/src/com/android/settings/network/telephony/ConvertToEsimPreferenceController.java b/src/com/android/settings/network/telephony/ConvertToEsimPreferenceController.java
index 4f9e138..46ec61d 100644
--- a/src/com/android/settings/network/telephony/ConvertToEsimPreferenceController.java
+++ b/src/com/android/settings/network/telephony/ConvertToEsimPreferenceController.java
@@ -114,15 +114,12 @@
     @Override
     public void onActiveSubInfoChanged(List<SubscriptionInfoEntity> subInfoEntityList) {
         // TODO(b/262195754): Need the intent to enabled the feature.
-//        if (DataServiceUtils.shouldUpdateEntityList(mSubscriptionInfoEntityList,
-//                subInfoEntityList)) {
-//            mSubscriptionInfoEntityList = subInfoEntityList;
-//            mSubscriptionInfoEntityList.forEach(entity -> {
-//                if (Integer.parseInt(entity.subId) == mSubId) {
-//                    mSubscriptionInfoEntity = entity;
-//                    update();
-//                }
-//            });
-//        }
+//        mSubscriptionInfoEntityList = subInfoEntityList;
+//        mSubscriptionInfoEntityList.forEach(entity -> {
+//            if (Integer.parseInt(entity.subId) == mSubId) {
+//                mSubscriptionInfoEntity = entity;
+//                update();
+//            }
+//        });
     }
 }
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
index 1ff5e17..d5b2c2e 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@@ -23,6 +23,7 @@
 import android.os.Bundle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -150,7 +151,7 @@
                         MobileNetworkUtils.getSearchableSubscriptionId(context));
                 Log.d(LOG_TAG, "display subId from intent: " + mSubId);
             } else {
-                Log.d(LOG_TAG, "intent is null, can not get the subId from intent.");
+                Log.d(LOG_TAG, "intent is null, can not get subId " + mSubId + " from intent.");
             }
         } else {
             mSubId = getArguments().getInt(Settings.EXTRA_SUB_ID,
@@ -165,9 +166,7 @@
                     mMobileNetworkRepository.queryMobileNetworkInfoBySubId(
                             String.valueOf(mSubId));
         });
-        if (mSubId <= SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
-            return Arrays.asList();
-        }
+
         return Arrays.asList(
                 new DataUsageSummaryPreferenceController(getActivity(), getSettingsLifecycle(),
                         this, mSubId),
@@ -178,8 +177,6 @@
                 new SmsDefaultSubscriptionController(context, KEY_SMS_PREF, getSettingsLifecycle(),
                         this),
                 new MobileDataPreferenceController(context, KEY_MOBILE_DATA_PREF,
-                        getSettingsLifecycle(), this, mSubId),
-                new ConvertToEsimPreferenceController(context, KEY_CONVERT_TO_ESIM_PREF,
                         getSettingsLifecycle(), this, mSubId));
     }
 
@@ -188,8 +185,14 @@
         super.onAttach(context);
 
         if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
-            Log.d(LOG_TAG, "Invalid subId request " + mSubId);
-            return;
+            Log.d(LOG_TAG, "Invalid subId, get the default subscription to show.");
+            SubscriptionInfo info = SubscriptionUtil.getSubscriptionOrDefault(context, mSubId);
+            if (info == null) {
+                Log.d(LOG_TAG, "Invalid subId request " + mSubId);
+                return;
+            }
+            mSubId = info.getSubscriptionId();
+            Log.d(LOG_TAG, "Show NetworkSettings fragment for subId" + mSubId);
         }
 
         Intent intent = getIntent();
@@ -291,7 +294,11 @@
         use(ContactDiscoveryPreferenceController.class).init(getParentFragmentManager(), mSubId);
         use(NrAdvancedCallingPreferenceController.class).init(mSubId);
         use(TransferEsimPreferenceController.class).init(mSubId, mSubscriptionInfoEntity);
-        use(ConvertToEsimPreferenceController.class).init(mSubId, mSubscriptionInfoEntity);
+        final ConvertToEsimPreferenceController convertToEsimPreferenceController =
+                use(ConvertToEsimPreferenceController.class);
+        if (convertToEsimPreferenceController != null) {
+            convertToEsimPreferenceController.init(mSubId, mSubscriptionInfoEntity);
+        }
     }
 
     @Override
@@ -321,7 +328,6 @@
     }
 
     private void onSubscriptionDetailChanged() {
-
         if (mSubscriptionInfoEntity != null) {
             /**
              * Update the title when SIM stats got changed
@@ -451,7 +457,7 @@
         ContactDiscoveryDialogFragment fragment = getContactDiscoveryFragment(mSubId);
 
         if (mSubscriptionInfoEntity == null) {
-            Log.d(LOG_TAG, "Zoey, showContactDiscoveryDialog, Invalid subId request " + mSubId);
+            Log.d(LOG_TAG, "showContactDiscoveryDialog, Invalid subId request " + mSubId);
             onDestroy();
             return;
         }
@@ -488,13 +494,20 @@
         }
 
         mSubInfoEntityList = subInfoEntityList;
-        mSubInfoEntityList.forEach(entity -> {
+        SubscriptionInfoEntity[] entityArray = mSubInfoEntityList.toArray(
+                new SubscriptionInfoEntity[0]);
+        for (SubscriptionInfoEntity entity : entityArray) {
             int subId = Integer.parseInt(entity.subId);
             mSubscriptionInfoMap.put(subId, entity);
-            if (subId == mSubId) {
+            if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID && subId == mSubId) {
                 mSubscriptionInfoEntity = entity;
-                onSubscriptionDetailChanged();
+                Log.d(LOG_TAG, "Set subInfo for subId " + mSubId);
+                break;
+            } else if (entity.isDefaultSubscriptionSelection) {
+                mSubscriptionInfoEntity = entity;
+                Log.d(LOG_TAG, "Set subInfo to the default subInfo.");
             }
-        });
+        }
+        onSubscriptionDetailChanged();
     }
 }
diff --git a/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceController.java b/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceController.java
index 92cd911..40bae5d 100644
--- a/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceController.java
+++ b/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceController.java
@@ -27,6 +27,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 
+import androidx.annotation.VisibleForTesting;
 import androidx.core.text.BidiFormatter;
 import androidx.lifecycle.LifecycleObserver;
 import androidx.preference.Preference;
@@ -54,7 +55,7 @@
 public class AppChannelsBypassingDndPreferenceController extends NotificationPreferenceController
         implements PreferenceControllerMixin, LifecycleObserver {
 
-    private static final String KEY = "zen_mode_bypassing_app_channels_list";
+    @VisibleForTesting static final String KEY = "zen_mode_bypassing_app_channels_list";
     private static final String ARG_FROM_SETTINGS = "fromSettings";
 
     private RestrictedSwitchPreference mAllNotificationsToggle;
@@ -74,8 +75,8 @@
         mAllNotificationsToggle = new RestrictedSwitchPreference(mPreferenceCategory.getContext());
         mAllNotificationsToggle.setTitle(R.string.zen_mode_bypassing_app_channels_toggle_all);
         mAllNotificationsToggle.setDisabledByAdmin(mAdmin);
-        mAllNotificationsToggle.setEnabled(
-                (mAdmin == null || !mAllNotificationsToggle.isDisabledByAdmin()));
+        mAllNotificationsToggle.setEnabled(!mAppRow.banned
+                && (mAdmin == null || !mAllNotificationsToggle.isDisabledByAdmin()));
         mAllNotificationsToggle.setOnPreferenceClickListener(
                 new Preference.OnPreferenceClickListener() {
                     @Override
@@ -206,6 +207,9 @@
     }
 
     private boolean areAllChannelsBypassing() {
+        if (mAppRow.banned) {
+            return false;
+        }
         boolean allChannelsBypassing = true;
         for (NotificationChannel channel : mChannels) {
             if (showNotification(channel)) {
@@ -226,7 +230,7 @@
      * Whether notifications from this channel would show if DND weren't on.
      */
     private boolean showNotification(NotificationChannel channel) {
-        return channel.getImportance() != IMPORTANCE_NONE;
+        return !mAppRow.banned && channel.getImportance() != IMPORTANCE_NONE;
     }
 
     /**
diff --git a/src/com/android/settings/notification/zen/ZenModeRuleSettingsBase.java b/src/com/android/settings/notification/zen/ZenModeRuleSettingsBase.java
index 5297801..cda5b1a 100644
--- a/src/com/android/settings/notification/zen/ZenModeRuleSettingsBase.java
+++ b/src/com/android/settings/notification/zen/ZenModeRuleSettingsBase.java
@@ -48,6 +48,7 @@
     protected boolean mDisableListeners;
     protected AutomaticZenRule mRule;
     protected String mId;
+    private boolean mRuleRemoved;
 
     protected ZenAutomaticRuleHeaderPreferenceController mHeader;
     protected ZenRuleButtonsPreferenceController mActionButtons;
@@ -162,6 +163,10 @@
     }
 
     private boolean refreshRuleOrFinish() {
+        if (mRuleRemoved && getActivity() != null) {
+            getActivity().finish();
+            return true;
+        }
         mRule = getZenRule();
         if (DEBUG) Log.d(TAG, "mRule=" + mRule);
         mHeader.setRule(mRule);
@@ -196,4 +201,8 @@
         }
         mDisableListeners = false;
     }
+
+    void onRuleRemoved() {
+        mRuleRemoved = true;
+    }
 }
diff --git a/src/com/android/settings/notification/zen/ZenRuleButtonsPreferenceController.java b/src/com/android/settings/notification/zen/ZenRuleButtonsPreferenceController.java
index 023a770..082b2a5 100644
--- a/src/com/android/settings/notification/zen/ZenRuleButtonsPreferenceController.java
+++ b/src/com/android/settings/notification/zen/ZenRuleButtonsPreferenceController.java
@@ -39,11 +39,11 @@
     implements PreferenceControllerMixin {
     public static final String KEY = "zen_action_buttons";
 
-    private final PreferenceFragmentCompat mFragment;
+    private final ZenModeRuleSettingsBase mFragment;
     private String mId;
     private AutomaticZenRule mRule;
 
-    public ZenRuleButtonsPreferenceController(Context context, PreferenceFragmentCompat fragment,
+    public ZenRuleButtonsPreferenceController(Context context, ZenModeRuleSettingsBase fragment,
             Lifecycle lc) {
         super(context, KEY, lc);
         mFragment = fragment;
@@ -106,12 +106,7 @@
                             mBackend.removeZenRule(id);
                             mMetricsFeatureProvider.action(mContext,
                                     SettingsEnums.ACTION_ZEN_DELETE_RULE_OK);
-                            new SubSettingLauncher(mContext)
-                                    .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
-                                    .setDestination(ZenModeAutomationSettings.class.getName())
-                                    .setSourceMetricsCategory(MetricsProto.MetricsEvent
-                                            .NOTIFICATION_ZEN_MODE_AUTOMATION)
-                                    .launch();
+                            mFragment.onRuleRemoved();
                         }
             });
         }
diff --git a/src/com/android/settings/password/ChooseLockSettingsHelper.java b/src/com/android/settings/password/ChooseLockSettingsHelper.java
index a1cd09f..020b725 100644
--- a/src/com/android/settings/password/ChooseLockSettingsHelper.java
+++ b/src/com/android/settings/password/ChooseLockSettingsHelper.java
@@ -22,7 +22,7 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.KeyguardManager;
-import android.app.StartLockscreenValidationRequest;
+import android.app.RemoteLockscreenValidationSession;
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -145,7 +145,7 @@
         private boolean mAllowAnyUserId;
         private boolean mForceVerifyPath;
         private boolean mRemoteLockscreenValidation;
-        @Nullable private StartLockscreenValidationRequest mStartLockscreenValidationRequest;
+        @Nullable private RemoteLockscreenValidationSession mRemoteLockscreenValidationSession;
         @Nullable private ComponentName mRemoteLockscreenValidationServiceComponent;
         boolean mRequestGatekeeperPasswordHandle;
 
@@ -272,7 +272,7 @@
 
         /**
          * @param isRemoteLockscreenValidation if true, remote device validation flow will be
-         *                                 started. {@link #setStartLockscreenValidationRequest} and
+         *                                 started. {@link #setRemoteLockscreenValidationSession},
          *                                 {@link #setRemoteLockscreenValidationServiceComponent}
          *                                 must also be used to set the required data.
          */
@@ -283,14 +283,14 @@
         }
 
         /**
-         * @param startLockScreenValidationRequest contains information necessary to perform remote
+         * @param remoteLockscreenValidationSession contains information necessary to perform remote
          *                                         lockscreen validation such as the remote device's
          *                                         lockscreen type, public key to be used for
          *                                         encryption, and remaining attempts.
          */
-        @NonNull public Builder setStartLockscreenValidationRequest(
-                StartLockscreenValidationRequest startLockScreenValidationRequest) {
-            mStartLockscreenValidationRequest = startLockScreenValidationRequest;
+        @NonNull public Builder setRemoteLockscreenValidationSession(
+                RemoteLockscreenValidationSession remoteLockscreenValidationSession) {
+            mRemoteLockscreenValidationSession = remoteLockscreenValidationSession;
             return this;
         }
 
@@ -369,7 +369,7 @@
                 mBuilder.mDescription, mBuilder.mReturnCredentials, mBuilder.mExternal,
                 mBuilder.mForceVerifyPath, mBuilder.mUserId, mBuilder.mAlternateButton,
                 mBuilder.mCheckBoxLabel, mBuilder.mRemoteLockscreenValidation,
-                mBuilder.mStartLockscreenValidationRequest,
+                mBuilder.mRemoteLockscreenValidationSession,
                 mBuilder.mRemoteLockscreenValidationServiceComponent, mBuilder.mAllowAnyUserId,
                 mBuilder.mForegroundOnly, mBuilder.mRequestGatekeeperPasswordHandle);
     }
@@ -379,18 +379,18 @@
             boolean returnCredentials, boolean external, boolean forceVerifyPath,
             int userId, @Nullable CharSequence alternateButton,
             @Nullable CharSequence checkboxLabel, boolean remoteLockscreenValidation,
-            @Nullable StartLockscreenValidationRequest startLockScreenValidationRequest,
+            @Nullable RemoteLockscreenValidationSession remoteLockscreenValidationSession,
             @Nullable ComponentName remoteLockscreenValidationServiceComponent,
             boolean allowAnyUser, boolean foregroundOnly, boolean requestGatekeeperPasswordHandle) {
         Optional<Class<?>> activityClass = determineAppropriateActivityClass(
-                returnCredentials, forceVerifyPath, userId, startLockScreenValidationRequest);
+                returnCredentials, forceVerifyPath, userId, remoteLockscreenValidationSession);
         if (activityClass.isEmpty()) {
             return false;
         }
 
         return launchConfirmationActivity(request, title, header, description, activityClass.get(),
                 returnCredentials, external, forceVerifyPath, userId, alternateButton,
-                checkboxLabel, remoteLockscreenValidation, startLockScreenValidationRequest,
+                checkboxLabel, remoteLockscreenValidation, remoteLockscreenValidationSession,
                 remoteLockscreenValidationServiceComponent, allowAnyUser, foregroundOnly,
                 requestGatekeeperPasswordHandle);
     }
@@ -400,7 +400,7 @@
             boolean external, boolean forceVerifyPath, int userId,
             @Nullable CharSequence alternateButton, @Nullable CharSequence checkbox,
             boolean remoteLockscreenValidation,
-            @Nullable StartLockscreenValidationRequest startLockScreenValidationRequest,
+            @Nullable RemoteLockscreenValidationSession remoteLockscreenValidationSession,
             @Nullable ComponentName remoteLockscreenValidationServiceComponent,
             boolean allowAnyUser, boolean foregroundOnly, boolean requestGatekeeperPasswordHandle) {
         final Intent intent = new Intent();
@@ -419,8 +419,8 @@
         intent.putExtra(Intent.EXTRA_USER_ID, userId);
         intent.putExtra(KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL, alternateButton);
         intent.putExtra(KeyguardManager.EXTRA_CHECKBOX_LABEL, checkbox);
-        intent.putExtra(KeyguardManager.EXTRA_START_LOCKSCREEN_VALIDATION_REQUEST,
-                startLockScreenValidationRequest);
+        intent.putExtra(KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
+                remoteLockscreenValidationSession);
         intent.putExtra(Intent.EXTRA_COMPONENT_NAME, remoteLockscreenValidationServiceComponent);
         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOREGROUND_ONLY, foregroundOnly);
         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_ALLOW_ANY_USER, allowAnyUser);
@@ -477,10 +477,10 @@
 
     private Optional<Class<?>> determineAppropriateActivityClass(boolean returnCredentials,
             boolean forceVerifyPath, int userId,
-            @Nullable StartLockscreenValidationRequest startLockscreenValidationRequest) {
+            @Nullable RemoteLockscreenValidationSession remoteLockscreenValidationSession) {
         int lockType;
-        if (startLockscreenValidationRequest != null) {
-            lockType = startLockscreenValidationRequest.getLockscreenUiType();
+        if (remoteLockscreenValidationSession != null) {
+            lockType = remoteLockscreenValidationSession.getLockType();
         } else {
             final int effectiveUserId = UserManager
                     .get(mActivity).getCredentialOwnerProfile(userId);
diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
index 31d9c74..328e440 100644
--- a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
+++ b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
@@ -28,7 +28,7 @@
 
 import android.app.Activity;
 import android.app.KeyguardManager;
-import android.app.StartLockscreenValidationRequest;
+import android.app.RemoteLockscreenValidationSession;
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.TrustManager;
 import android.content.ComponentName;
@@ -235,10 +235,10 @@
                     .setUserId(LockPatternUtils.USER_FRP)
                     .show();
         } else if (remoteValidation) {
-            StartLockscreenValidationRequest startLockScreenValidationRequest =
+            RemoteLockscreenValidationSession remoteLockscreenValidationSession =
                     intent.getParcelableExtra(
-                            KeyguardManager.EXTRA_START_LOCKSCREEN_VALIDATION_REQUEST,
-                            StartLockscreenValidationRequest.class);
+                            KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
+                            RemoteLockscreenValidationSession.class);
             ComponentName remoteLockscreenValidationServiceComponent =
                     intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME, ComponentName.class);
 
@@ -247,7 +247,7 @@
                     new ChooseLockSettingsHelper.Builder(this);
             launchedCDC = builder
                     .setRemoteLockscreenValidation(true)
-                    .setStartLockscreenValidationRequest(startLockScreenValidationRequest)
+                    .setRemoteLockscreenValidationSession(remoteLockscreenValidationSession)
                     .setRemoteLockscreenValidationServiceComponent(
                             remoteLockscreenValidationServiceComponent)
                     .setHeader(mTitle) // Show the title in the header location
diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java
index 7c3df61..1bb6df0 100644
--- a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java
+++ b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java
@@ -25,7 +25,7 @@
 import android.app.Dialog;
 import android.app.KeyguardManager;
 import android.app.RemoteLockscreenValidationResult;
-import android.app.StartLockscreenValidationRequest;
+import android.app.RemoteLockscreenValidationSession;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.ManagedSubscriptionsPolicy;
 import android.content.ComponentName;
@@ -107,7 +107,7 @@
     protected boolean mRemoteValidation;
     protected CharSequence mAlternateButtonText;
     protected BiometricManager mBiometricManager;
-    @Nullable protected StartLockscreenValidationRequest mStartLockscreenValidationRequest;
+    @Nullable protected RemoteLockscreenValidationSession mRemoteLockscreenValidationSession;
     /** Credential saved so the credential can be set for device if remote validation passes */
     @Nullable protected LockscreenCredential mDeviceCredentialGuess;
     @Nullable protected RemoteLockscreenValidationClient mRemoteLockscreenValidationClient;
@@ -141,12 +141,12 @@
             }
         }
         if (mRemoteValidation) {
-            mStartLockscreenValidationRequest = intent.getParcelableExtra(
-                    KeyguardManager.EXTRA_START_LOCKSCREEN_VALIDATION_REQUEST,
-                    StartLockscreenValidationRequest.class);
-            if (mStartLockscreenValidationRequest == null
-                    || mStartLockscreenValidationRequest.getRemainingAttempts() == 0) {
-                Log.e(TAG, "StartLockscreenValidationRequest is null or "
+            mRemoteLockscreenValidationSession = intent.getParcelableExtra(
+                    KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
+                    RemoteLockscreenValidationSession.class);
+            if (mRemoteLockscreenValidationSession == null
+                    || mRemoteLockscreenValidationSession.getRemainingAttempts() == 0) {
+                Log.e(TAG, "RemoteLockscreenValidationSession is null or "
                         + "no more attempts for remote lockscreen validation.");
                 getActivity().finish();
             }
@@ -437,7 +437,7 @@
 
     private byte[] encryptDeviceCredentialGuess(byte[] guess) {
         try {
-            byte[] encodedPublicKey = mStartLockscreenValidationRequest.getSourcePublicKey();
+            byte[] encodedPublicKey = mRemoteLockscreenValidationSession.getSourcePublicKey();
             PublicKey publicKey = SecureBox.decodePublicKey(encodedPublicKey);
             return SecureBox.encrypt(
                     publicKey,
diff --git a/src/com/android/settings/password/ConfirmLockPassword.java b/src/com/android/settings/password/ConfirmLockPassword.java
index 83dc85c..427b4ff 100644
--- a/src/com/android/settings/password/ConfirmLockPassword.java
+++ b/src/com/android/settings/password/ConfirmLockPassword.java
@@ -166,7 +166,7 @@
             mErrorTextView = (TextView) view.findViewById(R.id.errorText);
 
             if (mRemoteValidation) {
-                mIsAlpha = mStartLockscreenValidationRequest.getLockscreenUiType()
+                mIsAlpha = mRemoteLockscreenValidationSession.getLockType()
                         == KeyguardManager.PASSWORD;
                 // ProgressBar visibility is set to GONE until interacted with.
                 // Set progress bar to INVISIBLE, so the EditText does not get bumped down later.
@@ -633,6 +633,9 @@
                     break;
                 case RemoteLockscreenValidationResult.RESULT_NO_REMAINING_ATTEMPTS:
                     getActivity().finish();
+                    break;
+                case RemoteLockscreenValidationResult.RESULT_SESSION_EXPIRED:
+                    getActivity().finish();
             }
             mGlifLayout.setProgressBarShown(false);
         }
diff --git a/src/com/android/settings/password/ConfirmLockPattern.java b/src/com/android/settings/password/ConfirmLockPattern.java
index 0013d7a..c664daf 100644
--- a/src/com/android/settings/password/ConfirmLockPattern.java
+++ b/src/com/android/settings/password/ConfirmLockPattern.java
@@ -646,6 +646,9 @@
                     break;
                 case RemoteLockscreenValidationResult.RESULT_NO_REMAINING_ATTEMPTS:
                     getActivity().finish();
+                    break;
+                case RemoteLockscreenValidationResult.RESULT_SESSION_EXPIRED:
+                    getActivity().finish();
             }
             mGlifLayout.setProgressBarShown(false);
         }
diff --git a/src/com/android/settings/search/SearchFeatureProvider.java b/src/com/android/settings/search/SearchFeatureProvider.java
index b14a4d7..cd096ec 100644
--- a/src/com/android/settings/search/SearchFeatureProvider.java
+++ b/src/com/android/settings/search/SearchFeatureProvider.java
@@ -126,16 +126,24 @@
                 true /* finishSecondaryWithPrimary */,
                 false /* clearTop */);
 
-        toolbar.setOnClickListener(tb -> {
-            FeatureFactory.getFactory(context).getSlicesFeatureProvider()
-                    .indexSliceDataAsync(context);
+        toolbar.setOnClickListener(tb -> startSearchActivity(context, activity, pageId, intent));
 
-            FeatureFactory.getFactory(context).getMetricsFeatureProvider()
-                    .logSettingsTileClick(KEY_HOMEPAGE_SEARCH_BAR, pageId);
+        toolbar.setHandwritingDelegatorCallback(
+                () -> startSearchActivity(context, activity, pageId, intent));
+        toolbar.setAllowedHandwritingDelegatePackage(intent.getPackage());
+    }
 
-            final Bundle bundle = ActivityOptions.makeSceneTransitionAnimation(activity).toBundle();
-            activity.startActivity(intent, bundle);
-        });
+    /** Start the search activity. */
+    private static void startSearchActivity(
+            Context context, FragmentActivity activity, int pageId, Intent intent) {
+        FeatureFactory.getFactory(context).getSlicesFeatureProvider()
+                .indexSliceDataAsync(context);
+
+        FeatureFactory.getFactory(context).getMetricsFeatureProvider()
+                .logSettingsTileClick(KEY_HOMEPAGE_SEARCH_BAR, pageId);
+
+        final Bundle bundle = ActivityOptions.makeSceneTransitionAnimation(activity).toBundle();
+        activity.startActivity(intent, bundle);
     }
 
     Intent buildSearchIntent(Context context, int pageId);
diff --git a/src/com/android/settings/spa/SettingsSpaEnvironment.kt b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
index 87a916a..c2716b6 100644
--- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt
+++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
@@ -32,6 +32,7 @@
 import com.android.settings.spa.app.specialaccess.SpecialAppAccessPageProvider
 import com.android.settings.spa.app.specialaccess.WifiControlAppListProvider
 import com.android.settings.spa.app.specialaccess.UseFullScreenIntentAppListProvider
+import com.android.settings.spa.core.instrumentation.SpaLogProvider
 import com.android.settings.spa.development.UsageStatsPageProvider
 import com.android.settings.spa.home.HomePageProvider
 import com.android.settings.spa.network.NetworkAndInternetPageProvider
@@ -87,4 +88,5 @@
             ),
         )
     }
+    override val logger = SpaLogProvider
 }
diff --git a/src/com/android/settings/spa/SpaActivity.kt b/src/com/android/settings/spa/SpaActivity.kt
index 55883c1..27f7241 100644
--- a/src/com/android/settings/spa/SpaActivity.kt
+++ b/src/com/android/settings/spa/SpaActivity.kt
@@ -16,18 +16,29 @@
 
 package com.android.settings.spa
 
+import android.app.ActivityManager
 import android.content.Context
 import android.content.Intent
+import android.os.RemoteException
 import android.os.UserHandle
+import android.util.Log
 import com.android.settingslib.spa.framework.BrowseActivity
+import com.android.settingslib.spa.framework.util.SESSION_BROWSE
+import com.android.settingslib.spa.framework.util.SESSION_EXTERNAL
 import com.android.settingslib.spa.framework.util.appendSpaParams
 
 class SpaActivity : BrowseActivity() {
     companion object {
+        private const val TAG = "SpaActivity"
         @JvmStatic
         fun Context.startSpaActivity(destination: String) {
             val intent = Intent(this, SpaActivity::class.java)
                 .appendSpaParams(destination = destination)
+            if (isLaunchedFromInternal()) {
+                intent.appendSpaParams(sessionName = SESSION_BROWSE)
+            } else {
+                intent.appendSpaParams(sessionName = SESSION_EXTERNAL)
+            }
             startActivity(intent)
         }
 
@@ -37,5 +48,15 @@
             startSpaActivity("$destinationPrefix/$packageName/${UserHandle.myUserId()}")
             return true
         }
+
+        fun Context.isLaunchedFromInternal(): Boolean {
+            var pkg: String? = null
+            try {
+                pkg = ActivityManager.getService().getLaunchedFromPackage(getActivityToken())
+            } catch (e: RemoteException) {
+                Log.v(TAG, "Could not talk to activity manager.", e)
+            }
+            return applicationContext.packageName == pkg
+        }
     }
 }
diff --git a/src/com/android/settings/spa/app/appinfo/AppCreateButton.kt b/src/com/android/settings/spa/app/appinfo/AppCreateButton.kt
index 1414626..088680d 100644
--- a/src/com/android/settings/spa/app/appinfo/AppCreateButton.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppCreateButton.kt
@@ -32,6 +32,7 @@
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
+import android.widget.Toast;
 
 class AppCreateButton(packageInfoPresenter: PackageInfoPresenter) {
     private val context = packageInfoPresenter.context
@@ -55,10 +56,16 @@
             val cloneBackend = CloneBackend.getInstance(context)
             FeatureFactory.getFactory(context).metricsFeatureProvider.action(context,
                     SettingsEnums.ACTION_CREATE_CLONE_APP)
+            val appLabel = app.loadLabel(context.packageManager)
+            Toast.makeText(context, context.getString(R.string.cloned_app_creation_toast_summary,
+                appLabel),Toast.LENGTH_SHORT).show()
             coroutineScope.launch {
                 enabledState.value = false
                 val result = installCloneApp(app, cloneBackend)
                 if (result == CloneBackend.SUCCESS) {
+                    Toast.makeText(context,
+                        context.getString(R.string.cloned_app_created_toast_summary, appLabel),
+                            Toast.LENGTH_SHORT).show()
                     navController.navigate(getRoute(app.packageName, cloneBackend.cloneUserId),
                             /* popUpCurrent*/ true)
                 } else {
diff --git a/src/com/android/settings/spa/core/instrumentation/MetricsDataModel.kt b/src/com/android/settings/spa/core/instrumentation/MetricsDataModel.kt
new file mode 100644
index 0000000..62aa8df
--- /dev/null
+++ b/src/com/android/settings/spa/core/instrumentation/MetricsDataModel.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 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.spa.core.instrumentation
+
+import androidx.annotation.VisibleForTesting
+
+/**
+ * This class stores some metrics temporary data. Such as the timestamp of the page enter for
+ * calculating the duration time on page.
+ */
+class MetricsDataModel {
+    @VisibleForTesting
+    val pageTimeStampList = mutableListOf<PageTimeStamp>()
+
+    fun addTimeStamp(dataItem: PageTimeStamp){
+        pageTimeStampList.add(dataItem)
+    }
+
+    fun getPageDuration(pageId: String, removed: Boolean = true): String {
+        val lastItem = pageTimeStampList.findLast { it.pageId == pageId }
+        if (removed && lastItem != null) {
+            pageTimeStampList.remove(lastItem)
+        }
+        return if (lastItem == null) "0"
+            else (System.currentTimeMillis() - lastItem.timeStamp).toString()
+    }
+}
diff --git a/src/com/android/settings/spa/core/instrumentation/SpaLogProvider.kt b/src/com/android/settings/spa/core/instrumentation/SpaLogProvider.kt
new file mode 100644
index 0000000..9b3e2d6
--- /dev/null
+++ b/src/com/android/settings/spa/core/instrumentation/SpaLogProvider.kt
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2023 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.spa.core.instrumentation
+
+import android.app.settings.SettingsEnums
+import android.os.Bundle
+import androidx.annotation.VisibleForTesting
+import com.android.settings.core.instrumentation.ElapsedTimeUtils
+import com.android.settings.core.instrumentation.SettingsStatsLog
+import com.android.settingslib.spa.framework.common.LOG_DATA_SESSION_NAME
+import com.android.settingslib.spa.framework.common.LogCategory
+import com.android.settingslib.spa.framework.common.LogEvent
+import com.android.settingslib.spa.framework.common.SpaLogger
+import com.android.settingslib.spa.framework.util.SESSION_BROWSE
+import com.android.settingslib.spa.framework.util.SESSION_EXTERNAL
+import com.android.settingslib.spa.framework.util.SESSION_SEARCH
+import com.android.settingslib.spa.framework.util.SESSION_SLICE
+import com.android.settingslib.spa.framework.util.SESSION_UNKNOWN
+
+/**
+ * To receive the events from spa framework and logging the these events.
+ */
+object SpaLogProvider : SpaLogger {
+    private val dataModel = MetricsDataModel()
+
+    override fun event(id: String, event: LogEvent, category: LogCategory, extraData: Bundle) {
+        when(event) {
+            LogEvent.PAGE_ENTER, LogEvent.PAGE_LEAVE ->
+                write(SpaLogData(id, event, extraData, dataModel))
+            else -> return  //TODO(b/253979024): Will be implemented in subsequent CLs.
+        }
+    }
+
+    private fun write(data: SpaLogData) {
+        with(data) {
+            SettingsStatsLog.write(
+                SettingsStatsLog.SETTINGS_SPA_REPORTED /* atomName */,
+                getSessionType(),
+                getPageId(),
+                getTarget(),
+                getAction(),
+                getKey(),
+                getValue(),
+                getPreValue(),
+                getElapsedTime()
+            )
+        }
+    }
+}
+
+@VisibleForTesting
+class SpaLogData(val id: String, val event: LogEvent,
+                         val extraData: Bundle, val dataModel: MetricsDataModel) {
+
+    fun getSessionType(): Int {
+        if (!extraData.containsKey(LOG_DATA_SESSION_NAME)) {
+            return SettingsEnums.SESSION_UNKNOWN
+        }
+        val sessionSource = extraData.getString(LOG_DATA_SESSION_NAME)
+        return when(sessionSource) {
+            SESSION_BROWSE -> SettingsEnums.BROWSE
+            SESSION_SEARCH -> SettingsEnums.SEARCH
+            SESSION_SLICE -> SettingsEnums.SLICE_TYPE
+            SESSION_EXTERNAL -> SettingsEnums.EXTERNAL
+            else -> SettingsEnums.SESSION_UNKNOWN
+        }
+    }
+
+    fun getPageId(): String {
+        return when(event) {
+            LogEvent.PAGE_ENTER, LogEvent.PAGE_LEAVE -> id
+            else -> getPageIdByEntryId(id)
+        }
+    }
+
+    //TODO(b/253979024): Will be implemented in subsequent CLs.
+    fun getTarget(): String? {
+        return null
+    }
+
+    fun getAction(): Int {
+        return event.action
+    }
+
+    //TODO(b/253979024): Will be implemented in subsequent CLs.
+    fun getKey(): String? {
+        return null
+    }
+
+    fun getValue(): String? {
+        when(event) {
+            LogEvent.PAGE_ENTER -> dataModel.addTimeStamp(
+                PageTimeStamp(id, System.currentTimeMillis()))
+            LogEvent.PAGE_LEAVE -> return dataModel.getPageDuration(id)
+            else -> {} //TODO(b/253979024): Will be implemented in subsequent CLs.
+        }
+        return null
+    }
+
+    //TODO(b/253979024): Will be implemented in subsequent CLs.
+    fun getPreValue(): String? {
+        return null
+    }
+
+    fun getElapsedTime(): Long {
+        return ElapsedTimeUtils.getElapsedTime(System.currentTimeMillis())
+    }
+
+    //TODO(b/253979024): Will be implemented in subsequent CLs.
+    private fun getPageIdByEntryId(id: String): String {
+        return ""
+    }
+}
+
+/**
+ * The buffer is keeping the time stamp while spa page entering.
+ */
+data class PageTimeStamp(val pageId: String, val timeStamp: Long)
diff --git a/src/com/android/settings/wifi/factory/WifiFeatureProvider.java b/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
index 2f5f3ea..433ff0c 100644
--- a/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
+++ b/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
@@ -20,8 +20,13 @@
 import android.net.wifi.WifiManager;
 
 import androidx.annotation.NonNull;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.lifecycle.ViewModelStoreOwner;
 
 import com.android.settings.wifi.repository.WifiHotspotRepository;
+import com.android.settings.wifi.tether.WifiTetherViewModel;
+
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Wi-Fi Feature Provider
@@ -55,5 +60,13 @@
         }
         return mWifiHotspotRepository;
     }
+
+    /**
+     * Get WifiTetherViewModel
+     */
+    public WifiTetherViewModel getWifiTetherViewModel(@NotNull ViewModelStoreOwner owner) {
+        return new ViewModelProvider(owner).get(WifiTetherViewModel.class);
+    }
+
 }
 
diff --git a/src/com/android/settings/wifi/repository/WifiHotspotRepository.java b/src/com/android/settings/wifi/repository/WifiHotspotRepository.java
index b8a25dc..ee1ceea 100644
--- a/src/com/android/settings/wifi/repository/WifiHotspotRepository.java
+++ b/src/com/android/settings/wifi/repository/WifiHotspotRepository.java
@@ -16,13 +16,27 @@
 
 package com.android.settings.wifi.repository;
 
+import static android.net.wifi.SoftApConfiguration.BAND_2GHZ;
+import static android.net.wifi.SoftApConfiguration.BAND_5GHZ;
+import static android.net.wifi.SoftApConfiguration.BAND_6GHZ;
+import static android.net.wifi.WifiAvailableChannel.OP_MODE_SAP;
+
 import android.content.Context;
 import android.net.wifi.SoftApConfiguration;
+import android.net.wifi.WifiAvailableChannel;
 import android.net.wifi.WifiManager;
+import android.net.wifi.WifiScanner;
 import android.text.TextUtils;
+import android.util.Log;
 
 import androidx.annotation.NonNull;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.Transformations;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.UUID;
 import java.util.function.Consumer;
 
@@ -30,6 +44,36 @@
  * Wi-Fi Hotspot Repository
  */
 public class WifiHotspotRepository {
+    private static final String TAG = "WifiHotspotRepository";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    /** Wi-Fi hotspot band unknown. */
+    public static final int BAND_UNKNOWN = 0;
+    /** Wi-Fi hotspot band 2.4GHz and 5GHz. */
+    public static final int BAND_2GHZ_5GHZ = BAND_2GHZ | BAND_5GHZ;
+    /** Wi-Fi hotspot band 2.4GHz and 5GHz and 6GHz. */
+    public static final int BAND_2GHZ_5GHZ_6GHZ = BAND_2GHZ | BAND_5GHZ | BAND_6GHZ;
+
+    /** Wi-Fi hotspot speed unknown. */
+    public static final int SPEED_UNKNOWN = 0;
+    /** Wi-Fi hotspot speed 2.4GHz. */
+    public static final int SPEED_2GHZ = 1;
+    /** Wi-Fi hotspot speed 5GHz. */
+    public static final int SPEED_5GHZ = 2;
+    /** Wi-Fi hotspot speed 2.4GHz and 5GHz. */
+    public static final int SPEED_2GHZ_5GHZ = 3;
+    /** Wi-Fi hotspot speed 6GHz. */
+    public static final int SPEED_6GHZ = 4;
+
+    protected static Map<Integer, Integer> sSpeedMap = new HashMap<>();
+
+    static {
+        sSpeedMap.put(BAND_UNKNOWN, SPEED_UNKNOWN);
+        sSpeedMap.put(BAND_2GHZ, SPEED_2GHZ);
+        sSpeedMap.put(BAND_5GHZ, SPEED_5GHZ);
+        sSpeedMap.put(BAND_6GHZ, SPEED_6GHZ);
+        sSpeedMap.put(BAND_2GHZ_5GHZ, SPEED_2GHZ_5GHZ);
+    }
 
     protected final Context mAppContext;
     protected final WifiManager mWifiManager;
@@ -37,6 +81,14 @@
     protected String mLastPassword;
     protected LastPasswordListener mLastPasswordListener = new LastPasswordListener();
 
+    protected MutableLiveData<Integer> mSpeedType;
+
+    protected Boolean mIsDualBand;
+    protected Boolean mIs5gAvailable;
+    protected Boolean mIs6gAvailable;
+    protected String mCurrentCountryCode;
+    protected ActiveCountryCodeChangedCallback mActiveCountryCodeChangedCallback;
+
     public WifiHotspotRepository(@NonNull Context appContext, @NonNull WifiManager wifiManager) {
         mAppContext = appContext;
         mWifiManager = wifiManager;
@@ -73,4 +125,167 @@
         //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
         return randomUUID.substring(0, 8) + randomUUID.substring(9, 13);
     }
+
+    /**
+     * Sets the tethered Wi-Fi AP Configuration.
+     *
+     * @param config A valid SoftApConfiguration specifying the configuration of the SAP.
+     */
+    public void setSoftApConfiguration(@NonNull SoftApConfiguration config) {
+        mWifiManager.setSoftApConfiguration(config);
+        refresh();
+    }
+
+    /**
+     * Refresh data from the SoftApConfiguration.
+     */
+    public void refresh() {
+        updateSpeedType();
+    }
+
+    /**
+     * Set to auto refresh data.
+     *
+     * @param enabled whether the auto refresh should be enabled or not.
+     */
+    public void setAutoRefresh(boolean enabled) {
+        if (enabled) {
+            startAutoRefresh();
+        } else {
+            stopAutoRefresh();
+        }
+    }
+
+    /**
+     * Gets SpeedType LiveData
+     */
+    public LiveData<Integer> getSpeedType() {
+        if (mSpeedType == null) {
+            mSpeedType = new MutableLiveData<>();
+            updateSpeedType();
+        }
+        return Transformations.distinctUntilChanged(mSpeedType);
+    }
+
+    protected void updateSpeedType() {
+        if (mSpeedType == null) {
+            return;
+        }
+        SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
+        if (config == null) {
+            mSpeedType.setValue(SPEED_UNKNOWN);
+            return;
+        }
+        int keyBand = config.getBand();
+        logd("updateSpeedType(), getBand():" + keyBand);
+        if (!is5gAvailable()) {
+            keyBand &= ~BAND_5GHZ;
+        }
+        if (!is6gAvailable()) {
+            keyBand &= ~BAND_6GHZ;
+        }
+        if ((keyBand & BAND_6GHZ) != 0) {
+            keyBand = BAND_6GHZ;
+        } else if (isDualBand() && is5gAvailable()) {
+            keyBand = BAND_2GHZ_5GHZ;
+        } else if ((keyBand & BAND_5GHZ) != 0) {
+            keyBand = BAND_5GHZ;
+        } else if ((keyBand & BAND_2GHZ) != 0) {
+            keyBand = BAND_2GHZ;
+        } else {
+            keyBand = 0;
+        }
+        logd("updateSpeedType(), keyBand:" + keyBand);
+        mSpeedType.setValue(sSpeedMap.get(keyBand));
+    }
+
+    protected boolean isDualBand() {
+        if (mIsDualBand == null) {
+            mIsDualBand = mWifiManager.isBridgedApConcurrencySupported();
+            logd("isDualBand():" + mIsDualBand);
+        }
+        return mIsDualBand;
+    }
+
+    protected boolean is5gAvailable() {
+        if (mIs5gAvailable == null) {
+            // TODO(b/272450463): isBandAvailable(WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS) will
+            //  cause crash in the old model device, use a simple check to workaround it first.
+            mIs5gAvailable = (mWifiManager.is5GHzBandSupported() && mCurrentCountryCode != null);
+            logd("is5gAvailable():" + mIs5gAvailable);
+        }
+        return mIs5gAvailable;
+    }
+
+    protected boolean is6gAvailable() {
+        if (mIs6gAvailable == null) {
+            mIs6gAvailable = mWifiManager.is6GHzBandSupported()
+                    && isBandAvailable(WifiScanner.WIFI_BAND_6_GHZ);
+            logd("is6gAvailable():" + mIs6gAvailable);
+        }
+        return mIs6gAvailable;
+    }
+
+    /**
+     * Return whether the Hotspot band is available or not.
+     *
+     * @param band one of the following band constants defined in {@code WifiScanner#WIFI_BAND_*}
+     *             constants.
+     *             1. {@code WifiScanner#WIFI_BAND_5_GHZ_WITH_DFS}
+     *             2. {@code WifiScanner#WIFI_BAND_6_GHZ}
+     */
+    protected boolean isBandAvailable(int band) {
+        List<WifiAvailableChannel> channels = mWifiManager.getUsableChannels(band, OP_MODE_SAP);
+        return (channels != null && channels.size() > 0);
+    }
+
+    protected void purgeRefreshData() {
+        mIsDualBand = null;
+        mIs5gAvailable = null;
+        mIs6gAvailable = null;
+    }
+
+    protected void startAutoRefresh() {
+        if (mActiveCountryCodeChangedCallback != null) {
+            return;
+        }
+        logd("startMonitorSoftApConfiguration()");
+        mActiveCountryCodeChangedCallback = new ActiveCountryCodeChangedCallback();
+        mWifiManager.registerActiveCountryCodeChangedCallback(mAppContext.getMainExecutor(),
+                mActiveCountryCodeChangedCallback);
+    }
+
+    protected void stopAutoRefresh() {
+        if (mActiveCountryCodeChangedCallback == null) {
+            return;
+        }
+        logd("stopMonitorSoftApConfiguration()");
+        mWifiManager.unregisterActiveCountryCodeChangedCallback(mActiveCountryCodeChangedCallback);
+        mActiveCountryCodeChangedCallback = null;
+    }
+
+    protected class ActiveCountryCodeChangedCallback implements
+            WifiManager.ActiveCountryCodeChangedCallback {
+        @Override
+        public void onActiveCountryCodeChanged(String country) {
+            logd("onActiveCountryCodeChanged(), country:" + country);
+            mCurrentCountryCode = country;
+            purgeRefreshData();
+            refresh();
+        }
+
+        @Override
+        public void onCountryCodeInactive() {
+            logd("onCountryCodeInactive()");
+            mCurrentCountryCode = null;
+            purgeRefreshData();
+            refresh();
+        }
+    }
+
+    private static void logd(String msg) {
+        if (DEBUG) {
+            Log.d(TAG, msg);
+        }
+    }
 }
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
index 47dba76..3a3691a 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
@@ -34,11 +34,13 @@
 
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
 
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.core.FeatureFlags;
 import com.android.settings.dashboard.RestrictedDashboardFragment;
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.widget.SettingsMainSwitchBar;
 import com.android.settings.wifi.WifiUtils;
@@ -69,6 +71,8 @@
     @VisibleForTesting
     static final String KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY =
             WifiTetherMaximizeCompatibilityPreferenceController.PREF_KEY;
+    @VisibleForTesting
+    static final String KEY_WIFI_HOTSPOT_SPEED = "wifi_hotspot_speed";
 
     private WifiTetherSwitchBarController mSwitchBarController;
     private WifiTetherSSIDPreferenceController mSSIDPreferenceController;
@@ -84,6 +88,11 @@
     @VisibleForTesting
     TetherChangeReceiver mTetherChangeReceiver;
 
+    @VisibleForTesting
+    WifiTetherViewModel mWifiTetherViewModel;
+    @VisibleForTesting
+    Preference mWifiHotspotSpeed;
+
     static {
         TETHER_STATE_CHANGE_FILTER = new IntentFilter(WIFI_AP_STATE_CHANGED_ACTION);
     }
@@ -120,6 +129,13 @@
 
         setIfOnlyAvailableForAdmins(true);
         mUnavailable = isUiRestricted() || !mWifiRestriction.isHotspotAvailable(getContext());
+
+        mWifiTetherViewModel = FeatureFactory.getFactory(getContext()).getWifiFeatureProvider()
+                .getWifiTetherViewModel(this);
+        mWifiHotspotSpeed = findPreference(KEY_WIFI_HOTSPOT_SPEED);
+        if (mWifiHotspotSpeed != null && mWifiHotspotSpeed.isVisible()) {
+            mWifiTetherViewModel.getSpeedSummary().observe(this, this::onSpeedSummaryChanged);
+        }
     }
 
     @Override
@@ -175,6 +191,7 @@
             // Handle the initial state after register the receiver.
             updateDisplayWithNewConfig();
         }
+        mWifiTetherViewModel.refresh();
     }
 
     @Override
@@ -189,6 +206,9 @@
         }
     }
 
+    protected void onSpeedSummaryChanged(Integer summaryResId) {
+        mWifiHotspotSpeed.setSummary(summaryResId);
+    }
 
     @Override
     protected int getPreferenceScreenResId() {
@@ -228,7 +248,7 @@
             mRestartWifiApAfterConfigChange = true;
             mSwitchBarController.stopTether();
         }
-        mWifiManager.setSoftApConfiguration(config);
+        mWifiTetherViewModel.setSoftApConfiguration(config);
     }
 
     private SoftApConfiguration buildNewConfig() {
diff --git a/src/com/android/settings/wifi/tether/WifiTetherViewModel.java b/src/com/android/settings/wifi/tether/WifiTetherViewModel.java
new file mode 100644
index 0000000..4abca02
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/WifiTetherViewModel.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2023 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 static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2GHZ_5GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_5GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_6GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_UNKNOWN;
+
+import android.app.Application;
+import android.net.wifi.SoftApConfiguration;
+
+import androidx.lifecycle.AndroidViewModel;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.Transformations;
+
+import com.android.settings.R;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.wifi.repository.WifiHotspotRepository;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Wi-Fi Hotspot ViewModel
+ */
+public class WifiTetherViewModel extends AndroidViewModel {
+    private static final String TAG = "WifiTetherViewModel";
+
+    protected static Map<Integer, Integer> sSpeedSummaryResMap = new HashMap<>();
+
+    static {
+        sSpeedSummaryResMap.put(SPEED_UNKNOWN, R.string.summary_placeholder);
+        sSpeedSummaryResMap.put(SPEED_2GHZ, R.string.wifi_hotspot_speed_2g_summary);
+        sSpeedSummaryResMap.put(SPEED_5GHZ, R.string.wifi_hotspot_speed_5g_summary);
+        sSpeedSummaryResMap.put(SPEED_6GHZ, R.string.wifi_hotspot_speed_6g_summary);
+        sSpeedSummaryResMap.put(SPEED_2GHZ_5GHZ, R.string.wifi_hotspot_speed_2g_and_5g_summary);
+    }
+
+    protected final WifiHotspotRepository mWifiHotspotRepository;
+    protected MutableLiveData<Integer> mSpeedSummary;
+
+    public WifiTetherViewModel(@NotNull Application application) {
+        super(application);
+        mWifiHotspotRepository = FeatureFactory.getFactory(application).getWifiFeatureProvider()
+                .getWifiHotspotRepository();
+        mWifiHotspotRepository.setAutoRefresh(true);
+    }
+
+    @Override
+    protected void onCleared() {
+        mWifiHotspotRepository.setAutoRefresh(false);
+    }
+
+    /**
+     * Sets the tethered Wi-Fi AP Configuration.
+     *
+     * @param config A valid SoftApConfiguration specifying the configuration of the SAP.
+     */
+    public void setSoftApConfiguration(SoftApConfiguration config) {
+        mWifiHotspotRepository.setSoftApConfiguration(config);
+    }
+
+    /**
+     * Refresh data from the SoftApConfiguration.
+     */
+    public void refresh() {
+        mWifiHotspotRepository.refresh();
+    }
+
+    /**
+     * Gets SpeedSummary LiveData
+     */
+    public LiveData<Integer> getSpeedSummary() {
+        if (mSpeedSummary == null) {
+            mSpeedSummary = new MutableLiveData<>();
+            mWifiHotspotRepository.getSpeedType().observeForever(this::onSpeedTypeChanged);
+        }
+        return Transformations.distinctUntilChanged(mSpeedSummary);
+    }
+
+    protected void onSpeedTypeChanged(Integer speedType) {
+        mSpeedSummary.setValue(sSpeedSummaryResMap.get(speedType));
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/CameraFlashNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/CameraFlashNotificationPreferenceControllerTest.java
index db4e521..02ab32d 100644
--- a/tests/robotests/src/com/android/settings/accessibility/CameraFlashNotificationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/CameraFlashNotificationPreferenceControllerTest.java
@@ -16,7 +16,8 @@
 
 package com.android.settings.accessibility;
 
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
+import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
+import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
 import static com.android.settings.core.BasePreferenceController.AVAILABLE;
 import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
 
@@ -81,28 +82,30 @@
 
     @Test
     public void isChecked_setOff_assertFalse() {
-        Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 0);
+        Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, OFF);
         assertThat(mController.isChecked()).isFalse();
     }
 
     @Test
     public void isChecked_setOn_assertTrue() {
-        Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 1);
+        Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, ON);
         assertThat(mController.isChecked()).isTrue();
     }
 
     @Test
-    public void setChecked_setTrue_assertNotZero() {
+    public void setChecked_setTrue_assertNotOff() {
         mController.setChecked(true);
-        assertThat(Settings.System.getInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION,
-                0)).isNotEqualTo(0);
+        assertThat(
+                Settings.System.getInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION,
+                        OFF)).isNotEqualTo(OFF);
     }
 
     @Test
-    public void setChecked_setFalse_assertNotOne() {
+    public void setChecked_setFalse_assertNotOn() {
         mController.setChecked(false);
-        assertThat(Settings.System.getInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION,
-                1)).isNotEqualTo(1);
+        assertThat(
+                Settings.System.getInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION,
+                        OFF)).isNotEqualTo(ON);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/accessibility/ContrastLevelSeekBarPreferenceTest.java b/tests/robotests/src/com/android/settings/accessibility/ContrastLevelSeekBarPreferenceTest.java
deleted file mode 100644
index ff073f5..0000000
--- a/tests/robotests/src/com/android/settings/accessibility/ContrastLevelSeekBarPreferenceTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2022 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.android.settings.accessibility.ContrastLevelSeekBarPreference.CONTRAST_SLIDER_TICKS;
-
-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 com.android.settings.testutils.shadow.ShadowInteractionJankMonitor;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowInteractionJankMonitor.class})
-public class ContrastLevelSeekBarPreferenceTest {
-
-    private Context mContext;
-    private AttributeSet mAttrs;
-    private PreferenceViewHolder mHolder;
-    private ContrastLevelSeekBar mSeekBar;
-    private ContrastLevelSeekBarPreference mSeekBarPreference;
-
-    @Before
-    public void setUp() {
-        mContext = RuntimeEnvironment.application;
-        mSeekBarPreference = new ContrastLevelSeekBarPreference(mContext, mAttrs);
-        LayoutInflater inflater = LayoutInflater.from(mContext);
-        final View view =
-                inflater.inflate(mSeekBarPreference.getLayoutResource(),
-                        new LinearLayout(mContext), false);
-        mHolder = PreferenceViewHolder.createInstanceForTests(view);
-        mSeekBar = view.findViewById(com.android.internal.R.id.seekbar);
-    }
-
-    @Test
-    public void seekBarPreferenceOnBindViewHolder_shouldInitSeekBarValue() {
-        mSeekBarPreference.onBindViewHolder(mHolder);
-
-        assertThat(mSeekBar.getMax()).isEqualTo(CONTRAST_SLIDER_TICKS);
-        assertThat(mSeekBar.getProgress()).isEqualTo(0);
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/accessibility/ContrastLevelSeekBarTest.java b/tests/robotests/src/com/android/settings/accessibility/ContrastLevelSeekBarTest.java
deleted file mode 100644
index fd24436..0000000
--- a/tests/robotests/src/com/android/settings/accessibility/ContrastLevelSeekBarTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2022 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 android.view.HapticFeedbackConstants.CLOCK_TICK;
-import static android.view.HapticFeedbackConstants.CONTEXT_CLICK;
-
-import static com.android.settings.accessibility.ContrastLevelSeekBarPreference.CONTRAST_SLIDER_TICKS;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.robolectric.Shadows.shadowOf;
-
-import android.content.Context;
-import android.os.UserHandle;
-import android.provider.Settings;
-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 ContrastLevelSeekBarTest {
-
-    private Context mContext;
-    private ContrastLevelSeekBar mSeekBar;
-    private SeekBar.OnSeekBarChangeListener mProxySeekBarListener;
-
-    @Before
-    public void setUp() {
-        mContext = RuntimeEnvironment.application;
-        mSeekBar = new ContrastLevelSeekBar(mContext, null);
-        mProxySeekBarListener = shadowOf(mSeekBar).getOnSeekBarChangeListener();
-    }
-
-    @Test
-    public void onProgressChanged_minimumValue_shouldModifyContrast() {
-        // Assign the test value of SeekBar progress
-        mProxySeekBarListener.onProgressChanged(mSeekBar, 0, true);
-
-        assertThat(Settings.Secure.getFloatForUser(
-                mContext.getContentResolver(), Settings.Secure.CONTRAST_LEVEL,
-                -10f, UserHandle.USER_CURRENT)).isEqualTo(0);
-    }
-
-    @Test
-    public void onProgressChanged_centerValue_shouldModifyContrast() {
-        // Assign the test value of SeekBar progress
-        mProxySeekBarListener.onProgressChanged(mSeekBar, CONTRAST_SLIDER_TICKS / 2, true);
-
-        assertThat(Settings.Secure.getFloatForUser(
-                mContext.getContentResolver(), Settings.Secure.CONTRAST_LEVEL,
-                -10f, UserHandle.USER_CURRENT)).isWithin(1e-8f).of(0.5f);
-    }
-
-    @Test
-    public void onProgressChanged_maximumValue_shouldModifyContrast() {
-        // Assign the test value of SeekBar progress
-        mProxySeekBarListener.onProgressChanged(mSeekBar, CONTRAST_SLIDER_TICKS, true);
-
-        assertThat(Settings.Secure.getFloatForUser(
-                mContext.getContentResolver(), Settings.Secure.CONTRAST_LEVEL,
-                -10f, UserHandle.USER_CURRENT)).isEqualTo(1);
-    }
-
-    @Test
-    public void onProgressChanged_minimumValue_clockTickFeedbackPerformed() {
-        mSeekBar.performHapticFeedback(CONTEXT_CLICK);
-        mProxySeekBarListener.onProgressChanged(mSeekBar, 0, true);
-
-        assertThat(shadowOf(mSeekBar).lastHapticFeedbackPerformed()).isEqualTo(CLOCK_TICK);
-    }
-
-    @Test
-    public void onProgressChanged_centerValue_clockTickFeedbackPerformed() {
-        mSeekBar.performHapticFeedback(CONTEXT_CLICK);
-        mProxySeekBarListener.onProgressChanged(mSeekBar, CONTRAST_SLIDER_TICKS / 2, true);
-
-        assertThat(shadowOf(mSeekBar).lastHapticFeedbackPerformed()).isEqualTo(CLOCK_TICK);
-    }
-
-    @Test
-    public void onProgressChanged_maximumValue_clockTickFeedbackPerformed() {
-        mSeekBar.performHapticFeedback(CONTEXT_CLICK);
-        mProxySeekBarListener.onProgressChanged(mSeekBar, CONTRAST_SLIDER_TICKS, true);
-
-        assertThat(shadowOf(mSeekBar).lastHapticFeedbackPerformed()).isEqualTo(CLOCK_TICK);
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceControllerTest.java
index 5f1dfbb..98da926 100644
--- a/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceControllerTest.java
@@ -18,8 +18,6 @@
 
 import static com.android.settings.accessibility.FlashNotificationsUtil.ACTION_FLASH_NOTIFICATION_START_PREVIEW;
 import static com.android.settings.accessibility.FlashNotificationsUtil.EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
 import static com.android.settings.accessibility.FlashNotificationsUtil.TYPE_LONG_PREVIEW;
 import static com.android.settings.accessibility.FlashNotificationsUtil.TYPE_SHORT_PREVIEW;
 import static com.android.settings.accessibility.ShadowFlashNotificationsUtils.setFlashNotificationsState;
@@ -48,7 +46,6 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -131,7 +128,6 @@
         verify(mPreference).setEnabled(eq(true));
     }
 
-    @Ignore
     @Test
     public void testHandlePreferenceTreeClick_invalidPreference() {
         mController.handlePreferenceTreeClick(mock(Preference.class));
@@ -165,16 +161,16 @@
     public void onStateChanged_onResume_cameraUri_verifyRegister() {
         mController.onStateChanged(mock(LifecycleOwner.class), Lifecycle.Event.ON_RESUME);
         verify(mContentResolver).registerContentObserver(
-                eq(Settings.System.getUriFor(SETTING_KEY_CAMERA_FLASH_NOTIFICATION)), anyBoolean(),
-                eq(mController.mContentObserver));
+                eq(Settings.System.getUriFor(Settings.System.CAMERA_FLASH_NOTIFICATION)),
+                anyBoolean(), eq(mController.mContentObserver));
     }
 
     @Test
     public void onStateChanged_onResume_screenUri_verifyRegister() {
         mController.onStateChanged(mock(LifecycleOwner.class), Lifecycle.Event.ON_RESUME);
         verify(mContentResolver).registerContentObserver(
-                eq(Settings.System.getUriFor(SETTING_KEY_SCREEN_FLASH_NOTIFICATION)), anyBoolean(),
-                eq(mController.mContentObserver));
+                eq(Settings.System.getUriFor(Settings.System.SCREEN_FLASH_NOTIFICATION)),
+                anyBoolean(), eq(mController.mContentObserver));
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsUtilTest.java b/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsUtilTest.java
index c5fe3a7..f943e3a 100644
--- a/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsUtilTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsUtilTest.java
@@ -21,8 +21,8 @@
 import static android.hardware.camera2.CameraCharacteristics.LENS_FACING_BACK;
 import static android.hardware.camera2.CameraMetadata.LENS_FACING_FRONT;
 
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_CAMERA_FLASH_NOTIFICATION;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
+import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
+import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
 import static com.android.settings.accessibility.FlashNotificationsUtil.getColorDescriptionText;
 import static com.android.settings.accessibility.FlashNotificationsUtil.getFlashNotificationsState;
 import static com.android.settings.accessibility.FlashNotificationsUtil.getScreenColor;
@@ -156,8 +156,8 @@
     @Test
     public void getFlashNotificationsState_torchPresent_cameraOff_screenOff_assertOff() {
         setTorchPresent();
-        Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 0);
-        Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 0);
+        Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, OFF);
+        Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, OFF);
 
         assertThat(getFlashNotificationsState(mContext))
                 .isEqualTo(FlashNotificationsUtil.State.OFF);
@@ -166,8 +166,8 @@
     @Test
     public void getFlashNotificationsState_torchNotPresent_cameraOn_screenOff_assertOff() {
         setTorchNotPresent();
-        Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 1);
-        Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 0);
+        Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, ON);
+        Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, OFF);
 
         assertThat(getFlashNotificationsState(mContext))
                 .isEqualTo(FlashNotificationsUtil.State.OFF);
@@ -176,8 +176,8 @@
     @Test
     public void getFlashNotificationsState_torchPresent_cameraOn_screenOff_assertCamera() {
         setTorchPresent();
-        Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 1);
-        Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 0);
+        Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, ON);
+        Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, OFF);
 
         assertThat(getFlashNotificationsState(mContext))
                 .isEqualTo(FlashNotificationsUtil.State.CAMERA);
@@ -186,8 +186,8 @@
     @Test
     public void getFlashNotificationsState_torchPresent_cameraOff_screenOn_assertScreen() {
         setTorchPresent();
-        Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 0);
-        Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 1);
+        Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, OFF);
+        Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, ON);
 
         assertThat(getFlashNotificationsState(mContext))
                 .isEqualTo(FlashNotificationsUtil.State.SCREEN);
@@ -196,8 +196,8 @@
     @Test
     public void testGetFlashNotificationsState_torchPresent_cameraOn_screenOn_assertCameraScreen() {
         setTorchPresent();
-        Settings.System.putInt(mContentResolver, SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 1);
-        Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 1);
+        Settings.System.putInt(mContentResolver, Settings.System.CAMERA_FLASH_NOTIFICATION, ON);
+        Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, ON);
 
         assertThat(getFlashNotificationsState(mContext))
                 .isEqualTo(FlashNotificationsUtil.State.CAMERA_SCREEN);
diff --git a/tests/robotests/src/com/android/settings/accessibility/FontSizeDataTest.java b/tests/robotests/src/com/android/settings/accessibility/FontSizeDataTest.java
index 7e35714..adf7495 100644
--- a/tests/robotests/src/com/android/settings/accessibility/FontSizeDataTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/FontSizeDataTest.java
@@ -16,6 +16,9 @@
 
 package com.android.settings.accessibility;
 
+import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
+import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Context;
@@ -52,4 +55,19 @@
 
         assertThat(currentScale).isEqualTo(mFontSizeData.getValues().get(progress));
     }
+
+    @Test
+    public void commit_fontScalingHasBeenChangedIsOn() {
+        final int progress = 3;
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED, OFF);
+
+        mFontSizeData.commit(progress);
+        final int currentSettings = Settings.Secure.getInt(
+                mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
+                /* def= */ OFF);
+
+        assertThat(currentSettings).isEqualTo(ON);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceControllerTest.java
index 0662daa..5b8afe6 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceControllerTest.java
@@ -16,9 +16,9 @@
 
 package com.android.settings.accessibility;
 
+import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
+import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
 import static com.android.settings.accessibility.FlashNotificationsUtil.DEFAULT_SCREEN_FLASH_COLOR;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION;
-import static com.android.settings.accessibility.FlashNotificationsUtil.SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR;
 import static com.android.settings.core.BasePreferenceController.AVAILABLE;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -114,48 +114,50 @@
 
     @Test
     public void isChecked_setOff_assertFalse() {
-        Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 0);
+        Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, OFF);
         assertThat(mController.isChecked()).isFalse();
     }
 
     @Test
     public void isChecked_setOn_assertTrue() {
-        Settings.System.putInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 1);
+        Settings.System.putInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION, ON);
         assertThat(mController.isChecked()).isTrue();
     }
 
     @Test
     public void setChecked_whenTransparentColor_setTrue_assertNotTransparentColor() {
         Settings.System.putInt(mContentResolver,
-                SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, Color.TRANSPARENT);
+                Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, Color.TRANSPARENT);
         mController.setChecked(true);
         assertThat(Settings.System.getInt(mContentResolver,
-                SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, 0))
-                .isEqualTo(DEFAULT_SCREEN_FLASH_COLOR);
+                Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, 0)).isEqualTo(
+                DEFAULT_SCREEN_FLASH_COLOR);
     }
 
     @Test
     public void setChecked_whenNotTransparent_setTrue_assertSameColor() {
         Settings.System.putInt(mContentResolver,
-                SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, 0x4D0000FF);
+                Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, 0x4D0000FF);
         mController.setChecked(true);
         assertThat(Settings.System.getInt(mContentResolver,
-                SETTING_KEY_SCREEN_FLASH_NOTIFICATION_COLOR, 0))
+                Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR, 0))
                 .isEqualTo(0x4D0000FF);
     }
 
     @Test
     public void setChecked_setTrue_assertOn() {
         mController.setChecked(true);
-        assertThat(Settings.System.getInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION,
-                0)).isEqualTo(1);
+        assertThat(
+                Settings.System.getInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION,
+                        OFF)).isEqualTo(ON);
     }
 
     @Test
     public void setChecked_setFalse_assertOff() {
         mController.setChecked(false);
-        assertThat(Settings.System.getInt(mContentResolver, SETTING_KEY_SCREEN_FLASH_NOTIFICATION,
-                1)).isEqualTo(0);
+        assertThat(
+                Settings.System.getInt(mContentResolver, Settings.System.SCREEN_FLASH_NOTIFICATION,
+                        OFF)).isEqualTo(OFF);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
index 62230e2..2886194 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
@@ -452,6 +452,28 @@
         assertThat(getLayout().getDescriptionTextView().getVisibility()).isEqualTo(View.VISIBLE);
     }
 
+    @Test
+    public void testUdfpsConfigureEnrollmentStage_descriptionText() {
+        initializeActivityFor(TYPE_UDFPS_OPTICAL);
+
+        assertThat(getLayout().getDescriptionText()).isNotEqualTo("");
+
+        mActivity.configureEnrollmentStage(0 /* lottie */);
+
+        assertThat(getLayout().getDescriptionText()).isEqualTo("");
+    }
+
+    @Test
+    public void testSfpsConfigureEnrollmentStage_descriptionText() {
+        initializeActivityFor(TYPE_POWER_BUTTON);
+
+        assertThat(getLayout().getDescriptionTextView().getVisibility()).isEqualTo(View.GONE);
+
+        mActivity.configureEnrollmentStage(0 /* lottie */);
+
+        assertThat(getLayout().getDescriptionTextView().getVisibility()).isEqualTo(View.GONE);
+    }
+
     private GlifLayout getLayout() {
         return (GlifLayout) mActivity.findViewById(R.id.setup_wizard_layout);
     }
diff --git a/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java
index ec100d0..e334af5 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java
@@ -183,6 +183,26 @@
     }
 
     @Test
+    public void refresh_connectedUnknownType_behaveAsExpected() {
+        when(mBluetoothDevice.getMetadata(
+                BluetoothDevice.METADATA_DEVICE_TYPE)).thenReturn(
+                "UNKNOWN_TYPE".getBytes());
+        when(mBluetoothDevice.getMetadata(
+                BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn(
+                String.valueOf(false).getBytes());
+        when(mCachedDevice.isConnected()).thenReturn(true);
+
+        mController.refresh();
+
+        assertThat(mLayoutPreference.findViewById(R.id.layout_left).getVisibility()).isEqualTo(
+                View.GONE);
+        assertThat(mLayoutPreference.findViewById(R.id.layout_right).getVisibility()).isEqualTo(
+                View.GONE);
+        assertThat(mLayoutPreference.findViewById(R.id.layout_middle).getVisibility()).isEqualTo(
+                View.VISIBLE);
+    }
+
+    @Test
     public void refresh_connectedUntetheredHeadset_behaveAsExpected() {
         when(mBluetoothDevice.getMetadata(
                 BluetoothDevice.METADATA_DEVICE_TYPE)).thenReturn(
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdaterTest.java
index 10f3727..7fb17e2 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdaterTest.java
@@ -127,7 +127,7 @@
     @Test
     public void click_usiPreference_launchUsiDetailsPage() {
         doReturn(mSettingsActivity).when(mDashboardFragment).getContext();
-        doReturn(true).when(mStylusDeviceUpdater).isUsiConnectionValid();
+        doReturn(true).when(mStylusDeviceUpdater).isUsiBatteryValid();
         doReturn(false).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
         mStylusDeviceUpdater.forceUpdate();
         mStylusDeviceUpdater.mLastDetectedUsiId = 1;
@@ -144,7 +144,7 @@
 
     @Test
     public void forceUpdate_addsUsiPreference_validUsiDevice() {
-        doReturn(true).when(mStylusDeviceUpdater).isUsiConnectionValid();
+        doReturn(true).when(mStylusDeviceUpdater).isUsiBatteryValid();
         doReturn(false).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
 
         mStylusDeviceUpdater.forceUpdate();
@@ -154,7 +154,7 @@
 
     @Test
     public void forceUpdate_doesNotAddPreference_invalidUsiDevice() {
-        doReturn(false).when(mStylusDeviceUpdater).isUsiConnectionValid();
+        doReturn(false).when(mStylusDeviceUpdater).isUsiBatteryValid();
         doReturn(false).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
 
         mStylusDeviceUpdater.forceUpdate();
@@ -164,12 +164,12 @@
 
     @Test
     public void forceUpdate_removesUsiPreference_existingPreference_invalidUsiDevice() {
-        doReturn(true).when(mStylusDeviceUpdater).isUsiConnectionValid();
+        doReturn(true).when(mStylusDeviceUpdater).isUsiBatteryValid();
         doReturn(false).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
 
         mStylusDeviceUpdater.forceUpdate();
 
-        doReturn(false).when(mStylusDeviceUpdater).isUsiConnectionValid();
+        doReturn(false).when(mStylusDeviceUpdater).isUsiBatteryValid();
         mStylusDeviceUpdater.forceUpdate();
 
         assertThat(mStylusDeviceUpdater.mUsiPreference).isNull();
@@ -177,7 +177,7 @@
 
     @Test
     public void forceUpdate_doesNotAddUsiPreference_bluetoothStylusConnected() {
-        doReturn(true).when(mStylusDeviceUpdater).isUsiConnectionValid();
+        doReturn(true).when(mStylusDeviceUpdater).isUsiBatteryValid();
         doReturn(true).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
 
         mStylusDeviceUpdater.forceUpdate();
@@ -187,7 +187,7 @@
 
     @Test
     public void forceUpdate_addsUsiPreference_bluetoothStylusDisconnected() {
-        doReturn(true).when(mStylusDeviceUpdater).isUsiConnectionValid();
+        doReturn(true).when(mStylusDeviceUpdater).isUsiBatteryValid();
         doReturn(true).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
         mStylusDeviceUpdater.forceUpdate();
 
@@ -199,7 +199,7 @@
 
     @Test
     public void forceUpdate_removesUsiPreference_existingPreference_bluetoothStylusConnected() {
-        doReturn(true).when(mStylusDeviceUpdater).isUsiConnectionValid();
+        doReturn(true).when(mStylusDeviceUpdater).isUsiBatteryValid();
         doReturn(false).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
         mStylusDeviceUpdater.forceUpdate();
         doReturn(true).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
@@ -218,7 +218,7 @@
         mStylusDeviceUpdater.onBatteryStateChanged(1, SystemClock.uptimeMillis(),
                 batteryState);
 
-        assertThat(mStylusDeviceUpdater.isUsiConnectionValid()).isTrue();
+        assertThat(mStylusDeviceUpdater.isUsiBatteryValid()).isTrue();
     }
 
     @Test
@@ -230,19 +230,7 @@
         mStylusDeviceUpdater.onBatteryStateChanged(1, SystemClock.uptimeMillis(),
                 batteryState);
 
-        assertThat(mStylusDeviceUpdater.isUsiConnectionValid()).isFalse();
-    }
-
-    @Test
-    public void onBatteryStateChanged_ddetectsInvalidUsi_staleBatteryEventTime() {
-        doReturn(false).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
-        BatteryState batteryState = mock(BatteryState.class);
-        doReturn(true).when(batteryState).isPresent();
-        doReturn(0.5f).when(batteryState).getCapacity();
-
-        mStylusDeviceUpdater.onBatteryStateChanged(1, 0, batteryState);
-
-        assertThat(mStylusDeviceUpdater.isUsiConnectionValid()).isFalse();
+        assertThat(mStylusDeviceUpdater.isUsiBatteryValid()).isFalse();
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/datausage/lib/DataUsageLibTest.java b/tests/robotests/src/com/android/settings/datausage/lib/DataUsageLibTest.java
index 4391425..fccef4f 100644
--- a/tests/robotests/src/com/android/settings/datausage/lib/DataUsageLibTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/lib/DataUsageLibTest.java
@@ -103,11 +103,14 @@
     public void getMobileTemplate_groupUuidExist_returnMobileMerged() {
         when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(mInfo1);
         when(mInfo1.getGroupUuid()).thenReturn(mParcelUuid);
+        // In some rare cases (e.g. b/243015487), merged subscriberId list might contain
+        // duplicated items. The implementation should perform deduplication.
         when(mTelephonyManager.getMergedImsisFromGroup())
-                .thenReturn(new String[] {SUBSCRIBER_ID, SUBSCRIBER_ID_2});
+                .thenReturn(new String[] {SUBSCRIBER_ID, SUBSCRIBER_ID, SUBSCRIBER_ID_2});
 
         final NetworkTemplate networkTemplate = DataUsageLib.getMobileTemplate(mContext, SUB_ID);
         assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID)).isTrue();
         assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID_2)).isTrue();
+        assertThat(networkTemplate.getSubscriberIds().size() == 2).isTrue();
     }
 }
diff --git a/tests/robotests/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceControllerTest.java
new file mode 100644
index 0000000..f4e52ba
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/BluetoothLeAudioAllowListPreferenceControllerTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+import static android.bluetooth.BluetoothStatusCodes.FEATURE_SUPPORTED;
+
+import static com.android.settings.development.BluetoothLeAudioAllowListPreferenceController
+        .LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.os.SystemProperties;
+
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class BluetoothLeAudioAllowListPreferenceControllerTest {
+
+    @Mock
+    private PreferenceScreen mPreferenceScreen;
+    @Mock
+    private DevelopmentSettingsDashboardFragment mFragment;
+
+    @Mock
+    private BluetoothAdapter mBluetoothAdapter;
+
+    private Context mContext;
+    private SwitchPreference mPreference;
+    private BluetoothLeAudioPreferenceController mController;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mPreference = new SwitchPreference(mContext);
+        mController = spy(new BluetoothLeAudioPreferenceController(mContext, mFragment));
+        when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
+            .thenReturn(mPreference);
+        mController.mBluetoothAdapter = mBluetoothAdapter;
+        mController.displayPreference(mPreferenceScreen);
+        when(mBluetoothAdapter.isLeAudioSupported())
+            .thenReturn(FEATURE_SUPPORTED);
+    }
+
+    @Test
+    public void onRebootDialogConfirmedAsLeAudioAllowListDisabled_shouldSwitchStatus() {
+        SystemProperties.set(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, Boolean.toString(false));
+        mController.mChanged = true;
+
+        mController.onRebootDialogConfirmed();
+        final boolean mode = SystemProperties.getBoolean(
+                LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false);
+        assertThat(mode).isFalse();
+    }
+
+
+    @Test
+    public void onRebootDialogConfirmedAsLeAudioAllowListEnabled_shouldSwitchStatus() {
+        SystemProperties.set(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, Boolean.toString(true));
+        mController.mChanged = true;
+
+        mController.onRebootDialogConfirmed();
+        final boolean status = SystemProperties.getBoolean(
+                LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false);
+        assertThat(status).isTrue();
+    }
+
+    @Test
+    public void onRebootDialogCanceled_shouldNotSwitchStatus() {
+        SystemProperties.set(LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, Boolean.toString(false));
+        mController.mChanged = true;
+
+        mController.onRebootDialogCanceled();
+        final boolean status = SystemProperties.getBoolean(
+                LE_AUDIO_ALLOW_LIST_ENABLED_PROPERTY, false);
+        assertThat(status).isFalse();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/TransparentNavigationBarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/TransparentNavigationBarPreferenceControllerTest.java
new file mode 100644
index 0000000..a1b3892
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/TransparentNavigationBarPreferenceControllerTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class TransparentNavigationBarPreferenceControllerTest {
+
+    @Mock
+    private PreferenceScreen mScreen;
+    @Mock
+    private SwitchPreference mPreference;
+
+    private TransparentNavigationBarPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mController = new TransparentNavigationBarPreferenceController(
+                RuntimeEnvironment.application) {
+            private boolean mEnabled;
+
+            protected boolean isEnabled() {
+                return mEnabled;
+            }
+
+            protected void setEnabled(boolean enabled) {
+                mEnabled = enabled;
+            }
+        };
+        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
+        mController.displayPreference(mScreen);
+    }
+
+    @Test
+    public void updateState_enabled_shouldCheckedPreference() {
+        mController.setEnabled(true);
+        mController.updateState(mPreference);
+
+        verify(mPreference).setChecked(true);
+    }
+
+    @Test
+    public void updateState_disabled_shouldUncheckedPreference() {
+        mController.setEnabled(false);
+        mController.updateState(mPreference);
+
+        verify(mPreference).setChecked(false);
+    }
+
+    @Test
+    public void onPreferenceChange_preferenceChecked_shouldBeEnabled() {
+        mController.onPreferenceChange(mPreference, true /* new value */);
+
+        assertTrue(mController.isEnabled());
+    }
+
+    @Test
+    public void onPreferenceChange__preferenceUnchecked_shouldNotBeEnabled() {
+        mController.onPreferenceChange(mPreference, false /* new value */);
+
+        assertFalse(mController.isEnabled());
+    }
+
+    @Test
+    public void onDeveloperOptionsSwitchDisabled_preferenceShouldNotBeEnabled() {
+        mController.onDeveloperOptionsSwitchDisabled();
+
+        assertFalse(mController.isEnabled());
+        verify(mPreference).setEnabled(false);
+        verify(mPreference).setChecked(false);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java
index da0002c..f9cac56 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java
@@ -62,12 +62,6 @@
     }
 
     @Test
-    @Config(qualifiers = "mcc999")
-    public void getAvailabilityStatus_unsupportedWhenSet() {
-        assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
-    }
-
-    @Test
     public void convertClassPathToComponentName_nullInput_returnsNull() {
         assertThat(mController.convertClassPathToComponentName(null)).isNull();
     }
@@ -118,4 +112,4 @@
         assertThat(mController.getSummary())
                 .isEqualTo(mContext.getString(R.string.battery_missing_message));
     }
-}
\ No newline at end of file
+}
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 881a18d..9a7ef40 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceControllerTest.java
@@ -18,17 +18,13 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.doReturn;
-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.content.Context;
-import android.content.Intent;
 import android.os.PowerManager;
 import android.provider.Settings;
 import android.provider.SettingsSlicesContract;
@@ -113,11 +109,10 @@
     }
 
     @Test
-    public void setChecked_on_showWarningMessage() {
+    public void setChecked_on_setPowerSaveMode() {
         mController.setChecked(true);
 
-        verify(mContext).sendBroadcast(any(Intent.class));
-        verify(mPowerManager, never()).setPowerSaveModeEnabled(anyBoolean());
+        verify(mPowerManager).setPowerSaveModeEnabled(true);
     }
 
     @Test
@@ -152,5 +147,9 @@
                 mContext.getContentResolver(),
                 Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
                 acked);
+        Settings.Secure.putInt(
+                mContext.getContentResolver(),
+                Settings.Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED,
+                acked);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceControllerTest.java
index 36f891e..5cd137a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceControllerTest.java
@@ -26,8 +26,10 @@
 
 import androidx.preference.Preference;
 
+import com.android.settings.R;
 import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
 import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.shadow.SettingsShadowResources;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -36,8 +38,10 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = SettingsShadowResources.class)
 public class BatteryManagerPreferenceControllerTest {
     private static final int ON = 1;
     private static final int OFF = 0;
@@ -85,7 +89,10 @@
 
     @Test
     public void getAvailabilityStatus_supportBatteryManager_showPrefPage() {
+        SettingsShadowResources.overrideResource(
+                R.bool.config_battery_manager_consider_ac, true);
         when(mPowerUsageFeatureProvider.isBatteryManagerSupported()).thenReturn(true);
+        when(mPowerUsageFeatureProvider.isAdaptiveChargingSupported()).thenReturn(true);
 
         assertThat(mController.getAvailabilityStatus()).isEqualTo(
                 BatteryManagerPreferenceController.AVAILABLE_UNSEARCHABLE);
@@ -98,4 +105,26 @@
         assertThat(mController.getAvailabilityStatus()).isEqualTo(
                 BatteryManagerPreferenceController.UNSUPPORTED_ON_DEVICE);
     }
+
+    @Test
+    public void getAvailabilityStatus_supportBatteryManagerWithoutAC_notShowPrefPage() {
+        SettingsShadowResources.overrideResource(
+                R.bool.config_battery_manager_consider_ac, true);
+        when(mPowerUsageFeatureProvider.isBatteryManagerSupported()).thenReturn(true);
+        when(mPowerUsageFeatureProvider.isAdaptiveChargingSupported()).thenReturn(false);
+
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(
+                BatteryManagerPreferenceController.UNSUPPORTED_ON_DEVICE);
+    }
+
+    @Test
+    public void getAvailabilityStatus_ignoreBatteryManagerWithoutAC_showPrefPage() {
+        SettingsShadowResources.overrideResource(
+                R.bool.config_battery_manager_consider_ac, false);
+        when(mPowerUsageFeatureProvider.isBatteryManagerSupported()).thenReturn(true);
+        when(mPowerUsageFeatureProvider.isAdaptiveChargingSupported()).thenReturn(false);
+
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(
+                BatteryManagerPreferenceController.AVAILABLE_UNSEARCHABLE);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java
index ce70f50..3aad061 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java
@@ -85,7 +85,7 @@
     @Test
     public void getIcon_showIcon() {
         assertThat(mIncompatibleChargerTip.getIconId())
-                .isEqualTo(R.drawable.ic_battery_charging);
+                .isEqualTo(R.drawable.ic_battery_alert_24dp);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
index 58c69b1..f18228b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
@@ -88,7 +88,7 @@
         Locale.setDefault(new Locale("en_US"));
         org.robolectric.shadows.ShadowSettings.set24HourTimeFormat(false);
         TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
-        DataProcessor.sTestSystemAppsSet = Set.of();
+        DataProcessor.sTestSystemAppsPackageNames = Set.of();
         mFeatureFactory = FakeFeatureFactory.setupForTest();
         mContext = spy(RuntimeEnvironment.application);
         doReturn(mContext).when(mContext).getApplicationContext();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffDataTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffDataTest.java
index 0985fe7..27539a5 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffDataTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffDataTest.java
@@ -63,7 +63,7 @@
                 createBatteryDiffEntry(mContext, /*consumePower=*/ 0, /*isHidden=*/ true);
 
         final boolean needsCombineInSystemApp = BatteryDiffData.needsCombineInSystemApp(
-                hiddenDiffEntry, List.of(), Set.of());
+                hiddenDiffEntry, List.of(), Set.of(), Set.of());
 
         assertThat(needsCombineInSystemApp).isTrue();
     }
@@ -77,7 +77,7 @@
         mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
 
         final boolean needsCombineInSystemApp = BatteryDiffData.needsCombineInSystemApp(
-                batteryDiffEntry, List.of(), Set.of(ConvertUtils.FAKE_PACKAGE_NAME));
+                batteryDiffEntry, List.of(), Set.of(ConvertUtils.FAKE_PACKAGE_NAME), Set.of());
 
         assertThat(needsCombineInSystemApp).isTrue();
     }
@@ -91,7 +91,7 @@
         mApplicationInfo.flags = 0;
 
         final boolean needsCombineInSystemApp = BatteryDiffData.needsCombineInSystemApp(
-                batteryDiffEntry, List.of(), Set.of());
+                batteryDiffEntry, List.of(), Set.of(), Set.of());
 
         assertThat(needsCombineInSystemApp).isFalse();
     }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
index 395f655..37f05bc 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
@@ -107,7 +107,7 @@
         mBatteryDiffEntry = spy(mBatteryDiffEntry);
         mBatteryUsageBreakdownController.mBatteryDiffData =
                 new BatteryDiffData(mContext, Arrays.asList(mBatteryDiffEntry), Arrays.asList(),
-                        Set.of(), /* isAccumulated= */ false);
+                        Set.of(), Set.of(), /* isAccumulated= */ false);
         // Adds fake testing data.
         BatteryDiffEntry.sResourceCache.put(
                 "fakeBatteryDiffEntryKey",
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
index 67c972f..aab91e0 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
@@ -82,8 +82,8 @@
         doReturn(66).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_LEVEL), anyInt());
 
         mDataProcessManager = new DataProcessManager(
-                mContext, /*handler=*/ null,  /*callbackFunction=*/ null,
-                /*hourlyBatteryLevelsPerDay=*/ new ArrayList<>(),
+                mContext, /*handler=*/ null,  /*rawStartTimestamp=*/ 0L,
+                /*callbackFunction=*/ null, /*hourlyBatteryLevelsPerDay=*/ new ArrayList<>(),
                 /*batteryHistoryMap=*/ new HashMap<>());
     }
 
@@ -174,7 +174,7 @@
         DatabaseUtils.sFakeAppUsageEventSupplier = () -> cursor;
 
         final DataProcessManager dataProcessManager = new DataProcessManager(
-                mContext, /*handler=*/ null,  /*callbackFunction=*/ null,
+                mContext, /*handler=*/ null, /*rawStartTimestamp=*/ 2L,  /*callbackFunction=*/ null,
                 hourlyBatteryLevelsPerDay, /*batteryHistoryMap=*/ new HashMap<>());
         dataProcessManager.start();
 
@@ -250,42 +250,6 @@
     }
 
     @Test
-    public void getStartTimestampOfBatteryLevelData_returnExpectedResult() {
-        final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
-                new ArrayList<>();
-        final List<Long> timestamps = new ArrayList<>();
-        timestamps.add(101L);
-        timestamps.add(1001L);
-        final List<Integer> levels = new ArrayList<>();
-        levels.add(1);
-        levels.add(2);
-        hourlyBatteryLevelsPerDay.add(null);
-        hourlyBatteryLevelsPerDay.add(
-                new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
-
-        final DataProcessManager dataProcessManager = new DataProcessManager(
-                mContext, /*handler=*/ null,  /*callbackFunction=*/ null,
-                hourlyBatteryLevelsPerDay, /*batteryHistoryMap=*/ null);
-
-        assertThat(dataProcessManager.getStartTimestampOfBatteryLevelData()).isEqualTo(101);
-    }
-
-    @Test
-    public void getStartTimestampOfBatteryLevelData_emptyLevels_returnZero() {
-        final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
-                new ArrayList<>();
-        hourlyBatteryLevelsPerDay.add(null);
-        hourlyBatteryLevelsPerDay.add(
-                new BatteryLevelData.PeriodBatteryLevelData(new ArrayList<>(), new ArrayList<>()));
-
-        final DataProcessManager dataProcessManager = new DataProcessManager(
-                mContext, /*handler=*/ null,  /*callbackFunction=*/ null,
-                hourlyBatteryLevelsPerDay, /*batteryHistoryMap=*/ null);
-
-        assertThat(dataProcessManager.getStartTimestampOfBatteryLevelData()).isEqualTo(0);
-    }
-
-    @Test
     public void getBatteryLevelData_emptyHistoryMap_returnNull() {
         assertThat(DataProcessManager.getBatteryLevelData(
                 mContext,
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
index 1d3f72b..aa15472 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
@@ -93,7 +93,7 @@
         mFeatureFactory = FakeFeatureFactory.setupForTest();
         mPowerUsageFeatureProvider = mFeatureFactory.powerUsageFeatureProvider;
 
-        DataProcessor.sTestSystemAppsSet = Set.of();
+        DataProcessor.sTestSystemAppsPackageNames = Set.of();
         DataProcessor.sUsageStatsManager = mUsageStatsManager;
         doReturn(mIntent).when(mContext).registerReceiver(
                 isA(BroadcastReceiver.class), isA(IntentFilter.class));
@@ -250,7 +250,7 @@
 
         final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>> periodMap =
                 DataProcessor.generateAppUsagePeriodMap(
-                        hourlyBatteryLevelsPerDay, appUsageEventList);
+                        14400000L, hourlyBatteryLevelsPerDay, appUsageEventList);
 
         assertThat(periodMap).hasSize(3);
         // Day 1
@@ -288,7 +288,7 @@
         hourlyBatteryLevelsPerDay.add(
                 new BatteryLevelData.PeriodBatteryLevelData(new ArrayList<>(), new ArrayList<>()));
         assertThat(DataProcessor.generateAppUsagePeriodMap(
-                hourlyBatteryLevelsPerDay, new ArrayList<>())).isNull();
+                0L, hourlyBatteryLevelsPerDay, new ArrayList<>())).isNull();
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/inputmethod/KeyboardLayoutPickerControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/KeyboardLayoutPickerControllerTest.java
index 52d1083..734f610 100644
--- a/tests/robotests/src/com/android/settings/inputmethod/KeyboardLayoutPickerControllerTest.java
+++ b/tests/robotests/src/com/android/settings/inputmethod/KeyboardLayoutPickerControllerTest.java
@@ -93,13 +93,13 @@
     }
 
     @Test
-    public void testLifecycle_onStart_NoInputDevice_shouldFinish() {
+    public void testLifecycle_onStart_NoInputDevice_shouldReturn() {
         final FragmentActivity activity = Robolectric.setupActivity(FragmentActivity.class);
         when(mInputManager.getInputDeviceByDescriptor(anyString())).thenReturn(null);
         when(mFragment.getActivity()).thenReturn(activity);
 
         mController.onStart();
-        assertThat(activity.isFinishing()).isTrue();
+        verify(mInputManager, never()).getEnabledKeyboardLayoutsForInputDevice(any());
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceControllerTest.java
index d675e89..df05203 100644
--- a/tests/robotests/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceControllerTest.java
@@ -24,12 +24,13 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
 import android.view.InputDevice;
 
 import androidx.preference.Preference;
 
-import com.android.settings.R;
+import com.android.settings.inputmethod.PhysicalKeyboardFragment.HardKeyboardDeviceInfo;
 import com.android.settings.testutils.shadow.ShadowInputDevice;
 
 import org.junit.After;
@@ -42,15 +43,24 @@
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @RunWith(RobolectricTestRunner.class)
 public class PhysicalKeyboardPreferenceControllerTest {
 
+    private static final String DEVICE_NAME = "deviceName";
+    private static final String LAYOUT_LABEL = "deviceLayutLabel";
+    private static final String BLUETOOTHADDRESS = "deviceBluetoothAddress";
+
     @Mock
     private Context mContext;
     @Mock
     private InputManager mIm;
     @Mock
     private Preference mPreference;
+    @Mock
+    private InputDeviceIdentifier mIdentifier;
 
     private PhysicalKeyboardPreferenceController mController;
 
@@ -69,9 +79,18 @@
     @Test
     public void testPhysicalKeyboard_byDefault_shouldBeShown() {
         final Context context = spy(RuntimeEnvironment.application.getApplicationContext());
-        mController = new PhysicalKeyboardPreferenceController(context, null);
+        List<HardKeyboardDeviceInfo> keyboards = new ArrayList<>();
+        keyboards.add(new HardKeyboardDeviceInfo(
+                DEVICE_NAME,
+                mIdentifier,
+                LAYOUT_LABEL,
+                BLUETOOTHADDRESS));
+        mController = spy(new PhysicalKeyboardPreferenceController(context, null));
+        when(mController.getKeyboards()).thenReturn(keyboards);
 
-        assertThat(mController.isAvailable()).isTrue();
+        boolean result = mController.isAvailable();
+
+        assertThat(result).isTrue();
     }
 
     @Test
@@ -85,11 +104,11 @@
 
     @Test
     @Config(shadows = ShadowInputDevice.class)
-    public void updateState_noKeyboard_setDisconnectedSummary() {
+    public void updateState_noKeyboard_setPreferenceVisibleFalse() {
         ShadowInputDevice.sDeviceIds = new int[0];
         mController.updateState(mPreference);
 
-        verify(mPreference).setSummary(R.string.keyboard_disconnected);
+        verify(mPreference).setVisible(false);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceControllerTest.java
new file mode 100644
index 0000000..bcb641d
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceControllerTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2023 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.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.notification.NotificationBackend;
+import com.android.settingslib.PrimarySwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.shadows.ShadowApplication;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+@RunWith(RobolectricTestRunner.class)
+public class AppChannelsBypassingDndPreferenceControllerTest {
+
+    @Mock
+    private NotificationBackend mBackend;
+
+    private NotificationBackend.AppRow mAppRow;
+    private AppChannelsBypassingDndPreferenceController mController;
+
+    private PreferenceScreen mPreferenceScreen;
+    private PreferenceCategory mCategory;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        Context context = ApplicationProvider.getApplicationContext();
+
+        mAppRow = new NotificationBackend.AppRow();
+        mAppRow.uid = 42;
+        mAppRow.pkg = "com.example.exampling";
+
+        mController = new AppChannelsBypassingDndPreferenceController(context, mBackend);
+        mController.onResume(mAppRow, null, null, null, null, null, new ArrayList<>());
+
+        PreferenceManager preferenceManager = new PreferenceManager(context);
+        mPreferenceScreen = preferenceManager.createPreferenceScreen(context);
+        mCategory = new PreferenceCategory(context);
+        mCategory.setKey(AppChannelsBypassingDndPreferenceController.KEY);
+        mPreferenceScreen.addPreference(mCategory);
+    }
+
+    @Test
+    public void displayPreference_showsAllAndChannels() {
+        when(mBackend.getGroups(eq(mAppRow.pkg), eq(mAppRow.uid))).thenReturn(
+                buildGroupList(true, true, false));
+
+        mController.displayPreference(mPreferenceScreen);
+        ShadowApplication.runBackgroundTasks();
+
+        assertThat(mCategory.getPreferenceCount()).isEqualTo(4); // "All" + 3 channels
+        assertThat(mCategory.getPreference(0).getTitle().toString()).isEqualTo(
+                "Allow all notifications");
+        assertThat(mCategory.getPreference(1).getTitle().toString()).isEqualTo("Channel 1");
+        assertThat(mCategory.getPreference(2).getTitle().toString()).isEqualTo("Channel 2");
+        assertThat(mCategory.getPreference(3).getTitle().toString()).isEqualTo("Channel 3");
+    }
+
+    @Test
+    public void displayPreference_canToggleAllInterrupt() {
+        when(mBackend.getGroups(eq(mAppRow.pkg), eq(mAppRow.uid))).thenReturn(
+                buildGroupList(true, true, false));
+
+        mController.displayPreference(mPreferenceScreen);
+        ShadowApplication.runBackgroundTasks();
+
+        assertThat(mCategory.getPreference(0).isEnabled()).isTrue();
+    }
+
+    @Test
+    public void displayPreference_canToggleInterruptIfChannelEnabled() {
+        when(mBackend.getGroups(eq(mAppRow.pkg), eq(mAppRow.uid))).thenReturn(
+                buildGroupList(true, false, true));
+
+        mController.displayPreference(mPreferenceScreen);
+        ShadowApplication.runBackgroundTasks();
+
+        assertThat(((PrimarySwitchPreference) mCategory.getPreference(
+                1)).isSwitchEnabled()).isTrue();
+        assertThat(((PrimarySwitchPreference) mCategory.getPreference(
+                2)).isSwitchEnabled()).isFalse();
+        assertThat(((PrimarySwitchPreference) mCategory.getPreference(
+                3)).isSwitchEnabled()).isTrue();
+    }
+
+    @Test
+    public void displayPreference_appBlocked_cannotToggleAllOrChannelInterrupts() {
+        mAppRow.banned = true;
+        when(mBackend.getGroups(eq(mAppRow.pkg), eq(mAppRow.uid))).thenReturn(
+                buildGroupList(true, false, true));
+
+        mController.displayPreference(mPreferenceScreen);
+        ShadowApplication.runBackgroundTasks();
+
+        assertThat(mCategory.getPreference(0).isEnabled()).isFalse();
+        assertThat(((PrimarySwitchPreference) mCategory.getPreference(
+                1)).isSwitchEnabled()).isFalse();
+        assertThat(((PrimarySwitchPreference) mCategory.getPreference(
+                2)).isSwitchEnabled()).isFalse();
+        assertThat(((PrimarySwitchPreference) mCategory.getPreference(
+                3)).isSwitchEnabled()).isFalse();
+    }
+
+    private static ParceledListSlice<NotificationChannelGroup> buildGroupList(
+            boolean... enabledByChannel) {
+        NotificationChannelGroup group = new NotificationChannelGroup("group", "The Group");
+        for (int i = 0; i < enabledByChannel.length; i++) {
+            group.addChannel(new NotificationChannel("channel-" + (i + 1), "Channel " + (i + 1),
+                    enabledByChannel[i] ? NotificationManager.IMPORTANCE_DEFAULT
+                            : NotificationManager.IMPORTANCE_NONE));
+        }
+        return new ParceledListSlice<>(Collections.singletonList(group));
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java
index 2777529..fcab797 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java
@@ -2,7 +2,7 @@
 
 import static com.android.settings.password.TestUtils.COMPONENT_NAME;
 import static com.android.settings.password.TestUtils.VALID_REMAINING_ATTEMPTS;
-import static com.android.settings.password.TestUtils.createStartLockscreenValidationRequest;
+import static com.android.settings.password.TestUtils.createRemoteLockscreenValidationSession;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -15,7 +15,7 @@
 
 import android.app.Activity;
 import android.app.KeyguardManager;
-import android.app.StartLockscreenValidationRequest;
+import android.app.RemoteLockscreenValidationSession;
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -170,13 +170,13 @@
     public void launchConfirmPassword_remoteValidation_passwordLockType() throws Exception {
         Activity activity = Robolectric.setupActivity(Activity.class);
         ShadowActivity shadowActivity = Shadows.shadowOf(activity);
-        StartLockscreenValidationRequest request = createStartLockscreenValidationRequest(
+        RemoteLockscreenValidationSession request = createRemoteLockscreenValidationSession(
                 KeyguardManager.PASSWORD, VALID_REMAINING_ATTEMPTS);
 
         ChooseLockSettingsHelper chooseLockSettingsHelper = getChooseLockSettingsHelper(
                 new ChooseLockSettingsHelper.Builder(activity)
                         .setRemoteLockscreenValidation(true)
-                        .setStartLockscreenValidationRequest(request)
+                        .setRemoteLockscreenValidationSession(request)
                         .setRemoteLockscreenValidationServiceComponent(COMPONENT_NAME));
         chooseLockSettingsHelper.launch();
 
@@ -187,8 +187,8 @@
                 ConfirmDeviceCredentialBaseFragment.IS_REMOTE_LOCKSCREEN_VALIDATION, false)
         ).isTrue();
         assertThat(startedIntent.getParcelableExtra(
-                KeyguardManager.EXTRA_START_LOCKSCREEN_VALIDATION_REQUEST,
-                StartLockscreenValidationRequest.class)
+                KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
+                RemoteLockscreenValidationSession.class)
         ).isEqualTo(request);
         assertThat(startedIntent.getParcelableExtra(
                 Intent.EXTRA_COMPONENT_NAME, ComponentName.class)
@@ -199,13 +199,13 @@
     public void launchConfirmPassword_remoteValidation_pinLockType() throws Exception {
         Activity activity = Robolectric.setupActivity(Activity.class);
         ShadowActivity shadowActivity = Shadows.shadowOf(activity);
-        StartLockscreenValidationRequest request = createStartLockscreenValidationRequest(
+        RemoteLockscreenValidationSession request = createRemoteLockscreenValidationSession(
                 KeyguardManager.PIN, VALID_REMAINING_ATTEMPTS);
 
         ChooseLockSettingsHelper chooseLockSettingsHelper = getChooseLockSettingsHelper(
                 new ChooseLockSettingsHelper.Builder(activity)
                         .setRemoteLockscreenValidation(true)
-                        .setStartLockscreenValidationRequest(request)
+                        .setRemoteLockscreenValidationSession(request)
                         .setRemoteLockscreenValidationServiceComponent(COMPONENT_NAME));
         chooseLockSettingsHelper.launch();
 
@@ -216,8 +216,8 @@
                 ConfirmDeviceCredentialBaseFragment.IS_REMOTE_LOCKSCREEN_VALIDATION, false)
         ).isTrue();
         assertThat(startedIntent.getParcelableExtra(
-                KeyguardManager.EXTRA_START_LOCKSCREEN_VALIDATION_REQUEST,
-                StartLockscreenValidationRequest.class)
+                KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
+                RemoteLockscreenValidationSession.class)
         ).isEqualTo(request);
         assertThat(startedIntent.getParcelableExtra(
                 Intent.EXTRA_COMPONENT_NAME, ComponentName.class)
@@ -228,13 +228,13 @@
     public void launchConfirmPattern_remoteValidation_patternLockType() throws Exception {
         Activity activity = Robolectric.setupActivity(Activity.class);
         ShadowActivity shadowActivity = Shadows.shadowOf(activity);
-        StartLockscreenValidationRequest request = createStartLockscreenValidationRequest(
+        RemoteLockscreenValidationSession request = createRemoteLockscreenValidationSession(
                 KeyguardManager.PATTERN, VALID_REMAINING_ATTEMPTS);
 
         ChooseLockSettingsHelper chooseLockSettingsHelper = getChooseLockSettingsHelper(
                 new ChooseLockSettingsHelper.Builder(activity)
                         .setRemoteLockscreenValidation(true)
-                        .setStartLockscreenValidationRequest(request)
+                        .setRemoteLockscreenValidationSession(request)
                         .setRemoteLockscreenValidationServiceComponent(COMPONENT_NAME));
         chooseLockSettingsHelper.launch();
 
@@ -245,8 +245,8 @@
                 ConfirmDeviceCredentialBaseFragment.IS_REMOTE_LOCKSCREEN_VALIDATION, false)
         ).isTrue();
         assertThat(startedIntent.getParcelableExtra(
-                KeyguardManager.EXTRA_START_LOCKSCREEN_VALIDATION_REQUEST,
-                StartLockscreenValidationRequest.class)
+                KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
+                RemoteLockscreenValidationSession.class)
         ).isEqualTo(request);
         assertThat(startedIntent.getParcelableExtra(
                 Intent.EXTRA_COMPONENT_NAME, ComponentName.class)
diff --git a/tests/robotests/src/com/android/settings/password/ConfirmCredentialTest.java b/tests/robotests/src/com/android/settings/password/ConfirmCredentialTest.java
index 40b359e..299b1eb 100644
--- a/tests/robotests/src/com/android/settings/password/ConfirmCredentialTest.java
+++ b/tests/robotests/src/com/android/settings/password/ConfirmCredentialTest.java
@@ -23,7 +23,7 @@
 import static com.android.settings.password.TestUtils.buildConfirmDeviceCredentialBaseActivity;
 import static com.android.settings.password.TestUtils.createPackageInfoWithService;
 import static com.android.settings.password.TestUtils.createRemoteLockscreenValidationIntent;
-import static com.android.settings.password.TestUtils.createStartLockscreenValidationRequest;
+import static com.android.settings.password.TestUtils.createRemoteLockscreenValidationSession;
 import static com.android.settings.password.TestUtils.getConfirmDeviceCredentialBaseFragment;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -132,8 +132,8 @@
             throws Exception {
         Intent intentWithInvalidComponentName = new Intent()
                 .putExtra(ConfirmDeviceCredentialBaseFragment.IS_REMOTE_LOCKSCREEN_VALIDATION, true)
-                .putExtra(KeyguardManager.EXTRA_START_LOCKSCREEN_VALIDATION_REQUEST,
-                        createStartLockscreenValidationRequest(
+                .putExtra(KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
+                        createRemoteLockscreenValidationSession(
                                 KeyguardManager.PASSWORD, VALID_REMAINING_ATTEMPTS))
                 .putExtra(Intent.EXTRA_COMPONENT_NAME, new ComponentName("pkg", "cls"));
 
diff --git a/tests/robotests/src/com/android/settings/password/TestUtils.java b/tests/robotests/src/com/android/settings/password/TestUtils.java
index 246d926..ef08f05 100644
--- a/tests/robotests/src/com/android/settings/password/TestUtils.java
+++ b/tests/robotests/src/com/android/settings/password/TestUtils.java
@@ -18,7 +18,7 @@
 
 import android.app.KeyguardManager;
 import android.app.RemoteLockscreenValidationResult;
-import android.app.StartLockscreenValidationRequest;
+import android.app.RemoteLockscreenValidationSession;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -79,15 +79,15 @@
             int lockscreenType, int remainingAttempts) throws Exception {
         return new Intent()
                 .putExtra(ConfirmDeviceCredentialBaseFragment.IS_REMOTE_LOCKSCREEN_VALIDATION, true)
-                .putExtra(KeyguardManager.EXTRA_START_LOCKSCREEN_VALIDATION_REQUEST,
-                        createStartLockscreenValidationRequest(lockscreenType, remainingAttempts))
+                .putExtra(KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
+                        createRemoteLockscreenValidationSession(lockscreenType, remainingAttempts))
                 .putExtra(Intent.EXTRA_COMPONENT_NAME, COMPONENT_NAME);
     }
 
-    public static StartLockscreenValidationRequest createStartLockscreenValidationRequest(
+    public static RemoteLockscreenValidationSession createRemoteLockscreenValidationSession(
             int lockscreenType, int remainingAttempts) throws NoSuchAlgorithmException {
-        return new StartLockscreenValidationRequest.Builder()
-                .setLockscreenUiType(lockscreenType)
+        return new RemoteLockscreenValidationSession.Builder()
+                .setLockType(lockscreenType)
                 .setRemainingAttempts(remainingAttempts)
                 .setSourcePublicKey(SecureBox.genKeyPair().getPublic().getEncoded())
                 .build();
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
index 7f8a06d..582f792 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
@@ -41,6 +41,8 @@
 import android.widget.TextView;
 
 import androidx.fragment.app.FragmentActivity;
+import androidx.lifecycle.ViewModelStoreOwner;
+import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 import androidx.test.core.app.ApplicationProvider;
 
@@ -49,6 +51,8 @@
 import com.android.settings.dashboard.RestrictedDashboardFragment;
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.testutils.shadow.ShadowFragment;
+import com.android.settings.wifi.factory.WifiFeatureProvider;
+import com.android.settings.wifi.repository.WifiHotspotRepository;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -90,6 +94,10 @@
     private PreferenceScreen mPreferenceScreen;
     @Mock
     private TextView mEmptyTextView;
+    @Mock
+    WifiTetherViewModel mWifiTetherViewModel;
+    @Mock
+    WifiHotspotRepository mWifiHotspotRepository;
 
     private WifiTetherSettings mWifiTetherSettings;
 
@@ -106,6 +114,11 @@
         when(mWifiRestriction.isTetherAvailable(mContext)).thenReturn(true);
         when(mWifiRestriction.isHotspotAvailable(mContext)).thenReturn(true);
 
+        WifiFeatureProvider provider = FakeFeatureFactory.setupForTest().getWifiFeatureProvider();
+        when(provider.getWifiHotspotRepository()).thenReturn(mWifiHotspotRepository);
+        when(provider.getWifiTetherViewModel(mock(ViewModelStoreOwner.class)))
+                .thenReturn(mWifiTetherViewModel);
+
         mWifiTetherSettings = new WifiTetherSettings(mWifiRestriction);
     }
 
@@ -143,6 +156,16 @@
     }
 
     @Test
+    public void onSpeedSummaryChanged_canNotShowWifiHotspot_returnFalse() {
+        int stringResId = R.string.wifi_hotspot_speed_6g_summary;
+        mWifiTetherSettings.mWifiHotspotSpeed = mock(Preference.class);
+
+        mWifiTetherSettings.onSpeedSummaryChanged(stringResId);
+
+        verify(mWifiTetherSettings.mWifiHotspotSpeed).setSummary(stringResId);
+    }
+
+    @Test
     public void createPreferenceControllers_getPreferenceControllersNotEmpty() {
         assertThat(WifiTetherSettings.SEARCH_INDEX_DATA_PROVIDER.getPreferenceControllers(mContext))
                 .isNotEmpty();
diff --git a/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt b/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt
index 8a894d5..46b956e 100644
--- a/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt
@@ -25,12 +25,15 @@
 import com.android.settings.spa.SpaActivity.Companion.startSpaActivityForApp
 import com.android.settingslib.spa.framework.util.KEY_DESTINATION
 import com.google.common.truth.Truth.assertThat
+import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Answers
 import org.mockito.ArgumentCaptor
 import org.mockito.Mock
 import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
 import org.mockito.junit.MockitoJUnit
 import org.mockito.junit.MockitoRule
 
@@ -39,9 +42,14 @@
     @get:Rule
     val mockito: MockitoRule = MockitoJUnit.rule()
 
-    @Mock
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private lateinit var context: Context
 
+    @Before
+    fun setUp() {
+        `when`(context.applicationContext.packageName).thenReturn("com.android.settings")
+    }
+
     @Test
     fun startSpaActivity() {
         context.startSpaActivity(DESTINATION)
diff --git a/tests/spa_unit/src/com/android/settings/spa/core/instrumentation/MetricsDataModelTest.kt b/tests/spa_unit/src/com/android/settings/spa/core/instrumentation/MetricsDataModelTest.kt
new file mode 100644
index 0000000..2ba0302
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/spa/core/instrumentation/MetricsDataModelTest.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2023 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.spa.core.instrumentation
+
+import android.os.SystemClock
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests for {@link MetricsDataModel}. */
+@RunWith(AndroidJUnit4::class)
+class MetricsDataModelTest {
+    private val TEST_PID = "pseudo_page_id"
+
+    private lateinit var metricsDataModel: MetricsDataModel
+
+    @Before
+    fun setUp() {
+        metricsDataModel = MetricsDataModel()
+    }
+
+    @Test
+    fun initMetricsDataModel() {
+        assertThat(metricsDataModel.pageTimeStampList.size).isEqualTo(0)
+    }
+
+    @Test
+    fun addTimeStamp_addOnePageTimeStamp_sizeShouldBeOne() {
+        metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, System.currentTimeMillis()))
+
+        assertThat(metricsDataModel.pageTimeStampList.size).isEqualTo(1)
+    }
+
+    @Test
+    fun addTimeStamp_addTwoSamePageTimeStamp_sizeShouldBeTwo() {
+        metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, System.currentTimeMillis()))
+        metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, System.currentTimeMillis()))
+
+        assertThat(metricsDataModel.pageTimeStampList.size).isEqualTo(2)
+    }
+
+    @Test
+    fun getPageDuration_getExistPageId_mustFoundValue() {
+        metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, System.currentTimeMillis()))
+        SystemClock.sleep(5)
+
+        assertThat(metricsDataModel.getPageDuration(TEST_PID).toInt()).isGreaterThan(0)
+        assertThat(metricsDataModel.pageTimeStampList.size).isEqualTo(0)
+    }
+
+    @Test
+    fun getPageDuration_getNonExistPageId_valueShouldBeZero() {
+        metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, System.currentTimeMillis()))
+
+        assertThat(metricsDataModel.getPageDuration("WRONG_ID").toLong()).isEqualTo(0L)
+    }
+
+    @Test
+    fun getPageDuration_getExistPageIdAndDonotRemoved_sizeShouldBeOne() {
+        metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, System.currentTimeMillis()))
+        SystemClock.sleep(5)
+
+        assertThat(metricsDataModel.getPageDuration(TEST_PID, false).toLong()).isGreaterThan(0L)
+        assertThat(metricsDataModel.pageTimeStampList.size).isEqualTo(1)
+    }
+
+    @Test
+    fun getPageDuration_getTwoExistPageId_theOrderIsLIFO() {
+        metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, 10000L))
+        metricsDataModel.addTimeStamp(PageTimeStamp(TEST_PID, 20000L))
+
+        // The formula is d1 = t1 - 20000, d2 = t2 - 10000
+        // d2 - d1 = t2 - t1 + 10000, because t2 > t1 the result of d2 - d1 is greater 10000
+        val duration1 = metricsDataModel.getPageDuration(TEST_PID).toLong()
+        SystemClock.sleep(5)
+        val duration2 = metricsDataModel.getPageDuration(TEST_PID).toLong()
+
+        assertThat(duration2 - duration1).isGreaterThan(10000L)
+    }
+}
\ No newline at end of file
diff --git a/tests/spa_unit/src/com/android/settings/spa/core/instrumentation/SpaLogDataTest.kt b/tests/spa_unit/src/com/android/settings/spa/core/instrumentation/SpaLogDataTest.kt
new file mode 100644
index 0000000..19be10e
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/spa/core/instrumentation/SpaLogDataTest.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 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.spa.core.instrumentation
+
+import android.app.settings.SettingsEnums
+import android.os.Bundle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.framework.common.LOG_DATA_SESSION_NAME
+import com.android.settingslib.spa.framework.common.LogEvent
+import com.android.settingslib.spa.framework.util.SESSION_BROWSE
+import com.android.settingslib.spa.framework.util.SESSION_SEARCH
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests for {@link SpaLogData}. */
+@RunWith(AndroidJUnit4::class)
+class SpaLogDataTest {
+    private val TEST_PID = "pseudo_page_id"
+
+    private lateinit var bundle: Bundle
+    private lateinit var dataModel: MetricsDataModel
+
+    @Before
+    fun setUp() {
+        bundle = Bundle()
+        dataModel = MetricsDataModel()
+    }
+
+    @Test
+    fun getSessionType_withoutSessionExtraData_returnSessionUnknow() {
+        val spaLogData = SpaLogData(TEST_PID, LogEvent.PAGE_ENTER, bundle, dataModel)
+
+        assertThat(spaLogData.getSessionType()).isEqualTo(SettingsEnums.SESSION_UNKNOWN)
+    }
+
+    @Test
+    fun getSessionType_hasSessionBrowseExtraData_returnSessionBrowse() {
+        bundle.putString(LOG_DATA_SESSION_NAME, SESSION_BROWSE)
+        val spaLogData = SpaLogData(TEST_PID, LogEvent.PAGE_ENTER, bundle, dataModel)
+
+        assertThat(spaLogData.getSessionType()).isEqualTo(SettingsEnums.BROWSE)
+    }
+
+    @Test
+    fun getSessionType_hasSessionSearchExtraData_returnSessionSearch() {
+        bundle.putString(LOG_DATA_SESSION_NAME, SESSION_SEARCH)
+        val spaLogData = SpaLogData(TEST_PID, LogEvent.PAGE_ENTER, bundle, dataModel)
+
+        assertThat(spaLogData.getSessionType()).isEqualTo(SettingsEnums.SEARCH)
+    }
+
+    @Test
+    fun getSessionType_hasSessionUnknownExtraData_returnSessionUnknow() {
+        bundle.putString(LOG_DATA_SESSION_NAME, "SESSION_OTHER")
+        val spaLogData = SpaLogData(TEST_PID, LogEvent.PAGE_ENTER, bundle, dataModel)
+
+        assertThat(spaLogData.getSessionType()).isEqualTo(SettingsEnums.SESSION_UNKNOWN)
+    }
+
+    @Test
+    fun getPageId_withPageEvent_returnInputId() {
+        val spaLogData1 = SpaLogData(TEST_PID, LogEvent.PAGE_ENTER, bundle, dataModel)
+        assertThat(spaLogData1.getPageId()).isEqualTo(TEST_PID)
+
+        val spaLogData2 = SpaLogData(TEST_PID, LogEvent.PAGE_LEAVE, bundle, dataModel)
+        assertThat(spaLogData2.getPageId()).isEqualTo(TEST_PID)
+    }
+}
diff --git a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
index ff7e71a..2633ea7 100644
--- a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
@@ -27,12 +27,14 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ServiceInfo;
+import android.credentials.CredentialProviderInfo;
 import android.os.Looper;
 
 import androidx.lifecycle.Lifecycle;
 import androidx.preference.PreferenceCategory;
 import androidx.preference.PreferenceManager;
 import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
@@ -87,7 +89,7 @@
     @Test
     public void getAvailabilityStatus_withServices_returnsAvailable() {
         CredentialManagerPreferenceController controller =
-                createControllerWithServices(Lists.newArrayList(createServiceInfo()));
+                createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
         assertThat(controller.isConnected()).isFalse();
         assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
     }
@@ -103,24 +105,59 @@
     @Test
     public void displayPreference_withServices_preferencesAdded() {
         CredentialManagerPreferenceController controller =
-                createControllerWithServices(Lists.newArrayList(createServiceInfo()));
+                createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
         controller.displayPreference(mScreen);
         assertThat(controller.isConnected()).isFalse();
         assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(1);
     }
 
     @Test
+    public void buildSwitchPreference() {
+        CredentialProviderInfo providerInfo1 =
+                createCredentialProviderInfo(
+                        "com.android.provider1", "ClassA", "Service Title", false);
+        CredentialProviderInfo providerInfo2 =
+                createCredentialProviderInfo(
+                        "com.android.provider2", "ClassA", "Service Title", false);
+        CredentialManagerPreferenceController controller =
+                createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
+        assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+        assertThat(controller.isConnected()).isFalse();
+
+        // Test the data is correct.
+        assertThat(providerInfo1.isEnabled()).isFalse();
+        assertThat(providerInfo2.isEnabled()).isFalse();
+        assertThat(controller.getEnabledProviders().size()).isEqualTo(0);
+
+        // Toggle one provider and make sure it worked.
+        assertThat(controller.togglePackageNameEnabled("com.android.provider1")).isTrue();
+        Set<String> enabledProviders = controller.getEnabledProviders();
+        assertThat(enabledProviders.size()).isEqualTo(1);
+        assertThat(enabledProviders.contains("com.android.provider1")).isTrue();
+
+        // Create the pref (checked).
+        SwitchPreference pref = controller.createPreference(mContext, providerInfo1);
+        assertThat(pref.getTitle().toString()).isEqualTo("Service Title");
+        assertThat(pref.isChecked()).isTrue();
+
+        // Create the pref (not checked).
+        SwitchPreference pref2 = controller.createPreference(mContext, providerInfo2);
+        assertThat(pref2.getTitle().toString()).isEqualTo("Service Title");
+        assertThat(pref2.isChecked()).isFalse();
+    }
+
+    @Test
     public void getAvailabilityStatus_handlesToggleAndSave() {
         CredentialManagerPreferenceController controller =
                 createControllerWithServices(
                         Lists.newArrayList(
-                                createServiceInfo("com.android.provider1", "ClassA"),
-                                createServiceInfo("com.android.provider1", "ClassB"),
-                                createServiceInfo("com.android.provider2", "ClassA"),
-                                createServiceInfo("com.android.provider3", "ClassA"),
-                                createServiceInfo("com.android.provider4", "ClassA"),
-                                createServiceInfo("com.android.provider5", "ClassA"),
-                                createServiceInfo("com.android.provider6", "ClassA")));
+                                createCredentialProviderInfo("com.android.provider1", "ClassA"),
+                                createCredentialProviderInfo("com.android.provider1", "ClassB"),
+                                createCredentialProviderInfo("com.android.provider2", "ClassA"),
+                                createCredentialProviderInfo("com.android.provider3", "ClassA"),
+                                createCredentialProviderInfo("com.android.provider4", "ClassA"),
+                                createCredentialProviderInfo("com.android.provider5", "ClassA"),
+                                createCredentialProviderInfo("com.android.provider6", "ClassA")));
         assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
         assertThat(controller.isConnected()).isFalse();
 
@@ -177,8 +214,38 @@
         assertThat(currentlyEnabledServices.contains("com.android.provider6/ClassA")).isFalse();
     }
 
+    @Test
+    public void handlesCredentialProviderInfoEnabledDisabled() {
+        CredentialProviderInfo providerInfo1 =
+                createCredentialProviderInfo(
+                        "com.android.provider1", "ClassA", "Service Title", false);
+        CredentialProviderInfo providerInfo2 =
+                createCredentialProviderInfo(
+                        "com.android.provider2", "ClassA", "Service Title", true);
+        CredentialManagerPreferenceController controller =
+                createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
+        assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+        assertThat(controller.isConnected()).isFalse();
+
+        // Test the data is correct.
+        assertThat(providerInfo1.isEnabled()).isFalse();
+        assertThat(providerInfo2.isEnabled()).isTrue();
+
+        // Check that they are all actually registered.
+        Set<String> enabledProviders = controller.getEnabledProviders();
+        assertThat(enabledProviders.size()).isEqualTo(1);
+        assertThat(enabledProviders.contains("com.android.provider1")).isFalse();
+        assertThat(enabledProviders.contains("com.android.provider2")).isTrue();
+
+        // Check that the settings string has the right component names.
+        List<String> enabledServices = controller.getEnabledSettings();
+        assertThat(enabledServices.size()).isEqualTo(1);
+        assertThat(enabledServices.contains("com.android.provider1/ClassA")).isFalse();
+        assertThat(enabledServices.contains("com.android.provider2/ClassA")).isTrue();
+    }
+
     private CredentialManagerPreferenceController createControllerWithServices(
-            List<ServiceInfo> availableServices) {
+            List<CredentialProviderInfo> availableServices) {
         CredentialManagerPreferenceController controller =
                 new CredentialManagerPreferenceController(
                         mContext, mCredentialsPreferenceCategory.getKey());
@@ -186,11 +253,17 @@
         return controller;
     }
 
-    private ServiceInfo createServiceInfo() {
-        return createServiceInfo("com.android.provider", "CredManProvider");
+    private CredentialProviderInfo createCredentialProviderInfo() {
+        return createCredentialProviderInfo("com.android.provider", "CredManProvider");
     }
 
-    private ServiceInfo createServiceInfo(String packageName, String className) {
+    private CredentialProviderInfo createCredentialProviderInfo(
+            String packageName, String className) {
+        return createCredentialProviderInfo(packageName, className, null, false);
+    }
+
+    private CredentialProviderInfo createCredentialProviderInfo(
+            String packageName, String className, CharSequence label, boolean isEnabled) {
         ServiceInfo si = new ServiceInfo();
         si.packageName = packageName;
         si.name = className;
@@ -200,6 +273,9 @@
         si.applicationInfo.packageName = packageName;
         si.applicationInfo.nonLocalizedLabel = "test";
 
-        return si;
+        return new CredentialProviderInfo.Builder(si)
+                .setOverrideLabel(label)
+                .setEnabled(isEnabled)
+                .build();
     }
 }
diff --git a/tests/unit/src/com/android/settings/biometrics2/repository/FingerprintRepositoryTest.java b/tests/unit/src/com/android/settings/biometrics2/repository/FingerprintRepositoryTest.java
index 727559b..8989595 100644
--- a/tests/unit/src/com/android/settings/biometrics2/repository/FingerprintRepositoryTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/repository/FingerprintRepositoryTest.java
@@ -29,9 +29,16 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+
 import android.content.Context;
 import android.content.res.Resources;
+import android.hardware.biometrics.SensorProperties;
 import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -46,6 +53,8 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
+import java.util.ArrayList;
+
 @RunWith(AndroidJUnit4.class)
 public class FingerprintRepositoryTest {
 
@@ -139,4 +148,56 @@
         assertThat(repository.getMaxFingerprintsInSuw(mResources)).isEqualTo(20);
     }
 
+    @Test
+    public void testGetFirstFingerprintSensorPropertiesInternal() {
+        final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
+        final FingerprintSensorPropertiesInternal prop = new FingerprintSensorPropertiesInternal(
+                0 /* sensorId */,
+                SensorProperties.STRENGTH_STRONG,
+                5,
+                new ArrayList<>() /* componentInfo */,
+                TYPE_UDFPS_OPTICAL,
+                true /* resetLockoutRequiresHardwareAuthToken */);
+        props.add(prop);
+        doAnswer(invocation -> {
+            final IFingerprintAuthenticatorsRegisteredCallback callback =
+                    invocation.getArgument(0);
+            callback.onAllAuthenticatorsRegistered(props);
+            return null;
+        }).when(mFingerprintManager).addAuthenticatorsRegisteredCallback(any());
+
+        final FingerprintRepository repository = new FingerprintRepository(mFingerprintManager);
+        assertThat(repository.getFirstFingerprintSensorPropertiesInternal()).isEqualTo(prop);
+    }
+
+    @Test
+    public void testGetEnrollStageCount() {
+        final FingerprintRepository repository = newFingerprintRepository(mFingerprintManager,
+                TYPE_UNKNOWN, 999);
+
+        final int expectedValue = 24;
+        doReturn(expectedValue).when(mFingerprintManager).getEnrollStageCount();
+
+        assertThat(repository.getEnrollStageCount()).isEqualTo(expectedValue);
+    }
+
+    @Test
+    public void testGetEnrollStageThreshold() {
+        final FingerprintRepository repository = newFingerprintRepository(mFingerprintManager,
+                TYPE_UNKNOWN, 999);
+
+        final float expectedValue0 = 0.42f;
+        final float expectedValue1 = 0.24f;
+        final float expectedValue2 = 0.33f;
+        final float expectedValue3 = 0.90f;
+        doReturn(expectedValue0).when(mFingerprintManager).getEnrollStageThreshold(0);
+        doReturn(expectedValue1).when(mFingerprintManager).getEnrollStageThreshold(1);
+        doReturn(expectedValue2).when(mFingerprintManager).getEnrollStageThreshold(2);
+        doReturn(expectedValue3).when(mFingerprintManager).getEnrollStageThreshold(3);
+
+        assertThat(repository.getEnrollStageThreshold(2)).isEqualTo(expectedValue2);
+        assertThat(repository.getEnrollStageThreshold(1)).isEqualTo(expectedValue1);
+        assertThat(repository.getEnrollStageThreshold(3)).isEqualTo(expectedValue3);
+        assertThat(repository.getEnrollStageThreshold(0)).isEqualTo(expectedValue0);
+    }
 }
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/model/CredentialModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/model/CredentialModelTest.java
index 57b7420..8dfca01 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/model/CredentialModelTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/model/CredentialModelTest.java
@@ -48,11 +48,10 @@
 
     private final Clock mClock = SystemClock.elapsedRealtimeClock();
 
-    public static Bundle newCredentialModelIntentExtras(int userId, long challenge, int sensorId,
+    public static Bundle newCredentialModelIntentExtras(int userId, long challenge,
             @Nullable byte[] token, long gkPwHandle) {
         final Bundle bundle = new Bundle();
         bundle.putInt(Intent.EXTRA_USER_ID, userId);
-        bundle.putInt(EXTRA_KEY_SENSOR_ID, sensorId);
         bundle.putLong(EXTRA_KEY_CHALLENGE, challenge);
         bundle.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
         bundle.putLong(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
@@ -60,17 +59,17 @@
     }
 
     public static Bundle newValidTokenCredentialIntentExtras(int userId) {
-        return newCredentialModelIntentExtras(userId, 1L, 1, new byte[] { 0, 1, 2 },
+        return newCredentialModelIntentExtras(userId, 1L, new byte[] { 0, 1, 2 },
                 INVALID_GK_PW_HANDLE);
     }
 
     public static Bundle newOnlySensorValidCredentialIntentExtras(int userId) {
-        return newCredentialModelIntentExtras(userId, INVALID_CHALLENGE, 1, null,
+        return newCredentialModelIntentExtras(userId, INVALID_CHALLENGE, null,
                 INVALID_GK_PW_HANDLE);
     }
 
     public static Bundle newGkPwHandleCredentialIntentExtras(int userId, long gkPwHandle) {
-        return newCredentialModelIntentExtras(userId, INVALID_CHALLENGE, 1, null, gkPwHandle);
+        return newCredentialModelIntentExtras(userId, INVALID_CHALLENGE, null, gkPwHandle);
     }
 
     private static void checkBundleLongValue(@NonNull Bundle bundle1, @NonNull Bundle bundle2,
@@ -118,7 +117,6 @@
             @NonNull CredentialModel model2) {
 
         assertThat(model1.getUserId()).isEqualTo(model2.getUserId());
-        assertThat(model1.getSensorId()).isEqualTo(model2.getSensorId());
         assertThat(model1.getChallenge()).isEqualTo(model2.getChallenge());
         assertThat(model1.getGkPwHandle()).isEqualTo(model2.getGkPwHandle());
 
@@ -154,7 +152,7 @@
 
     @Test
     public void testSameValueFromBundle() {
-        final Bundle bundle = newCredentialModelIntentExtras(1234, 6677L, 1,
+        final Bundle bundle = newCredentialModelIntentExtras(1234, 6677L,
                 new byte[] { 33, 44, 55 }, 987654321);
 
         final CredentialModel model1 = new CredentialModel(bundle, mClock);
@@ -165,7 +163,7 @@
 
     @Test
     public void testSameValueFromBundle_nullToken() {
-        final Bundle bundle = newCredentialModelIntentExtras(22, 33L, 1, null, 21L);
+        final Bundle bundle = newCredentialModelIntentExtras(22, 33L, null, 21L);
 
         final CredentialModel model1 = new CredentialModel(bundle, mClock);
         final CredentialModel model2 = new CredentialModel(model1.getBundle(), mClock);
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModelTest.java
index c12be68..05a7239 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModelTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModelTest.java
@@ -22,10 +22,8 @@
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
 
 import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_CHALLENGE;
-import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_SENSOR_ID;
 import static com.android.settings.biometrics2.ui.model.CredentialModel.INVALID_CHALLENGE;
 import static com.android.settings.biometrics2.ui.model.CredentialModel.INVALID_GK_PW_HANDLE;
-import static com.android.settings.biometrics2.ui.model.CredentialModel.INVALID_SENSOR_ID;
 import static com.android.settings.biometrics2.ui.model.CredentialModelTest.newCredentialModelIntentExtras;
 import static com.android.settings.biometrics2.ui.model.CredentialModelTest.newGkPwHandleCredentialIntentExtras;
 import static com.android.settings.biometrics2.ui.model.CredentialModelTest.newOnlySensorValidCredentialIntentExtras;
@@ -103,7 +101,7 @@
 
     @Test
     public void testSetCredentialModel_sameResultFromSavedInstanceOrIntent() {
-        final Bundle extras = newCredentialModelIntentExtras(12, 33, 1, new byte[] { 2, 3 }, 3L);
+        final Bundle extras = newCredentialModelIntentExtras(12, 33, new byte[] { 2, 3 }, 3L);
 
         AutoCredentialViewModel viewModel2 = new AutoCredentialViewModel(
                 ApplicationProvider.getApplicationContext(),
@@ -115,18 +113,9 @@
         mViewModel.onSaveInstanceState(savedInstance);
         viewModel2.setCredentialModel(savedInstance, new Intent());
 
-        final Bundle bundle1 = mViewModel.createCredentialIntentExtra();
-        final Bundle bundle2 = viewModel2.createCredentialIntentExtra();
-        assertThat(bundle1.getLong(EXTRA_KEY_GK_PW_HANDLE))
-                .isEqualTo(bundle2.getLong(EXTRA_KEY_GK_PW_HANDLE));
-        assertThat(bundle1.getLong(Intent.EXTRA_USER_ID))
-                .isEqualTo(bundle2.getLong(Intent.EXTRA_USER_ID));
-        assertThat(bundle1.getLong(EXTRA_KEY_CHALLENGE))
-                .isEqualTo(bundle2.getLong(EXTRA_KEY_CHALLENGE));
-        assertThat(bundle1.getInt(EXTRA_KEY_SENSOR_ID))
-                .isEqualTo(bundle2.getInt(EXTRA_KEY_SENSOR_ID));
-        final byte[] token1 = bundle1.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN);
-        final byte[] token2 = bundle2.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN);
+        assertThat(mViewModel.getUserId()).isEqualTo(viewModel2.getUserId());
+        final byte[] token1 = mViewModel.getToken();
+        final byte[] token2 = viewModel2.getToken();
         assertThat(token1).isNotNull();
         assertThat(token2).isNotNull();
         assertThat(token1.length).isEqualTo(token2.length);
@@ -138,7 +127,7 @@
     @Test
     public void testSetCredentialModel_sameResultFromSavedInstanceOrIntent_invalidValues() {
         final Bundle extras = newCredentialModelIntentExtras(UserHandle.USER_NULL,
-                INVALID_CHALLENGE, INVALID_SENSOR_ID, null, INVALID_GK_PW_HANDLE);
+                INVALID_CHALLENGE, null, INVALID_GK_PW_HANDLE);
 
         AutoCredentialViewModel viewModel2 = new AutoCredentialViewModel(
                 ApplicationProvider.getApplicationContext(),
@@ -150,16 +139,10 @@
         mViewModel.onSaveInstanceState(savedInstance);
         viewModel2.setCredentialModel(savedInstance, new Intent());
 
-        final Bundle bundle1 = mViewModel.createCredentialIntentExtra();
-        final Bundle bundle2 = viewModel2.createCredentialIntentExtra();
-        assertThat(bundle1.containsKey(EXTRA_KEY_GK_PW_HANDLE)).isFalse();
-        assertThat(bundle2.containsKey(EXTRA_KEY_GK_PW_HANDLE)).isFalse();
-        assertThat(bundle1.containsKey(EXTRA_KEY_CHALLENGE_TOKEN)).isFalse();
-        assertThat(bundle2.containsKey(EXTRA_KEY_CHALLENGE_TOKEN)).isFalse();
-        assertThat(bundle1.containsKey(EXTRA_KEY_SENSOR_ID)).isTrue();
-        assertThat(bundle2.containsKey(EXTRA_KEY_SENSOR_ID)).isTrue();
-        assertThat(bundle1.containsKey(Intent.EXTRA_USER_ID)).isFalse();
-        assertThat(bundle2.containsKey(Intent.EXTRA_USER_ID)).isFalse();
+        assertThat(mViewModel.getUserId()).isEqualTo(UserHandle.USER_NULL);
+        assertThat(viewModel2.getUserId()).isEqualTo(UserHandle.USER_NULL);
+        assertThat(mViewModel.getToken()).isNull();
+        assertThat(viewModel2.getToken()).isNull();
     }
 
     @Test
@@ -316,12 +299,7 @@
         assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isNull();
 
         // Check data inside CredentialModel
-        final Bundle extras = mViewModel.createCredentialIntentExtra();
-        assertThat(extras.getInt(EXTRA_KEY_SENSOR_ID)).isEqualTo(newSensorId);
-        assertThat(extras.getLong(EXTRA_KEY_CHALLENGE)).isEqualTo(newChallenge);
-        assertThat(extras.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN)).isNotNull();
-        assertThat(extras.getLong(EXTRA_KEY_GK_PW_HANDLE)).isEqualTo(INVALID_GK_PW_HANDLE);
-        assertThat(extras.getLong(EXTRA_KEY_CHALLENGE)).isNotEqualTo(INVALID_CHALLENGE);
+        assertThat(mViewModel.getToken()).isNotNull();
         assertThat(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
         assertThat(hasCalledRemoveGkPwHandle.get()).isFalse();
 
@@ -534,11 +512,7 @@
 
         assertThat(ret).isTrue();
         assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isNull();
-        final Bundle extras = mViewModel.createCredentialIntentExtra();
-        assertThat(extras.getInt(EXTRA_KEY_SENSOR_ID)).isEqualTo(newSensorId);
-        assertThat(extras.getLong(EXTRA_KEY_CHALLENGE)).isEqualTo(newChallenge);
-        assertThat(extras.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN)).isNotNull();
-        assertThat(extras.getLong(EXTRA_KEY_GK_PW_HANDLE)).isEqualTo(INVALID_GK_PW_HANDLE);
+        assertThat(mViewModel.getToken()).isNotNull();
         assertThat(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
         assertThat(hasCalledRemoveGkPwHandle.get()).isTrue();
     }
@@ -571,17 +545,13 @@
 
         assertThat(ret).isTrue();
         assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isNull();
-        final Bundle extras = mViewModel.createCredentialIntentExtra();
-        assertThat(extras.getInt(EXTRA_KEY_SENSOR_ID)).isEqualTo(newSensorId);
-        assertThat(extras.getLong(EXTRA_KEY_CHALLENGE)).isEqualTo(newChallenge);
-        assertThat(extras.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN)).isNotNull();
-        assertThat(extras.getLong(EXTRA_KEY_GK_PW_HANDLE)).isEqualTo(INVALID_GK_PW_HANDLE);
+        assertThat(mViewModel.getToken()).isNotNull();
         assertThat(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
         assertThat(hasCalledRemoveGkPwHandle.get()).isTrue();
     }
 
     public static class TestChallengeGenerator implements ChallengeGenerator {
-        public int mSensorId = INVALID_SENSOR_ID;
+        public int mSensorId = -1;
         public int mUserId = UserHandle.myUserId();
         public long mChallenge = INVALID_CHALLENGE;
         public int mCallbackRunCount = 0;
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModelTest.java
new file mode 100644
index 0000000..4de1057
--- /dev/null
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModelTest.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2023 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.biometrics2.ui.viewmodel;
+
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR;
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC;
+
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.ErrorDialogData;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_RESTART;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FingerprintErrorDialogAction;
+import static com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.newFingerprintRepository;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+
+import android.app.Application;
+import android.hardware.biometrics.SensorProperties;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
+
+import androidx.lifecycle.LiveData;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.biometrics2.data.repository.FingerprintRepository;
+import com.android.settings.testutils.InstantTaskExecutorRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+public class FingerprintEnrollEnrollingViewModelTest {
+
+    private static final int TEST_USER_ID = 33;
+
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+    @Rule
+    public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
+
+    @Mock
+    private FingerprintManager mFingerprintManager;
+
+    private Application mApplication;
+    private FingerprintEnrollEnrollingViewModel mViewModel;
+
+    @Before
+    public void setUp() {
+        mApplication = ApplicationProvider.getApplicationContext();
+        mViewModel = new FingerprintEnrollEnrollingViewModel(
+                mApplication,
+                TEST_USER_ID,
+                newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, 5)
+            );
+    }
+
+    @Test
+    public void testShowErrorDialogLiveData() {
+        assertThat(mViewModel.getErrorDialogLiveData().getValue()).isEqualTo(null);
+
+        final ErrorDialogData data = new ErrorDialogData("errMsg", "errTitle", 0);
+        mViewModel.showErrorDialog(data);
+        assertThat(mViewModel.getErrorDialogLiveData().getValue()).isEqualTo(data);
+    }
+
+    @Test
+    public void testIconTouchDialog() {
+        final LiveData<Integer> actionLiveData = mViewModel.getActionLiveData();
+        assertThat(actionLiveData.getValue()).isEqualTo(null);
+
+        mViewModel.showIconTouchDialog();
+        assertThat(actionLiveData.getValue()).isEqualTo(
+                FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG);
+
+        mViewModel.onIconTouchDialogDismiss();
+        assertThat(actionLiveData.getValue()).isEqualTo(
+                FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG);
+    }
+
+    @Test
+    public void testErrorDialogActionLiveData() {
+        assertThat(mViewModel.getErrorDialogActionLiveData().getValue()).isEqualTo(null);
+
+        @FingerprintErrorDialogAction int action = FINGERPRINT_ERROR_DIALOG_ACTION_RESTART;
+        mViewModel.onErrorDialogAction(action);
+        assertThat(mViewModel.getErrorDialogActionLiveData().getValue()).isEqualTo(action);
+
+        action = FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT;
+        mViewModel.onErrorDialogAction(action);
+        assertThat(mViewModel.getErrorDialogActionLiveData().getValue()).isEqualTo(action);
+
+        action = FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH;
+        mViewModel.onErrorDialogAction(action);
+        assertThat(mViewModel.getErrorDialogActionLiveData().getValue()).isEqualTo(action);
+    }
+
+    @Test
+    public void tesBackPressedScenario() {
+        final LiveData<Integer> actionLiveData = mViewModel.getActionLiveData();
+        assertThat(actionLiveData.getValue()).isEqualTo(null);
+        assertThat(mViewModel.getOnBackPressed()).isEqualTo(false);
+
+        mViewModel.setOnBackPressed();
+        assertThat(mViewModel.getOnBackPressed()).isEqualTo(true);
+
+        mViewModel.onCancelledDueToOnBackPressed();
+        assertThat(mViewModel.getOnBackPressed()).isEqualTo(false);
+        assertThat(actionLiveData.getValue()).isEqualTo(
+                FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED);
+    }
+
+    @Test
+    public void testSkipPressedScenario() {
+        final LiveData<Integer> actionLiveData = mViewModel.getActionLiveData();
+        assertThat(actionLiveData.getValue()).isEqualTo(null);
+        assertThat(mViewModel.getOnSkipPressed()).isEqualTo(false);
+
+        mViewModel.setOnSkipPressed();
+        assertThat(mViewModel.getOnSkipPressed()).isEqualTo(true);
+
+        mViewModel.onCancelledDueToOnSkipPressed();
+        assertThat(mViewModel.getOnSkipPressed()).isEqualTo(false);
+        assertThat(actionLiveData.getValue()).isEqualTo(
+                FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP);
+    }
+
+    @Test
+    public void testCanAssumeUdfps_forUdfpsUltrasonicSensor() {
+        mViewModel = new FingerprintEnrollEnrollingViewModel(
+                mApplication,
+                TEST_USER_ID,
+                newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_ULTRASONIC, 5)
+        );
+        assertThat(mViewModel.canAssumeUdfps()).isEqualTo(true);
+    }
+
+    @Test
+    public void testCanAssumeUdfps_forRearSensor() {
+        mViewModel = new FingerprintEnrollEnrollingViewModel(
+                mApplication,
+                TEST_USER_ID,
+                newFingerprintRepository(mFingerprintManager,  TYPE_REAR, 5)
+        );
+        assertThat(mViewModel.canAssumeUdfps()).isEqualTo(false);
+    }
+
+    @Test
+    public void testGetFirstFingerprintSensorPropertiesInternal() {
+        final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
+        final FingerprintSensorPropertiesInternal prop = new FingerprintSensorPropertiesInternal(
+                0 /* sensorId */,
+                SensorProperties.STRENGTH_STRONG,
+                5,
+                new ArrayList<>() /* componentInfo */,
+                TYPE_UDFPS_OPTICAL,
+                true /* resetLockoutRequiresHardwareAuthToken */);
+        props.add(prop);
+        doAnswer(invocation -> {
+            final IFingerprintAuthenticatorsRegisteredCallback callback =
+                    invocation.getArgument(0);
+            callback.onAllAuthenticatorsRegistered(props);
+            return null;
+        }).when(mFingerprintManager).addAuthenticatorsRegisteredCallback(any());
+
+        mViewModel = new FingerprintEnrollEnrollingViewModel(
+                mApplication,
+                TEST_USER_ID,
+                new FingerprintRepository(mFingerprintManager)
+        );
+
+        assertThat(mViewModel.getFirstFingerprintSensorPropertiesInternal()).isEqualTo(prop);
+    }
+
+    @Test
+    public void testGetEnrollStageCount() {
+        final int expectedValue = 24;
+        doReturn(expectedValue).when(mFingerprintManager).getEnrollStageCount();
+
+        assertThat(mViewModel.getEnrollStageCount()).isEqualTo(expectedValue);
+    }
+
+    @Test
+    public void testGetEnrollStageThreshold() {
+        final float expectedValue0 = 0.42f;
+        final float expectedValue1 = 0.24f;
+        final float expectedValue2 = 0.33f;
+        final float expectedValue3 = 0.90f;
+
+        doReturn(expectedValue0).when(mFingerprintManager).getEnrollStageThreshold(0);
+        doReturn(expectedValue1).when(mFingerprintManager).getEnrollStageThreshold(1);
+        doReturn(expectedValue2).when(mFingerprintManager).getEnrollStageThreshold(2);
+        doReturn(expectedValue3).when(mFingerprintManager).getEnrollStageThreshold(3);
+
+        assertThat(mViewModel.getEnrollStageThreshold(2)).isEqualTo(expectedValue2);
+        assertThat(mViewModel.getEnrollStageThreshold(1)).isEqualTo(expectedValue1);
+        assertThat(mViewModel.getEnrollStageThreshold(3)).isEqualTo(expectedValue3);
+        assertThat(mViewModel.getEnrollStageThreshold(0)).isEqualTo(expectedValue0);
+    }
+}
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFindSensorViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFindSensorViewModelTest.java
index 43df08d..a72175d 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFindSensorViewModelTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFindSensorViewModelTest.java
@@ -18,7 +18,6 @@
 
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP;
-import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -40,61 +39,45 @@
     @Rule public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
 
     private Application mApplication;
+    private FingerprintEnrollFindSensorViewModel mViewModel;
 
     @Before
     public void setUp() {
         mApplication = ApplicationProvider.getApplicationContext();
+        mViewModel = new FingerprintEnrollFindSensorViewModel(mApplication, false);
     }
 
     @Test
-    public void testClickStartButton() {
-        final FingerprintEnrollFindSensorViewModel viewModel =
-                new FingerprintEnrollFindSensorViewModel(mApplication, false);
-
-        viewModel.onStartButtonClick();
-        assertThat(viewModel.getActionLiveData().getValue()).isEqualTo(
-                FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START);
-    }
-
-    @Test
-    public void testClickSkipButton() {
-        final FingerprintEnrollFindSensorViewModel viewModel =
-                new FingerprintEnrollFindSensorViewModel(mApplication, false);
-
-        viewModel.onSkipButtonClick();
-        assertThat(viewModel.getActionLiveData().getValue()).isEqualTo(
+    public void testClickSkipButtonNotInSuw() {
+        mViewModel = new FingerprintEnrollFindSensorViewModel(mApplication, false);
+        mViewModel.onSkipButtonClick();
+        assertThat(mViewModel.getActionLiveData().getValue()).isEqualTo(
                 FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP);
     }
 
     @Test
     public void testClickSkipButtonInSuw() {
-        final FingerprintEnrollFindSensorViewModel viewModel =
-                new FingerprintEnrollFindSensorViewModel(mApplication, true);
-
-        viewModel.onSkipButtonClick();
-        assertThat(viewModel.getActionLiveData().getValue()).isEqualTo(
+        mViewModel = new FingerprintEnrollFindSensorViewModel(mApplication, true);
+        mViewModel.onSkipButtonClick();
+        assertThat(mViewModel.getActionLiveData().getValue()).isEqualTo(
                 FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG);
     }
 
     @Test
     public void testClickSkipDialogButton() {
-        final FingerprintEnrollFindSensorViewModel viewModel =
-                new FingerprintEnrollFindSensorViewModel(mApplication, true);
-
-        viewModel.onSkipDialogButtonClick();
-        assertThat(viewModel.getActionLiveData().getValue()).isEqualTo(
+        mViewModel.onSkipDialogButtonClick();
+        assertThat(mViewModel.getActionLiveData().getValue()).isEqualTo(
                 FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP);
     }
 
     @Test
     public void testClearActionLiveData() {
-        final FingerprintEnrollFindSensorViewModel viewModel =
-                new FingerprintEnrollFindSensorViewModel(mApplication, false);
+        assertThat(mViewModel.getActionLiveData().getValue()).isNull();
 
-        viewModel.onStartButtonClick();
-        assertThat(viewModel.getActionLiveData().getValue()).isNotNull();
+        mViewModel.onStartButtonClick();
+        assertThat(mViewModel.getActionLiveData().getValue()).isNotNull();
 
-        viewModel.clearActionLiveData();
-        assertThat(viewModel.getActionLiveData().getValue()).isNull();
+        mViewModel.clearActionLiveData();
+        assertThat(mViewModel.getActionLiveData().getValue()).isNull();
     }
 }
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFinishViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFinishViewModelTest.java
new file mode 100644
index 0000000..34ef801
--- /dev/null
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFinishViewModelTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2023 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.biometrics2.ui.viewmodel;
+
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON;
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR;
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
+
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK;
+import static com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.newFingerprintRepository;
+import static com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.setupFingerprintEnrolledFingerprints;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Application;
+import android.content.Intent;
+import android.hardware.fingerprint.FingerprintManager;
+
+import androidx.lifecycle.LiveData;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.biometrics2.ui.model.EnrollmentRequest;
+import com.android.settings.testutils.InstantTaskExecutorRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidJUnit4.class)
+public class FingerprintEnrollFinishViewModelTest {
+
+    private static final int USER_ID = 334;
+    private static final int MAX_ENROLLABLE = 5;
+
+    @Rule public final MockitoRule mockito = MockitoJUnit.rule();
+    @Rule public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
+
+    @Mock private FingerprintManager mFingerprintManager;
+
+    private Application mApplication;
+    private EnrollmentRequest mRequest;
+    private FingerprintEnrollFinishViewModel mViewModel;
+
+    @Before
+    public void setUp() {
+        mApplication = ApplicationProvider.getApplicationContext();
+        mRequest = new EnrollmentRequest(new Intent(), mApplication);
+        mViewModel = new FingerprintEnrollFinishViewModel(mApplication, USER_ID, mRequest,
+                newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, MAX_ENROLLABLE));
+    }
+
+    @Test
+    public void testCanAssumeSfps() {
+        mViewModel = new FingerprintEnrollFinishViewModel(mApplication, USER_ID, mRequest,
+                newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, MAX_ENROLLABLE));
+        assertThat(mViewModel.canAssumeSfps()).isFalse();
+
+        mViewModel = new FingerprintEnrollFinishViewModel(mApplication, USER_ID, mRequest,
+                newFingerprintRepository(mFingerprintManager, TYPE_REAR, MAX_ENROLLABLE));
+        assertThat(mViewModel.canAssumeSfps()).isFalse();
+
+        mViewModel = new FingerprintEnrollFinishViewModel(mApplication, USER_ID, mRequest,
+                newFingerprintRepository(mFingerprintManager, TYPE_POWER_BUTTON, MAX_ENROLLABLE));
+        assertThat(mViewModel.canAssumeSfps()).isTrue();
+    }
+
+    @Test
+    public void testIsAnotherFingerprintEnrollable() {
+        setupFingerprintEnrolledFingerprints(mFingerprintManager, USER_ID, MAX_ENROLLABLE);
+        assertThat(mViewModel.isAnotherFingerprintEnrollable()).isFalse();
+
+        setupFingerprintEnrolledFingerprints(mFingerprintManager, USER_ID, MAX_ENROLLABLE - 1);
+        assertThat(mViewModel.isAnotherFingerprintEnrollable()).isTrue();
+    }
+
+    @Test
+    public void testGetRequest() {
+        assertThat(mViewModel.getRequest()).isEqualTo(mRequest);
+    }
+
+    @Test
+    public void testOnAddButtonClick() {
+        final LiveData<Integer> actionLiveData = mViewModel.getActionLiveData();
+
+        // Test init value
+        assertThat(actionLiveData.getValue()).isNull();
+
+        // Test onAddButtonClick()
+        mViewModel.onAddButtonClick();
+        assertThat(actionLiveData.getValue()).isEqualTo(
+                FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK);
+
+        // Clear
+        mViewModel.clearActionLiveData();
+        assertThat(actionLiveData.getValue()).isNull();
+    }
+
+    @Test
+    public void testOnNextButtonClick() {
+        final LiveData<Integer> actionLiveData = mViewModel.getActionLiveData();
+
+        // Test init value
+        assertThat(actionLiveData.getValue()).isNull();
+
+        // Test onNextButtonClick()
+        mViewModel.onNextButtonClick();
+        assertThat(actionLiveData.getValue()).isEqualTo(
+                FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK);
+
+        // Clear
+        mViewModel.clearActionLiveData();
+        assertThat(actionLiveData.getValue()).isNull();
+    }
+}
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModelTest.java
index fbcbb16..41d8226 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModelTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModelTest.java
@@ -211,7 +211,7 @@
     }
 
     @Test
-    public void textCanAssumeUdfps_forUdfpsUltrasonicSensor() {
+    public void testCanAssumeUdfps_forUdfpsUltrasonicSensor() {
         final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
                 newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_ULTRASONIC, 5),
                 newAllFalseRequest(mApplication));
@@ -220,7 +220,7 @@
     }
 
     @Test
-    public void textCanAssumeUdfps_forRearSensor() {
+    public void testCanAssumeUdfps_forRearSensor() {
         final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
                 newFingerprintRepository(mFingerprintManager, TYPE_REAR, 5),
                 newAllFalseRequest(mApplication));
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java
index 634514f..323618a 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java
@@ -36,11 +36,13 @@
 import android.content.res.Resources;
 import android.os.CancellationSignal;
 
+import androidx.lifecycle.LiveData;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import com.android.settings.R;
 import com.android.settings.biometrics.fingerprint.FingerprintUpdater;
 import com.android.settings.biometrics2.ui.model.EnrollmentProgress;
+import com.android.settings.biometrics2.ui.model.EnrollmentStatusMessage;
 import com.android.settings.testutils.InstantTaskExecutorRule;
 
 import org.junit.Before;
@@ -64,6 +66,8 @@
     @Mock private FingerprintUpdater mFingerprintUpdater;
 
     private FingerprintEnrollProgressViewModel mViewModel;
+    private final TestWrapper<CancellationSignal> mCancellationSignalWrapper = new TestWrapper<>();
+    private final TestWrapper<EnrollmentCallback> mCallbackWrapper = new TestWrapper<>();
 
     @Before
     public void setUp() {
@@ -72,6 +76,15 @@
                 .thenReturn(false);
         mViewModel = new FingerprintEnrollProgressViewModel(mApplication, mFingerprintUpdater,
                 TEST_USER_ID);
+
+        mCancellationSignalWrapper.mValue = null;
+        mCallbackWrapper.mValue = null;
+        doAnswer(invocation -> {
+            mCancellationSignalWrapper.mValue = invocation.getArgument(1);
+            mCallbackWrapper.mValue = invocation.getArgument(3);
+            return null;
+        }).when(mFingerprintUpdater).enroll(any(byte[].class), any(CancellationSignal.class),
+                eq(TEST_USER_ID), any(EnrollmentCallback.class), anyInt());
     }
 
     @Test
@@ -100,64 +113,151 @@
 
     @Test
     public void testCancelEnrollment() {
-        @EnrollReason final int enrollReason = ENROLL_ENROLL;
-        final byte[] token = new byte[] { 1, 2, 3 };
-        mViewModel.setToken(token);
-
-        final TestWrapper<CancellationSignal> signalWrapper = new TestWrapper<>();
-        doAnswer(invocation -> {
-            signalWrapper.mValue = invocation.getArgument(1);
-            return null;
-        }).when(mFingerprintUpdater).enroll(any(byte[].class), any(CancellationSignal.class),
-                eq(TEST_USER_ID), any(EnrollmentCallback.class), anyInt());
-
         // Start enrollment
-        final boolean ret = mViewModel.startEnrollment(enrollReason);
+        mViewModel.setToken(new byte[] { 1, 2, 3 });
+        final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
         assertThat(ret).isTrue();
-        assertThat(signalWrapper.mValue).isNotNull();
+        assertThat(mCancellationSignalWrapper.mValue).isNotNull();
 
         // Cancel enrollment
         mViewModel.cancelEnrollment();
 
-        assertThat(signalWrapper.mValue.isCanceled()).isTrue();
+        assertThat(mCancellationSignalWrapper.mValue.isCanceled()).isTrue();
     }
 
     @Test
     public void testProgressUpdate() {
-        @EnrollReason final int enrollReason = ENROLL_ENROLL;
-        final byte[] token = new byte[] { 1, 2, 3 };
-        mViewModel.setToken(token);
-
-        final TestWrapper<EnrollmentCallback> callbackWrapper = new TestWrapper<>();
-        doAnswer(invocation -> {
-            callbackWrapper.mValue = invocation.getArgument(3);
-            return null;
-        }).when(mFingerprintUpdater).enroll(any(byte[].class), any(CancellationSignal.class),
-                eq(TEST_USER_ID), any(EnrollmentCallback.class), anyInt());
-
         // Start enrollment
-        final boolean ret = mViewModel.startEnrollment(enrollReason);
+        mViewModel.setToken(new byte[] { 1, 2, 3 });
+        final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
         assertThat(ret).isTrue();
-        assertThat(callbackWrapper.mValue).isNotNull();
+        assertThat(mCallbackWrapper.mValue).isNotNull();
+
+        // Test default value
+        final LiveData<EnrollmentProgress> progressLiveData = mViewModel.getProgressLiveData();
+        EnrollmentProgress progress = progressLiveData.getValue();
+        assertThat(progress).isNotNull();
+        assertThat(progress.getSteps()).isEqualTo(-1);
+        assertThat(progress.getRemaining()).isEqualTo(0);
 
         // Update first progress
-        callbackWrapper.mValue.onEnrollmentProgress(25);
-        EnrollmentProgress progress = mViewModel.getProgressLiveData().getValue();
+        mCallbackWrapper.mValue.onEnrollmentProgress(25);
+        progress = progressLiveData.getValue();
         assertThat(progress).isNotNull();
         assertThat(progress.getSteps()).isEqualTo(25);
         assertThat(progress.getRemaining()).isEqualTo(25);
 
         // Update second progress
-        callbackWrapper.mValue.onEnrollmentProgress(20);
-        progress = mViewModel.getProgressLiveData().getValue();
+        mCallbackWrapper.mValue.onEnrollmentProgress(20);
+        progress = progressLiveData.getValue();
         assertThat(progress).isNotNull();
         assertThat(progress.getSteps()).isEqualTo(25);
         assertThat(progress.getRemaining()).isEqualTo(20);
+
+        // Update latest progress
+        mCallbackWrapper.mValue.onEnrollmentProgress(0);
+        progress = progressLiveData.getValue();
+        assertThat(progress).isNotNull();
+        assertThat(progress.getSteps()).isEqualTo(25);
+        assertThat(progress.getRemaining()).isEqualTo(0);
     }
 
-    // TODO(b/260957933): FingerprintEnrollProgressViewModel::getErrorLiveData() and
-    // FingerprintEnrollProgressViewModel::getHelpLiveData() doesn't built into apk because no one
-    // uses it. We shall test it when new FingerprintEnrollEnrolling has used these 2 methods.
+    @Test
+    public void testGetErrorMessageLiveData() {
+        // Start enrollment
+        mViewModel.setToken(new byte[] { 1, 2, 3 });
+        final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+        assertThat(ret).isTrue();
+        assertThat(mCallbackWrapper.mValue).isNotNull();
+
+        // Check default value
+        final LiveData<EnrollmentStatusMessage> liveData = mViewModel.getErrorMessageLiveData();
+        assertThat(liveData.getValue()).isNull();
+
+        // Notify error message
+        final int errMsgId = 3;
+        final String errMsg = "test error message";
+        mCallbackWrapper.mValue.onEnrollmentError(errMsgId, errMsg);
+        final EnrollmentStatusMessage value = liveData.getValue();
+        assertThat(value).isNotNull();
+        assertThat(value.getMsgId()).isEqualTo(errMsgId);
+        assertThat(value.getStr().toString()).isEqualTo(errMsg);
+    }
+
+    @Test
+    public void testGetHelpMessageLiveData() {
+        // Start enrollment
+        mViewModel.setToken(new byte[] { 1, 2, 3 });
+        final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+        assertThat(ret).isTrue();
+        assertThat(mCallbackWrapper.mValue).isNotNull();
+
+        // Check default value
+        final LiveData<EnrollmentStatusMessage> liveData = mViewModel.getHelpMessageLiveData();
+        assertThat(liveData.getValue()).isNull();
+
+        // Notify help message
+        final int errMsgId = 3;
+        final String errMsg = "test error message";
+        mCallbackWrapper.mValue.onEnrollmentHelp(errMsgId, errMsg);
+        final EnrollmentStatusMessage value = liveData.getValue();
+        assertThat(value).isNotNull();
+        assertThat(value.getMsgId()).isEqualTo(errMsgId);
+        assertThat(value.getStr().toString()).isEqualTo(errMsg);
+    }
+
+    @Test
+    public void testGetAcquireLiveData() {
+        // Start enrollment
+        mViewModel.setToken(new byte[] { 1, 2, 3 });
+        final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+        assertThat(ret).isTrue();
+        assertThat(mCallbackWrapper.mValue).isNotNull();
+
+        // Check default value
+        final LiveData<Boolean> liveData = mViewModel.getAcquireLiveData();
+        assertThat(liveData.getValue()).isNull();
+
+        // Notify acquire message
+        mCallbackWrapper.mValue.onAcquired(true);
+        assertThat(liveData.getValue()).isTrue();
+    }
+
+    @Test
+    public void testGetPointerDownLiveData() {
+        // Start enrollment
+        mViewModel.setToken(new byte[] { 1, 2, 3 });
+        final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+        assertThat(ret).isTrue();
+        assertThat(mCallbackWrapper.mValue).isNotNull();
+
+        // Check default value
+        final LiveData<Integer> liveData = mViewModel.getPointerDownLiveData();
+        assertThat(liveData.getValue()).isNull();
+
+        // Notify acquire message
+        final int value = 33;
+        mCallbackWrapper.mValue.onPointerDown(value);
+        assertThat(liveData.getValue()).isEqualTo(value);
+    }
+
+    @Test
+    public void testGetPointerUpLiveData() {
+        // Start enrollment
+        mViewModel.setToken(new byte[] { 1, 2, 3 });
+        final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL);
+        assertThat(ret).isTrue();
+        assertThat(mCallbackWrapper.mValue).isNotNull();
+
+        // Check default value
+        final LiveData<Integer> liveData = mViewModel.getPointerUpLiveData();
+        assertThat(liveData.getValue()).isNull();
+
+        // Notify acquire message
+        final int value = 44;
+        mCallbackWrapper.mValue.onPointerUp(value);
+        assertThat(liveData.getValue()).isEqualTo(value);
+    }
 
     private static class TestWrapper<T> {
         T mValue;
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModelTest.java
index 2c3fbf0..945ce8a 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModelTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollmentViewModelTest.java
@@ -69,27 +69,34 @@
     public void testSetSavedInstanceState() {
         // setSavedInstanceState() as false
         final Bundle bundle = new Bundle();
+        final Bundle outBundle = new Bundle();
+
+        // Set SAVED_STATE_IS_WAITING_ACTIVITY_RESULT to true
         bundle.putBoolean(SAVED_STATE_IS_WAITING_ACTIVITY_RESULT, false);
         mViewModel.setSavedInstanceState(bundle);
         assertThat(mViewModel.isWaitingActivityResult().get()).isFalse();
 
-        // setSavedInstanceState() as false
+        // Set SAVED_STATE_IS_WAITING_ACTIVITY_RESULT to true
         bundle.clear();
         bundle.putBoolean(SAVED_STATE_IS_WAITING_ACTIVITY_RESULT, true);
         mViewModel.setSavedInstanceState(bundle);
         assertThat(mViewModel.isWaitingActivityResult().get()).isTrue();
 
-        // setSavedInstanceState() as false
+        // Set SAVED_STATE_IS_NEW_FINGERPRINT_ADDED to false
         bundle.clear();
         bundle.putBoolean(SAVED_STATE_IS_NEW_FINGERPRINT_ADDED, false);
         mViewModel.setSavedInstanceState(bundle);
-        assertThat(mViewModel.isNewFingerprintAdded()).isFalse();
+        outBundle.clear();
+        mViewModel.onSaveInstanceState(outBundle);
+        assertThat(outBundle.getBoolean(SAVED_STATE_IS_NEW_FINGERPRINT_ADDED)).isFalse();
 
-        // setSavedInstanceState() as false
+        // Set SAVED_STATE_IS_NEW_FINGERPRINT_ADDED to true
         bundle.clear();
         bundle.putBoolean(SAVED_STATE_IS_NEW_FINGERPRINT_ADDED, true);
         mViewModel.setSavedInstanceState(bundle);
-        assertThat(mViewModel.isNewFingerprintAdded()).isTrue();
+        outBundle.clear();
+        mViewModel.onSaveInstanceState(outBundle);
+        assertThat(outBundle.getBoolean(SAVED_STATE_IS_NEW_FINGERPRINT_ADDED)).isTrue();
     }
 
     @Test
diff --git a/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java b/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java
new file mode 100644
index 0000000..5b10adf
--- /dev/null
+++ b/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2023 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.localepicker;
+
+import static com.android.settings.localepicker.LocaleDialogFragment.ARG_DIALOG_TYPE;
+import static com.android.settings.localepicker.LocaleDialogFragment.ARG_RESULT_RECEIVER;
+import static com.android.settings.localepicker.LocaleDialogFragment.ARG_TARGET_LOCALE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.app.Activity;
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.os.ResultReceiver;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.internal.app.LocaleStore;
+import com.android.settings.testutils.ResourcesUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.Locale;
+
+@UiThreadTest
+public class LocaleDialogFragmentTest {
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+
+    private Context mContext;
+    private LocaleDialogFragment mDialogFragment;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = ApplicationProvider.getApplicationContext();
+        mDialogFragment = new LocaleDialogFragment();
+    }
+
+    private void setArgument(
+            int type, ResultReceiver receiver) {
+        LocaleStore.LocaleInfo localeInfo = LocaleStore.getLocaleInfo(Locale.ENGLISH);
+        Bundle args = new Bundle();
+        args.putInt(ARG_DIALOG_TYPE, type);
+        args.putSerializable(ARG_TARGET_LOCALE, localeInfo);
+        args.putParcelable(ARG_RESULT_RECEIVER, receiver);
+        mDialogFragment.setArguments(args);
+    }
+
+    @Test
+    public void getDialogContent_confirmSystemDefault_has2ButtonText() {
+        setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, null);
+        LocaleDialogFragment.LocaleDialogController controller =
+                new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
+
+        LocaleDialogFragment.LocaleDialogController.DialogContent dialogContent =
+                controller.getDialogContent();
+
+        assertEquals(ResourcesUtils.getResourcesString(
+                mContext, "button_label_confirmation_of_system_locale_change"),
+                dialogContent.mPositiveButton);
+        assertEquals(ResourcesUtils.getResourcesString(mContext, "cancel"),
+                dialogContent.mNegativeButton);
+    }
+
+    @Test
+    public void getDialogContent_unavailableLocale_has1ButtonText() {
+        setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE, null);
+        LocaleDialogFragment.LocaleDialogController controller =
+                new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
+
+        LocaleDialogFragment.LocaleDialogController.DialogContent dialogContent =
+                controller.getDialogContent();
+
+        assertEquals(ResourcesUtils.getResourcesString(mContext, "okay"),
+                dialogContent.mPositiveButton);
+        assertTrue(dialogContent.mNegativeButton.isEmpty());
+    }
+
+    @Test
+    public void onClick_clickPositiveButton_sendOK() {
+        ResultReceiver resultReceiver = spy(new ResultReceiver(null));
+        setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, resultReceiver);
+        LocaleDialogFragment.LocaleDialogController controller =
+                new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
+
+        controller.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        verify(resultReceiver).send(eq(Activity.RESULT_OK), any());
+    }
+
+    @Test
+    public void onClick_clickNegativeButton_sendCancel() {
+        ResultReceiver resultReceiver = spy(new ResultReceiver(null));
+        setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, resultReceiver);
+        LocaleDialogFragment.LocaleDialogController controller =
+                new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
+
+        controller.onClick(null, DialogInterface.BUTTON_NEGATIVE);
+
+        verify(resultReceiver).send(eq(Activity.RESULT_CANCELED), any());
+    }
+
+    @Test
+    public void getMetricsCategory_systemLocaleChange() {
+        setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, null);
+
+        int result = mDialogFragment.getMetricsCategory();
+
+        assertEquals(SettingsEnums.DIALOG_SYSTEM_LOCALE_CHANGE, result);
+    }
+
+    @Test
+    public void getMetricsCategory_unavailableLocale() {
+        setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE, null);
+
+        int result = mDialogFragment.getMetricsCategory();
+
+        assertEquals(SettingsEnums.DIALOG_SYSTEM_LOCALE_UNAVAILABLE, result);
+    }
+}
diff --git a/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java b/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java
index 58a9d1c..52f02f5 100644
--- a/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java
+++ b/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java
@@ -16,12 +16,21 @@
 
 package com.android.settings.wifi.repository;
 
+import static android.net.wifi.SoftApConfiguration.BAND_2GHZ;
 import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_OPEN;
 import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE;
 
+import static com.android.settings.wifi.repository.WifiHotspotRepository.BAND_2GHZ_5GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.BAND_2GHZ_5GHZ_6GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2GHZ_5GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_5GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_6GHZ;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -30,6 +39,8 @@
 import android.net.wifi.SoftApConfiguration;
 import android.net.wifi.WifiManager;
 
+import androidx.lifecycle.MutableLiveData;
+import androidx.test.annotation.UiThreadTest;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
@@ -46,6 +57,10 @@
 public class WifiHotspotRepositoryTest {
     static final String WIFI_SSID = "wifi_ssid";
     static final String WIFI_PASSWORD = "wifi_password";
+    static final String WIFI_CURRENT_COUNTRY_CODE = "US";
+
+    static final int WIFI_5GHZ_BAND_PREFERRED = BAND_2GHZ_5GHZ;
+    static final int WIFI_6GHZ_BAND_PREFERRED = BAND_2GHZ_5GHZ_6GHZ;
 
     @Rule
     public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@@ -53,6 +68,8 @@
     Context mContext = ApplicationProvider.getApplicationContext();
     @Mock
     WifiManager mWifiManager;
+    @Mock
+    MutableLiveData<Integer> mSpeedType;
 
     WifiHotspotRepository mWifiHotspotRepository;
     SoftApConfiguration mSoftApConfiguration;
@@ -60,6 +77,10 @@
     @Before
     public void setUp() {
         mWifiHotspotRepository = new WifiHotspotRepository(mContext, mWifiManager);
+        mWifiHotspotRepository.mCurrentCountryCode = WIFI_CURRENT_COUNTRY_CODE;
+        mWifiHotspotRepository.mIsDualBand = true;
+        mWifiHotspotRepository.mIs5gAvailable = true;
+        mWifiHotspotRepository.mIs6gAvailable = true;
     }
 
     @Test
@@ -105,4 +126,171 @@
         assertThat(password).isNotEqualTo(WIFI_PASSWORD);
         assertThat(password.length()).isNotEqualTo(0);
     }
+
+    @Test
+    public void setSoftApConfiguration_setConfigByWifiManager() {
+        SoftApConfiguration config = new SoftApConfiguration.Builder().build();
+
+        mWifiHotspotRepository.setSoftApConfiguration(config);
+
+        verify(mWifiManager).setSoftApConfiguration(config);
+    }
+
+    @Test
+    public void refresh_liveDataNotUsed_doNothing() {
+        // If LiveData is not used then it's null.
+        mWifiHotspotRepository.mSpeedType = null;
+
+        mWifiHotspotRepository.refresh();
+
+        verify(mWifiManager, never()).getSoftApConfiguration();
+    }
+
+    @Test
+    public void refresh_liveDataIsUsed_getConfigAndUpdateLiveData() {
+        // If LiveData is used then it's not null.
+        mWifiHotspotRepository.mSpeedType = mSpeedType;
+
+        mWifiHotspotRepository.refresh();
+
+        verify(mWifiManager).getSoftApConfiguration();
+        verify(mSpeedType).setValue(anyInt());
+    }
+
+    @Test
+    public void setAutoRefresh_setEnabled_registerCallback() {
+        mWifiHotspotRepository.mActiveCountryCodeChangedCallback = null;
+
+        mWifiHotspotRepository.setAutoRefresh(true);
+
+        verify(mWifiManager).registerActiveCountryCodeChangedCallback(any(), any());
+    }
+
+    @Test
+    public void setAutoRefresh_setDisabled_registerCallback() {
+        mWifiHotspotRepository.setAutoRefresh(true);
+
+        mWifiHotspotRepository.setAutoRefresh(false);
+
+        verify(mWifiManager).unregisterActiveCountryCodeChangedCallback(any());
+    }
+
+    @Test
+    @UiThreadTest
+    public void getSpeedType_shouldNotReturnNull() {
+        // If LiveData is not used then it's null.
+        mWifiHotspotRepository.mSpeedType = null;
+        SoftApConfiguration config = new SoftApConfiguration.Builder().setBand(BAND_2GHZ).build();
+        when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+
+        assertThat(mWifiHotspotRepository.getSpeedType()).isNotNull();
+    }
+
+    @Test
+    public void updateSpeedType_singleBand2g_get2gSpeedType() {
+        mWifiHotspotRepository.mIsDualBand = false;
+        SoftApConfiguration config = new SoftApConfiguration.Builder().setBand(BAND_2GHZ).build();
+        when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+        mWifiHotspotRepository.mSpeedType = mSpeedType;
+
+        mWifiHotspotRepository.updateSpeedType();
+
+        verify(mSpeedType).setValue(SPEED_2GHZ);
+    }
+
+    @Test
+    public void updateSpeedType_singleBand5gPreferred_get5gSpeedType() {
+        mWifiHotspotRepository.mIsDualBand = false;
+        SoftApConfiguration config = new SoftApConfiguration.Builder()
+                .setBand(WIFI_5GHZ_BAND_PREFERRED).build();
+        when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+        mWifiHotspotRepository.mSpeedType = mSpeedType;
+
+        mWifiHotspotRepository.updateSpeedType();
+
+        verify(mSpeedType).setValue(SPEED_5GHZ);
+    }
+
+    @Test
+    public void updateSpeedType_singleBand5gPreferredBut5gUnavailable_get2gSpeedType() {
+        mWifiHotspotRepository.mIsDualBand = false;
+        mWifiHotspotRepository.mIs5gAvailable = false;
+        SoftApConfiguration config = new SoftApConfiguration.Builder()
+                .setBand(WIFI_5GHZ_BAND_PREFERRED).build();
+        when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+        mWifiHotspotRepository.mSpeedType = mSpeedType;
+
+        mWifiHotspotRepository.updateSpeedType();
+
+        verify(mSpeedType).setValue(SPEED_2GHZ);
+    }
+
+    @Test
+    public void updateSpeedType_singleBand6gPreferred_get6gSpeedType() {
+        mWifiHotspotRepository.mIsDualBand = false;
+        SoftApConfiguration config = new SoftApConfiguration.Builder()
+                .setBand(WIFI_6GHZ_BAND_PREFERRED).build();
+        when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+        mWifiHotspotRepository.mSpeedType = mSpeedType;
+
+        mWifiHotspotRepository.updateSpeedType();
+
+        verify(mSpeedType).setValue(SPEED_6GHZ);
+    }
+
+    @Test
+    public void updateSpeedType_singleBand6gPreferredBut6gUnavailable_get5gSpeedType() {
+        mWifiHotspotRepository.mIsDualBand = false;
+        mWifiHotspotRepository.mIs6gAvailable = false;
+        SoftApConfiguration config = new SoftApConfiguration.Builder()
+                .setBand(WIFI_6GHZ_BAND_PREFERRED).build();
+        when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+        mWifiHotspotRepository.mSpeedType = mSpeedType;
+
+        mWifiHotspotRepository.updateSpeedType();
+
+        verify(mSpeedType).setValue(SPEED_5GHZ);
+    }
+
+    @Test
+    public void updateSpeedType_singleBand6gPreferredBut5gAnd6gUnavailable_get2gSpeedType() {
+        mWifiHotspotRepository.mIsDualBand = false;
+        mWifiHotspotRepository.mIs5gAvailable = false;
+        mWifiHotspotRepository.mIs6gAvailable = false;
+        SoftApConfiguration config = new SoftApConfiguration.Builder()
+                .setBand(WIFI_6GHZ_BAND_PREFERRED).build();
+        when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+        mWifiHotspotRepository.mSpeedType = mSpeedType;
+
+        mWifiHotspotRepository.updateSpeedType();
+
+        verify(mSpeedType).setValue(SPEED_2GHZ);
+    }
+
+    @Test
+    public void updateSpeedType_dualBand2gAnd5g_get2gAnd5gSpeedType() {
+        mWifiHotspotRepository.mIsDualBand = true;
+        SoftApConfiguration config = new SoftApConfiguration.Builder()
+                .setBand(WIFI_5GHZ_BAND_PREFERRED).build();
+        when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+        mWifiHotspotRepository.mSpeedType = mSpeedType;
+
+        mWifiHotspotRepository.updateSpeedType();
+
+        verify(mSpeedType).setValue(SPEED_2GHZ_5GHZ);
+    }
+
+    @Test
+    public void updateSpeedType_dualBand2gAnd5gBut5gUnavailable_get2gSpeedType() {
+        mWifiHotspotRepository.mIsDualBand = true;
+        mWifiHotspotRepository.mIs5gAvailable = false;
+        SoftApConfiguration config = new SoftApConfiguration.Builder()
+                .setBand(WIFI_5GHZ_BAND_PREFERRED).build();
+        when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+        mWifiHotspotRepository.mSpeedType = mSpeedType;
+
+        mWifiHotspotRepository.updateSpeedType();
+
+        verify(mSpeedType).setValue(SPEED_2GHZ);
+    }
 }
diff --git a/tests/unit/src/com/android/settings/wifi/tether/WifiTetherViewModelTest.java b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherViewModelTest.java
new file mode 100644
index 0000000..6724dd5
--- /dev/null
+++ b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherViewModelTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2023 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 static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Application;
+import android.net.wifi.SoftApConfiguration;
+
+import androidx.lifecycle.MutableLiveData;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.wifi.repository.WifiHotspotRepository;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.concurrent.Executor;
+
+@RunWith(AndroidJUnit4.class)
+public class WifiTetherViewModelTest {
+    @Rule
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Mock
+    Application mApplication;
+    @Mock
+    Executor mExecutor;
+    @Mock
+    WifiHotspotRepository mWifiHotspotRepository;
+    @Mock
+    MutableLiveData<Integer> mSpeedType;
+
+    WifiTetherViewModel mViewModel;
+
+    @Before
+    public void setUp() {
+        when(mApplication.getMainExecutor()).thenReturn(mExecutor);
+
+        FakeFeatureFactory featureFactory = FakeFeatureFactory.setupForTest();
+        when(featureFactory.getWifiFeatureProvider().getWifiHotspotRepository())
+                .thenReturn(mWifiHotspotRepository);
+        when(mWifiHotspotRepository.getSpeedType()).thenReturn(mSpeedType);
+
+        mViewModel = new WifiTetherViewModel(mApplication);
+    }
+
+    @Test
+    public void constructor_setAutoRefreshTrue() {
+        verify(mWifiHotspotRepository).setAutoRefresh(true);
+    }
+
+    @Test
+    public void onCleared_setAutoRefreshFalse() {
+        mViewModel.onCleared();
+
+        verify(mWifiHotspotRepository).setAutoRefresh(false);
+    }
+
+    @Test
+    public void setSoftApConfiguration_setConfigByRepository() {
+        SoftApConfiguration config = new SoftApConfiguration.Builder().build();
+
+        mViewModel.setSoftApConfiguration(config);
+
+        verify(mWifiHotspotRepository).setSoftApConfiguration(config);
+    }
+
+    @Test
+    public void refresh_refreshByRepository() {
+        mViewModel.refresh();
+
+        verify(mWifiHotspotRepository).refresh();
+    }
+
+    @Test
+    @UiThreadTest
+    public void getSpeedSummary_returnNotNull() {
+        mViewModel.mSpeedSummary = null;
+
+        mViewModel.getSpeedSummary();
+
+        assertThat(mViewModel.mSpeedSummary).isNotNull();
+    }
+}