Merge "Run body of applyTopology for all non-noop drags" into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 177e750..de54b83 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -5515,12 +5515,12 @@
             android:exported="true"
             android:permission="android.permission.BLUETOOTH_PRIVILEGED" />
 
-        <!-- Once b/364771256 is fixed, add android:featureFlag="com.android.settings.flags.catalyst_service". -->
-        <!-- Permission is not yet finalized, use READ_BASIC_PHONE_STATE temporarily. -->
+        <!-- Service based on settingslib ipc to expose Preference Metadata and Get/Set functionality. -->
         <service
             android:name=".SettingsService"
             android:exported="true"
-            android:permission="android.permission.READ_BASIC_PHONE_STATE">
+            android:featureFlag="com.android.settings.flags.catalyst_service"
+            android:permission="android.permission.READ_SYSTEM_PREFERENCES">
             <intent-filter>
                 <action android:name="com.android.settingslib.PREFERENCE_SERVICE" />
             </intent-filter>
diff --git a/res/drawable/search_bar_selected_background.xml b/res/drawable/search_bar_selected_background.xml
index b98ed9f..a1299c5 100644
--- a/res/drawable/search_bar_selected_background.xml
+++ b/res/drawable/search_bar_selected_background.xml
@@ -16,5 +16,5 @@
 
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
         android:color="?android:attr/colorControlHighlight">
-    <item android:drawable="@color/search_bar_background"/>
+    <item android:drawable="@color/settingslib_materialColorSurfaceContainerLowest"/>
 </ripple>
diff --git a/res/layout-land/bluetooth_audio_streams_qr_code.xml b/res/layout-land/bluetooth_audio_streams_qr_code.xml
index 432d75e..918b3ac 100644
--- a/res/layout-land/bluetooth_audio_streams_qr_code.xml
+++ b/res/layout-land/bluetooth_audio_streams_qr_code.xml
@@ -45,8 +45,8 @@
 
                 <ImageView
                     android:id="@+id/qrcode_view"
-                    android:layout_width="@dimen/qrcode_size"
-                    android:layout_height="@dimen/qrcode_size"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
                     android:contentDescription="@string/qr_code_content_description"
                     android:focusable="true" />
 
diff --git a/res/layout/bluetooth_audio_streams_qr_code.xml b/res/layout/bluetooth_audio_streams_qr_code.xml
index ab61f50..7c02355 100644
--- a/res/layout/bluetooth_audio_streams_qr_code.xml
+++ b/res/layout/bluetooth_audio_streams_qr_code.xml
@@ -38,11 +38,11 @@
 
         <ImageView
             android:id="@+id/qrcode_view"
-            android:layout_width="@dimen/qrcode_size"
-            android:layout_height="@dimen/qrcode_size"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
             android:contentDescription="@string/qr_code_content_description"
             android:focusable="true"
-            android:paddingTop="70dp"/>
+            android:layout_marginTop="70dp"/>
 
         <TextView
             android:id="@+id/password"
diff --git a/res/layout/dialog_custom_body_audio_sharing.xml b/res/layout/dialog_custom_body_audio_sharing.xml
index 5e9f239..f165ed1 100644
--- a/res/layout/dialog_custom_body_audio_sharing.xml
+++ b/res/layout/dialog_custom_body_audio_sharing.xml
@@ -47,6 +47,15 @@
             android:paddingBottom="24dp"
             android:visibility="gone" />
 
+        <TextView
+            android:id="@+id/description_text_2"
+            style="@style/DeviceAudioSharingText"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:paddingBottom="24dp"
+            android:visibility="gone" />
+
         <androidx.recyclerview.widget.RecyclerView
             android:id="@+id/device_btn_list"
             android:layout_width="match_parent"
diff --git a/res/layout/dialog_keyboard_a11y_input_setting_keys.xml b/res/layout/dialog_keyboard_a11y_input_setting_keys.xml
index d826fee..01f247c 100644
--- a/res/layout/dialog_keyboard_a11y_input_setting_keys.xml
+++ b/res/layout/dialog_keyboard_a11y_input_setting_keys.xml
@@ -88,6 +88,7 @@
                 android:layout_width="wrap_content"
                 android:layout_height="48dp"
                 android:layout_gravity="center_vertical"
+                android:contentDescription="@string/input_setting_keys_custom_title"
                 android:background="@null"/>
             <LinearLayout
                 android:id="@+id/input_setting_keys_custom_value_option"
diff --git a/res/layout/dialog_mobile_network_rename.xml b/res/layout/dialog_mobile_network_rename.xml
index 87f34bc..7a409f7 100644
--- a/res/layout/dialog_mobile_network_rename.xml
+++ b/res/layout/dialog_mobile_network_rename.xml
@@ -46,7 +46,7 @@
                 android:layout_height="wrap_content"
                 android:inputType="text"
                 android:paddingTop="@dimen/sim_label_padding"
-                android:maxLength="50"
+                android:maxLength="@integer/sim_label_max_length"
                 android:singleLine="true"/>
 
             <TextView
diff --git a/res/layout/preference_text_view.xml b/res/layout/preference_text_view.xml
index 3d0b2a1..9d8fafd 100644
--- a/res/layout/preference_text_view.xml
+++ b/res/layout/preference_text_view.xml
@@ -18,8 +18,8 @@
           android:id="@+id/text"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
-          android:layout_marginStart="24dp"
-          android:layout_marginTop="8dp"
+          android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+          android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
           android:textAlignment="viewStart"
           android:textAppearance="?android:attr/textAppearanceSmall"
           android:textColor="?android:attr/textColorPrimary" />
\ No newline at end of file
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
index df061b7..79949ce 100644
--- a/res/values-night/colors.xml
+++ b/res/values-night/colors.xml
@@ -19,7 +19,6 @@
     <color name="homepage_accessibility_background">#783BE5</color>
     <color name="homepage_support_background">#3F5FBD</color>
     <color name="contextual_card_background">@*android:color/material_grey_900</color>
-    <color name="search_bar_background">@androidprv:color/materialColorSurfaceBright</color>
     <color name="notification_importance_button_unselected">#5F6368</color>
 
     <!-- Palette list preference colors. -->
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 5c516d5..73efeb2 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -93,9 +93,6 @@
     <!-- launcher icon color -->
     <color name="icon_launcher_setting_color">@*android:color/accent_device_default_light</color>
 
-    <!-- Search bar background color -->
-    <color name="search_bar_background">@androidprv:color/materialColorSurfaceBright</color>
-
     <color name="face_enroll_icon_color">#42a5f5</color> <!-- Blue 400 -->
 
     <color name="back_gesture_indicator">#4182ef</color>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 3bdea5a..0d0b9e6 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -529,6 +529,7 @@
     <dimen name="contrast_button_horizontal_spacing">16dp</dimen>
 
     <dimen name="audio_streams_qrcode_size">264dp</dimen>
+    <dimen name="audio_streams_qrcode_margin">1.8dp</dimen>
     <dimen name="audio_streams_qrcode_preview_size">300dp</dimen>
     <dimen name="audio_streams_qrcode_preview_radius">30dp</dimen>
     <dimen name="audio_streams_qrcode_scanner_fragment_padding">16dp</dimen>
diff --git a/res/values/integers.xml b/res/values/integers.xml
index 5631e40..9610b32 100644
--- a/res/values/integers.xml
+++ b/res/values/integers.xml
@@ -42,4 +42,6 @@
     <integer name="pointer_scale_seek_bar_end">3</integer>
 
     <integer name="max_integer">2147483647</integer>
+
+    <integer name="sim_label_max_length">50</integer>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c6f7909..4763ab6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -965,6 +965,8 @@
     <string name="security_settings_fingerprint">Fingerprint</string>
     <!-- Title shown for a category shown for fingerprint settings page. [CHAR LIMIT=22] -->
     <string name="security_settings_fingerprint_title">Fingerprints</string>
+    <!-- Description shown for fingerprint settings page. [CHAR LIMIT=22] -->
+    <string name="security_settings_fingerprint_description"></string>
     <!-- Fingerprint category title - fingerprint options for unlocking the device. [CHAR LIMIT=60] -->
     <string name="security_settings_category_use_fingerprint">Use fingerprint to</string>
     <!-- Title shown for menu item that launches fingerprint settings or enrollment [CHAR LIMIT=22] -->
@@ -1671,6 +1673,9 @@
     <!-- Message shown in screen lock picker for setting up a work profile screen lock. [CHAR LIMIT=80] -->
     <string name="lock_settings_picker_profile_message">If you forget this lock, ask your IT admin to reset it</string>
 
+    <!-- Title for the category in screen lock settings page -->
+    <string name="lock_settings_screen_lock_settings_title">Screen lock settings</string>
+
     <!-- Label for button in screen lock settings, allowing users to choose other types of screen locks. [CHAR LIMIT=40] -->
     <string name="setup_lock_settings_options_button_label">Screen lock options</string>
 
@@ -3870,7 +3875,7 @@
     <string name="ethernet_tether_checkbox_text">Ethernet tethering</string>
 
     <!-- Tethering footer info [CHAR LIMIT=NONE]-->
-    <string name="tethering_footer_info">Use hotspot and tethering to provide internet to other devices through your mobile data connection. Apps can also create a hotspot to share content with nearby devices.</string>
+    <string name="tethering_footer_info">Use hotspot and tethering to provide internet to other devices through your data connection. Apps can also create a hotspot to share content with nearby devices.</string>
     <!-- Tethering footer info for the device which supports Wi-Fi and Wi-Fi tethering enabled at the same time [CHAR LIMIT=NONE]-->
     <string name="tethering_footer_info_sta_ap_concurrency">Use hotspot and tethering to provide internet to other devices through your Wi\u2011Fi or mobile data connection. Apps can also create a hotspot to share content with nearby devices.</string>
 
@@ -4711,6 +4716,11 @@
     <string name="input_setting_keys_custom_title">Custom</string>
     <!-- Option subtitle for the input setting keys threshold dialog for custom value. [CHAR LIMIT=35] -->
     <string name="input_setting_keys_custom_value">custom value</string>
+    <!-- Content description for the bounce key threshold dialog for custom value seekbar. [CHAR LIMIT=35] -->
+    <string name="input_setting_bounce_keys_seekbar_desc">Bounce key threshold time</string>
+    <!-- Content description for the slow key threshold dialog for custom value seekbar. [CHAR LIMIT=35] -->
+    <string name="input_setting_slow_keys_seekbar_desc">Slow key threshold time</string>
+
 
     <!-- Title for the 'Slow keys' preference switch. [CHAR LIMIT=35] -->
     <string name="slow_keys">Slow keys</string>
@@ -4731,6 +4741,8 @@
     <!-- Summary text for the 'Mouse reverse scrolling' preference switch indicating to users that when the setting is enabled that scrolling up with their mouse wheel will move the page content down. [CHAR LIMIT=NONE] -->
     <string name="mouse_reverse_vertical_scrolling_summary">Content moves up when you scroll down</string>
     <!-- TODO(b/383555305): finalize these strings and mark them translatable. -->
+    <!-- Title for the scrolling section of the mouse settings page. [CHAR LIMIT=60] -->
+    <string name="mouse_scrolling_category_title" translatable="false">Scrolling</string>
     <!-- Title for the 'Mouse controlled scrolling' preference switch, which disables the mouse scrolling acceleration so that the scrolling speed becomes directly proportional to the speed at which the wheel is turned. [CHAR LIMIT=60]-->
     <string name="mouse_scrolling_acceleration" translatable="false">Controlled scrolling</string>
     <!-- Title for the 'Scrolling speed' slider seekbar, which controls how fast content scrolls when the user moves the scroll wheel. [CHAR LIMIT=60]-->
@@ -4746,17 +4758,17 @@
     <!-- page title for Mouse key main page. [CHAR LIMIT=NONE] -->
     <string name="mouse_key_main_page_title">Mouse keys for <xliff:g id="keyboard name" example="my keyboard">%s</xliff:g></string>
     <!-- Summary text for Mouse keys directional image. [CHAR LIMIT=NONE] -->
-    <string name="mouse_keys_directional_summary">Use the \“<xliff:g id="directional_label" example="7,8,9,u,o,j,k,l">%s</xliff:g>\” keys to move the mouse pointer</string>
+    <string name="mouse_keys_directional_summary">Use the \"<xliff:g id="directional_label" example="7,8,9,u,o,j,k,l">%s</xliff:g>\" keys to move the mouse pointer</string>
     <!-- Summary text for Mouse keys click image. [CHAR LIMIT=NONE] -->
-    <string name="mouse_keys_click_summary">Use the \“<xliff:g id="click_label" example="i">%s</xliff:g>\” key to click the primary mouse button</string>
+    <string name="mouse_keys_click_summary">Use the \"<xliff:g id="click_label" example="i">%s</xliff:g>\" key to click the primary mouse button</string>
     <!-- Summary text for Mouse keys press hold image. [CHAR LIMIT=NONE] -->
-    <string name="mouse_keys_press_hold_summary">Use the \“<xliff:g id="press_hold_label" example="m">%s</xliff:g>\” key to press &amp; hold the primary mouse button</string>
+    <string name="mouse_keys_press_hold_summary">Use the \"<xliff:g id="press_hold_label" example="m">%s</xliff:g>\" key to press &amp; hold the primary mouse button</string>
     <!-- Summary text for Mouse keys release image. [CHAR LIMIT=NONE] -->
-    <string name="mouse_keys_release_summary">Use the \“<xliff:g id="release_label" example=",">%s</xliff:g>\” key to release the primary mouse button</string>
+    <string name="mouse_keys_release_summary">Use the \"<xliff:g id="release_label" example=",">%s</xliff:g>\" key to release the primary mouse button</string>
     <!-- Summary text for Mouse keys toggle scroll image. [CHAR LIMIT=NONE] -->
-    <string name="mouse_keys_toggle_scroll_summary">Use the \“<xliff:g id="release_label_1" example=".">%1$s</xliff:g>\” key to toggle scroll mode. This will make the \“<xliff:g id="release_label_2" example="8, k, o, u">%2$s</xliff:g>\” keys scroll the view top, down, left or right</string>
+    <string name="mouse_keys_toggle_scroll_summary">Use the \"<xliff:g id="release_label_1" example=".">%1$s</xliff:g>\" key to toggle scroll mode. This will make the \"<xliff:g id="release_label_2" example="8, k, o, u">%2$s</xliff:g>\" keys scroll the view top, down, left or right</string>
     <!-- Summary text for Mouse keys click secondary button image. [CHAR LIMIT=NONE] -->
-    <string name="mouse_keys_release2_summary">Use the \“<xliff:g id="release_2_label" example="/">%s</xliff:g>\” key to click the secondary mouse button</string>
+    <string name="mouse_keys_release2_summary">Use the \"<xliff:g id="release_2_label" example="/">%s</xliff:g>\" key to click the secondary mouse button</string>
 
     <!-- Title for the button to trigger the 'keyboard shortcuts helper' dialog. [CHAR LIMIT=35] -->
     <string name="keyboard_shortcuts_helper">View keyboard shortcuts</string>
@@ -4776,7 +4788,7 @@
     <!-- Title for the button to trigger the 'mouse settings' page if connect with a mouse. [CHAR LIMIT=35] -->
     <string name="mouse_settings">Mouse</string>
     <!-- Summary text for mouse setting page. [CHAR LIMIT=35] -->
-    <string name="mouse_settings_summary">Pointer speed, swap buttons, button customisation</string>
+    <string name="mouse_settings_summary">Pointer speed, swap buttons, button customization</string>
     <!-- Summary text for the 'trackpad settings' page. [CHAR LIMIT=100] -->
     <string name="trackpad_settings_summary">Pointer speed, gestures</string>
 
@@ -4801,7 +4813,7 @@
     <!-- Title text for 'Pointer speed'. [CHAR LIMIT=35] -->
     <string name="trackpad_pointer_speed">Cursor speed</string>
     <!-- Title text for 'Three finger tap' touchpad preference. This preference allows the user to select an action that will trigger when they tap three fingers on a touchpad. [CHAR LIMIT=60] -->
-    <string name="three_finger_tap_preference_title">Customise 3-finger tap</string>
+    <string name="three_finger_tap_preference_title">Customize 3-finger tap</string>
     <!-- Title for the 'Touchpad acceleration' preference switch, which dynamically adjusts cursor movement based on speed. [CHAR LIMIT=60] -->
     <string name="touchpad_acceleration_title">Touchpad acceleration</string>
     <!-- Summary text for the 'Touchpad acceleration' preference switch indicating to users that when this switch is enabled, faster movements with your fingers will move the cursor farther. [CHAR LIMIT=NONE] -->
@@ -13927,6 +13939,10 @@
     <string name="audio_sharing_close_button_label">Close</string>
     <!-- Content for audio sharing share dialog with no device, ask users to connect device  [CHAR LIMIT=none]-->
     <string name="audio_sharing_dialog_connect_device_content">Connect another pair of compatible headphones, or share your stream\'s name and password with the other person</string>
+    <!-- Content for audio sharing share dialog with no device, ask users to scan qr code [CHAR LIMIT=none]-->
+    <string name="audio_sharing_dialog_qr_code_content">Let others scan this code and listen to your audio\n\nStream name: <xliff:g example="Pixel 8" id="stream_name">%1$s</xliff:g>\nPassword: <xliff:g example="123456" id="password">%2$s</xliff:g></string>
+    <!-- Content for audio sharing share dialog with no device, ask users to pair new device [CHAR LIMIT=none]-->
+    <string name="audio_sharing_dialog_pair_new_device_content">or pair another set of compatible headphones</string>
     <!-- Content for audio sharing share dialog with no device, ask users to pair device  [CHAR LIMIT=none]-->
     <string name="audio_sharing_dialog_pair_device_content">Pair another set of compatible headphones, or share your audio stream QR code with the other person</string>
     <!-- Text for sharing audio sharing state [CHAR LIMIT=none]-->
@@ -14035,7 +14051,7 @@
     <!-- The preference summary when add source succeed [CHAR LIMIT=NONE] -->
     <string name="audio_streams_listening_now">Listening now</string>
     <!-- The preference summary when source is present on sinks [CHAR LIMIT=NONE] -->
-    <string name="audio_streams_present_now">Paused by host</string>
+    <string name="audio_streams_present_now">Stream paused</string>
     <!-- Le audio streams service notification leave broadcast text [CHAR LIMIT=NONE] -->
     <string name="audio_streams_media_service_notification_leave_broadcast_text">Stop listening</string>
     <!-- Le audio streams no le device dialog title [CHAR LIMIT=NONE] -->
diff --git a/res/xml/mouse_settings.xml b/res/xml/mouse_settings.xml
index 35279ec..e4b3f1c 100644
--- a/res/xml/mouse_settings.xml
+++ b/res/xml/mouse_settings.xml
@@ -21,36 +21,26 @@
     android:title="@string/mouse_settings">
 
     <SwitchPreferenceCompat
-        android:key="mouse_swap_primary_button"
-        android:title="@string/mouse_swap_primary_button"
-        android:summary="@string/mouse_swap_primary_button_summary"
-        settings:controller="com.android.settings.inputmethod.MouseSwapPrimaryButtonPreferenceController" />
-
-    <SwitchPreferenceCompat
-        android:key="mouse_reverse_vertical_scrolling"
-        android:title="@string/mouse_reverse_vertical_scrolling"
-        android:summary="@string/mouse_reverse_vertical_scrolling_summary"
-        settings:controller="com.android.settings.inputmethod.MouseReverseVerticalScrollingPreferenceController" />
-
-    <SwitchPreferenceCompat
-        android:key="mouse_swap_primary_button"
-        android:title="@string/mouse_swap_primary_button"
-        android:summary="@string/mouse_swap_primary_button_summary"
-        settings:controller="com.android.settings.inputmethod.MouseSwapPrimaryButtonPreferenceController" />
-
-    <SwitchPreferenceCompat
         android:key="mouse_pointer_acceleration"
         android:title="@string/mouse_pointer_acceleration"
         android:summary="@string/mouse_pointer_acceleration_summary"
+        android:order="10"
         settings:controller="com.android.settings.inputmethod.MousePointerAccelerationPreferenceController" />
 
     <com.android.settings.widget.SeekBarPreference
         android:key="trackpad_pointer_speed"
         android:title="@string/trackpad_pointer_speed"
-        android:order="40"
+        android:order="20"
         android:selectable="false"
         settings:controller="com.android.settings.inputmethod.TouchpadPointerSpeedPreferenceController"/>
 
+    <SwitchPreferenceCompat
+        android:key="mouse_swap_primary_button"
+        android:title="@string/mouse_swap_primary_button"
+        android:summary="@string/mouse_swap_primary_button_summary"
+        android:order="30"
+        settings:controller="com.android.settings.inputmethod.MouseSwapPrimaryButtonPreferenceController" />
+
     <Preference
         android:fragment="com.android.settings.inputmethod.PointerTouchpadFragment"
         android:key="accessibility_pointer_and_touchpad"
@@ -60,17 +50,32 @@
         android:summary="@string/accessibility_pointer_and_touchpad_summary"
         settings:searchable="true"/>
 
-    <SwitchPreferenceCompat
-        android:key="mouse_scrolling_acceleration"
-        android:title="@string/mouse_scrolling_acceleration"
-        android:order="55"
-        settings:controller="com.android.settings.inputmethod.MouseScrollingAccelerationPreferenceController" />
+    <PreferenceCategory
+        android:key="pointer_category"
+        android:persistent="false"
+        android:order="51"
+        android:title="@string/mouse_scrolling_category_title">
 
-    <com.android.settings.widget.SeekBarPreference
-        android:key="mouse_scrolling_speed"
-        android:title="@string/mouse_scrolling_speed"
-        android:order="60"
-        android:selectable="false"
-        settings:controller="com.android.settings.inputmethod.MouseScrollingSpeedPreferenceController"/>
+        <SwitchPreferenceCompat
+            android:key="mouse_reverse_vertical_scrolling"
+            android:order="52"
+            android:title="@string/mouse_reverse_vertical_scrolling"
+            android:summary="@string/mouse_reverse_vertical_scrolling_summary"
+            settings:controller="com.android.settings.inputmethod.MouseReverseVerticalScrollingPreferenceController" />
+
+        <SwitchPreferenceCompat
+            android:order="55"
+            android:key="mouse_scrolling_acceleration"
+            android:title="@string/mouse_scrolling_acceleration"
+            settings:controller="com.android.settings.inputmethod.MouseScrollingAccelerationPreferenceController" />
+
+        <com.android.settings.widget.SeekBarPreference
+            android:key="mouse_scrolling_speed"
+            android:title="@string/mouse_scrolling_speed"
+            android:order="60"
+            android:selectable="false"
+            settings:controller="com.android.settings.inputmethod.MouseScrollingSpeedPreferenceController"/>
+
+    </PreferenceCategory>
 
 </PreferenceScreen>
diff --git a/res/xml/security_settings_fingerprint.xml b/res/xml/security_settings_fingerprint.xml
index 701d493..2868351 100644
--- a/res/xml/security_settings_fingerprint.xml
+++ b/res/xml/security_settings_fingerprint.xml
@@ -19,6 +19,11 @@
     xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:title="@string/security_settings_fingerprint_preference_title">
 
+    <com.android.settingslib.widget.TopIntroPreference
+        android:key="security_settings_fingerprint_description"
+        settings:searchable="false"
+        settings:isPreferenceVisible="false" />
+
     <PreferenceCategory
         android:key="biometric_settings_use_fingerprint_to"
         android:title="@string/security_settings_category_use_fingerprint"
diff --git a/res/xml/security_settings_picker.xml b/res/xml/security_settings_picker.xml
index aa77b4f..2536264 100644
--- a/res/xml/security_settings_picker.xml
+++ b/res/xml/security_settings_picker.xml
@@ -69,7 +69,7 @@
 
     <PreferenceCategory
         android:key="unlock_settings"
-        android:title="@string/security_settings_fingerprint_settings_preferences_category"
+        android:title="@string/lock_settings_screen_lock_settings_title"
         settings:isPreferenceVisible="false">
 
         <!-- available in pattern -->
diff --git a/src/com/android/settings/SettingsService.kt b/src/com/android/settings/SettingsService.kt
index b7c6220..8eaa1e9 100644
--- a/src/com/android/settings/SettingsService.kt
+++ b/src/com/android/settings/SettingsService.kt
@@ -16,21 +16,19 @@
 
 package com.android.settings
 
-import android.content.Intent
-import com.android.settings.flags.Flags
+import android.Manifest.permission.WRITE_SYSTEM_PREFERENCES
+import android.app.AppOpsManager.OP_WRITE_SYSTEM_PREFERENCES
 import com.android.settings.metrics.SettingsRemoteOpMetricsLogger
 import com.android.settingslib.ipc.ApiPermissionChecker
+import com.android.settingslib.ipc.AppOpApiPermissionChecker
 import com.android.settingslib.service.PreferenceService
 
 /** Service to expose settings APIs. */
 class SettingsService :
     PreferenceService(
         graphPermissionChecker = ApiPermissionChecker.alwaysAllow(),
-        setterPermissionChecker = ApiPermissionChecker.alwaysAllow(),
+        setterPermissionChecker =
+            AppOpApiPermissionChecker(OP_WRITE_SYSTEM_PREFERENCES, WRITE_SYSTEM_PREFERENCES),
         getterPermissionChecker = ApiPermissionChecker.alwaysAllow(),
         metricsLogger = SettingsRemoteOpMetricsLogger(),
-    ) {
-
-    override fun onBind(intent: Intent) =
-        if (Flags.catalystService()) super.onBind(intent) else null
-}
+    )
diff --git a/src/com/android/settings/applications/contacts/ContactsStorageSettings.java b/src/com/android/settings/applications/contacts/ContactsStorageSettings.java
index 4b70d46..1eb6ab0 100644
--- a/src/com/android/settings/applications/contacts/ContactsStorageSettings.java
+++ b/src/com/android/settings/applications/contacts/ContactsStorageSettings.java
@@ -232,7 +232,7 @@
                     getPrefContext());
             preference.setTitle(R.string.sim_card_label);
             preference.setIcon(R.drawable.ic_sim_card);
-            preference.setSummary(R.string.sim_card_label);
+            preference.setSummary(R.string.contacts_storage_device_only_preference_summary);
             preference.setKey(preferenceKey);
             preference.setOnClickListener(this);
             mAccountMap.put(preferenceKey, currentDefaultAccountAndState);
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintFeatureProvider.java b/src/com/android/settings/biometrics/fingerprint/FingerprintFeatureProvider.java
index 783da72..aa80fb3 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintFeatureProvider.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintFeatureProvider.java
@@ -71,4 +71,13 @@
     ) {
         return new FingerprintExtPreferencesProvider();
     }
+
+    /**
+     * Gets the feature provider for FingerprintSettings page
+     * @return the provider
+     */
+    @NonNull
+    default FingerprintSettingsFeatureProvider getFingerprintSettingsFeatureProvider() {
+        return FingerprintSettingsFeatureProvider.getInstance();
+    }
 }
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index 08bd450..9531f73 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -28,6 +28,8 @@
 import static com.android.settings.biometrics.BiometricEnrollBase.BIOMETRIC_AUTH_REQUEST;
 import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY;
 import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_CHALLENGE;
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
 
 import android.annotation.SuppressLint;
 import android.app.Activity;
@@ -37,6 +39,7 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.content.res.ResourceId;
 import android.graphics.drawable.Drawable;
 import android.hardware.fingerprint.Fingerprint;
 import android.hardware.fingerprint.FingerprintManager;
@@ -276,6 +279,8 @@
                 "security_settings_fingerprint_unlock_category";
         private static final String KEY_FINGERPRINT_UNLOCK_FOOTER =
                 "security_settings_fingerprint_footer";
+        private static final String KEY_FINGERPRINT_DESCRIPTION =
+                "security_settings_fingerprint_description";
         private static final String KEY_BIOMETRICS_AUTHENTICATION_REQUESTED =
                 "biometrics_authentication_requested";
         private static final String KEY_BIOMETRICS_USE_FINGERPRINT_TO_CATEGORY =
@@ -327,6 +332,8 @@
         private boolean mIsEnrolling;
         /** SaveInstance key if we are waiting activity result from a extension preference */
         @NonNull private String mLaunchedExtPrefKey = "";
+        /** key list for changing visibility */
+        @NonNull private final ArrayList<String> mExtPrefKeys = new ArrayList<>();
 
         private long mChallenge;
 
@@ -469,6 +476,7 @@
                 if (preference instanceof PrimarySwitchIntentPreference) {
                     preference.setOnPreferenceClickListener(this::onExtIntentPreferenceClick);
                 }
+                mExtPrefKeys.add(preference.getKey());
                 mFingerprintUnlockCategory.addPreference(preference);
             }
         }
@@ -648,13 +656,16 @@
                 mFooterColumns.add(column2);
             } else {
                 final FooterColumn column = new FooterColumn();
+                final FingerprintSettingsFeatureProvider featureProvider =
+                        FeatureFactory.getFeatureFactory().getFingerprintFeatureProvider()
+                                .getFingerprintSettingsFeatureProvider();
                 column.mTitle = getString(isPrivateProfile()
                         ? R.string.private_space_fingerprint_enroll_introduction_message
                         : R.string.security_settings_fingerprint_enroll_introduction_v3_message,
                         DeviceHelper.getDeviceName(getActivity()));
                 column.mLearnMoreClickListener = learnMoreClickListener;
                 column.mLearnMoreOverrideText = getText(
-                        R.string.security_settings_fingerprint_settings_footer_learn_more);
+                        featureProvider.getSettingPageFooterLearnMoreDescription());
                 mFooterColumns.add(column);
             }
         }
@@ -735,6 +746,14 @@
                 scrollToPreference(fpPrefKey);
                 addFingerprintUnlockCategory();
             }
+            final int descriptionRes = FeatureFactory.getFeatureFactory()
+                    .getFingerprintFeatureProvider().getFingerprintSettingsFeatureProvider()
+                    .getSettingPageDescription();
+            if (ResourceId.isValid(descriptionRes)) {
+                final Preference preference = findPreference(KEY_FINGERPRINT_DESCRIPTION);
+                preference.setTitle(descriptionRes);
+                preference.setVisible(true);
+            }
             createFooterPreference(root);
         }
 
@@ -748,8 +767,7 @@
                         R.string.security_settings_fingerprint_title));
             }
 
-            String keyToReturn = mIsExpressiveThemeStyle
-                    ? KEY_FINGERPRINT_ADD_EXPRESSIVE : KEY_FINGERPRINT_ADD;
+            String keyToReturn = getAddFingerprintPreferenceKey();
             final List<Fingerprint> items = mFingerprintManager.getEnrolledFingerprints(mUserId);
             final int fingerprintCount = items.size();
             for (int i = 0; i < fingerprintCount; i++) {
@@ -785,8 +803,7 @@
                 mFingerprintsEnrolledCategory.addPreference(pref);
                 pref.setOnPreferenceChangeListener(this);
             }
-            mAddFingerprintPreference = findPreference(mIsExpressiveThemeStyle
-                    ? KEY_FINGERPRINT_ADD_EXPRESSIVE : KEY_FINGERPRINT_ADD);
+            mAddFingerprintPreference = findPreference(getAddFingerprintPreferenceKey());
             setupAddFingerprintPreference();
             return keyToReturn;
         }
@@ -812,8 +829,17 @@
             updateAddPreference();
         }
 
+        /**
+         * Lambda function for setCategoryHasChildrenSupplier
+         */
+        private boolean fingerprintUnlockCategoryHasChild() {
+            return mFingerprintUnlockCategory.getPreferenceCount() > 0;
+        }
+
         private void addFingerprintUnlockCategory() {
             mFingerprintUnlockCategory = findPreference(KEY_FINGERPRINT_UNLOCK_CATEGORY);
+            mFingerprintUnlockCategoryPreferenceController.setCategoryHasChildrenSupplier(
+                    this::fingerprintUnlockCategoryHasChild);
             if (isSfps()) {
                 // For both SFPS "screen on to auth" and "rest to unlock"
                 final Preference restToUnlockPreference = FeatureFactory.getFeatureFactory()
@@ -839,18 +865,39 @@
         }
 
         private void updateFingerprintUnlockCategoryVisibility() {
-            final boolean fingerprintUnlockCategoryAvailable =
-                    mFingerprintUnlockCategoryPreferenceController.isAvailable();
-            if (mFingerprintUnlockCategory.isVisible() != fingerprintUnlockCategoryAvailable) {
-                mFingerprintUnlockCategory.setVisible(fingerprintUnlockCategoryAvailable);
-            }
+            final int categoryStatus =
+                    mFingerprintUnlockCategoryPreferenceController.getAvailabilityStatus();
+            updatePreferenceVisibility(categoryStatus, mFingerprintUnlockCategory);
+
             if (mRequireScreenOnToAuthPreferenceController != null) {
-                mRequireScreenOnToAuthPreference.setVisible(
-                        mRequireScreenOnToAuthPreferenceController.isAvailable());
+                final int status =
+                        mRequireScreenOnToAuthPreferenceController.getAvailabilityStatus();
+                updatePreferenceVisibility(status, mRequireScreenOnToAuthPreference);
             }
             if (mScreenOffUnlockUdfpsPreferenceController != null) {
-                mScreenOffUnlockUdfpsPreference.setVisible(
-                        mScreenOffUnlockUdfpsPreferenceController.isAvailable());
+                final int status =
+                        mScreenOffUnlockUdfpsPreferenceController.getAvailabilityStatus();
+                updatePreferenceVisibility(status, mScreenOffUnlockUdfpsPreference);
+            }
+            if (!mExtPrefKeys.isEmpty()) {
+                for (String key: mExtPrefKeys) {
+                    Preference preference = mFingerprintUnlockCategory.findPreference(key);
+                    if (preference != null) {
+                        updatePreferenceVisibility(categoryStatus, preference);
+                    }
+                }
+            }
+        }
+
+        private void updatePreferenceVisibility(int availabilityStatus, Preference preference) {
+            if (availabilityStatus == AVAILABLE) {
+                preference.setVisible(true);
+                preference.setEnabled(true);
+            } else if (availabilityStatus == CONDITIONALLY_UNAVAILABLE) {
+                preference.setVisible(true);
+                preference.setEnabled(false);
+            } else {
+                preference.setVisible(false);
             }
         }
 
@@ -898,8 +945,29 @@
                     .setOnPreferenceChangeListener(fingerprintAppController);
         }
 
+        private void updateUseFingerprintToEnableStatus() {
+            final PreferenceCategory category =
+                    findPreference(KEY_BIOMETRICS_USE_FINGERPRINT_TO_CATEGORY);
+            if (!category.isVisible()) {
+                return;
+            }
+            final boolean hasFingerprintEnrolled =
+                    mFingerprintManager.getEnrolledFingerprints(mUserId).size() > 0;
+
+            final FingerprintSettingsKeyguardUnlockPreferenceController fpUnlockController =
+                    use(FingerprintSettingsKeyguardUnlockPreferenceController.class);
+            findPreference(fpUnlockController.getPreferenceKey())
+                    .setEnabled(hasFingerprintEnrolled);
+
+            final FingerprintSettingsAppsPreferenceController fingerprintAppController =
+                    use(FingerprintSettingsAppsPreferenceController.class);
+            findPreference(fingerprintAppController.getPreferenceKey())
+                    .setEnabled(hasFingerprintEnrolled);
+        }
+
         private void updatePreferencesAfterFingerprintRemoved() {
             updateAddPreference();
+            updateUseFingerprintToEnableStatus();
             if (isSfps() || (screenOffUnlockUdfps() && isScreenOffUnlcokSupported())) {
                 updateFingerprintUnlockCategoryVisibility();
             }
@@ -911,8 +979,7 @@
                 return; // Activity went away
             }
 
-            mAddFingerprintPreference = findPreference(
-                    mIsExpressiveThemeStyle ? KEY_FINGERPRINT_ADD_EXPRESSIVE : KEY_FINGERPRINT_ADD);
+            mAddFingerprintPreference = findPreference(getAddFingerprintPreferenceKey());
 
             if (mAddFingerprintPreference == null) {
                 return; // b/275519315 Skip if updateAddPreference() invoke before addPreference()
@@ -945,11 +1012,11 @@
                     findPreference(KEY_FINGERPRINT_ADD_EXPRESSIVE);
 
             if (nonExpressiveBtnPreference != null) {
-                nonExpressiveBtnPreference.setVisible(!mIsExpressiveThemeStyle);
+                nonExpressiveBtnPreference.setVisible(!shouldShowExpressiveAddFingerprintPref());
             }
 
             if (expressiveBtnPreference != null) {
-                expressiveBtnPreference.setVisible(mIsExpressiveThemeStyle);
+                expressiveBtnPreference.setVisible(shouldShowExpressiveAddFingerprintPref());
             }
         }
 
@@ -1053,7 +1120,7 @@
         @Override
         public boolean onPreferenceTreeClick(Preference pref) {
             final String key = pref.getKey();
-            if (!mIsExpressiveThemeStyle && KEY_FINGERPRINT_ADD.equals(key)) {
+            if (KEY_FINGERPRINT_ADD.equals(key)) {
                 mIsEnrolling = true;
                 Intent intent = new Intent();
                 intent.setClassName(SETTINGS_PACKAGE_NAME,
@@ -1451,6 +1518,16 @@
             return Utils.isPrivateProfile(mUserId, getContext());
         }
 
+        private String getAddFingerprintPreferenceKey() {
+            return shouldShowExpressiveAddFingerprintPref()
+                    ? KEY_FINGERPRINT_ADD_EXPRESSIVE : KEY_FINGERPRINT_ADD;
+        }
+
+        private boolean shouldShowExpressiveAddFingerprintPref() {
+            return Flags.biometricsOnboardingEducation() && mIsExpressiveThemeStyle
+                    && mFingerprintManager.hasEnrolledTemplates(mUserId);
+        }
+
         public static class DeleteFingerprintDialog extends InstrumentedDialogFragment
                 implements DialogInterface.OnClickListener {
 
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsAppsPreferenceController.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsAppsPreferenceController.java
index 2cd92fc..e53ba85 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsAppsPreferenceController.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsAppsPreferenceController.java
@@ -23,6 +23,7 @@
 import android.provider.Settings;
 
 import androidx.annotation.NonNull;
+import androidx.preference.Preference;
 
 import com.android.settings.Utils;
 import com.android.settings.biometrics.activeunlock.ActiveUnlockStatusUtils;
@@ -54,6 +55,20 @@
     }
 
     @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        if (!FingerprintSettings.isFingerprintHardwareDetected(mContext)) {
+            preference.setEnabled(false);
+        } else if (!mFingerprintManager.hasEnrolledTemplates(getUserId())) {
+            preference.setEnabled(false);
+        } else if (getRestrictingAdmin() != null) {
+            preference.setEnabled(false);
+        } else {
+            preference.setEnabled(true);
+        }
+    }
+
+    @Override
     public int getAvailabilityStatus() {
         final ActiveUnlockStatusUtils activeUnlockStatusUtils =
                 new ActiveUnlockStatusUtils(mContext);
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFeatureProvider.kt b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFeatureProvider.kt
new file mode 100644
index 0000000..3138a0b
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFeatureProvider.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2025 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.biometrics.fingerprint
+
+import com.android.settings.R
+
+/**
+ * Provide features for FingerprintSettings page.
+ */
+open class FingerprintSettingsFeatureProvider {
+    /**
+     * Get the description shown in the FingerprintSetting page.
+     */
+    open fun getSettingPageDescription(): Int {
+        return 0
+    }
+
+    /**
+     * Get the learn more description shown in the footer of the FingerprintSetting page.
+     */
+    open fun getSettingPageFooterLearnMoreDescription(): Int {
+        return R.string.security_settings_fingerprint_settings_footer_learn_more
+    }
+
+    companion object {
+        @JvmStatic
+        val instance = FingerprintSettingsFeatureProvider()
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsKeyguardUnlockPreferenceController.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsKeyguardUnlockPreferenceController.java
index 55c75ab..6b17584 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsKeyguardUnlockPreferenceController.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsKeyguardUnlockPreferenceController.java
@@ -19,9 +19,11 @@
 import static android.provider.Settings.Secure.FINGERPRINT_KEYGUARD_ENABLED;
 
 import android.content.Context;
+import android.hardware.fingerprint.FingerprintManager;
 import android.provider.Settings;
 
 import androidx.annotation.NonNull;
+import androidx.preference.Preference;
 
 import com.android.settings.Utils;
 import com.android.settings.biometrics.activeunlock.ActiveUnlockStatusUtils;
@@ -33,9 +35,12 @@
     private static final int OFF = 0;
     private static final int DEFAULT = ON;
 
+    private FingerprintManager mFingerprintManager;
+
     public FingerprintSettingsKeyguardUnlockPreferenceController(
             @NonNull Context context, @NonNull String key) {
         super(context, key);
+        mFingerprintManager = Utils.getFingerprintManagerOrNull(context);
     }
 
     @Override
@@ -51,6 +56,20 @@
     }
 
     @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        if (!FingerprintSettings.isFingerprintHardwareDetected(mContext)) {
+            preference.setEnabled(false);
+        } else if (!mFingerprintManager.hasEnrolledTemplates(getUserId())) {
+            preference.setEnabled(false);
+        } else if (getRestrictingAdmin() != null) {
+            preference.setEnabled(false);
+        } else {
+            preference.setEnabled(true);
+        }
+    }
+
+    @Override
     public int getAvailabilityStatus() {
         final ActiveUnlockStatusUtils activeUnlockStatusUtils =
                 new ActiveUnlockStatusUtils(mContext);
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintUnlockCategoryController.java b/src/com/android/settings/biometrics/fingerprint/FingerprintUnlockCategoryController.java
index c949d3d..2febce1 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintUnlockCategoryController.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintUnlockCategoryController.java
@@ -16,8 +16,7 @@
 
 package com.android.settings.biometrics.fingerprint;
 
-import static android.hardware.biometrics.Flags.screenOffUnlockUdfps;
-
+import android.annotation.Nullable;
 import android.content.Context;
 import android.hardware.fingerprint.FingerprintManager;
 
@@ -25,6 +24,8 @@
 import com.android.settings.Utils;
 import com.android.settings.core.BasePreferenceController;
 
+import java.util.function.Supplier;
+
 /**
  * Preference controller that controls the fingerprint unlock features to be shown / be hidden.
  */
@@ -34,17 +35,31 @@
     private int mUserId;
     @VisibleForTesting
     protected FingerprintManager mFingerprintManager;
+    @Nullable
+    private Supplier<Boolean> mCategoryHasChildSupplier = null;
 
     public FingerprintUnlockCategoryController(Context context, String key) {
         super(context, key);
         mFingerprintManager = Utils.getFingerprintManagerOrNull(context);
     }
 
+    public void setCategoryHasChildrenSupplier(
+            @Nullable Supplier<Boolean> categoryHasChildSupplier
+    ) {
+        mCategoryHasChildSupplier = categoryHasChildSupplier;
+    }
+
     @Override
     public int getAvailabilityStatus() {
+        Supplier<Boolean> categoryHasChildSupplier = mCategoryHasChildSupplier;
+        boolean hasChild = false;
+        if (categoryHasChildSupplier != null) {
+            hasChild = categoryHasChildSupplier.get();
+        }
+
         if (mFingerprintManager != null
                 && mFingerprintManager.isHardwareDetected()
-                && (mFingerprintManager.isPowerbuttonFps() || screenOffUnlockUdfps())) {
+                && hasChild) {
             return mFingerprintManager.hasEnrolledTemplates(getUserId())
                     ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
         } else {
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsAmbientVolumePreferenceController.java b/src/com/android/settings/bluetooth/BluetoothDetailsAmbientVolumePreferenceController.java
index defa7e9..8dbfedf 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsAmbientVolumePreferenceController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsAmbientVolumePreferenceController.java
@@ -129,8 +129,11 @@
 
     @Override
     public boolean isAvailable() {
-        return mCachedDevice.isHearingDevice() && mCachedDevice.getProfiles().stream().anyMatch(
-                profile -> profile instanceof VolumeControlProfile);
+        return mCachedDevice.isHearingDevice()
+                && mCachedDevice.getProfiles().stream().anyMatch(
+                        profile -> profile instanceof VolumeControlProfile)
+                && mAmbientUiController != null
+                && mAmbientUiController.isAmbientControlAvailable();
     }
 
     @Nullable
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsAudioDeviceTypeController.java b/src/com/android/settings/bluetooth/BluetoothDetailsAudioDeviceTypeController.java
index e7c4c19..3930580 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsAudioDeviceTypeController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsAudioDeviceTypeController.java
@@ -16,14 +16,12 @@
 
 package com.android.settings.bluetooth;
 
-import static android.bluetooth.BluetoothDevice.DEVICE_TYPE_LE;
 import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_CARKIT;
 import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_HEADPHONES;
 import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_HEARING_AID;
 import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_OTHER;
 import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_SPEAKER;
 import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_UNKNOWN;
-import static android.media.audio.Flags.automaticBtDeviceType;
 
 import android.content.Context;
 import android.media.AudioManager;
@@ -108,15 +106,8 @@
                     final int index = pref.findIndexOfValue(value);
                     if (index >= 0) {
                         pref.setSummary(pref.getEntries()[index]);
-                        if (automaticBtDeviceType()) {
-                            mAudioManager.setBluetoothAudioDeviceCategory(
-                                    mCachedDevice.getAddress(), Integer.parseInt(value));
-                        } else {
-                            mAudioManager.setBluetoothAudioDeviceCategory_legacy(
-                                    mCachedDevice.getAddress(),
-                                    mCachedDevice.getDevice().getType() == DEVICE_TYPE_LE,
-                                    Integer.parseInt(value));
-                        }
+                        mAudioManager.setBluetoothAudioDeviceCategory(
+                                mCachedDevice.getAddress(), Integer.parseInt(value));
                         mCachedDevice.onAudioDeviceCategoryChanged();
                     }
                 }
@@ -174,15 +165,8 @@
                 Integer.toString(AUDIO_DEVICE_CATEGORY_OTHER),
         });
 
-        @AudioDeviceCategory int deviceCategory;
-        if (automaticBtDeviceType()) {
-            deviceCategory = mAudioManager.getBluetoothAudioDeviceCategory(
-                    mCachedDevice.getAddress());
-        } else {
-            deviceCategory = mAudioManager.getBluetoothAudioDeviceCategory_legacy(
-                    mCachedDevice.getAddress(),
-                    mCachedDevice.getDevice().getType() == DEVICE_TYPE_LE);
-        }
+        @AudioDeviceCategory int deviceCategory = mAudioManager.getBluetoothAudioDeviceCategory(
+                mCachedDevice.getAddress());
         if (DEBUG) {
             Log.v(TAG, "getBluetoothAudioDeviceCategory() device: "
                     + mCachedDevice.getDevice().getAnonymizedAddress()
@@ -190,10 +174,8 @@
         }
         mAudioDeviceTypePreference.setValue(Integer.toString(deviceCategory));
 
-        if (automaticBtDeviceType()) {
-            if (mAudioManager.isBluetoothAudioDeviceCategoryFixed(mCachedDevice.getAddress())) {
-                mAudioDeviceTypePreference.setEnabled(false);
-            }
+        if (mAudioManager.isBluetoothAudioDeviceCategoryFixed(mCachedDevice.getAddress())) {
+            mAudioDeviceTypePreference.setEnabled(false);
         }
 
         mAudioDeviceTypePreference.setSummary(mAudioDeviceTypePreference.getEntry());
diff --git a/src/com/android/settings/connecteddevice/BluetoothPreference.kt b/src/com/android/settings/connecteddevice/BluetoothPreference.kt
index 8c12024..6ff41a8 100644
--- a/src/com/android/settings/connecteddevice/BluetoothPreference.kt
+++ b/src/com/android/settings/connecteddevice/BluetoothPreference.kt
@@ -18,6 +18,7 @@
 
 import android.Manifest
 import android.annotation.SuppressLint
+import android.app.settings.SettingsEnums.ACTION_SETTINGS_MASTER_SWITCH_BLUETOOTH_TOGGLE
 import android.bluetooth.BluetoothAdapter
 import android.content.BroadcastReceiver
 import android.content.Context
@@ -27,8 +28,10 @@
 import android.provider.Settings
 import android.widget.Toast
 import androidx.preference.Preference
+import com.android.settings.PreferenceActionMetricsProvider
 import com.android.settings.PreferenceRestrictionMixin
 import com.android.settings.R
+import com.android.settings.contract.KEY_BLUETOOTH
 import com.android.settings.network.SatelliteRepository.Companion.isSatelliteOn
 import com.android.settings.network.SatelliteWarningDialogActivity
 import com.android.settings.widget.MainSwitchBarMetadata
@@ -43,7 +46,10 @@
 
 @SuppressLint("MissingPermission")
 class BluetoothPreference(private val bluetoothDataStore: BluetoothDataStore) :
-    MainSwitchBarMetadata, PreferenceRestrictionMixin, Preference.OnPreferenceChangeListener {
+    MainSwitchBarMetadata,
+    PreferenceActionMetricsProvider,
+    PreferenceRestrictionMixin,
+    Preference.OnPreferenceChangeListener {
 
     override val key
         get() = KEY
@@ -51,6 +57,11 @@
     override val title
         get() = R.string.bluetooth_main_switch_title
 
+    override val preferenceActionMetrics: Int
+        get() = ACTION_SETTINGS_MASTER_SWITCH_BLUETOOTH_TOGGLE
+
+    override fun tags(context: Context) = arrayOf(KEY_BLUETOOTH)
+
     override val restrictionKeys: Array<String>
         get() = arrayOf(UserManager.DISALLOW_BLUETOOTH, UserManager.DISALLOW_CONFIG_BLUETOOTH)
 
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFactory.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFactory.java
index b16bceb..3d46361 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFactory.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFactory.java
@@ -18,7 +18,7 @@
 
 import android.content.Context;
 import android.content.DialogInterface;
-import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.Button;
@@ -162,13 +162,13 @@
         /**
          * Sets the custom image of the dialog custom body.
          *
-         * @param bitmap The bitmap to be used for the image.
+         * @param drawable The drawable to be used for the image.
          * @return This builder.
          */
         @NonNull
-        public AudioSharingDialogFactory.DialogBuilder setCustomImage(Bitmap bitmap) {
+        public AudioSharingDialogFactory.DialogBuilder setCustomImage(Drawable drawable) {
             ImageView image = mCustomBody.findViewById(R.id.description_image);
-            image.setImageBitmap(bitmap);
+            image.setImageDrawable(drawable);
             image.setVisibility(View.VISIBLE);
             return this;
         }
@@ -203,6 +203,21 @@
         }
 
         /**
+         * Sets the custom message below image.
+         *
+         * @param messageRes Resource ID of the string to be used for the message body.
+         * @return This builder.
+         */
+        @NonNull
+        public AudioSharingDialogFactory.DialogBuilder setCustomMessage2(
+                @StringRes int messageRes) {
+            TextView subTitle = mCustomBody.findViewById(R.id.description_text_2);
+            subTitle.setText(messageRes);
+            subTitle.setVisibility(View.VISIBLE);
+            return this;
+        }
+
+        /**
          * Sets the custom device actions of the dialog custom body.
          *
          * @param adapter The adapter for device items to build dialog actions.
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java
index c121f55..cf71d5f 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java
@@ -17,13 +17,13 @@
 package com.android.settings.connecteddevice.audiosharing;
 
 import static com.android.settings.connecteddevice.audiosharing.AudioSharingDashboardFragment.SHARE_THEN_PAIR_REQUEST_CODE;
-import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsQrCodeFragment.getQrCodeBitmap;
+import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsQrCodeFragment.getQrCodeDrawable;
 import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_PAIR_AND_JOIN_SHARING;
 
 import android.app.Dialog;
 import android.app.settings.SettingsEnums;
 import android.bluetooth.BluetoothLeBroadcastMetadata;
-import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.util.Log;
 import android.util.Pair;
@@ -45,6 +45,7 @@
 
 import com.google.common.collect.Iterables;
 
+import java.nio.charset.StandardCharsets;
 import java.util.List;
 
 public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
@@ -159,7 +160,6 @@
         }
         if (deviceItems.isEmpty()) {
             builder.setTitle(R.string.audio_sharing_share_dialog_title)
-                    .setCustomMessage(R.string.audio_sharing_dialog_connect_device_content)
                     .setCustomPositiveButton(
                             R.string.audio_sharing_pair_button_label,
                             v -> {
@@ -183,14 +183,23 @@
                             });
             BluetoothLeBroadcastMetadata metadata = arguments.getParcelable(
                     BUNDLE_KEY_BROADCAST_METADATA, BluetoothLeBroadcastMetadata.class);
-            Bitmap qrCodeBitmap = metadata == null ? null : getQrCodeBitmap(metadata,
+            Drawable qrCodeDrawable = metadata == null ? null : getQrCodeDrawable(metadata,
                     getContext()).orElse(null);
-            if (qrCodeBitmap != null) {
-                builder.setCustomImage(qrCodeBitmap)
-                        .setCustomNegativeButton(com.android.settings.R.string.cancel,
+            if (qrCodeDrawable != null) {
+                builder.setCustomImage(qrCodeDrawable)
+                        .setCustomMessage(
+                                getString(
+                                        R.string.audio_sharing_dialog_qr_code_content,
+                                        metadata.getBroadcastName(),
+                                        new String(
+                                                metadata.getBroadcastCode(),
+                                                StandardCharsets.UTF_8)))
+                        .setCustomMessage2(R.string.audio_sharing_dialog_pair_new_device_content)
+                        .setCustomNegativeButton(R.string.audio_streams_dialog_close,
                                 v -> onCancelClick());
             } else {
                 builder.setCustomImage(R.drawable.audio_sharing_guidance)
+                        .setCustomMessage(R.string.audio_sharing_dialog_connect_device_content)
                         .setCustomNegativeButton(
                                 R.string.audio_sharing_qrcode_button_label,
                                 v -> {
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaService.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaService.java
index 5023166..031f29f 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaService.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaService.java
@@ -16,6 +16,9 @@
 
 package com.android.settings.connecteddevice.audiosharing.audiostreams;
 
+import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.PAUSED;
+import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.STREAMING;
+
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
@@ -23,6 +26,7 @@
 import android.app.settings.SettingsEnums;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeBroadcastReceiveState;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothVolumeControl;
 import android.content.Intent;
@@ -64,7 +68,8 @@
     static final String DEVICES = "audio_stream_media_service_devices";
     private static final String TAG = "AudioStreamMediaService";
     private static final int NOTIFICATION_ID = 1;
-    private static final int BROADCAST_CONTENT_TEXT = R.string.audio_streams_listening_now;
+    private static final int BROADCAST_LISTENING_NOW_TEXT = R.string.audio_streams_listening_now;
+    private static final int BROADCAST_STREAM_PAUSED_TEXT = R.string.audio_streams_present_now;
     @VisibleForTesting static final String LEAVE_BROADCAST_ACTION = "leave_broadcast_action";
     private static final String LEAVE_BROADCAST_TEXT = "Leave Broadcast";
     private static final String CHANNEL_ID = "bluetooth_notification_channel";
@@ -94,11 +99,22 @@
                             LEAVE_BROADCAST_ACTION,
                             LEAVE_BROADCAST_TEXT,
                             com.android.settings.R.drawable.ic_clear);
+    private final PlaybackState.Builder mPlayStateHysteresisBuilder =
+            new PlaybackState.Builder()
+                    .setState(
+                            PlaybackState.STATE_STOPPED,
+                            STATIC_PLAYBACK_POSITION,
+                            ZERO_PLAYBACK_SPEED)
+                    .addCustomAction(
+                            LEAVE_BROADCAST_ACTION,
+                            LEAVE_BROADCAST_TEXT,
+                            com.android.settings.R.drawable.ic_clear);
 
     private final MetricsFeatureProvider mMetricsFeatureProvider =
             FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
     private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
     private final AtomicBoolean mIsMuted = new AtomicBoolean(false);
+    private final AtomicBoolean mIsHysteresis = new AtomicBoolean(false);
     // Set 25 as default as the volume range from `VolumeControlProfile` is from 0 to 255.
     // If the initial volume from `onDeviceVolumeChanged` is larger than zero (not muted), we will
     // override this value. Otherwise, we raise the volume to 25 when the play button is clicked.
@@ -255,6 +271,9 @@
     }
 
     private PlaybackState getPlaybackState() {
+        if (mIsHysteresis.get()) {
+            return mPlayStateHysteresisBuilder.build();
+        }
         return mIsMuted.get() ? mPlayStatePausingBuilder.build() : mPlayStatePlayingBuilder.build();
     }
 
@@ -283,7 +302,9 @@
                 new Notification.Builder(this, CHANNEL_ID)
                         .setSmallIcon(com.android.settingslib.R.drawable.ic_bt_le_audio_sharing)
                         .setStyle(mediaStyle)
-                        .setContentText(getString(BROADCAST_CONTENT_TEXT))
+                        .setContentText(getString(
+                                mIsHysteresis.get() ? BROADCAST_STREAM_PAUSED_TEXT :
+                                        BROADCAST_LISTENING_NOW_TEXT))
                         .setSilent(true);
         return notificationBuilder.build();
     }
@@ -307,6 +328,38 @@
             handleRemoveSource();
         }
 
+        @Override
+        public void onReceiveStateChanged(
+                BluetoothDevice sink, int sourceId, BluetoothLeBroadcastReceiveState state) {
+            super.onReceiveStateChanged(sink, sourceId, state);
+            if (!mHysteresisModeFixAvailable || mDevices == null || !mDevices.contains(sink)) {
+                return;
+            }
+            var sourceState = LocalBluetoothLeBroadcastAssistant.getLocalSourceState(state);
+            boolean streaming = sourceState == STREAMING;
+            boolean paused = sourceState == PAUSED;
+            // Exit early if the state is neither streaming nor paused
+            if (!streaming && !paused) {
+                return;
+            }
+            // Atomically update mIsHysteresis if its current value is not the current paused state
+            if (mIsHysteresis.compareAndSet(!paused, paused)) {
+                synchronized (mLocalSessionLock) {
+                    if (mLocalSession == null) {
+                        return;
+                    }
+                    mLocalSession.setPlaybackState(getPlaybackState());
+                    if (mNotificationManager != null) {
+                        mNotificationManager.notify(
+                                NOTIFICATION_ID,
+                                buildNotification(mLocalSession.getSessionToken())
+                        );
+                    }
+                    Log.d(TAG, "updating hysteresis mode to : " + paused);
+                }
+            }
+        }
+
         private void handleRemoveSource() {
             if (mAudioStreamsHelper != null
                     && !mAudioStreamsHelper.getConnectedBroadcastIdAndState(
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragment.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragment.java
index 656694d..daa7a2e 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragment.java
@@ -19,7 +19,9 @@
 import android.app.settings.SettingsEnums;
 import android.bluetooth.BluetoothLeBroadcastMetadata;
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -30,6 +32,8 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
 
 import com.android.settings.R;
 import com.android.settings.bluetooth.Utils;
@@ -70,15 +74,16 @@
                     if (broadcastMetadata == null) {
                         return;
                     }
-                    Bitmap bm = getQrCodeBitmap(broadcastMetadata, getActivity()).orElse(null);
-                    if (bm == null) {
+                    Drawable drawable = getQrCodeDrawable(broadcastMetadata, getActivity()).orElse(
+                            null);
+                    if (drawable == null) {
                         return;
                     }
 
                     ThreadUtils.postOnMainThread(
                             () -> {
                                 ((ImageView) view.requireViewById(R.id.qrcode_view))
-                                        .setImageBitmap(bm);
+                                        .setImageDrawable(drawable);
                                 if (broadcastMetadata.getBroadcastCode() != null) {
                                     String password =
                                             new String(
@@ -101,28 +106,33 @@
                 });
     }
 
-    /** Gets an optional bitmap from metadata. */
-    public static Optional<Bitmap> getQrCodeBitmap(@Nullable BluetoothLeBroadcastMetadata metadata,
+    /** Gets an optional drawable from metadata. */
+    public static Optional<Drawable> getQrCodeDrawable(
+            @Nullable BluetoothLeBroadcastMetadata metadata,
             Context context) {
         if (metadata == null) {
-            Log.d(TAG, "getQrCodeBitmap: broadcastMetadata is empty!");
+            Log.d(TAG, "getQrCodeDrawable: broadcastMetadata is empty!");
             return Optional.empty();
         }
         String metadataStr = BluetoothLeBroadcastMetadataExt.INSTANCE.toQrCodeString(metadata);
         if (metadataStr.isEmpty()) {
-            Log.d(TAG, "getQrCodeBitmap: metadataStr is empty!");
+            Log.d(TAG, "getQrCodeDrawable: metadataStr is empty!");
             return Optional.empty();
         }
-        Log.d(TAG, "getQrCodeBitmap: metadata : " + metadata);
+        Log.d(TAG, "getQrCodeDrawable: metadata : " + metadata);
         try {
-            int qrcodeSize =
-                    context.getResources().getDimensionPixelSize(R.dimen.audio_streams_qrcode_size);
-            Bitmap bitmap = QrCodeGenerator.encodeQrCode(metadataStr, qrcodeSize);
-            return Optional.of(bitmap);
+            Resources resources = context.getResources();
+            int qrcodeSize = resources.getDimensionPixelSize(R.dimen.audio_streams_qrcode_size);
+            int margin = resources.getDimensionPixelSize(R.dimen.audio_streams_qrcode_margin);
+            Bitmap bitmap = QrCodeGenerator.encodeQrCode(metadataStr, qrcodeSize, margin);
+            RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(resources, bitmap);
+            drawable.setCornerRadius(resources.getDimensionPixelSize(
+                    R.dimen.audio_streams_qrcode_preview_radius));
+            return Optional.of(drawable);
         } catch (WriterException e) {
             Log.d(
                     TAG,
-                    "getQrCodeBitmap: broadcastMetadata "
+                    "getQrCodeDrawable: broadcastMetadata "
                             + metadata
                             + " qrCode generation exception "
                             + e);
diff --git a/src/com/android/settings/contract/SettingsContract.kt b/src/com/android/settings/contract/SettingsContract.kt
index d3798da..99db497 100644
--- a/src/com/android/settings/contract/SettingsContract.kt
+++ b/src/com/android/settings/contract/SettingsContract.kt
@@ -47,3 +47,42 @@
 
 /** Contract key for the "Screen attention" setting. */
 const val KEY_SCREEN_ATTENTION = "screen_attention"
+
+/** Contract key for the "Use adaptive connectivity" setting. */
+const val KEY_ADAPTIVE_CONNECTIVITY = "adaptive_connectivity"
+
+/** Contract key for the "WiFi hotspot" setting. */
+const val KEY_WIFI_HOTSPOT = "enable_wifi_ap"
+
+/** Contract key for the "Battery Gauge Slider" setting. */
+const val KEY_BATTERY_LEVEL = "battery_level"
+
+/** Contract key for the "Battery Percentage" setting. */
+const val KEY_BATTERY_PERCENTAGE = "battery_percentage"
+
+/** Contract key for the "Brightness level" setting. */
+const val KEY_BRIGHTNESS_LEVEL = "brightness_level"
+
+/** Contract key for the "Smooth display" setting. */
+const val KEY_SMOOTH_DISPLAY = "smooth_display"
+
+/** Contract key for the "Dark theme" setting. */
+const val KEY_DARK_THEME = "dark_theme"
+
+/** Contract key for the "Always show time and info" setting. */
+const val KEY_AMBIENT_DISPLAY_ALWAYS_ON = "ambient_display_always_on"
+
+/** Contract key for the "Use vibration & haptics" setting. */
+const val KEY_VIBRATION_HAPTICS = "vibration_haptics"
+
+/** Contract key for the "Media volume" setting. */
+const val KEY_MEDIA_VOLUME = "media_volume"
+
+/** Contract key for the "Call volume" setting. */
+const val KEY_CALL_VOLUME = "call_volume"
+
+/** Contract key for the "Ring volume" setting. */
+const val KEY_RING_VOLUME = "separate_ring_volume"
+
+/** Contract key for the "Remove animation" setting. */
+const val KEY_REMOVE_ANIMATION = "remove_animation"
diff --git a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
index 849a80b..4afe987 100644
--- a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
+++ b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
@@ -47,6 +47,7 @@
 import com.android.settings.security.LockscreenDashboardFragment;
 import com.android.settings.security.SecurityAdvancedSettings;
 import com.android.settings.security.SecuritySettings;
+import com.android.settings.supervision.SupervisionDashboardFragment;
 import com.android.settings.system.SystemDashboardFragment;
 import com.android.settingslib.drawer.CategoryKey;
 
@@ -132,6 +133,8 @@
                 CategoryKey.CATEGORY_SPECIAL_APP_ACCESS);
         PARENT_TO_CATEGORY_KEY_MAP.put(MoreSecurityPrivacyFragment.class.getName(),
                 CategoryKey.CATEGORY_MORE_SECURITY_PRIVACY_SETTINGS);
+        PARENT_TO_CATEGORY_KEY_MAP.put(SupervisionDashboardFragment.class.getName(),
+                CategoryKey.CATEGORY_SUPERVISION);
 
         CATEGORY_KEY_TO_PARENT_MAP = new ArrayMap<>(PARENT_TO_CATEGORY_KEY_MAP.size());
 
diff --git a/src/com/android/settings/datausage/DataSaverMainSwitchPreference.kt b/src/com/android/settings/datausage/DataSaverMainSwitchPreference.kt
index b46fe99..33d756e 100644
--- a/src/com/android/settings/datausage/DataSaverMainSwitchPreference.kt
+++ b/src/com/android/settings/datausage/DataSaverMainSwitchPreference.kt
@@ -16,7 +16,6 @@
 
 package com.android.settings.datausage
 
-import android.Manifest
 import android.app.settings.SettingsEnums.ACTION_DATA_SAVER_MODE
 import android.content.Context
 import com.android.settings.PreferenceActionMetricsProvider
@@ -50,11 +49,9 @@
 
     override fun storage(context: Context) = createDataStore(context)
 
-    override fun getReadPermissions(context: Context) =
-        Permissions.allOf(Manifest.permission.MANAGE_NETWORK_POLICY)
+    override fun getReadPermissions(context: Context) = Permissions.EMPTY
 
-    override fun getWritePermissions(context: Context) =
-        Permissions.allOf(Manifest.permission.MANAGE_NETWORK_POLICY)
+    override fun getWritePermissions(context: Context) = Permissions.EMPTY
 
     override fun getReadPermit(context: Context, callingPid: Int, callingUid: Int) =
         ReadWritePermit.ALLOW
diff --git a/src/com/android/settings/display/AdaptiveSleepPreference.kt b/src/com/android/settings/display/AdaptiveSleepPreference.kt
index 45b05ec..e9efc2f 100644
--- a/src/com/android/settings/display/AdaptiveSleepPreference.kt
+++ b/src/com/android/settings/display/AdaptiveSleepPreference.kt
@@ -16,6 +16,7 @@
 
 package com.android.settings.display
 
+import android.app.settings.SettingsEnums.ACTION_SCREEN_ATTENTION_CHANGED
 import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
@@ -26,8 +27,10 @@
 import android.os.PowerManager
 import android.os.UserManager
 import android.provider.Settings
+import com.android.settings.PreferenceActionMetricsProvider
 import com.android.settings.PreferenceRestrictionMixin
 import com.android.settings.R
+import com.android.settings.contract.KEY_SCREEN_ATTENTION
 import com.android.settingslib.RestrictedSwitchPreference
 import com.android.settingslib.datastore.KeyValueStore
 import com.android.settingslib.datastore.KeyedObservableDelegate
@@ -46,6 +49,7 @@
 class AdaptiveSleepPreference :
     BooleanValuePreference,
     SwitchPreferenceBinding,
+    PreferenceActionMetricsProvider,
     PreferenceLifecycleProvider,
     PreferenceBindingPlaceholder, // not needed once controller class is cleaned up
     PreferenceAvailabilityProvider,
@@ -63,6 +67,11 @@
     override val summary: Int
         get() = R.string.adaptive_sleep_description
 
+    override val preferenceActionMetrics: Int
+        get() = ACTION_SCREEN_ATTENTION_CHANGED
+
+    override fun tags(context: Context) = arrayOf(KEY_SCREEN_ATTENTION)
+
     override fun isIndexable(context: Context) = false
 
     override fun isEnabled(context: Context) =
diff --git a/src/com/android/settings/display/AmbientDisplayAlwaysOnPreference.kt b/src/com/android/settings/display/AmbientDisplayAlwaysOnPreference.kt
index 3cc608b..453593f 100644
--- a/src/com/android/settings/display/AmbientDisplayAlwaysOnPreference.kt
+++ b/src/com/android/settings/display/AmbientDisplayAlwaysOnPreference.kt
@@ -24,6 +24,7 @@
 import android.provider.Settings.Secure.DOZE_ALWAYS_ON
 import com.android.settings.PreferenceRestrictionMixin
 import com.android.settings.R
+import com.android.settings.contract.KEY_AMBIENT_DISPLAY_ALWAYS_ON
 import com.android.settings.display.AmbientDisplayAlwaysOnPreferenceController.isAodSuppressedByBedtime
 import com.android.settingslib.datastore.AbstractKeyedDataObservable
 import com.android.settingslib.datastore.HandlerExecutor
@@ -123,7 +124,7 @@
     }
 
     companion object {
-        const val KEY = "ambient_display_always_on"
+        const val KEY = KEY_AMBIENT_DISPLAY_ALWAYS_ON
         private const val PROP_AWARE_AVAILABLE = "ro.vendor.aware_available"
     }
 }
diff --git a/src/com/android/settings/display/AutoBrightnessScreen.kt b/src/com/android/settings/display/AutoBrightnessScreen.kt
index b594b55..7018f81 100644
--- a/src/com/android/settings/display/AutoBrightnessScreen.kt
+++ b/src/com/android/settings/display/AutoBrightnessScreen.kt
@@ -15,6 +15,7 @@
  */
 package com.android.settings.display
 
+import android.app.settings.SettingsEnums.ACTION_ADAPTIVE_BRIGHTNESS
 import android.content.Context
 import android.os.UserManager
 import android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE
@@ -22,8 +23,10 @@
 import android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL
 import androidx.preference.Preference
 import androidx.preference.PreferenceScreen
+import com.android.settings.PreferenceActionMetricsProvider
 import com.android.settings.PreferenceRestrictionMixin
 import com.android.settings.R
+import com.android.settings.contract.KEY_ADAPTIVE_BRIGHTNESS
 import com.android.settings.flags.Flags
 import com.android.settingslib.PrimarySwitchPreferenceBinding
 import com.android.settingslib.datastore.AbstractKeyedDataObservable
@@ -47,6 +50,7 @@
     PreferenceScreenCreator,
     PreferenceScreenBinding, // binding for screen page
     PrimarySwitchPreferenceBinding, // binding for screen entry point widget
+    PreferenceActionMetricsProvider,
     PreferenceAvailabilityProvider,
     PreferenceRestrictionMixin,
     BooleanValuePreference {
@@ -56,6 +60,11 @@
     override val title: Int
         get() = R.string.auto_brightness_title
 
+    override val preferenceActionMetrics: Int
+        get() = ACTION_ADAPTIVE_BRIGHTNESS
+
+    override fun tags(context: Context) = arrayOf(KEY_ADAPTIVE_BRIGHTNESS)
+
     override fun isFlagEnabled(context: Context) = Flags.catalystScreenBrightnessMode()
 
     override fun fragmentClass() = AutoBrightnessSettings::class.java
diff --git a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java
index 6c95823..8bb526f 100644
--- a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java
@@ -152,8 +152,8 @@
     }
 
     /** Sets the {@link OptimizationMode} for associated app. */
-    public void setAppUsageState(@OptimizationMode int mode, Action action) {
-        if (getAppOptimizationMode() == mode) {
+    public void setAppUsageState(@OptimizationMode int mode, Action action, boolean forceMode) {
+        if (!forceMode && getAppOptimizationMode() == mode) {
             Log.w(TAG, "set the same optimization mode for: " + mPackageName);
             return;
         }
@@ -161,6 +161,11 @@
                 mContext, mode, mUid, mPackageName, mBatteryUtils, mPowerAllowListBackend, action);
     }
 
+    /** Sets the {@link OptimizationMode} for associated app. */
+    public void setAppUsageState(@OptimizationMode int mode, Action action) {
+        setAppUsageState(mode, action, /* forceMode= */ false);
+    }
+
     /** Return {@code true} if it is disabled for default optimized mode only. */
     public boolean isDisabledForOptimizeModeOnly() {
         return getForceBatteryOptimizeModeList(mContext).contains(mPackageName)
diff --git a/src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizations.java b/src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizations.java
index d948cc0..6cb6442 100644
--- a/src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizations.java
+++ b/src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizations.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.fuelgauge;
 
+import static com.android.settings.fuelgauge.BatteryOptimizeUtils.MODE_UNRESTRICTED;
+
 import android.Manifest;
 import android.content.DialogInterface;
 import android.content.pm.ApplicationInfo;
@@ -24,20 +26,25 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.PowerManager;
-import android.os.PowerWhitelistManager;
+import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.internal.app.AlertActivity;
 import com.android.internal.app.AlertController;
 import com.android.settings.R;
+import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
 
 public class RequestIgnoreBatteryOptimizations extends AlertActivity
         implements DialogInterface.OnClickListener {
     private static final String TAG = "RequestIgnoreBatteryOptimizations";
     private static final boolean DEBUG = false;
 
-    private PowerWhitelistManager mPowerWhitelistManager;
-    private String mPackageName;
+    @VisibleForTesting
+    static BatteryOptimizeUtils sTestBatteryOptimizeUtils = null;
+
+    private ApplicationInfo mApplicationInfo;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -47,8 +54,6 @@
                         android.view.WindowManager.LayoutParams
                                 .SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
 
-        mPowerWhitelistManager = getSystemService(PowerWhitelistManager.class);
-
         Uri data = getIntent().getData();
         if (data == null) {
             debugLog(
@@ -56,17 +61,18 @@
             finish();
             return;
         }
-        mPackageName = data.getSchemeSpecificPart();
-        if (mPackageName == null) {
+        final String packageName = data.getSchemeSpecificPart();
+        if (TextUtils.isEmpty(packageName)) {
             debugLog(
                     "No data supplied for IGNORE_BATTERY_OPTIMIZATION_SETTINGS in: " + getIntent());
             finish();
             return;
         }
 
+        // Package in Unrestricted mode already ignoring the battery optimizations.
         PowerManager power = getSystemService(PowerManager.class);
-        if (power.isIgnoringBatteryOptimizations(mPackageName)) {
-            debugLog("Not should prompt, already ignoring optimizations: " + mPackageName);
+        if (power.isIgnoringBatteryOptimizations(packageName)) {
+            debugLog("Not should prompt, already ignoring optimizations: " + packageName);
             finish();
             return;
         }
@@ -74,29 +80,28 @@
         if (getPackageManager()
                         .checkPermission(
                                 Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
-                                mPackageName)
+                                packageName)
                 != PackageManager.PERMISSION_GRANTED) {
             debugLog(
                     "Requested package "
-                            + mPackageName
+                            + packageName
                             + " does not hold permission "
                             + Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
             finish();
             return;
         }
 
-        ApplicationInfo ai;
         try {
-            ai = getPackageManager().getApplicationInfo(mPackageName, 0);
+            mApplicationInfo = getPackageManager().getApplicationInfo(packageName, 0);
         } catch (PackageManager.NameNotFoundException e) {
-            debugLog("Requested package doesn't exist: " + mPackageName);
+            debugLog("Requested package doesn't exist: " + packageName);
             finish();
             return;
         }
 
         final AlertController.AlertParams p = mAlertParams;
         final CharSequence appLabel =
-                ai.loadSafeLabel(
+                mApplicationInfo.loadSafeLabel(
                         getPackageManager(),
                         PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
                         PackageItemInfo.SAFE_LABEL_FLAG_TRIM
@@ -114,7 +119,15 @@
     public void onClick(DialogInterface dialog, int which) {
         switch (which) {
             case BUTTON_POSITIVE:
-                mPowerWhitelistManager.addToWhitelist(mPackageName);
+                BatteryOptimizeUtils batteryOptimizeUtils =
+                        sTestBatteryOptimizeUtils != null
+                                ? sTestBatteryOptimizeUtils
+                                : new BatteryOptimizeUtils(
+                                        getApplicationContext(),
+                                        mApplicationInfo.uid,
+                                        mApplicationInfo.packageName);
+                batteryOptimizeUtils.setAppUsageState(
+                        MODE_UNRESTRICTED, Action.APPLY, /* forceMode= */ true);
                 break;
             case BUTTON_NEGATIVE:
                 break;
diff --git a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverPreference.kt b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverPreference.kt
index 3e5cee9..c98b7ba 100644
--- a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverPreference.kt
+++ b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverPreference.kt
@@ -16,9 +16,12 @@
 package com.android.settings.fuelgauge.batterysaver
 
 import android.Manifest
+import android.app.settings.SettingsEnums.ACTION_BATTERY_SAVER
 import android.content.Context
 import android.os.PowerManager
+import com.android.settings.PreferenceActionMetricsProvider
 import com.android.settings.R
+import com.android.settings.contract.KEY_BATTERY_SAVER
 import com.android.settings.fuelgauge.BatterySaverReceiver
 import com.android.settings.fuelgauge.BatterySaverReceiver.BatterySaverListener
 import com.android.settingslib.datastore.AbstractKeyedDataObservable
@@ -40,7 +43,13 @@
 
 // LINT.IfChange
 class BatterySaverPreference :
-    MainSwitchPreference(KEY, R.string.battery_saver_master_switch_title) {
+    MainSwitchPreference(KEY, R.string.battery_saver_master_switch_title),
+    PreferenceActionMetricsProvider {
+
+    override val preferenceActionMetrics: Int
+        get() = ACTION_BATTERY_SAVER
+
+    override fun tags(context: Context) = arrayOf(KEY_BATTERY_SAVER)
 
     override fun storage(context: Context) = BatterySaverStore(context)
 
diff --git a/src/com/android/settings/fuelgauge/batteryusage/ScreenOnTimeController.java b/src/com/android/settings/fuelgauge/batteryusage/ScreenOnTimeController.java
index 379cef3..9c56c17 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/ScreenOnTimeController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/ScreenOnTimeController.java
@@ -30,6 +30,7 @@
 import com.android.settings.Utils;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settingslib.widget.SettingsThemeHelper;
 
 import java.util.Locale;
 import java.util.regex.Matcher;
@@ -119,10 +120,11 @@
         }
 
         final SpannableString spannableText = new SpannableString(text);
+        final int enlargeFontSizeDp = SettingsThemeHelper.isExpressiveTheme(context) ? 64 : 36;
         final Matcher matcher = NUMBER_PATTERN.matcher(text);
         while (matcher.find()) {
             spannableText.setSpan(
-                    new AbsoluteSizeSpan(36, true /* dip */),
+                    new AbsoluteSizeSpan(enlargeFontSizeDp, true /* dip */),
                     matcher.start(),
                     matcher.end(),
                     Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/TextViewPreference.java b/src/com/android/settings/fuelgauge/batteryusage/TextViewPreference.java
index b20ef39..c904738 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/TextViewPreference.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/TextViewPreference.java
@@ -25,9 +25,10 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
+import com.android.settingslib.widget.GroupSectionDividerMixin;
 
 /** A preference for a single text view. */
-public class TextViewPreference extends Preference {
+public class TextViewPreference extends Preference implements GroupSectionDividerMixin {
     private static final String TAG = "TextViewPreference";
 
     @VisibleForTesting CharSequence mText;
diff --git a/src/com/android/settings/inputmethod/InputSettingPreferenceController.java b/src/com/android/settings/inputmethod/InputSettingPreferenceController.java
index f18c9f4..17b70b3 100644
--- a/src/com/android/settings/inputmethod/InputSettingPreferenceController.java
+++ b/src/com/android/settings/inputmethod/InputSettingPreferenceController.java
@@ -25,36 +25,29 @@
 import android.net.Uri;
 import android.os.Handler;
 import android.os.UserHandle;
-import android.view.View;
-import android.widget.RadioButton;
-import android.widget.RadioGroup;
-import android.widget.SeekBar;
-import android.widget.TextView;
 
 import androidx.annotation.NonNull;
 import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
 import androidx.lifecycle.LifecycleObserver;
 import androidx.lifecycle.OnLifecycleEvent;
 import androidx.preference.Preference;
 
-import com.android.settings.R;
 import com.android.settings.core.TogglePreferenceController;
 import com.android.settings.keyboard.Flags;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
-import java.text.NumberFormat;
-import java.util.concurrent.TimeUnit;
-
 /**
  * Abstract class for toggle controllers of Keyboard input setting related function.
  */
 public abstract class InputSettingPreferenceController extends TogglePreferenceController implements
         LifecycleObserver {
-    private static final int CUSTOM_PROGRESS_INTERVAL = 100;
-    private static final long MILLISECOND_IN_SECONDS = TimeUnit.SECONDS.toMillis(1);
     private final ContentResolver mContentResolver;
     protected final MetricsFeatureProvider mMetricsFeatureProvider;
+    protected FragmentManager mFragmentManager;
+
     private final ContentObserver mContentObserver = new ContentObserver(new Handler(true)) {
         @Override
         public void onChange(boolean selfChange, Uri uri) {
@@ -72,13 +65,6 @@
     protected void updateInputSettingKeysValue(int thresholdTimeMillis) {
     }
 
-    protected int getInputSettingKeysValue() {
-        return 0;
-    }
-
-    protected void onCustomValueUpdated(int thresholdTimeMillis) {
-    }
-
     public InputSettingPreferenceController(@NonNull Context context,
             @NonNull String preferenceKey) {
         super(context, preferenceKey);
@@ -86,6 +72,10 @@
         mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
     }
 
+    public void setFragment(Fragment fragment) {
+        mFragmentManager = fragment.getParentFragmentManager();
+    }
+
     @Override
     public void updateState(@NonNull Preference preference) {
         super.updateState(preference);
@@ -127,113 +117,4 @@
     private void unregisterSettingsObserver() {
         mContentResolver.unregisterContentObserver(mContentObserver);
     }
-
-    protected void constructDialog(Context context, int titleRes, int subtitleRes) {
-        mAlertDialog = new AlertDialog.Builder(context)
-                .setView(R.layout.dialog_keyboard_a11y_input_setting_keys)
-                .setPositiveButton(android.R.string.ok,
-                        (dialog, which) -> {
-                            RadioGroup radioGroup =
-                                    mAlertDialog.findViewById(
-                                            R.id.input_setting_keys_value_group);
-                            SeekBar seekbar = mAlertDialog.findViewById(
-                                    R.id.input_setting_keys_value_custom_slider);
-                            RadioButton customRadioButton = mAlertDialog.findViewById(
-                                    R.id.input_setting_keys_value_custom);
-                            int threshold;
-                            if (customRadioButton.isChecked()) {
-                                threshold = seekbar.getProgress() * CUSTOM_PROGRESS_INTERVAL;
-                            } else {
-                                int checkedRadioButtonId = radioGroup.getCheckedRadioButtonId();
-                                if (checkedRadioButtonId == R.id.input_setting_keys_value_600) {
-                                    threshold = 600;
-                                } else if (checkedRadioButtonId
-                                        == R.id.input_setting_keys_value_400) {
-                                    threshold = 400;
-                                } else if (checkedRadioButtonId
-                                        == R.id.input_setting_keys_value_200) {
-                                    threshold = 200;
-                                } else {
-                                    threshold = 0;
-                                }
-                            }
-                            updateInputSettingKeysValue(threshold);
-                            onCustomValueUpdated(threshold);
-                        })
-                .setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss())
-                .create();
-        mAlertDialog.setOnShowListener(dialog -> {
-            RadioGroup cannedValueRadioGroup = mAlertDialog.findViewById(
-                    R.id.input_setting_keys_value_group);
-            RadioButton customRadioButton = mAlertDialog.findViewById(
-                    R.id.input_setting_keys_value_custom);
-            TextView customValueTextView = mAlertDialog.findViewById(
-                    R.id.input_setting_keys_value_custom_value);
-            SeekBar customProgressBar = mAlertDialog.findViewById(
-                    R.id.input_setting_keys_value_custom_slider);
-            TextView titleTextView = mAlertDialog.findViewById(
-                    R.id.input_setting_keys_dialog_title);
-            TextView subTitleTextView = mAlertDialog.findViewById(
-                    R.id.input_setting_keys_dialog_subtitle);
-            titleTextView.setText(titleRes);
-            subTitleTextView.setText(subtitleRes);
-
-            customProgressBar.incrementProgressBy(CUSTOM_PROGRESS_INTERVAL);
-            customProgressBar.setProgress(1);
-            View customValueView = mAlertDialog.findViewById(
-                    R.id.input_setting_keys_custom_value_option);
-            customValueView.setOnClickListener(l -> customRadioButton.performClick());
-            customRadioButton.setOnCheckedChangeListener((buttonView, isChecked) -> {
-                if (isChecked) {
-                    cannedValueRadioGroup.clearCheck();
-                }
-                customValueTextView.setVisibility(isChecked ? View.VISIBLE : View.GONE);
-                customValueTextView.setText(
-                        progressToThresholdInSecond(customProgressBar.getProgress()));
-                customProgressBar.setVisibility(isChecked ? View.VISIBLE : View.GONE);
-                buttonView.setChecked(isChecked);
-            });
-            cannedValueRadioGroup.setOnCheckedChangeListener(
-                    (group, checkedId) -> customRadioButton.setChecked(false));
-            customProgressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
-                @Override
-                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-                    customValueTextView.setText(progressToThresholdInSecond(progress));
-                }
-
-                @Override
-                public void onStartTrackingTouch(SeekBar seekBar) {
-                }
-
-                @Override
-                public void onStopTrackingTouch(SeekBar seekBar) {
-                }
-            });
-            initStateBasedOnThreshold(cannedValueRadioGroup, customRadioButton, customValueTextView,
-                    customProgressBar);
-        });
-    }
-
-    private static String progressToThresholdInSecond(int progress) {
-        return NumberFormat.getInstance().format((float) progress * CUSTOM_PROGRESS_INTERVAL
-                / MILLISECOND_IN_SECONDS);
-    }
-
-    private void initStateBasedOnThreshold(RadioGroup cannedValueRadioGroup,
-            RadioButton customRadioButton, TextView customValueTextView,
-            SeekBar customProgressBar) {
-        int inputSettingKeysThreshold = getInputSettingKeysValue();
-        switch (inputSettingKeysThreshold) {
-            case 600 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_600);
-            case 400 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_400);
-            case 0, 200 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_200);
-            default -> {
-                customValueTextView.setText(
-                        String.valueOf(
-                                (double) inputSettingKeysThreshold / MILLISECOND_IN_SECONDS));
-                customProgressBar.setProgress(inputSettingKeysThreshold / CUSTOM_PROGRESS_INTERVAL);
-                customRadioButton.setChecked(true);
-            }
-        }
-    }
 }
diff --git a/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysController.java b/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysController.java
index 9a0f1c0..69fbe6b 100644
--- a/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysController.java
+++ b/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysController.java
@@ -16,7 +16,6 @@
 
 package com.android.settings.inputmethod;
 
-import static android.app.settings.SettingsEnums.ACTION_BOUNCE_KEYS_CUSTOM_VALUE_CHANGE;
 import static android.app.settings.SettingsEnums.ACTION_BOUNCE_KEYS_DISABLED;
 import static android.app.settings.SettingsEnums.ACTION_BOUNCE_KEYS_ENABLED;
 
@@ -32,13 +31,13 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
-import com.android.settings.R;
 import com.android.settingslib.PrimarySwitchPreference;
 
 public class KeyboardAccessibilityBounceKeysController extends
         InputSettingPreferenceController implements
         LifecycleObserver {
     public static final int BOUNCE_KEYS_THRESHOLD = 500;
+    private static final String KEY_TAG = "bounce_keys_dialog_tag";
 
     @Nullable
     private PrimarySwitchPreference mPrimaryPreference;
@@ -46,8 +45,6 @@
     public KeyboardAccessibilityBounceKeysController(@NonNull Context context,
             @NonNull String key) {
         super(context, key);
-        constructDialog(context, R.string.bounce_keys_dialog_title,
-                R.string.bounce_keys_dialog_subtitle);
     }
 
     @Override
@@ -65,12 +62,11 @@
 
     @Override
     public boolean handlePreferenceTreeClick(@NonNull Preference preference) {
-        if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+        if (!TextUtils.equals(preference.getKey(), getPreferenceKey())
+                || mFragmentManager == null) {
             return false;
         }
-        if (mAlertDialog != null) {
-            mAlertDialog.show();
-        }
+        KeyboardAccessibilityBounceKeysDialogFragment.getInstance().show(mFragmentManager, KEY_TAG);
         return true;
     }
 
@@ -88,12 +84,6 @@
     }
 
     @Override
-    protected void onCustomValueUpdated(int thresholdTimeMillis) {
-        mMetricsFeatureProvider.action(mContext, ACTION_BOUNCE_KEYS_CUSTOM_VALUE_CHANGE,
-                thresholdTimeMillis);
-    }
-
-    @Override
     protected void onInputSettingUpdated() {
         if (mPrimaryPreference != null) {
             mPrimaryPreference.setChecked(
@@ -111,9 +101,4 @@
     protected void updateInputSettingKeysValue(int thresholdTimeMillis) {
         InputSettings.setAccessibilityBounceKeysThreshold(mContext, thresholdTimeMillis);
     }
-
-    @Override
-    protected int getInputSettingKeysValue() {
-        return InputSettings.getAccessibilityBounceKeysThreshold(mContext);
-    }
 }
diff --git a/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysDialogFragment.java b/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysDialogFragment.java
new file mode 100644
index 0000000..5e5bd06
--- /dev/null
+++ b/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysDialogFragment.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2025 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.inputmethod;
+
+import static android.app.settings.SettingsEnums.ACTION_BOUNCE_KEYS_CUSTOM_VALUE_CHANGE;
+
+import android.hardware.input.InputSettings;
+import android.os.Bundle;
+
+import com.android.settings.R;
+
+public class KeyboardAccessibilityBounceKeysDialogFragment extends
+        KeyboardAccessibilityKeysDialogFragment {
+
+    static KeyboardAccessibilityBounceKeysDialogFragment getInstance() {
+        final KeyboardAccessibilityBounceKeysDialogFragment result =
+                new KeyboardAccessibilityBounceKeysDialogFragment();
+        Bundle bundle = new Bundle();
+        bundle.putInt(EXTRA_TITLE_RES, R.string.bounce_keys_dialog_title);
+        bundle.putInt(EXTRA_SUBTITLE_RES, R.string.bounce_keys_dialog_subtitle);
+        bundle.putInt(EXTRA_SEEKBAR_CONTENT_DESCRIPTION,
+                R.string.input_setting_bounce_keys_seekbar_desc);
+        result.setArguments(bundle);
+        return result;
+    }
+
+    @Override
+    protected void updateInputSettingKeysValue(int thresholdTimeMillis) {
+        InputSettings.setAccessibilityBounceKeysThreshold(getContext(), thresholdTimeMillis);
+    }
+
+    @Override
+    protected void onCustomValueUpdated(int thresholdTimeMillis) {
+        mMetricsFeatureProvider.action(getContext(), ACTION_BOUNCE_KEYS_CUSTOM_VALUE_CHANGE,
+                thresholdTimeMillis);
+    }
+
+    @Override
+    protected int getInputSettingKeysValue() {
+        return InputSettings.getAccessibilityBounceKeysThreshold(getContext());
+    }
+}
diff --git a/src/com/android/settings/inputmethod/KeyboardAccessibilityKeysDialogFragment.java b/src/com/android/settings/inputmethod/KeyboardAccessibilityKeysDialogFragment.java
new file mode 100644
index 0000000..252ce54
--- /dev/null
+++ b/src/com/android/settings/inputmethod/KeyboardAccessibilityKeysDialogFragment.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2025 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.inputmethod;
+
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.widget.RadioButton;
+import android.widget.RadioGroup;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+import androidx.fragment.app.DialogFragment;
+
+import com.android.settings.R;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+
+import org.jspecify.annotations.Nullable;
+
+import java.util.Locale;
+import java.util.concurrent.TimeUnit;
+
+public abstract class KeyboardAccessibilityKeysDialogFragment extends DialogFragment {
+    private static final int CUSTOM_PROGRESS_INTERVAL = 100;
+    private static final long MILLISECOND_IN_SECONDS = TimeUnit.SECONDS.toMillis(1);
+    protected static final String EXTRA_TITLE_RES = "extra_title_res";
+    protected static final String EXTRA_SUBTITLE_RES = "extra_subtitle_res";
+    protected static final String EXTRA_SEEKBAR_CONTENT_DESCRIPTION =
+            "extra_seekbar_content_description_res";
+
+    protected final MetricsFeatureProvider mMetricsFeatureProvider;
+
+    public KeyboardAccessibilityKeysDialogFragment() {
+        mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
+    }
+
+    protected void updateInputSettingKeysValue(int thresholdTimeMillis) {
+    }
+
+    protected void onCustomValueUpdated(int thresholdTimeMillis) {
+    }
+
+    protected int getInputSettingKeysValue() {
+        return 0;
+    }
+
+    @Override
+    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+        super.onCreateDialog(savedInstanceState);
+        int titleRes = getArguments().getInt(EXTRA_TITLE_RES);
+        int subtitleRes = getArguments().getInt(EXTRA_SUBTITLE_RES);
+        int seekbarContentDescriptionRes = getArguments().getInt(EXTRA_SEEKBAR_CONTENT_DESCRIPTION);
+
+        Activity activity = getActivity();
+        View dialoglayout =
+                LayoutInflater.from(activity).inflate(
+                        R.layout.dialog_keyboard_a11y_input_setting_keys, null);
+        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(activity);
+        dialogBuilder.setView(dialoglayout);
+        dialogBuilder.setPositiveButton(android.R.string.ok,
+                        (dialog, which) -> {
+                            RadioGroup radioGroup =
+                                    dialoglayout.findViewById(
+                                            R.id.input_setting_keys_value_group);
+                            SeekBar seekbar = dialoglayout.findViewById(
+                                    R.id.input_setting_keys_value_custom_slider);
+                            RadioButton customRadioButton = dialoglayout.findViewById(
+                                    R.id.input_setting_keys_value_custom);
+                            int threshold;
+                            if (customRadioButton.isChecked()) {
+                                threshold = seekbar.getProgress() * CUSTOM_PROGRESS_INTERVAL;
+                            } else {
+                                int checkedRadioButtonId = radioGroup.getCheckedRadioButtonId();
+                                if (checkedRadioButtonId == R.id.input_setting_keys_value_600) {
+                                    threshold = 600;
+                                } else if (checkedRadioButtonId
+                                        == R.id.input_setting_keys_value_400) {
+                                    threshold = 400;
+                                } else if (checkedRadioButtonId
+                                        == R.id.input_setting_keys_value_200) {
+                                    threshold = 200;
+                                } else {
+                                    threshold = 0;
+                                }
+                            }
+                            updateInputSettingKeysValue(threshold);
+                            onCustomValueUpdated(threshold);
+                        })
+                .setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss());
+        AlertDialog accessibilityKeyDialog = dialogBuilder.create();
+        accessibilityKeyDialog.setOnShowListener(dialog -> {
+            RadioGroup cannedValueRadioGroup = accessibilityKeyDialog.findViewById(
+                    R.id.input_setting_keys_value_group);
+            RadioButton customRadioButton = accessibilityKeyDialog.findViewById(
+                    R.id.input_setting_keys_value_custom);
+            TextView customValueTextView = accessibilityKeyDialog.findViewById(
+                    R.id.input_setting_keys_value_custom_value);
+            SeekBar customProgressBar = accessibilityKeyDialog.findViewById(
+                    R.id.input_setting_keys_value_custom_slider);
+            TextView titleTextView = accessibilityKeyDialog.findViewById(
+                    R.id.input_setting_keys_dialog_title);
+            TextView subTitleTextView = accessibilityKeyDialog.findViewById(
+                    R.id.input_setting_keys_dialog_subtitle);
+            titleTextView.setText(titleRes);
+            subTitleTextView.setText(subtitleRes);
+
+            if (seekbarContentDescriptionRes != 0) {
+                customProgressBar.setContentDescription(
+                        getContext().getString(seekbarContentDescriptionRes));
+            }
+            customProgressBar.incrementProgressBy(CUSTOM_PROGRESS_INTERVAL);
+            customProgressBar.setProgress(1);
+            View customValueView = accessibilityKeyDialog.findViewById(
+                    R.id.input_setting_keys_custom_value_option);
+            customValueView.setOnClickListener(l -> customRadioButton.performClick());
+            customRadioButton.setOnCheckedChangeListener((buttonView, isChecked) -> {
+                if (isChecked) {
+                    cannedValueRadioGroup.clearCheck();
+                }
+                customValueTextView.setVisibility(isChecked ? View.VISIBLE : View.GONE);
+                customValueTextView.setText(
+                        progressToThresholdInSecond(customProgressBar.getProgress()));
+                customProgressBar.setVisibility(isChecked ? View.VISIBLE : View.GONE);
+                buttonView.setChecked(isChecked);
+            });
+            cannedValueRadioGroup.setOnCheckedChangeListener(
+                    (group, checkedId) -> customRadioButton.setChecked(false));
+            customProgressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+                @Override
+                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                    String threshold = progressToThresholdInSecond(progress);
+                    customValueTextView.setText(threshold);
+                    customProgressBar.setContentDescription(threshold);
+                }
+
+                @Override
+                public void onStartTrackingTouch(SeekBar seekBar) {
+                }
+
+                @Override
+                public void onStopTrackingTouch(SeekBar seekBar) {
+                }
+            });
+            initStateBasedOnThreshold(cannedValueRadioGroup, customRadioButton, customValueTextView,
+                    customProgressBar);
+        });
+
+        final Window window = accessibilityKeyDialog.getWindow();
+        window.setType(TYPE_SYSTEM_DIALOG);
+
+        return accessibilityKeyDialog;
+    }
+
+    private String progressToThresholdInSecond(int progress) {
+        return (double) progress * CUSTOM_PROGRESS_INTERVAL
+                / MILLISECOND_IN_SECONDS + " " + TimeUnit.SECONDS.name().toLowerCase(
+                Locale.getDefault());
+    }
+
+    private void initStateBasedOnThreshold(RadioGroup cannedValueRadioGroup,
+            RadioButton customRadioButton, TextView customValueTextView,
+            SeekBar customProgressBar) {
+        int inputSettingKeysThreshold = getInputSettingKeysValue();
+        switch (inputSettingKeysThreshold) {
+            case 600 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_600);
+            case 400 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_400);
+            case 0, 200 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_200);
+            default -> {
+                customValueTextView.setText(
+                        String.valueOf(
+                                (double) inputSettingKeysThreshold / MILLISECOND_IN_SECONDS));
+                customProgressBar.setProgress(inputSettingKeysThreshold / CUSTOM_PROGRESS_INTERVAL);
+                customRadioButton.setChecked(true);
+            }
+        }
+    }
+}
diff --git a/src/com/android/settings/inputmethod/KeyboardAccessibilityMouseKeysController.java b/src/com/android/settings/inputmethod/KeyboardAccessibilityMouseKeysController.java
index 2db0e05..a8d9f30 100644
--- a/src/com/android/settings/inputmethod/KeyboardAccessibilityMouseKeysController.java
+++ b/src/com/android/settings/inputmethod/KeyboardAccessibilityMouseKeysController.java
@@ -35,7 +35,7 @@
 public class KeyboardAccessibilityMouseKeysController extends
         InputSettingPreferenceController implements
         LifecycleObserver {
-    private static final String KEY_MOUSE_KEY = "accessibility_mouse_keys";
+    private static final String KEY_MOUSE_KEY = "keyboard_a11y_page_mouse_keys";
     private static final String KEY_MOUSE_KEY_MAIN_PAGE = "mouse_keys_main_switch";
 
     @Nullable
diff --git a/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysController.java b/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysController.java
index 451742f..f3d7407 100644
--- a/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysController.java
+++ b/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysController.java
@@ -16,7 +16,6 @@
 
 package com.android.settings.inputmethod;
 
-import static android.app.settings.SettingsEnums.ACTION_SLOW_KEYS_CUSTOM_VALUE_CHANGE;
 import static android.app.settings.SettingsEnums.ACTION_SLOW_KEYS_DISABLED;
 import static android.app.settings.SettingsEnums.ACTION_SLOW_KEYS_ENABLED;
 
@@ -32,20 +31,19 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
-import com.android.settings.R;
 import com.android.settingslib.PrimarySwitchPreference;
 
 public class KeyboardAccessibilitySlowKeysController extends
         InputSettingPreferenceController implements
         LifecycleObserver {
     public static final int SLOW_KEYS_THRESHOLD = 500;
+    private static final String KEY_TAG = "slow_keys_dialog_tag";
 
     @Nullable
     private PrimarySwitchPreference mPrimarySwitchPreference;
 
     public KeyboardAccessibilitySlowKeysController(@NonNull Context context, @NonNull String key) {
         super(context, key);
-        constructDialog(context, R.string.slow_keys, R.string.slow_keys_summary);
     }
 
     @Override
@@ -90,12 +88,11 @@
 
     @Override
     public boolean handlePreferenceTreeClick(@NonNull Preference preference) {
-        if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+        if (!TextUtils.equals(preference.getKey(), getPreferenceKey())
+                || mFragmentManager == null) {
             return false;
         }
-        if (mAlertDialog != null) {
-            mAlertDialog.show();
-        }
+        KeyboardAccessibilitySlowKeysDialogFragment.getInstance().show(mFragmentManager, KEY_TAG);
         return true;
     }
 
@@ -103,15 +100,4 @@
     protected void updateInputSettingKeysValue(int thresholdTimeMillis) {
         InputSettings.setAccessibilitySlowKeysThreshold(mContext, thresholdTimeMillis);
     }
-
-    @Override
-    protected void onCustomValueUpdated(int thresholdTimeMillis) {
-        mMetricsFeatureProvider.action(mContext,
-                ACTION_SLOW_KEYS_CUSTOM_VALUE_CHANGE, thresholdTimeMillis);
-    }
-
-    @Override
-    protected int getInputSettingKeysValue() {
-        return InputSettings.getAccessibilitySlowKeysThreshold(mContext);
-    }
 }
diff --git a/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysDialogFragment.java b/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysDialogFragment.java
new file mode 100644
index 0000000..e411d7a
--- /dev/null
+++ b/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysDialogFragment.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2025 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.inputmethod;
+
+import static android.app.settings.SettingsEnums.ACTION_SLOW_KEYS_CUSTOM_VALUE_CHANGE;
+
+import android.hardware.input.InputSettings;
+import android.os.Bundle;
+
+import com.android.settings.R;
+
+public class KeyboardAccessibilitySlowKeysDialogFragment extends
+        KeyboardAccessibilityKeysDialogFragment {
+
+    static KeyboardAccessibilitySlowKeysDialogFragment getInstance() {
+        final KeyboardAccessibilitySlowKeysDialogFragment result =
+                new KeyboardAccessibilitySlowKeysDialogFragment();
+        Bundle bundle = new Bundle();
+        bundle.putInt(EXTRA_TITLE_RES, R.string.slow_keys);
+        bundle.putInt(EXTRA_SUBTITLE_RES, R.string.slow_keys_summary);
+        bundle.putInt(EXTRA_SEEKBAR_CONTENT_DESCRIPTION,
+                R.string.input_setting_slow_keys_seekbar_desc);
+        result.setArguments(bundle);
+        return result;
+    }
+
+    @Override
+    protected void updateInputSettingKeysValue(int thresholdTimeMillis) {
+        InputSettings.setAccessibilitySlowKeysThreshold(getContext(), thresholdTimeMillis);
+    }
+
+    @Override
+    protected void onCustomValueUpdated(int thresholdTimeMillis) {
+        mMetricsFeatureProvider.action(getContext(),
+                ACTION_SLOW_KEYS_CUSTOM_VALUE_CHANGE, thresholdTimeMillis);
+    }
+
+    @Override
+    protected int getInputSettingKeysValue() {
+        return InputSettings.getAccessibilitySlowKeysThreshold(getContext());
+    }
+}
diff --git a/src/com/android/settings/inputmethod/PhysicalKeyboardA11yFragment.java b/src/com/android/settings/inputmethod/PhysicalKeyboardA11yFragment.java
index 117aadb..67a808f 100644
--- a/src/com/android/settings/inputmethod/PhysicalKeyboardA11yFragment.java
+++ b/src/com/android/settings/inputmethod/PhysicalKeyboardA11yFragment.java
@@ -51,6 +51,8 @@
         super.onAttach(context);
         mInputManager = Preconditions.checkNotNull(getActivity()
                 .getSystemService(InputManager.class));
+        use(KeyboardAccessibilitySlowKeysController.class).setFragment(this /*parent*/);
+        use(KeyboardAccessibilityBounceKeysController.class).setFragment(this /*parent*/);
     }
 
     @Override
diff --git a/src/com/android/settings/network/AdaptiveConnectivityTogglePreference.kt b/src/com/android/settings/network/AdaptiveConnectivityTogglePreference.kt
index ec5061e..c9ba714 100644
--- a/src/com/android/settings/network/AdaptiveConnectivityTogglePreference.kt
+++ b/src/com/android/settings/network/AdaptiveConnectivityTogglePreference.kt
@@ -16,7 +16,6 @@
 
 package com.android.settings.network
 
-import android.Manifest
 import android.content.Context
 import android.net.wifi.WifiManager
 import android.provider.Settings.Secure.ADAPTIVE_CONNECTIVITY_ENABLED
@@ -39,8 +38,7 @@
 
     override fun getReadPermissions(context: Context) = SettingsSecureStore.getReadPermissions()
 
-    override fun getWritePermissions(context: Context) =
-        SettingsSecureStore.getWritePermissions() and Manifest.permission.NETWORK_SETTINGS
+    override fun getWritePermissions(context: Context) = SettingsSecureStore.getWritePermissions()
 
     override fun getReadPermit(context: Context, callingPid: Int, callingUid: Int) =
         ReadWritePermit.ALLOW
diff --git a/src/com/android/settings/network/MobileDataPreference.kt b/src/com/android/settings/network/MobileDataPreference.kt
index 80f58e0..6cb3da2 100644
--- a/src/com/android/settings/network/MobileDataPreference.kt
+++ b/src/com/android/settings/network/MobileDataPreference.kt
@@ -17,9 +17,12 @@
 package com.android.settings.network
 
 import android.Manifest
+import android.app.settings.SettingsEnums.ACTION_MOBILE_DATA
 import android.content.Context
 import android.telephony.SubscriptionManager
+import com.android.settings.PreferenceActionMetricsProvider
 import com.android.settings.R
+import com.android.settings.contract.KEY_MOBILE_DATA
 import com.android.settings.network.telephony.MobileDataRepository
 import com.android.settings.network.telephony.SubscriptionRepository
 import com.android.settingslib.datastore.KeyValueStore
@@ -38,8 +41,14 @@
         R.string.mobile_data_settings_title,
         R.string.mobile_data_settings_summary,
     ),
+    PreferenceActionMetricsProvider,
     PreferenceAvailabilityProvider {
 
+    override val preferenceActionMetrics: Int
+        get() = ACTION_MOBILE_DATA
+
+    override fun tags(context: Context) = arrayOf(KEY_MOBILE_DATA)
+
     override fun isAvailable(context: Context) =
         SubscriptionRepository(context).getSelectableSubscriptionInfoList().any {
             it.simSlotIndex > -1
@@ -59,7 +68,7 @@
     override fun getWritePermissions(context: Context) =
         Permissions.allOf(
             // TelephonyManager.setDataEnabledForReason
-            Manifest.permission.MODIFY_PHONE_STATE,
+            Manifest.permission.MODIFY_PHONE_STATE
         )
 
     override fun getReadPermit(context: Context, callingPid: Int, callingUid: Int) =
diff --git a/src/com/android/settings/network/telephony/RenameMobileNetworkDialogFragment.java b/src/com/android/settings/network/telephony/RenameMobileNetworkDialogFragment.java
index ebc5575..73f80f6 100644
--- a/src/com/android/settings/network/telephony/RenameMobileNetworkDialogFragment.java
+++ b/src/com/android/settings/network/telephony/RenameMobileNetworkDialogFragment.java
@@ -165,9 +165,9 @@
         }
         final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
                 info, getContext());
-        mNameView.setText(displayName);
         if (!TextUtils.isEmpty(displayName)) {
-            mNameView.setSelection(displayName.length());
+            mNameView.setSelection(Math.min(displayName.length(),
+                    getResources().getInteger(R.integer.sim_label_max_length)));
         }
 
         mColorSpinner = view.findViewById(R.id.color_spinner);
@@ -176,7 +176,7 @@
         mColorSpinner.setAdapter(adapter);
         mColorSpinner.setSelection(getSimColorIndex(info.getIconTint()));
 
-        if(Flags.isDualSimOnboardingEnabled()){
+        if (Flags.isDualSimOnboardingEnabled()) {
             return;
         }
 
@@ -293,10 +293,10 @@
     }
 
     /*
-    * Get the color index from previous color that defined in Android OS
-    * (frameworks/base/core/res/res/values/arrays.xml). If can't find the color, continue to look
-    * for it in the new color plattee. If not, give it the first index.
-    */
+     * Get the color index from previous color that defined in Android OS
+     * (frameworks/base/core/res/res/values/arrays.xml). If can't find the color, continue to look
+     * for it in the new color plattee. If not, give it the first index.
+     */
 
     private int getSimColorIndex(int color) {
         int index = -1;
diff --git a/src/com/android/settings/notification/OWNERS b/src/com/android/settings/notification/OWNERS
index 29484c6..424e6cc 100644
--- a/src/com/android/settings/notification/OWNERS
+++ b/src/com/android/settings/notification/OWNERS
@@ -1,7 +1,6 @@
 # Default reviewers for this and subdirectories.
-aroederer@google.com
 beverlyt@google.com
 dsandler@android.com
 juliacr@google.com
 matiashe@google.com
-yurilin@google.com
\ No newline at end of file
+yurilin@google.com
diff --git a/src/com/android/settings/safetycenter/LockScreenSafetySource.java b/src/com/android/settings/safetycenter/LockScreenSafetySource.java
index 14ad268..00a4c67 100644
--- a/src/com/android/settings/safetycenter/LockScreenSafetySource.java
+++ b/src/com/android/settings/safetycenter/LockScreenSafetySource.java
@@ -95,8 +95,7 @@
                 new SafetySourceStatus.Builder(
                                 context.getString(R.string.unlock_set_unlock_launch_picker_title),
                                 lockScreenAllowedByAdmin
-                                        ? screenLockPreferenceDetailsUtils.getSummary(
-                                                UserHandle.myUserId())
+                                        ? getScreenLockSummary(screenLockPreferenceDetailsUtils)
                                         : context.getString(R.string.disabled_by_policy_title),
                                 severityLevel)
                         .setPendingIntent(lockScreenAllowedByAdmin ? pendingIntent : null)
@@ -114,6 +113,12 @@
                 .setSafetySourceData(context, SAFETY_SOURCE_ID, safetySourceData, safetyEvent);
     }
 
+    private static String getScreenLockSummary(
+            ScreenLockPreferenceDetailsUtils screenLockPreferenceDetailsUtils) {
+        String summary = screenLockPreferenceDetailsUtils.getSummary(UserHandle.myUserId());
+        return summary != null ? summary : "";
+    }
+
     /** Notifies Safety Center of a change in lock screen settings. */
     public static void onLockScreenChange(Context context) {
         setSafetySourceData(
diff --git a/src/com/android/settings/security/ScreenLockPreferenceDetailsUtils.java b/src/com/android/settings/security/ScreenLockPreferenceDetailsUtils.java
index bc38feb..b168568 100644
--- a/src/com/android/settings/security/ScreenLockPreferenceDetailsUtils.java
+++ b/src/com/android/settings/security/ScreenLockPreferenceDetailsUtils.java
@@ -23,6 +23,7 @@
 import android.os.UserManager;
 import android.os.storage.StorageManager;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.StringRes;
 
 import com.android.internal.app.UnlaunchableAppActivity;
@@ -43,6 +44,7 @@
 
     private final int mUserId = UserHandle.myUserId();
     private final Context mContext;
+    @Nullable
     private final LockPatternUtils mLockPatternUtils;
     private final int mProfileChallengeUserId;
     private final UserManager mUm;
@@ -85,7 +87,7 @@
      * Returns whether the lock pattern is secure.
      */
     public boolean isLockPatternSecure() {
-        return mLockPatternUtils.isSecure(mUserId);
+        return mLockPatternUtils != null && mLockPatternUtils.isSecure(mUserId);
     }
 
     /**
@@ -148,6 +150,7 @@
         // profile with unified challenge on FBE-enabled devices. Otherwise, vold would not be
         // able to complete the operation due to the lack of (old) encryption key.
         if (mProfileChallengeUserId != UserHandle.USER_NULL
+                && mLockPatternUtils != null
                 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(mProfileChallengeUserId)
                 && StorageManager.isFileEncrypted()) {
             if (mUm.isQuietModeEnabled(UserHandle.of(mProfileChallengeUserId))) {
@@ -166,8 +169,12 @@
                 .toIntent();
     }
 
+    @Nullable
     @StringRes
     private Integer getSummaryResId(int userId) {
+        if (mLockPatternUtils == null) {
+            return null;
+        }
         if (!mLockPatternUtils.isSecure(userId)) {
             if (userId == mProfileChallengeUserId
                     || mLockPatternUtils.isLockScreenDisabled(userId)) {
diff --git a/src/com/android/settings/service/PreferenceService.kt b/src/com/android/settings/service/PreferenceService.kt
index 9843847..6710f92 100644
--- a/src/com/android/settings/service/PreferenceService.kt
+++ b/src/com/android/settings/service/PreferenceService.kt
@@ -16,6 +16,8 @@
 
 package com.android.settings.service
 
+import android.Manifest.permission.WRITE_SYSTEM_PREFERENCES
+import android.app.AppOpsManager.OP_WRITE_SYSTEM_PREFERENCES
 import android.os.Binder
 import android.os.OutcomeReceiver
 import android.service.settings.preferences.GetValueRequest
@@ -32,6 +34,7 @@
 import com.android.settingslib.graph.PreferenceGetterFlags
 import com.android.settingslib.graph.PreferenceSetterApiHandler
 import com.android.settingslib.ipc.ApiPermissionChecker
+import com.android.settingslib.ipc.AppOpApiPermissionChecker
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.SupervisorJob
@@ -47,10 +50,15 @@
 
     init {
         val metricsLogger = SettingsRemoteOpMetricsLogger()
+        // PreferenceService specifies READ_SYSTEM_PREFERENCES permission in AndroidManifest.xml
         getApiHandler =
             PreferenceGetterApiHandler(1, ApiPermissionChecker.alwaysAllow(), metricsLogger)
         setApiHandler =
-            PreferenceSetterApiHandler(2, ApiPermissionChecker.alwaysAllow(), metricsLogger)
+            PreferenceSetterApiHandler(
+                2,
+                AppOpApiPermissionChecker(OP_WRITE_SYSTEM_PREFERENCES, WRITE_SYSTEM_PREFERENCES),
+                metricsLogger,
+            )
         graphApi =
             GetPreferenceGraphApiHandler(3, ApiPermissionChecker.alwaysAllow(), metricsLogger)
     }
diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java
index 41f1892..38ca5cd 100644
--- a/src/com/android/settings/slices/CustomSliceRegistry.java
+++ b/src/com/android/settings/slices/CustomSliceRegistry.java
@@ -171,7 +171,7 @@
             .scheme(ContentResolver.SCHEME_CONTENT)
             .authority(SettingsSliceProvider.SLICE_AUTHORITY)
             .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
-            .appendPath("call_volume")
+            .appendPath(SettingsContractKt.KEY_CALL_VOLUME)
             .build();
     /**
      * Full {@link Uri} for the Media Volume Slice.
@@ -180,7 +180,7 @@
             .scheme(ContentResolver.SCHEME_CONTENT)
             .authority(SettingsSliceProvider.SLICE_AUTHORITY)
             .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
-            .appendPath("media_volume")
+            .appendPath(SettingsContractKt.KEY_MEDIA_VOLUME)
             .build();
 
     /**
@@ -190,7 +190,7 @@
             .scheme(ContentResolver.SCHEME_CONTENT)
             .authority(SettingsSliceProvider.SLICE_AUTHORITY)
             .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
-            .appendPath("separate_ring_volume")
+            .appendPath(SettingsContractKt.KEY_RING_VOLUME)
             .build();
 
     /**
@@ -268,7 +268,7 @@
             .scheme(ContentResolver.SCHEME_CONTENT)
             .authority(SettingsSliceProvider.SLICE_AUTHORITY)
             .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
-            .appendPath("dark_theme")
+            .appendPath(SettingsContractKt.KEY_DARK_THEME)
             .build();
 
     /**
diff --git a/src/com/android/settings/wifi/WifiSwitchPreference.kt b/src/com/android/settings/wifi/WifiSwitchPreference.kt
index 2b2b344..53445c5 100644
--- a/src/com/android/settings/wifi/WifiSwitchPreference.kt
+++ b/src/com/android/settings/wifi/WifiSwitchPreference.kt
@@ -17,6 +17,7 @@
 package com.android.settings.wifi
 
 import android.Manifest
+import android.app.settings.SettingsEnums.ACTION_WIFI
 import android.app.settings.SettingsEnums.ACTION_WIFI_OFF
 import android.app.settings.SettingsEnums.ACTION_WIFI_ON
 import android.content.BroadcastReceiver
@@ -29,8 +30,10 @@
 import android.widget.Toast
 import androidx.preference.Preference
 import androidx.preference.Preference.OnPreferenceChangeListener
+import com.android.settings.PreferenceActionMetricsProvider
 import com.android.settings.PreferenceRestrictionMixin
 import com.android.settings.R
+import com.android.settings.contract.KEY_WIFI
 import com.android.settings.network.SatelliteRepository.Companion.isSatelliteOn
 import com.android.settings.network.SatelliteWarningDialogActivity
 import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
@@ -54,6 +57,7 @@
 class WifiSwitchPreference :
     SwitchPreference(KEY, R.string.wifi),
     SwitchPreferenceBinding,
+    PreferenceActionMetricsProvider,
     OnPreferenceChangeListener,
     PreferenceLifecycleProvider,
     PreferenceRestrictionMixin {
@@ -61,6 +65,11 @@
     override val keywords: Int
         get() = R.string.keywords_wifi
 
+    override val preferenceActionMetrics: Int
+        get() = ACTION_WIFI
+
+    override fun tags(context: Context) = arrayOf(KEY_WIFI)
+
     override fun isEnabled(context: Context) = super<PreferenceRestrictionMixin>.isEnabled(context)
 
     override val restrictionKeys
diff --git a/src/com/android/settings/wifi/calling/WifiCallingMainSwitchPreference.kt b/src/com/android/settings/wifi/calling/WifiCallingMainSwitchPreference.kt
index 8765547..ccf89d0 100644
--- a/src/com/android/settings/wifi/calling/WifiCallingMainSwitchPreference.kt
+++ b/src/com/android/settings/wifi/calling/WifiCallingMainSwitchPreference.kt
@@ -19,12 +19,15 @@
 import android.Manifest.permission.MODIFY_PHONE_STATE
 import android.Manifest.permission.READ_PRECISE_PHONE_STATE
 import android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE
+import android.app.settings.SettingsEnums.ACTION_WIFI_CALLING
 import android.content.Context
 import android.telephony.SubscriptionManager
 import android.telephony.TelephonyManager
 import android.telephony.ims.ImsMmTelManager
 import android.util.Log
+import com.android.settings.PreferenceActionMetricsProvider
 import com.android.settings.R
+import com.android.settings.contract.KEY_WIFI_CALLING
 import com.android.settings.network.ims.WifiCallingQueryImsState
 import com.android.settings.network.telephony.wificalling.WifiCallingRepository
 import com.android.settings.widget.SettingsMainSwitchPreference
@@ -47,7 +50,10 @@
  * TODO(b/372732219): apply metadata to UI
  */
 class WifiCallingMainSwitchPreference(private val subId: Int) :
-    BooleanValuePreference, BooleanValuePreferenceBinding, PreferenceAvailabilityProvider {
+    BooleanValuePreference,
+    BooleanValuePreferenceBinding,
+    PreferenceActionMetricsProvider,
+    PreferenceAvailabilityProvider {
 
     override val key: String
         get() = KEY
@@ -55,6 +61,11 @@
     override val title: Int
         get() = R.string.wifi_calling_main_switch_title
 
+    override val preferenceActionMetrics: Int
+        get() = ACTION_WIFI_CALLING
+
+    override fun tags(context: Context) = arrayOf(KEY_WIFI_CALLING)
+
     override fun isEnabled(context: Context) =
         context.isCallStateIdle(subId) &&
             WifiCallingQueryImsState(context, subId).isAllowUserControl
diff --git a/src/com/android/settings/wifi/calling/WifiCallingSettings.java b/src/com/android/settings/wifi/calling/WifiCallingSettings.java
index 0c3457c..6110d28 100644
--- a/src/com/android/settings/wifi/calling/WifiCallingSettings.java
+++ b/src/com/android/settings/wifi/calling/WifiCallingSettings.java
@@ -94,6 +94,7 @@
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
+        super.onCreateView(inflater, container, savedInstanceState);
         if (MobileNetworkUtils.isMobileNetworkUserRestricted(getActivity())) {
             return new ViewStub(getActivity());
         }
diff --git a/tests/robotests/src/com/android/settings/applications/contacts/ContactsStorageSettingsTest.java b/tests/robotests/src/com/android/settings/applications/contacts/ContactsStorageSettingsTest.java
index 0abacec..e1bf874 100644
--- a/tests/robotests/src/com/android/settings/applications/contacts/ContactsStorageSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/applications/contacts/ContactsStorageSettingsTest.java
@@ -345,7 +345,8 @@
         SelectorWithWidgetPreference simPreference = accountCategory.findPreference(
                 String.valueOf(SIM_ACCOUNT.hashCode()));
         assertThat(simPreference.getTitle()).isEqualTo("SIM");
-        assertThat(simPreference.getSummary()).isEqualTo("SIM");
+        assertThat(simPreference.getSummary()).isEqualTo(
+                "Contacts may not sync or be available on your other devices");
         assertThat(simPreference.getIcon()).isNotNull();
         assertThat(simPreference.isChecked()).isTrue();
     }
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
index 02825d2..47ba523 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
@@ -135,16 +135,20 @@
     @Mock
     private Vibrator mVibrator;
 
+    private FingerprintSettingsFeatureProvider mFingerprintSettingsFeatureProvider;
+
+    private FakeFeatureFactory mFakeFeatureFactory;
     private FingerprintAuthenticateSidecar mFingerprintAuthenticateSidecar;
     private FingerprintRemoveSidecar mFingerprintRemoveSidecar;
 
     @Before
     public void setUp() {
         ShadowUtils.setFingerprintManager(mFingerprintManager);
-        FakeFeatureFactory.setupForTest();
+        mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
 
         mContext = spy(ApplicationProvider.getApplicationContext());
         mFragment = spy(new FingerprintSettingsFragment());
+        mFingerprintSettingsFeatureProvider = new FingerprintSettingsFeatureProvider();
         doReturn(mContext).when(mFragment).getContext();
         doReturn(mBiometricManager).when(mContext).getSystemService(BiometricManager.class);
         doReturn(true).when(mFingerprintManager).isHardwareDetected();
@@ -152,6 +156,9 @@
         when(mBiometricManager.canAuthenticate(PRIMARY_USER_ID,
                 BiometricManager.Authenticators.IDENTITY_CHECK))
                 .thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
+        when(mFakeFeatureFactory.getFingerprintFeatureProvider()
+                .getFingerprintSettingsFeatureProvider())
+                .thenReturn(mFingerprintSettingsFeatureProvider);
     }
 
     @After
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAmbientVolumePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAmbientVolumePreferenceControllerTest.java
index 4c20a88..a7523ef 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAmbientVolumePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAmbientVolumePreferenceControllerTest.java
@@ -98,30 +98,44 @@
     @Test
     public void isAvailable_notHearingDevice_returnFalse() {
         when(mCachedDevice.isHearingDevice()).thenReturn(false);
+        when(mCachedDevice.getProfiles()).thenReturn(List.of(mVolumeControlProfile));
+        when(mUiController.isAmbientControlAvailable()).thenReturn(true);
 
         assertThat(mController.isAvailable()).isFalse();
     }
 
     @Test
-    public void isAvailable_isHearingDeviceAndNotSupportVcp_returnFalse() {
+    public void isAvailable_notSupportVcp_returnFalse() {
         when(mCachedDevice.isHearingDevice()).thenReturn(true);
         when(mCachedDevice.getProfiles()).thenReturn(List.of());
+        when(mUiController.isAmbientControlAvailable()).thenReturn(true);
 
         assertThat(mController.isAvailable()).isFalse();
     }
 
     @Test
-    public void isAvailable_isHearingDeviceAndSupportVcp_returnTrue() {
+    public void isAvailable_noValidAmbientControlPoint_returnFalse() {
         when(mCachedDevice.isHearingDevice()).thenReturn(true);
         when(mCachedDevice.getProfiles()).thenReturn(List.of(mVolumeControlProfile));
+        when(mUiController.isAmbientControlAvailable()).thenReturn(false);
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_isHearingDevice_supportVcp_validAmbientControl_returnTrue() {
+        when(mCachedDevice.isHearingDevice()).thenReturn(true);
+        when(mCachedDevice.getProfiles()).thenReturn(List.of(mVolumeControlProfile));
+        when(mUiController.isAmbientControlAvailable()).thenReturn(true);
 
         assertThat(mController.isAvailable()).isTrue();
     }
 
     @Test
-    public void refresh_isHearingDeviceAndNotSupportVcp_verifyUiControllerNoRefresh() {
-        when(mCachedDevice.isHearingDevice()).thenReturn(true);
-        when(mCachedDevice.getProfiles()).thenReturn(List.of());
+    public void refresh_notHearingDevice_verifyUiControllerNotRefresh() {
+        when(mCachedDevice.isHearingDevice()).thenReturn(false);
+        when(mCachedDevice.getProfiles()).thenReturn(List.of(mVolumeControlProfile));
+        when(mUiController.isAmbientControlAvailable()).thenReturn(true);
 
         mController.refresh();
 
@@ -129,9 +143,32 @@
     }
 
     @Test
-    public void refresh_isHearingDeviceAndSupportVcp_verifyUiControllerRefresh() {
+    public void refresh_notSupportVcp_verifyUiControllerNotRefresh() {
+        when(mCachedDevice.isHearingDevice()).thenReturn(true);
+        when(mCachedDevice.getProfiles()).thenReturn(List.of());
+        when(mUiController.isAmbientControlAvailable()).thenReturn(true);
+
+        mController.refresh();
+
+        verify(mUiController, never()).refresh();
+    }
+
+    @Test
+    public void refresh_noValidAmbientControl_verifyUiControllerNotRefresh() {
         when(mCachedDevice.isHearingDevice()).thenReturn(true);
         when(mCachedDevice.getProfiles()).thenReturn(List.of(mVolumeControlProfile));
+        when(mUiController.isAmbientControlAvailable()).thenReturn(false);
+
+        mController.refresh();
+
+        verify(mUiController, never()).refresh();
+    }
+
+    @Test
+    public void refresh_isHearingDevice_supportVcp_validAmbientControl_verifyUiControllerRefresh() {
+        when(mCachedDevice.isHearingDevice()).thenReturn(true);
+        when(mCachedDevice.getProfiles()).thenReturn(List.of(mVolumeControlProfile));
+        when(mUiController.isAmbientControlAvailable()).thenReturn(true);
 
         mController.refresh();
 
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioDeviceTypeControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioDeviceTypeControllerTest.java
index 2010502..3cdb302 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioDeviceTypeControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioDeviceTypeControllerTest.java
@@ -18,7 +18,6 @@
 
 import static android.bluetooth.BluetoothDevice.DEVICE_TYPE_LE;
 import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_SPEAKER;
-import static android.media.audio.Flags.automaticBtDeviceType;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -98,12 +97,7 @@
     @Test
     public void createAudioDeviceTypePreference_btDeviceIsCategorized_checkSelection() {
         int deviceType = AUDIO_DEVICE_CATEGORY_SPEAKER;
-        if (automaticBtDeviceType()) {
-            when(mAudioManager.getBluetoothAudioDeviceCategory(MAC_ADDRESS)).thenReturn(deviceType);
-        } else {
-            when(mAudioManager.getBluetoothAudioDeviceCategory_legacy(MAC_ADDRESS, /*isBle=*/
-                    true)).thenReturn(deviceType);
-        }
+        when(mAudioManager.getBluetoothAudioDeviceCategory(MAC_ADDRESS)).thenReturn(deviceType);
 
         mController.createAudioDeviceTypePreference(mContext);
         mAudioDeviceTypePref = mController.getAudioDeviceTypePreference();
@@ -118,12 +112,7 @@
 
         mController.onPreferenceChange(mAudioDeviceTypePref, Integer.toString(deviceType));
 
-        if (automaticBtDeviceType()) {
-            verify(mAudioManager).setBluetoothAudioDeviceCategory(eq(MAC_ADDRESS),
-                    eq(AUDIO_DEVICE_CATEGORY_SPEAKER));
-        } else {
-            verify(mAudioManager).setBluetoothAudioDeviceCategory_legacy(eq(MAC_ADDRESS), eq(true),
-                    eq(AUDIO_DEVICE_CATEGORY_SPEAKER));
-        }
+        verify(mAudioManager).setBluetoothAudioDeviceCategory(eq(MAC_ADDRESS),
+                eq(AUDIO_DEVICE_CATEGORY_SPEAKER));
     }
 }
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragmentTest.java
index b4c0a20..145a5c7 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragmentTest.java
@@ -60,6 +60,7 @@
 import org.robolectric.shadow.api.Shadow;
 import org.robolectric.shadows.androidx.fragment.FragmentController;
 
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -263,6 +264,18 @@
         assertThat(dialog).isNotNull();
         ImageView image = dialog.findViewById(R.id.description_image);
         assertThat(image).isNotNull();
+        TextView text = dialog.findViewById(R.id.description_text);
+        assertThat(text).isNotNull();
+        assertThat(METADATA).isNotNull();
+        assertThat(text.getText().toString()).isEqualTo(
+                mParent.getString(R.string.audio_sharing_dialog_qr_code_content,
+                        METADATA.getBroadcastName(), new String(
+                                METADATA.getBroadcastCode(),
+                                StandardCharsets.UTF_8)));
+        TextView textBottom = dialog.findViewById(R.id.description_text_2);
+        assertThat(textBottom).isNotNull();
+        assertThat(textBottom.getText().toString()).isEqualTo(
+                mParent.getString(R.string.audio_sharing_dialog_pair_new_device_content));
         Button cancelBtn = dialog.findViewById(R.id.negative_btn);
         assertThat(cancelBtn).isNotNull();
         cancelBtn.performClick();
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaServiceTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaServiceTest.java
index bfb474b..a0e971b 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaServiceTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaServiceTest.java
@@ -40,6 +40,7 @@
 import android.app.settings.SettingsEnums;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeBroadcastReceiveState;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothStatusCodes;
 import android.content.Context;
@@ -86,6 +87,7 @@
 import org.robolectric.util.ReflectionHelpers;
 
 import java.util.ArrayList;
+import java.util.List;
 import java.util.Set;
 
 @RunWith(RobolectricTestRunner.class)
@@ -99,11 +101,13 @@
 public class AudioStreamMediaServiceTest {
     @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
     @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+    private static final String DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
     private static final String CHANNEL_ID = "bluetooth_notification_channel";
     private static final String DEVICE_NAME = "name";
     @Mock private Resources mResources;
     @Mock private LocalBluetoothManager mLocalBtManager;
     @Mock private LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
+    @Mock private BluetoothLeBroadcastReceiveState mBroadcastReceiveState;
     @Mock private AudioStreamsHelper mAudioStreamsHelper;
     @Mock private NotificationManager mNotificationManager;
     @Mock private MediaSessionManager mMediaSessionManager;
@@ -305,6 +309,63 @@
     }
 
     @Test
+    public void assistantCallback_onReceiveStateChanged_connected_doNothing() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+
+        mAudioStreamMediaService.onCreate();
+        mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
+
+        assertThat(mAudioStreamMediaService.mBroadcastAssistantCallback).isNotNull();
+        List<Long> bisSyncState = new ArrayList<>();
+        bisSyncState.add(1L);
+        when(mBroadcastReceiveState.getBisSyncState()).thenReturn(bisSyncState);
+        when(mDevice.getAddress()).thenReturn(DEVICE_ADDRESS);
+        when(mBroadcastReceiveState.getSourceDevice()).thenReturn(mDevice);
+
+        mAudioStreamMediaService.mBroadcastAssistantCallback.onReceiveStateChanged(
+                mDevice, /* sourceId= */ 0, /* state= */ mBroadcastReceiveState);
+
+        verify(mNotificationManager, never()).notify(anyInt(), any());
+    }
+
+    @Test
+    public void assistantCallback_onReceiveStateChanged_hysteresis_updateNotification() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+
+        mAudioStreamMediaService.onCreate();
+        mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
+
+        assertThat(mAudioStreamMediaService.mBroadcastAssistantCallback).isNotNull();
+        when(mBroadcastReceiveState.getBisSyncState()).thenReturn(new ArrayList<>());
+        when(mDevice.getAddress()).thenReturn(DEVICE_ADDRESS);
+        when(mBroadcastReceiveState.getSourceDevice()).thenReturn(mDevice);
+
+        mAudioStreamMediaService.mBroadcastAssistantCallback.onReceiveStateChanged(
+                mDevice, /* sourceId= */ 0, /* state= */ mBroadcastReceiveState);
+
+        verify(mNotificationManager).notify(anyInt(), any());
+    }
+
+    @Test
+    public void assistantCallback_onReceiveStateChanged_hysteresis_flagOff_doNothing() {
+        mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+
+        mAudioStreamMediaService.onCreate();
+        mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
+
+        assertThat(mAudioStreamMediaService.mBroadcastAssistantCallback).isNotNull();
+        mAudioStreamMediaService.mBroadcastAssistantCallback.onReceiveStateChanged(
+                mDevice, /* sourceId= */ 0, /* state= */ mBroadcastReceiveState);
+
+        verify(mBroadcastReceiveState, never()).getBisSyncState();
+        verify(mBroadcastReceiveState, never()).getSourceDevice();
+        verify(mNotificationManager, never()).notify(anyInt(), any());
+    }
+
+    @Test
     public void bluetoothCallback_onBluetoothOff_stopSelf() {
         mAudioStreamMediaService.onCreate();
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizationsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizationsTest.java
new file mode 100644
index 0000000..b7ffa38
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizationsTest.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2025 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.fuelgauge;
+
+import static com.android.settings.fuelgauge.BatteryOptimizeUtils.MODE_RESTRICTED;
+import static com.android.settings.fuelgauge.BatteryOptimizeUtils.MODE_UNRESTRICTED;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.PowerManager;
+
+import com.android.settings.testutils.shadow.ShadowUtils;
+import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowUtils.class})
+public class RequestIgnoreBatteryOptimizationsTest {
+    private static final int UID = 12345;
+    private static final String PACKAGE_NAME = "com.android.app";
+    private static final String UNKNOWN_PACKAGE_NAME = "com.android.unknown";
+    private static final String PACKAGE_LABEL = "app";
+    @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    private Context mContext;
+    private RequestIgnoreBatteryOptimizations mActivity;
+    private BatteryOptimizeUtils mBatteryOptimizeUtils;
+    private PowerAllowlistBackend mPowerAllowlistBackend;
+
+    @Mock private PowerManager mMockPowerManager;
+    @Mock private PackageManager mMockPackageManager;
+    @Mock private ApplicationInfo mMockApplicationInfo;
+    @Mock private BatteryUtils mMockBatteryUtils;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        mActivity = spy(Robolectric.setupActivity(RequestIgnoreBatteryOptimizations.class));
+        mBatteryOptimizeUtils = spy(new BatteryOptimizeUtils(mContext, UID, PACKAGE_NAME));
+        mPowerAllowlistBackend = spy(PowerAllowlistBackend.getInstance(mContext));
+        mBatteryOptimizeUtils.mPowerAllowListBackend = mPowerAllowlistBackend;
+        mBatteryOptimizeUtils.mBatteryUtils = mMockBatteryUtils;
+        RequestIgnoreBatteryOptimizations.sTestBatteryOptimizeUtils = mBatteryOptimizeUtils;
+
+        when(mActivity.getApplicationContext()).thenReturn(mContext);
+        doReturn(mMockPowerManager).when(mActivity).getSystemService(PowerManager.class);
+        doReturn(mMockPackageManager).when(mActivity).getPackageManager();
+        doReturn(mMockApplicationInfo)
+                .when(mMockPackageManager)
+                .getApplicationInfo(PACKAGE_NAME, 0);
+        doThrow(new PackageManager.NameNotFoundException(""))
+                .when(mMockPackageManager)
+                .getApplicationInfo(UNKNOWN_PACKAGE_NAME, 0);
+        doReturn(PACKAGE_LABEL)
+                .when(mMockApplicationInfo)
+                .loadSafeLabel(
+                        mMockPackageManager,
+                        PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
+                        PackageItemInfo.SAFE_LABEL_FLAG_TRIM
+                                | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE);
+
+        doReturn(PackageManager.PERMISSION_GRANTED)
+                .when(mMockPackageManager)
+                .checkPermission(
+                        eq(Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS), anyString());
+    }
+
+    @After
+    public void tearDown() {
+        ShadowUtils.reset();
+        PowerAllowlistBackend.resetInstance();
+    }
+
+    @Test
+    public void onCreate_withIntent_shouldNotFinish() {
+        mActivity.setIntent(createIntent(PACKAGE_NAME));
+
+        mActivity.onCreate(new Bundle());
+
+        verify(mActivity, never()).finish();
+    }
+
+    @Test
+    public void onCreate_withNoDataIntent_shouldFinish() {
+        mActivity.setIntent(new Intent());
+
+        mActivity.onCreate(new Bundle());
+
+        verify(mActivity).finish();
+    }
+
+    @Test
+    public void onCreate_withEmptyPackageName_shouldFinish() {
+        mActivity.setIntent(createIntent(""));
+
+        mActivity.onCreate(new Bundle());
+
+        verify(mActivity).finish();
+    }
+
+    @Test
+    public void onCreate_withPkgAlreadyIgnoreOptimization_shouldFinish() {
+        mActivity.setIntent(createIntent(PACKAGE_NAME));
+        doReturn(true).when(mMockPowerManager).isIgnoringBatteryOptimizations(PACKAGE_NAME);
+
+        mActivity.onCreate(new Bundle());
+
+        verify(mActivity).finish();
+    }
+
+    @Test
+    public void onCreate_withPkgWithoutPermission_shouldFinish() {
+        mActivity.setIntent(createIntent(PACKAGE_NAME));
+        doReturn(PackageManager.PERMISSION_DENIED)
+                .when(mMockPackageManager)
+                .checkPermission(
+                        Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, PACKAGE_NAME);
+
+        mActivity.onCreate(new Bundle());
+
+        verify(mActivity).finish();
+    }
+
+    @Test
+    public void onCreate_withPkgNameNotFound_shouldFinish() {
+        mActivity.setIntent(createIntent(UNKNOWN_PACKAGE_NAME));
+
+        mActivity.onCreate(new Bundle());
+
+        verify(mActivity).finish();
+    }
+
+    @Test
+    public void onClick_clickNegativeButton_doNothing() {
+        mActivity.onClick(null, DialogInterface.BUTTON_NEGATIVE);
+
+        verifyNoInteractions(mBatteryOptimizeUtils);
+    }
+
+    @Test
+    public void onClick_clickPositiveButtonWithUnrestrictedMode_addAllowlist() {
+        when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(MODE_UNRESTRICTED);
+
+        mActivity.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        verify(mBatteryOptimizeUtils)
+                .setAppUsageState(
+                        MODE_UNRESTRICTED,
+                        BatteryOptimizeHistoricalLogEntry.Action.APPLY,
+                        /* forceMode= */ true);
+        verify(mPowerAllowlistBackend).addApp(PACKAGE_NAME, UID);
+        verify(mMockBatteryUtils).setForceAppStandby(UID, PACKAGE_NAME, AppOpsManager.MODE_ALLOWED);
+    }
+
+    @Test
+    public void onClick_clickPositiveButtonWithRestrictedMode_addAllowlistAndSetStandby() {
+        when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(MODE_RESTRICTED);
+        doNothing().when(mMockBatteryUtils).setForceAppStandby(anyInt(), anyString(), anyInt());
+
+        mActivity.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        verify(mBatteryOptimizeUtils)
+                .setAppUsageState(
+                        MODE_UNRESTRICTED,
+                        BatteryOptimizeHistoricalLogEntry.Action.APPLY,
+                        /* forceMode= */ true);
+        verify(mPowerAllowlistBackend).addApp(PACKAGE_NAME, UID);
+        verify(mMockBatteryUtils).setForceAppStandby(UID, PACKAGE_NAME, AppOpsManager.MODE_ALLOWED);
+    }
+
+    private Intent createIntent(String packageName) {
+        final Intent intent = new Intent();
+        intent.setData(new Uri.Builder().scheme("package").opaquePart(packageName).build());
+        return intent;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysControllerTest.java
index b385b2f..d9aa79c 100644
--- a/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysControllerTest.java
+++ b/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysControllerTest.java
@@ -18,6 +18,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
@@ -25,12 +28,12 @@
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
-import android.widget.RadioGroup;
 
-import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentTransaction;
 import androidx.preference.Preference;
 
-import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.keyboard.Flags;
 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
@@ -45,10 +48,13 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowLooper;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
 
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {
+        KeyboardAccessibilityBounceKeysControllerTest
+                .ShadowKeyboardAccessibilityBounceKeysDialogFragment.class,
         com.android.settings.testutils.shadow.ShadowFragment.class,
         ShadowAlertDialogCompat.class,
 })
@@ -60,6 +66,15 @@
     private static final String PREFERENCE_KEY = "keyboard_a11y_page_bounce_keys";
     @Mock
     private Preference mPreference;
+    @Mock
+    private Fragment mFragment;
+    @Mock
+    private FragmentManager mFragmentManager;
+    @Mock
+    private FragmentTransaction mFragmentTransaction;
+    @Mock
+    private KeyboardAccessibilityBounceKeysDialogFragment
+            mKeyboardAccessibilityBounceKeysDialogFragment;
     private Context mContext;
     private KeyboardAccessibilityBounceKeysController mKeyboardAccessibilityBounceKeysController;
 
@@ -71,6 +86,11 @@
                 mContext,
                 PREFERENCE_KEY);
         when(mPreference.getKey()).thenReturn(PREFERENCE_KEY);
+        when(mFragment.getParentFragmentManager()).thenReturn(mFragmentManager);
+        when(mFragmentManager.beginTransaction()).thenReturn(mFragmentTransaction);
+        mKeyboardAccessibilityBounceKeysController.setFragment(mFragment);
+        ShadowKeyboardAccessibilityBounceKeysDialogFragment.setInstance(
+                mKeyboardAccessibilityBounceKeysDialogFragment);
     }
 
     @Test
@@ -107,23 +127,25 @@
     public void handlePreferenceTreeClick_dialogShows() {
         mKeyboardAccessibilityBounceKeysController.handlePreferenceTreeClick(mPreference);
 
-        AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
-
-        assertThat(alertDialog.isShowing()).isTrue();
+        verify(mKeyboardAccessibilityBounceKeysDialogFragment).show(any(FragmentManager.class),
+                anyString());
     }
 
-    @Test
-    public void handlePreferenceTreeClick_performClickOn200_updatesBounceKeysThreshold() {
-        mKeyboardAccessibilityBounceKeysController.handlePreferenceTreeClick(mPreference);
-        AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
-        RadioGroup radioGroup = alertDialog.findViewById(R.id.input_setting_keys_value_group);
-        radioGroup.check(R.id.input_setting_keys_value_200);
+    /**
+     * Note: Actually, shadow of KeyboardAccessibilitySlowKeysDialogFragment will not be used.
+     * Instance that returned with {@link #getInstance} should be set with {@link #setInstance}
+     */
+    @Implements(KeyboardAccessibilityBounceKeysDialogFragment.class)
+    public static class ShadowKeyboardAccessibilityBounceKeysDialogFragment {
+        static KeyboardAccessibilityBounceKeysDialogFragment sInstance = null;
 
-        alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).performClick();
-        ShadowLooper.idleMainLooper();
+        @Implementation
+        protected static KeyboardAccessibilityBounceKeysDialogFragment getInstance() {
+            return sInstance;
+        }
 
-        assertThat(alertDialog.isShowing()).isFalse();
-        int threshold = InputSettings.getAccessibilityBounceKeysThreshold(mContext);
-        assertThat(threshold).isEqualTo(200);
+        public static void setInstance(KeyboardAccessibilityBounceKeysDialogFragment instance) {
+            sInstance = instance;
+        }
     }
 }
diff --git a/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysDialogFragmentTest.java b/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysDialogFragmentTest.java
new file mode 100644
index 0000000..8e5f84e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysDialogFragmentTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2025 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.inputmethod;
+
+import static com.android.settings.inputmethod.KeyboardAccessibilityKeysDialogFragment.EXTRA_SUBTITLE_RES;
+import static com.android.settings.inputmethod.KeyboardAccessibilityKeysDialogFragment.EXTRA_TITLE_RES;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.AlertDialog;
+import android.hardware.input.InputSettings;
+import android.os.Bundle;
+import android.widget.RadioGroup;
+
+import androidx.fragment.app.testing.FragmentScenario;
+import androidx.lifecycle.Lifecycle;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.shadows.ShadowLooper;
+
+@RunWith(RobolectricTestRunner.class)
+public class KeyboardAccessibilityBounceKeysDialogFragmentTest {
+    private AlertDialog mAlertDialog;
+
+    @Before
+    public void setUp() {
+        Bundle bundle = new Bundle();
+        bundle.putInt(EXTRA_TITLE_RES, R.string.bounce_keys_dialog_title);
+        bundle.putInt(EXTRA_SUBTITLE_RES, R.string.bounce_keys_dialog_subtitle);
+
+        FragmentScenario<KeyboardAccessibilityBounceKeysDialogFragment> mFragmentScenario =
+                FragmentScenario.launch(
+                        KeyboardAccessibilityBounceKeysDialogFragment.class,
+                        bundle,
+                        R.style.Theme_AlertDialog_SettingsLib,
+                        Lifecycle.State.INITIALIZED);
+        mFragmentScenario.moveToState(Lifecycle.State.RESUMED);
+
+        mFragmentScenario.onFragment(fragment -> {
+            assertThat(fragment.getDialog()).isNotNull();
+            assertThat(fragment.requireDialog().isShowing()).isTrue();
+            assertThat(fragment.requireDialog()).isInstanceOf(AlertDialog.class);
+            mAlertDialog = (AlertDialog) fragment.requireDialog();
+        });
+    }
+
+    @Test
+    public void handlePreferenceTreeClick_performClickOn200_updatesBounceKeysThreshold() {
+        assertThat(mAlertDialog.isShowing()).isTrue();
+        RadioGroup radioGroup = mAlertDialog.findViewById(R.id.input_setting_keys_value_group);
+        radioGroup.check(R.id.input_setting_keys_value_200);
+
+        mAlertDialog.getButton(AlertDialog.BUTTON_POSITIVE).performClick();
+        ShadowLooper.idleMainLooper();
+
+        assertThat(mAlertDialog.isShowing()).isFalse();
+        int threshold = InputSettings.getAccessibilityBounceKeysThreshold(
+                ApplicationProvider.getApplicationContext());
+        assertThat(threshold).isEqualTo(200);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysControllerTest.java
index 9f82b75..137f15b 100644
--- a/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysControllerTest.java
+++ b/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysControllerTest.java
@@ -18,6 +18,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
@@ -25,12 +28,12 @@
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
-import android.widget.RadioGroup;
 
-import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentTransaction;
 import androidx.preference.Preference;
 
-import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.keyboard.Flags;
 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
@@ -45,10 +48,13 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowLooper;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
 
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {
+        KeyboardAccessibilitySlowKeysControllerTest
+                .ShadowKeyboardAccessibilitySlowKeysDialogFragment.class,
         com.android.settings.testutils.shadow.ShadowFragment.class,
         ShadowAlertDialogCompat.class,
 })
@@ -60,6 +66,15 @@
     private static final String PREFERENCE_KEY = "keyboard_a11y_page_slow_keys";
     @Mock
     private Preference mPreference;
+    @Mock
+    private Fragment mFragment;
+    @Mock
+    private FragmentManager mFragmentManager;
+    @Mock
+    private FragmentTransaction mFragmentTransaction;
+    @Mock
+    private KeyboardAccessibilitySlowKeysDialogFragment
+            mKeyboardAccessibilitySlowKeysDialogFragment;
     private Context mContext;
     private KeyboardAccessibilitySlowKeysController mKeyboardAccessibilitySlowKeysController;
 
@@ -71,6 +86,11 @@
                 mContext,
                 PREFERENCE_KEY);
         when(mPreference.getKey()).thenReturn(PREFERENCE_KEY);
+        when(mFragment.getParentFragmentManager()).thenReturn(mFragmentManager);
+        when(mFragmentManager.beginTransaction()).thenReturn(mFragmentTransaction);
+        mKeyboardAccessibilitySlowKeysController.setFragment(mFragment);
+        ShadowKeyboardAccessibilitySlowKeysDialogFragment.setInstance(
+                mKeyboardAccessibilitySlowKeysDialogFragment);
     }
 
     @Test
@@ -107,23 +127,25 @@
     public void handlePreferenceTreeClick_dialogShows() {
         mKeyboardAccessibilitySlowKeysController.handlePreferenceTreeClick(mPreference);
 
-        AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
-
-        assertThat(alertDialog.isShowing()).isTrue();
+        verify(mKeyboardAccessibilitySlowKeysDialogFragment).show(any(FragmentManager.class),
+                anyString());
     }
 
-    @Test
-    public void handlePreferenceTreeClick_performClickOn200_updatesSlowKeysThreshold() {
-        mKeyboardAccessibilitySlowKeysController.handlePreferenceTreeClick(mPreference);
-        AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
-        RadioGroup radioGroup = alertDialog.findViewById(R.id.input_setting_keys_value_group);
-        radioGroup.check(R.id.input_setting_keys_value_200);
+    /**
+     * Note: Actually, shadow of KeyboardAccessibilitySlowKeysDialogFragment will not be used.
+     * Instance that returned with {@link #getInstance} should be set with {@link #setInstance}
+     */
+    @Implements(KeyboardAccessibilitySlowKeysDialogFragment.class)
+    public static class ShadowKeyboardAccessibilitySlowKeysDialogFragment {
+        static KeyboardAccessibilitySlowKeysDialogFragment sInstance = null;
 
-        alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).performClick();
-        ShadowLooper.idleMainLooper();
+        @Implementation
+        protected static KeyboardAccessibilitySlowKeysDialogFragment getInstance() {
+            return sInstance;
+        }
 
-        assertThat(alertDialog.isShowing()).isFalse();
-        int threshold = InputSettings.getAccessibilitySlowKeysThreshold(mContext);
-        assertThat(threshold).isEqualTo(200);
+        public static void setInstance(KeyboardAccessibilitySlowKeysDialogFragment instance) {
+            sInstance = instance;
+        }
     }
 }
diff --git a/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysDialogFragmentTest.java b/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysDialogFragmentTest.java
new file mode 100644
index 0000000..3a3010e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/inputmethod/KeyboardAccessibilitySlowKeysDialogFragmentTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2025 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.inputmethod;
+
+import static com.android.settings.inputmethod.KeyboardAccessibilityKeysDialogFragment.EXTRA_SUBTITLE_RES;
+import static com.android.settings.inputmethod.KeyboardAccessibilityKeysDialogFragment.EXTRA_TITLE_RES;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.AlertDialog;
+import android.hardware.input.InputSettings;
+import android.os.Bundle;
+import android.widget.RadioGroup;
+
+import androidx.fragment.app.testing.FragmentScenario;
+import androidx.lifecycle.Lifecycle;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.shadows.ShadowLooper;
+
+@RunWith(RobolectricTestRunner.class)
+public class KeyboardAccessibilitySlowKeysDialogFragmentTest {
+    private AlertDialog mAlertDialog;
+
+    @Before
+    public void setUp() {
+        Bundle bundle = new Bundle();
+        bundle.putInt(EXTRA_TITLE_RES, R.string.slow_keys);
+        bundle.putInt(EXTRA_SUBTITLE_RES, R.string.slow_keys_summary);
+
+        FragmentScenario<KeyboardAccessibilitySlowKeysDialogFragment> mFragmentScenario =
+                FragmentScenario.launch(
+                        KeyboardAccessibilitySlowKeysDialogFragment.class,
+                        bundle,
+                        R.style.Theme_AlertDialog_SettingsLib,
+                        Lifecycle.State.INITIALIZED);
+        mFragmentScenario.moveToState(Lifecycle.State.RESUMED);
+
+        mFragmentScenario.onFragment(fragment -> {
+            assertThat(fragment.getDialog()).isNotNull();
+            assertThat(fragment.requireDialog().isShowing()).isTrue();
+            assertThat(fragment.requireDialog()).isInstanceOf(AlertDialog.class);
+            mAlertDialog = (AlertDialog) fragment.requireDialog();
+        });
+    }
+
+    @Test
+    public void handlePreferenceTreeClick_performClickOn200_updatesSlowKeysThreshold() {
+        assertThat(mAlertDialog.isShowing()).isTrue();
+        RadioGroup radioGroup = mAlertDialog.findViewById(R.id.input_setting_keys_value_group);
+        radioGroup.check(R.id.input_setting_keys_value_200);
+
+        mAlertDialog.getButton(AlertDialog.BUTTON_POSITIVE).performClick();
+        ShadowLooper.idleMainLooper();
+
+        assertThat(mAlertDialog.isShowing()).isFalse();
+        int threshold = InputSettings.getAccessibilitySlowKeysThreshold(
+                ApplicationProvider.getApplicationContext());
+        assertThat(threshold).isEqualTo(200);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
index c9cf5a2..c6bdebd 100644
--- a/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
@@ -56,6 +56,7 @@
 import com.android.wifitrackerlib.WifiEntry.ConnectedState;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -72,6 +73,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+@Ignore("b/394813533")
 @Deprecated(forRemoval = true)
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {
diff --git a/tests/unit/src/com/android/settings/security/ScreenLockPreferenceDetailsUtilsTest.java b/tests/unit/src/com/android/settings/security/ScreenLockPreferenceDetailsUtilsTest.java
index abc982d..2535870 100644
--- a/tests/unit/src/com/android/settings/security/ScreenLockPreferenceDetailsUtilsTest.java
+++ b/tests/unit/src/com/android/settings/security/ScreenLockPreferenceDetailsUtilsTest.java
@@ -78,6 +78,7 @@
     private StorageManager mStorageManager;
 
     private Context mContext;
+    private FakeFeatureFactory mFeatureFactory;
 
     private ScreenLockPreferenceDetailsUtils mScreenLockPreferenceDetailsUtils;
 
@@ -95,8 +96,8 @@
         doNothing().when(mContext).startActivity(any());
         when(mUserManager.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{});
 
-        final FakeFeatureFactory featureFactory = FakeFeatureFactory.setupForTest();
-        when(featureFactory.securityFeatureProvider.getLockPatternUtils(mContext))
+        mFeatureFactory = FakeFeatureFactory.setupForTest();
+        when(mFeatureFactory.securityFeatureProvider.getLockPatternUtils(mContext))
                 .thenReturn(mLockPatternUtils);
 
         mScreenLockPreferenceDetailsUtils = new ScreenLockPreferenceDetailsUtils(mContext);
@@ -231,6 +232,15 @@
     }
 
     @Test
+    public void getSummary_noLockPatternUtils_shouldReturnNull() {
+        when(mFeatureFactory.securityFeatureProvider.getLockPatternUtils(mContext))
+                .thenReturn(null);
+        mScreenLockPreferenceDetailsUtils = new ScreenLockPreferenceDetailsUtils(mContext);
+
+        assertNull(mScreenLockPreferenceDetailsUtils.getSummary(USER_ID));
+    }
+
+    @Test
     public void isPasswordQualityManaged_withoutAdmin_shouldReturnFalse() {
         final RestrictedLockUtils.EnforcedAdmin admin = null;
 
@@ -275,6 +285,15 @@
     }
 
     @Test
+    public void isLockPatternSecure_noLockPatterUtils_shouldReturnFalse() {
+        when(mFeatureFactory.securityFeatureProvider.getLockPatternUtils(mContext))
+                .thenReturn(null);
+        mScreenLockPreferenceDetailsUtils = new ScreenLockPreferenceDetailsUtils(mContext);
+
+        assertThat(mScreenLockPreferenceDetailsUtils.isLockPatternSecure()).isFalse();
+    }
+
+    @Test
     @RequiresFlagsEnabled(Flags.FLAG_BIOMETRIC_ONBOARDING_EDUCATION)
     public void shouldShowGearMenu_patternIsSecure_flagOn_shouldReturnFalse() {
         when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
@@ -341,6 +360,20 @@
                 ChooseLockGeneric.ChooseLockGenericFragment.class.getName());
     }
 
+    @Test
+    public void getLaunchChooseLockGenericFragmentIntent_noLockPatternUtils_returnsIntent() {
+        when(mFeatureFactory.securityFeatureProvider.getLockPatternUtils(mContext))
+                .thenReturn(null);
+        mScreenLockPreferenceDetailsUtils = new ScreenLockPreferenceDetailsUtils(mContext);
+        when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
+
+        final Intent intent = mScreenLockPreferenceDetailsUtils
+                .getLaunchChooseLockGenericFragmentIntent(SOURCE_METRICS_CATEGORY);
+
+        assertFragmentLaunchIntent(intent,
+                ChooseLockGeneric.ChooseLockGenericFragment.class.getName());
+    }
+
     private void whenConfigShowUnlockSetOrChangeIsEnabled(boolean enabled) {
         final int resId = ResourcesUtils.getResourcesId(
                 ApplicationProvider.getApplicationContext(), "bool",