Merge "Toggle switch back when user dismisses dialog by tapping screen" into udc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 5904282..ff4096f 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3717,7 +3717,7 @@
         <!-- Show channel-level notification settings (channel passed in as extras) -->
         <activity android:name=".notification.app.ChannelPanelActivity"
                   android:label="@string/notification_channel_title"
-                  android:theme="@style/Theme.Panel"
+                  android:theme="@style/Theme.Panel.Material"
                   android:excludeFromRecents="true"
                   android:configChanges="keyboardHidden|screenSize"
                   android:exported="true">
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 836806c..4e85cb8 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -2,6 +2,20 @@
   "presubmit": [
     {
       "name": "SettingsSpaUnitTests"
+    },
+    {
+      "name": "SettingsUnitTests",
+      "options": [
+        {
+          "include-filter": "com.android.settings.password"
+        },
+        {
+          "include-filter": "com.android.settings.biometrics"
+        },
+        {
+          "include-filter": "com.android.settings.biometrics2"
+        }
+      ]
     }
   ],
   "postsubmit": [
diff --git a/protos/fuelgauge_log.proto b/protos/fuelgauge_log.proto
index 8512cb8..150c2e2 100644
--- a/protos/fuelgauge_log.proto
+++ b/protos/fuelgauge_log.proto
@@ -20,6 +20,7 @@
     RESET = 3;
     RESTORE = 4;
     BACKUP = 5;
+    FORCE_RESET = 6;
   }
 
   optional string package_name = 1;
diff --git a/res/drawable/button_border_selected.xml b/res/drawable/button_border_selected.xml
index 0cd4aa5..1402380 100644
--- a/res/drawable/button_border_selected.xml
+++ b/res/drawable/button_border_selected.xml
@@ -15,10 +15,7 @@
   limitations under the License.
   -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
-       xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
        android:shape="rectangle">
-    <solid
-        android:color="?androidprv:attr/materialColorSurfaceContainer" />
     <stroke
         android:width="2dp"
         android:color="?android:attr/colorAccent"/>
diff --git a/res/drawable/button_border_unselected.xml b/res/drawable/button_border_unselected.xml
index 2c2ef3d..d0ce75b 100644
--- a/res/drawable/button_border_unselected.xml
+++ b/res/drawable/button_border_unselected.xml
@@ -18,7 +18,7 @@
        android:shape="rectangle">
     <stroke
         android:width="1dp"
-        android:color="@color/notification_importance_button_unselected"/>
+        android:color="?android:attr/colorAccent"/>
 
     <corners android:radius="@dimen/rect_button_radius" />
 </shape>
diff --git a/res/drawable/checkbox_circle_shape.xml b/res/drawable/checkbox_circle_shape.xml
index 68c5a2e..51a567c 100644
--- a/res/drawable/checkbox_circle_shape.xml
+++ b/res/drawable/checkbox_circle_shape.xml
@@ -1,24 +1,31 @@
 <!--
-  ~ Copyright (C) 2023 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
+     Copyright (C) 2023 The Android Open Source Project
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item
-        android:state_checked="true"
-        android:drawable="@drawable/ic_check_circle_filled_24dp" />
-    <item
-        android:state_checked="false"
-        android:drawable="@drawable/ic_circle_outline_24dp" />
-</selector>
\ No newline at end of file
+        android:bottom="12dp"
+        android:left="12dp"
+        android:right="12dp"
+        android:top="12dp">
+        <selector>
+            <item
+                android:state_checked="true"
+                android:drawable="@drawable/ic_check_circle_filled_24dp" />
+            <item
+                android:state_checked="false"
+                android:drawable="@drawable/ic_circle_outline_24dp" />
+        </selector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/ic_check_circle_filled_24dp.xml b/res/drawable/ic_check_circle_filled_24dp.xml
index 9d2e296..507bf67 100644
--- a/res/drawable/ic_check_circle_filled_24dp.xml
+++ b/res/drawable/ic_check_circle_filled_24dp.xml
@@ -20,7 +20,7 @@
         android:height="24dp"
         android:viewportWidth="24"
         android:viewportHeight="24"
-        android:tint="?androidprv:attr/materialColorPrimaryContainer">
+        android:tint="?android:attr/colorPrimary">
     <path
         android:fillColor="@android:color/white"
         android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10c5.52,0 10,-4.48 10,-10S17.52,2 12,2zM10.59,16.6l-4.24,-4.24l1.41,-1.41l2.83,2.83l5.66,-5.66l1.41,1.41L10.59,16.6z"/>
diff --git a/res/layout/choose_lock_password.xml b/res/layout/choose_lock_password.xml
index b748f94..5819774 100644
--- a/res/layout/choose_lock_password.xml
+++ b/res/layout/choose_lock_password.xml
@@ -74,7 +74,6 @@
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_horizontal"
                 android:gravity="center"
-                android:paddingLeft="14dp"
                 android:text="@string/auto_pin_confirm_user_message"
                 android:textSize="16sp"
                 android:button="@drawable/checkbox_circle_shape"
diff --git a/res/values/config.xml b/res/values/config.xml
index 52d7183..334d4e5 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -526,6 +526,10 @@
         <item>content://com.android.settings.slices/intent/media_output_indicator</item>
     </string-array>
 
+    <!-- List containing the apps cannot be changed the battery optimize modes -->
+    <string-array name="config_disable_optimization_mode_apps" translatable="false">
+    </string-array>
+
     <!-- Uri to query non-public Slice Uris. -->
     <string name="config_non_public_slice_query_uri" translatable="false"></string>
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index add226a..bad0dcc 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -129,7 +129,9 @@
     <!-- Title for all hearing devices related controls section. [CHAR LIMIT=60] -->
     <string name="bluetooth_device_controls_general">For all available hearing devices</string>
     <!-- Connected devices settings. Title of the preference to show the entrance of the hearing device controls related page. [CHAR LIMIT=65] -->
-    <string name="bluetooth_device_controls_title">Shortcuts &amp; hearing aid compatibility</string>
+    <string name="bluetooth_device_controls_title">Hearing device settings</string>
+    <!-- Connected devices settings. Title of the preference to show the entrance of the hearing device controls related page. [CHAR LIMIT=65] -->
+    <string name="bluetooth_device_controls_summary">Audio output, shortcut, hearing aid compatibility</string>
     <!-- Title for this device specific controls section. [CHAR LIMIT=30] -->
     <string name="bluetooth_device_controls_specific">For this device</string>
     <!-- Connected devices settings. Title of the preference to show the entrance of the audio output page. It can change different types of audio are played on phone or other bluetooth devices. [CHAR LIMIT=35] -->
@@ -4241,7 +4243,7 @@
     <string name="accessibility_screen_magnification_follow_typing_title">Magnify typing</string>
     <!-- Summary for accessibility follow typing preference for magnification. [CHAR LIMIT=none] -->
     <string name="accessibility_screen_magnification_follow_typing_summary">Magnifier follows text as you type</string>
-    <!-- Title for accessibility magnifier preference where the magnifier never turns off while switching apps. [CHAR LIMIT=35] -->
+    <!-- Title for accessibility magnifier preference where the magnifier never turns off while switching apps. [CHAR LIMIT=60] -->
     <string name="accessibility_screen_magnification_always_on_title">Keep on while switching apps</string>
     <!-- Summary for accessibility magnifier preference where the magnifier never turns off while switching apps. [CHAR LIMIT=none] -->
     <string name="accessibility_screen_magnification_always_on_summary">Magnifier stays on and zooms out when you switch apps</string>
@@ -5877,12 +5879,8 @@
     <string name="add_account_label">Add account</string>
     <!-- Label for the state of the work profile [CHAR LIMIT=80] -->
     <string name="managed_profile_not_available_label">Work profile isn\u2019t available yet</string>
-    <!-- This string is the title of a setting. If a user taps the setting, they can turn their work profile on or off. The work profile is a section of their phone that's managed by their employer. "Work" is an adjective. -->
-    <string name="work_mode_label">Work profile</string>
-    <!-- This string is located under a setting and describes what the setting does. It's letting a user know whether their work profile is on or off, and they can use the setting to turn it on or off. The work profile is a section of their phone that's managed by their employer. "Work" is an adjective.-->
-    <string name="work_mode_on_summary">Managed by your organization</string>
-    <!-- This string is located under a setting and describes what the setting does. It's letting a user know whether their work profile is on or off, and they can use the setting to turn it on or off. The work profile is a section of their phone that's managed by their employer. "Work" is an adjective.-->
-    <string name="work_mode_off_summary">Apps and notifications are off</string>
+    <!-- This string is the title of a setting. If a user taps the setting, they can turn their work apps on or off. The work apps are a group of apps that are managed by the the user's employer. While this setting is off, the user cannot interact with those apps or get notifications from them. "Work" is an adjective. -->
+    <string name="work_mode_label">Work apps</string>
     <!-- Button label to remove the work profile [CHAR LIMIT=35] -->
     <string name="remove_managed_profile_label">Remove work profile</string>
     <!-- Data synchronization settings screen, title of setting that controls whether background data should be used [CHAR LIMIT=30] -->
@@ -7175,7 +7173,7 @@
     <string name="docking_sounds_title">Docking sounds</string>
 
     <!-- Sound: Other sounds: Title for the option enabling touch sounds. [CHAR LIMIT=30] -->
-    <string name="touch_sounds_title">Touch sounds</string>
+    <string name="touch_sounds_title">Tap &amp; click sounds</string>
 
     <!-- Sound: Other sounds: Title for the option enabling the vibrate icon. [CHAR LIMIT=50] -->
     <string name="vibrate_icon_title">Always show icon when in vibrate mode</string>
@@ -9783,6 +9781,8 @@
     <string name="cross_profile_calendar_title">Cross-profile calendar</string>
     <!-- [CHAR LIMIT=NONE] Setting description. If the user turns on this setting, they can see their work events on their personal calendar. -->
     <string name="cross_profile_calendar_summary">Show work events on your personal calendar</string>
+    <!-- [CHAR_LIMIT_NONE] Footer description. Explains to the user what will happen when work apps are turned off. -->
+    <string name="managed_profile_settings_footer">When work apps are off, they’re paused and can’t be accessed or send you notifications</string>
 
     <!-- Used as title on the automatic storage manager settings. [CHAR LIMIT=60] -->
     <string name="automatic_storage_manager_settings">Manage storage</string>
diff --git a/res/values/themes.xml b/res/values/themes.xml
index eeba1c7..8f13279 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -227,6 +227,9 @@
         <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
     </style>
 
+    <style name="Theme.Panel.Material" parent="Theme.Panel" >
+        <item name="android:switchStyle">@style/Switch.SettingsLib</item>
+    </style>
     <!-- Material theme for the pages containing TabLayout and ViewPager -->
     <style name="Theme.TabTheme" parent="@style/Theme.MaterialComponents.DayNight">
         <item name="colorPrimary">@*android:color/edge_effect_device_default_light</item>
diff --git a/res/xml/bluetooth_audio_routing_fragment.xml b/res/xml/accessibility_audio_routing_fragment.xml
similarity index 85%
rename from res/xml/bluetooth_audio_routing_fragment.xml
rename to res/xml/accessibility_audio_routing_fragment.xml
index 5edf6cd..12e75f2 100644
--- a/res/xml/bluetooth_audio_routing_fragment.xml
+++ b/res/xml/accessibility_audio_routing_fragment.xml
@@ -31,7 +31,7 @@
         android:key="audio_routing_ringtone"
         android:persistent="false"
         android:title="@string/bluetooth_ringtone_title"
-        settings:controller="com.android.settings.bluetooth.HearingDeviceRingtoneRoutingPreferenceController" />
+        settings:controller="com.android.settings.accessibility.HearingDeviceRingtoneRoutingPreferenceController" />
 
     <ListPreference
         android:entries="@array/bluetooth_audio_routing_titles"
@@ -40,7 +40,7 @@
         android:key="audio_routing_call"
         android:persistent="false"
         android:title="@string/bluetooth_call_title"
-        settings:controller="com.android.settings.bluetooth.HearingDeviceCallRoutingPreferenceController" />
+        settings:controller="com.android.settings.accessibility.HearingDeviceCallRoutingPreferenceController" />
 
     <ListPreference
         android:entries="@array/bluetooth_audio_routing_titles"
@@ -49,7 +49,7 @@
         android:key="audio_routing_media"
         android:persistent="false"
         android:title="@string/bluetooth_media_title"
-        settings:controller="com.android.settings.bluetooth.HearingDeviceMediaRoutingPreferenceController" />
+        settings:controller="com.android.settings.accessibility.HearingDeviceMediaRoutingPreferenceController" />
 
     <ListPreference
         android:entries="@array/bluetooth_audio_routing_titles"
@@ -58,7 +58,7 @@
         android:key="audio_routing_system_sounds"
         android:persistent="false"
         android:title="@string/bluetooth_system_sounds_title"
-        settings:controller="com.android.settings.bluetooth.HearingDeviceSystemSoundsRoutingPreferenceController" />
+        settings:controller="com.android.settings.accessibility.HearingDeviceSystemSoundsRoutingPreferenceController" />
 
     <com.android.settings.accessibility.AccessibilityFooterPreference
         android:key="hearing_device_footer"
diff --git a/res/xml/accessibility_hearing_aids.xml b/res/xml/accessibility_hearing_aids.xml
index e813cf2..b13eb74 100644
--- a/res/xml/accessibility_hearing_aids.xml
+++ b/res/xml/accessibility_hearing_aids.xml
@@ -45,8 +45,17 @@
     <PreferenceCategory
         android:key="hearing_options_category"
         android:title="@string/accessibility_screen_option">
+
+        <Preference
+            android:key="audio_routing"
+            android:title="@string/bluetooth_audio_routing_title"
+            android:summary="@string/bluetooth_audio_routing_summary"
+            android:fragment="com.android.settings.accessibility.AccessibilityAudioRoutingFragment"
+            settings:controller="com.android.settings.accessibility.HearingAidAudioRoutingPreferenceController"/>
+
         <SwitchPreference
             android:key="hearing_aid_compatibility"
+            android:order="30"
             android:title="@string/accessibility_hac_mode_title"
             android:summary="@string/accessibility_hac_mode_summary"
             settings:searchable="true"
diff --git a/res/xml/app_info_settings.xml b/res/xml/app_info_settings.xml
index d8af009..73241b7 100644
--- a/res/xml/app_info_settings.xml
+++ b/res/xml/app_info_settings.xml
@@ -193,6 +193,8 @@
             android:key="long_background_tasks"
             android:title="@string/long_background_tasks_title"
             android:summary="@string/summary_placeholder"
+            settings:isPreferenceVisible="false"
+            settings:searchable="false"
             settings:controller="com.android.settings.applications.appinfo.LongBackgroundTasksDetailsPreferenceController" />
 
     </PreferenceCategory>
diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml
index 8d74a39..35359f7 100644
--- a/res/xml/bluetooth_device_details_fragment.xml
+++ b/res/xml/bluetooth_device_details_fragment.xml
@@ -69,12 +69,7 @@
         android:key="device_companion_apps"/>
 
     <PreferenceCategory
-        android:key="device_controls_general"
-        android:title="@string/bluetooth_device_controls_general"/>
-
-    <PreferenceCategory
-        android:key="device_controls_specific"
-        android:title="@string/bluetooth_device_controls_specific"/>
+        android:key="device_controls_general" />
 
     <PreferenceCategory
         android:key="spatial_audio_group"/>
diff --git a/res/xml/managed_profile_settings.xml b/res/xml/managed_profile_settings.xml
index 20f6d3d..ddfb869 100644
--- a/res/xml/managed_profile_settings.xml
+++ b/res/xml/managed_profile_settings.xml
@@ -19,10 +19,9 @@
                   android:key="managed_profile_settings_screen"
                   android:title="@string/managed_profile_settings_title">
 
-    <SwitchPreference
+    <com.android.settingslib.widget.MainSwitchPreference
         android:key="work_mode"
         android:title="@string/work_mode_label"
-        android:summary="@string/summary_placeholder"
         settings:controller="com.android.settings.accounts.WorkModePreferenceController"/>
 
     <com.android.settingslib.RestrictedSwitchPreference
@@ -38,4 +37,9 @@
         android:title="@string/cross_profile_calendar_title"
         settings:controller="com.android.settings.accounts.CrossProfileCalendarPreferenceController"/>
 
+    <com.android.settingslib.widget.FooterPreference
+        android:title="@string/managed_profile_settings_footer"
+        android:key="managed_profile_footer"
+        settings:searchable="false"/>
+
 </PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/reset_dashboard_fragment.xml b/res/xml/reset_dashboard_fragment.xml
index 98f6c02..3bd7a13 100644
--- a/res/xml/reset_dashboard_fragment.xml
+++ b/res/xml/reset_dashboard_fragment.xml
@@ -38,9 +38,10 @@
         settings:controller="com.android.settings.network.BluetoothWiFiResetPreferenceController" />
 
     <!-- Reset app preferences -->
-    <Preference
+    <com.android.settingslib.RestrictedPreference
         android:key="reset_app_prefs"
-        android:title="@string/reset_app_preferences" />
+        android:title="@string/reset_app_preferences"
+        settings:userRestriction="no_control_apps" />
 
     <!-- Erase Euicc data -->
     <Preference
diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml
index 2fb4af4..b3f3f7d 100644
--- a/res/xml/special_access.xml
+++ b/res/xml/special_access.xml
@@ -128,6 +128,8 @@
         android:title="@string/long_background_tasks_title"
         android:order="-800"
         android:fragment="com.android.settings.applications.manageapplications.ManageApplications"
+        settings:isPreferenceVisible="false"
+        settings:searchable="false"
         settings:keywords="@string/keywords_long_background_tasks"
         settings:controller="com.android.settings.applications.specialaccess.applications.LongBackgroundTaskController">
         <extra
diff --git a/src/com/android/settings/SettingsApplication.java b/src/com/android/settings/SettingsApplication.java
index 7d8055d..8c050ea 100644
--- a/src/com/android/settings/SettingsApplication.java
+++ b/src/com/android/settings/SettingsApplication.java
@@ -51,8 +51,9 @@
         // Set Spa environment.
         setSpaEnvironment();
 
-        if (FeatureFlagUtils.isEnabled(this, FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN)
-                && ActivityEmbeddingUtils.isSettingsSplitEnabled(this)) {
+        if (ActivityEmbeddingUtils.isSettingsSplitEnabled(this)
+                && FeatureFlagUtils.isEnabled(this,
+                        FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN)) {
             if (WizardManagerHelper.isUserSetupComplete(this)) {
                 new ActivityEmbeddingRulesController(this).initRules();
             } else {
diff --git a/src/com/android/settings/accessibility/AccessibilityAudioRoutingFragment.java b/src/com/android/settings/accessibility/AccessibilityAudioRoutingFragment.java
new file mode 100644
index 0000000..6eb2112
--- /dev/null
+++ b/src/com/android/settings/accessibility/AccessibilityAudioRoutingFragment.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
+
+import android.app.settings.SettingsEnums;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.RestrictedDashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+
+/** Settings fragment containing bluetooth audio routing. */
+public class AccessibilityAudioRoutingFragment extends RestrictedDashboardFragment {
+    private static final String TAG = "AccessibilityAudioRoutingFragment";
+
+    public AccessibilityAudioRoutingFragment() {
+        super(DISALLOW_CONFIG_BLUETOOTH);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.HEARING_AID_AUDIO_ROUTING;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.accessibility_audio_routing_fragment;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider(R.xml.accessibility_audio_routing_fragment);
+}
diff --git a/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java b/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java
index cd76b47..e4611fe 100644
--- a/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java
+++ b/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java
@@ -17,7 +17,6 @@
 package com.android.settings.accessibility;
 
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHapClient;
 import android.bluetooth.BluetoothHearingAid;
 import android.bluetooth.BluetoothLeAudio;
@@ -41,20 +40,14 @@
 import com.android.settings.core.SubSettingLauncher;
 import com.android.settingslib.bluetooth.BluetoothCallback;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.HapClientProfile;
 import com.android.settingslib.bluetooth.HearingAidInfo;
-import com.android.settingslib.bluetooth.HearingAidProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.OnStart;
 import com.android.settingslib.core.lifecycle.events.OnStop;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Set;
-import java.util.stream.Collectors;
 
 /**
  * Controller that shows and updates the bluetooth device name
@@ -73,10 +66,8 @@
     };
 
     private final LocalBluetoothManager mLocalBluetoothManager;
-    private final BluetoothAdapter mBluetoothAdapter;
     private final LocalBluetoothProfileManager mProfileManager;
-    private final CachedBluetoothDeviceManager mCachedDeviceManager;
-
+    private final HearingAidHelper mHelper;
     private FragmentManager mFragmentManager;
 
     public AccessibilityHearingAidPreferenceController(Context context, String preferenceKey) {
@@ -84,8 +75,7 @@
         mLocalBluetoothManager = com.android.settings.bluetooth.Utils.getLocalBluetoothManager(
                 context);
         mProfileManager = mLocalBluetoothManager.getProfileManager();
-        mCachedDeviceManager = mLocalBluetoothManager.getCachedDeviceManager();
-        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+        mHelper = new HearingAidHelper(context);
     }
 
     @Override
@@ -96,7 +86,7 @@
 
     @Override
     public int getAvailabilityStatus() {
-        return isHearingAidSupported() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+        return mHelper.isHearingAidSupported() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
     }
 
     @Override
@@ -111,7 +101,7 @@
         // Can't get connected hearing aids when hearing aids related profiles are not ready. The
         // profiles will be ready after the services are connected. Needs to add listener and
         // updates the information when all hearing aids related services are connected.
-        if (isAnyHearingAidRelatedProfilesNotReady()) {
+        if (!mHelper.isAllHearingAidRelatedProfilesReady()) {
             mProfileManager.addServiceListener(this);
         }
     }
@@ -126,7 +116,7 @@
     @Override
     public boolean handlePreferenceTreeClick(Preference preference) {
         if (TextUtils.equals(preference.getKey(), getPreferenceKey())) {
-            final CachedBluetoothDevice device = getConnectedHearingAidDevice();
+            final CachedBluetoothDevice device = mHelper.getConnectedHearingAidDevice();
             if (FeatureFlagUtils.isEnabled(mContext,
                     FeatureFlagUtils.SETTINGS_ACCESSIBILITY_HEARING_AID_PAGE)) {
                 launchHearingAidPage();
@@ -144,10 +134,7 @@
 
     @Override
     public CharSequence getSummary() {
-        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
-            return mContext.getText(R.string.accessibility_hearingaid_not_connected_summary);
-        }
-        final CachedBluetoothDevice device = getConnectedHearingAidDevice();
+        final CachedBluetoothDevice device = mHelper.getConnectedHearingAidDevice();
         if (device == null) {
             return mContext.getText(R.string.accessibility_hearingaid_not_connected_summary);
         }
@@ -203,7 +190,7 @@
 
     @Override
     public void onServiceConnected() {
-        if (!isAnyHearingAidRelatedProfilesNotReady()) {
+        if (mHelper.isAllHearingAidRelatedProfilesReady()) {
             updateState(mHearingAidPreference);
             mProfileManager.removeServiceListener(this);
         }
@@ -218,53 +205,8 @@
         mFragmentManager = fragmentManager;
     }
 
-    @VisibleForTesting
-    CachedBluetoothDevice getConnectedHearingAidDevice() {
-        final List<BluetoothDevice> deviceList = getConnectedHearingAidDeviceList();
-        return deviceList.isEmpty() ? null : mCachedDeviceManager.findDevice(deviceList.get(0));
-    }
-
     private int getConnectedHearingAidDeviceNum() {
-        return getConnectedHearingAidDeviceList().size();
-    }
-
-    private List<BluetoothDevice> getConnectedHearingAidDeviceList() {
-        if (!isHearingAidSupported()) {
-            return new ArrayList<>();
-        }
-        final List<BluetoothDevice> deviceList = new ArrayList<>();
-        final HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
-        if (hapClientProfile != null) {
-            deviceList.addAll(hapClientProfile.getConnectedDevices());
-        }
-        final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
-        if (hearingAidProfile != null) {
-            deviceList.addAll(hearingAidProfile.getConnectedDevices());
-        }
-        return deviceList.stream()
-                .distinct()
-                .filter(d -> !mCachedDeviceManager.isSubDevice(d)).collect(Collectors.toList());
-    }
-
-    private boolean isHearingAidSupported() {
-        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
-            return false;
-        }
-        final List<Integer> supportedList = mBluetoothAdapter.getSupportedProfiles();
-        return supportedList.contains(BluetoothProfile.HEARING_AID)
-                || supportedList.contains(BluetoothProfile.HAP_CLIENT);
-    }
-
-    private boolean isAnyHearingAidRelatedProfilesNotReady() {
-        HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
-        if (hearingAidProfile != null && !hearingAidProfile.isProfileReady()) {
-            return true;
-        }
-        HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
-        if (hapClientProfile != null && !hapClientProfile.isProfileReady()) {
-            return true;
-        }
-        return false;
+        return mHelper.getConnectedHearingAidDeviceList().size();
     }
 
     @VisibleForTesting(otherwise = VisibleForTesting.NONE)
diff --git a/src/com/android/settings/accessibility/AccessibilityHearingAidsFragment.java b/src/com/android/settings/accessibility/AccessibilityHearingAidsFragment.java
index 547c456..33fef62 100644
--- a/src/com/android/settings/accessibility/AccessibilityHearingAidsFragment.java
+++ b/src/com/android/settings/accessibility/AccessibilityHearingAidsFragment.java
@@ -39,7 +39,7 @@
 
     private static final String TAG = "AccessibilityHearingAidsFragment";
     private static final String KEY_HEARING_OPTIONS_CATEGORY = "hearing_options_category";
-    private static final int FIRST_PREFERENCE_IN_CATEGORY_INDEX = -1;
+    private static final int SHORTCUT_PREFERENCE_IN_CATEGORY_INDEX = 20;
     private String mFeatureName;
 
     public AccessibilityHearingAidsFragment() {
@@ -65,7 +65,7 @@
         final View view = super.onCreateView(inflater, container, savedInstanceState);
         final PreferenceCategory controlCategory = findPreference(KEY_HEARING_OPTIONS_CATEGORY);
         // To move the shortcut preference under controlCategory need to remove the original added.
-        mShortcutPreference.setOrder(FIRST_PREFERENCE_IN_CATEGORY_INDEX);
+        mShortcutPreference.setOrder(SHORTCUT_PREFERENCE_IN_CATEGORY_INDEX);
         getPreferenceScreen().removePreference(mShortcutPreference);
         controlCategory.addPreference(mShortcutPreference);
         return view;
diff --git a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
index 01158bf..b414add 100644
--- a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
@@ -322,6 +322,18 @@
                 getComponentName());
     };
 
+    private static CharSequence getSoftwareShortcutTypeSummary(Context context) {
+        int resId;
+        if (AccessibilityUtil.isFloatingMenuEnabled(context)) {
+            resId = R.string.accessibility_shortcut_edit_summary_software;
+        } else if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
+            resId = R.string.accessibility_shortcut_edit_summary_software_gesture;
+        } else {
+            resId = R.string.accessibility_shortcut_edit_summary_software;
+        }
+        return context.getText(resId);
+    }
+
     /**
      * This method will be invoked when a button in the tutorial dialog is clicked.
      *
@@ -429,11 +441,9 @@
                 getComponentName().flattenToString(), AccessibilityUtil.UserShortcutType.SOFTWARE);
 
         final List<CharSequence> list = new ArrayList<>();
-        final CharSequence softwareTitle = context.getText(
-                R.string.accessibility_shortcut_edit_summary_software);
 
         if (hasShortcutType(shortcutTypes, AccessibilityUtil.UserShortcutType.SOFTWARE)) {
-            list.add(softwareTitle);
+            list.add(getSoftwareShortcutTypeSummary(context));
         }
         if (hasShortcutType(shortcutTypes, AccessibilityUtil.UserShortcutType.HARDWARE)) {
             final CharSequence hardwareTitle = context.getText(
@@ -443,7 +453,7 @@
 
         // Show software shortcut if first time to use.
         if (list.isEmpty()) {
-            list.add(softwareTitle);
+            list.add(getSoftwareShortcutTypeSummary(context));
         }
 
         return CaseMap.toTitle().wholeString().noLowercase().apply(Locale.getDefault(), /* iter= */
diff --git a/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceController.java
new file mode 100644
index 0000000..54022ef
--- /dev/null
+++ b/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceController.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import com.android.settings.core.BasePreferenceController;
+
+/**
+ * The controller of the audio routing.
+ */
+public class HearingAidAudioRoutingPreferenceController extends BasePreferenceController {
+    public HearingAidAudioRoutingPreferenceController(Context context,
+            String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_AUDIO_ROUTING)
+                ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+    }
+}
diff --git a/src/com/android/settings/accessibility/HearingAidHelper.java b/src/com/android/settings/accessibility/HearingAidHelper.java
new file mode 100644
index 0000000..66a37f8
--- /dev/null
+++ b/src/com/android/settings/accessibility/HearingAidHelper.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.HapClientProfile;
+import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * A helper class to get and check hearing aids and its status.
+ */
+public class HearingAidHelper {
+
+    private final BluetoothAdapter mBluetoothAdapter;
+    private final LocalBluetoothProfileManager mProfileManager;
+    private final CachedBluetoothDeviceManager mCachedDeviceManager;
+
+    public HearingAidHelper(Context context) {
+        final LocalBluetoothManager localBluetoothManager =
+                com.android.settings.bluetooth.Utils.getLocalBluetoothManager(context);
+        mProfileManager = localBluetoothManager.getProfileManager();
+        mCachedDeviceManager = localBluetoothManager.getCachedDeviceManager();
+        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+    }
+
+    /**
+     * Gets the connected hearing aids device whose profiles are
+     * {@link BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#HAP_CLIENT}.
+     *
+     * @return a list of hearing aids {@link BluetoothDevice} objects
+     */
+    public List<BluetoothDevice> getConnectedHearingAidDeviceList() {
+        if (!isHearingAidSupported()) {
+            return new ArrayList<>();
+        }
+        final List<BluetoothDevice> deviceList = new ArrayList<>();
+        final HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
+        if (hapClientProfile != null) {
+            deviceList.addAll(hapClientProfile.getConnectedDevices());
+        }
+        final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
+        if (hearingAidProfile != null) {
+            deviceList.addAll(hearingAidProfile.getConnectedDevices());
+        }
+        return deviceList.stream()
+                .distinct()
+                .filter(d -> !mCachedDeviceManager.isSubDevice(d)).collect(Collectors.toList());
+    }
+
+    /**
+     * Gets the first connected hearing aids device.
+     *
+     * @return a {@link CachedBluetoothDevice} that is hearing aids device
+     */
+    public CachedBluetoothDevice getConnectedHearingAidDevice() {
+        final List<BluetoothDevice> deviceList = getConnectedHearingAidDeviceList();
+        return deviceList.isEmpty() ? null : mCachedDeviceManager.findDevice(deviceList.get(0));
+    }
+
+    /**
+     * Checks if {@link BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#HAP_CLIENT}
+     * supported.
+     */
+    public boolean isHearingAidSupported() {
+        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
+            return false;
+        }
+        final List<Integer> supportedList = mBluetoothAdapter.getSupportedProfiles();
+        return supportedList.contains(BluetoothProfile.HEARING_AID)
+                || supportedList.contains(BluetoothProfile.HAP_CLIENT);
+    }
+
+    /**
+     * Checks if {@link BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#HAP_CLIENT}
+     * profiles all ready.
+     */
+    public boolean isAllHearingAidRelatedProfilesReady() {
+        HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
+        if (hearingAidProfile != null && !hearingAidProfile.isProfileReady()) {
+            return false;
+        }
+        HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
+        if (hapClientProfile != null && !hapClientProfile.isProfileReady()) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceController.java
similarity index 79%
rename from src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceController.java
rename to src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceController.java
index e93863a..3599f48 100644
--- a/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceController.java
+++ b/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceController.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
 
 import android.content.ContentResolver;
 import android.content.Context;
@@ -47,19 +47,24 @@
     private static final String TAG = "HARoutingBasePreferenceController";
     private static final boolean DEBUG = false;
 
-    private final HearingAidAudioRoutingHelper mHelper;
+    private final HearingAidAudioRoutingHelper mAudioRoutingHelper;
+    private final HearingAidHelper mHearingAidHelper;
 
     public HearingDeviceAudioRoutingBasePreferenceController(Context context,
             String preferenceKey) {
-        super(context, preferenceKey);
-        mHelper = new HearingAidAudioRoutingHelper(context);
+        this(context, preferenceKey,
+                new HearingAidAudioRoutingHelper(context),
+                new HearingAidHelper(context));
     }
 
     @VisibleForTesting
     public HearingDeviceAudioRoutingBasePreferenceController(Context context,
-            String preferenceKey, HearingAidAudioRoutingHelper helper) {
+            String preferenceKey, HearingAidAudioRoutingHelper audioRoutingHelper,
+            HearingAidHelper hearingAidHelper) {
         super(context, preferenceKey);
-        mHelper = helper;
+
+        mAudioRoutingHelper = audioRoutingHelper;
+        mHearingAidHelper = hearingAidHelper;
     }
 
     @Override
@@ -81,7 +86,11 @@
         final Integer routingValue = Ints.tryParse((String) newValue);
 
         saveRoutingValue(mContext, routingValue);
-        trySetAudioRoutingConfig(getSupportedAttributeList(), getHearingDevice(), routingValue);
+        final CachedBluetoothDevice device = mHearingAidHelper.getConnectedHearingAidDevice();
+        if (device != null) {
+            trySetAudioRoutingConfig(getSupportedAttributeList(),
+                    mHearingAidHelper.getConnectedHearingAidDevice(), routingValue);
+        }
 
         return true;
     }
@@ -89,10 +98,10 @@
     private void trySetAudioRoutingConfig(int[] audioAttributes,
             CachedBluetoothDevice hearingDevice,
             @HearingAidAudioRoutingConstants.RoutingValue int routingValue) {
-        final List<AudioProductStrategy> supportedStrategies = mHelper.getSupportedStrategies(
-                audioAttributes);
+        final List<AudioProductStrategy> supportedStrategies =
+                mAudioRoutingHelper.getSupportedStrategies(audioAttributes);
         final AudioDeviceAttributes hearingDeviceAttributes =
-                mHelper.getMatchedHearingDeviceAttributes(hearingDevice);
+                mAudioRoutingHelper.getMatchedHearingDeviceAttributes(hearingDevice);
         if (hearingDeviceAttributes == null) {
             if (DEBUG) {
                 Log.d(TAG,
@@ -103,8 +112,8 @@
             return;
         }
 
-        final boolean status = mHelper.setPreferredDeviceRoutingStrategies(supportedStrategies,
-                hearingDeviceAttributes, routingValue);
+        final boolean status = mAudioRoutingHelper.setPreferredDeviceRoutingStrategies(
+                supportedStrategies, hearingDeviceAttributes, routingValue);
 
         if (!status) {
             final List<String> strategiesName = supportedStrategies.stream()
@@ -122,12 +131,6 @@
     protected abstract int[] getSupportedAttributeList();
 
     /**
-     * Gets the {@link CachedBluetoothDevice} hearing device that is used to configure audio
-     * routing.
-     */
-    protected abstract CachedBluetoothDevice getHearingDevice();
-
-    /**
      * Saves the routing value.
      *
      * @param context the valid context used to get the {@link ContentResolver}
diff --git a/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceController.java
similarity index 81%
rename from src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceController.java
rename to src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceController.java
index 4e5e193..8ca2663 100644
--- a/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceController.java
+++ b/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceController.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
 
 import android.content.Context;
 import android.provider.Settings;
@@ -35,15 +35,6 @@
         super(context, preferenceKey);
     }
 
-    /**
-     * Initializes objects in this controller. Need to call this before using the controller.
-     *
-     * @param cachedBluetoothDevice the hearing device to configure audio routing
-     */
-    public void init(CachedBluetoothDevice cachedBluetoothDevice) {
-        mHearingDevice = cachedBluetoothDevice;
-    }
-
     @Override
     public int getAvailabilityStatus() {
         return Utils.isVoiceCapable(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
@@ -55,11 +46,6 @@
     }
 
     @Override
-    protected CachedBluetoothDevice getHearingDevice() {
-        return mHearingDevice;
-    }
-
-    @Override
     protected void saveRoutingValue(Context context, int routingValue) {
         Settings.Secure.putInt(context.getContentResolver(),
                 Settings.Secure.HEARING_AID_CALL_ROUTING, routingValue);
diff --git a/src/com/android/settings/bluetooth/HearingDeviceMediaRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceMediaRoutingPreferenceController.java
similarity index 79%
rename from src/com/android/settings/bluetooth/HearingDeviceMediaRoutingPreferenceController.java
rename to src/com/android/settings/accessibility/HearingDeviceMediaRoutingPreferenceController.java
index 1ea36c7..cd99ce0 100644
--- a/src/com/android/settings/bluetooth/HearingDeviceMediaRoutingPreferenceController.java
+++ b/src/com/android/settings/accessibility/HearingDeviceMediaRoutingPreferenceController.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
 
 import android.content.Context;
 import android.provider.Settings;
@@ -34,15 +34,6 @@
         super(context, preferenceKey);
     }
 
-    /**
-     * Initializes objects in this controller. Need to call this before using the controller.
-     *
-     * @param cachedBluetoothDevice the hearing device to configure audio routing
-     */
-    public void init(CachedBluetoothDevice cachedBluetoothDevice) {
-        mHearingDevice = cachedBluetoothDevice;
-    }
-
     @Override
     protected int[] getSupportedAttributeList() {
         return HearingAidAudioRoutingConstants.MEDIA_ROUTING_ATTRIBUTES;
@@ -50,11 +41,6 @@
     }
 
     @Override
-    protected CachedBluetoothDevice getHearingDevice() {
-        return mHearingDevice;
-    }
-
-    @Override
     protected void saveRoutingValue(Context context, int routingValue) {
         Settings.Secure.putInt(context.getContentResolver(),
                 Settings.Secure.HEARING_AID_MEDIA_ROUTING, routingValue);
diff --git a/src/com/android/settings/bluetooth/HearingDeviceRingtoneRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceRingtoneRoutingPreferenceController.java
similarity index 79%
rename from src/com/android/settings/bluetooth/HearingDeviceRingtoneRoutingPreferenceController.java
rename to src/com/android/settings/accessibility/HearingDeviceRingtoneRoutingPreferenceController.java
index 006cb6b..3e8f79c 100644
--- a/src/com/android/settings/bluetooth/HearingDeviceRingtoneRoutingPreferenceController.java
+++ b/src/com/android/settings/accessibility/HearingDeviceRingtoneRoutingPreferenceController.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
 
 import android.content.Context;
 import android.provider.Settings;
@@ -34,15 +34,6 @@
         super(context, preferenceKey);
     }
 
-    /**
-     * Initializes objects in this controller. Need to call this before using the controller.
-     *
-     * @param cachedBluetoothDevice the hearing device to configure audio routing
-     */
-    public void init(CachedBluetoothDevice cachedBluetoothDevice) {
-        mHearingDevice = cachedBluetoothDevice;
-    }
-
     @Override
     protected int[] getSupportedAttributeList() {
         return HearingAidAudioRoutingConstants.RINGTONE_ROUTING_ATTRIBUTE;
@@ -50,11 +41,6 @@
     }
 
     @Override
-    protected CachedBluetoothDevice getHearingDevice() {
-        return mHearingDevice;
-    }
-
-    @Override
     protected void saveRoutingValue(Context context, int routingValue) {
         Settings.Secure.putInt(context.getContentResolver(),
                 Settings.Secure.HEARING_AID_RINGTONE_ROUTING, routingValue);
diff --git a/src/com/android/settings/bluetooth/HearingDeviceSystemSoundsRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceSystemSoundsRoutingPreferenceController.java
similarity index 80%
rename from src/com/android/settings/bluetooth/HearingDeviceSystemSoundsRoutingPreferenceController.java
rename to src/com/android/settings/accessibility/HearingDeviceSystemSoundsRoutingPreferenceController.java
index a66cfab..1bc0090 100644
--- a/src/com/android/settings/bluetooth/HearingDeviceSystemSoundsRoutingPreferenceController.java
+++ b/src/com/android/settings/accessibility/HearingDeviceSystemSoundsRoutingPreferenceController.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
 
 import android.content.Context;
 import android.provider.Settings;
@@ -35,15 +35,6 @@
         super(context, preferenceKey);
     }
 
-    /**
-     * Initializes objects in this controller. Need to call this before using the controller.
-     *
-     * @param cachedBluetoothDevice the hearing device to configure audio routing
-     */
-    public void init(CachedBluetoothDevice cachedBluetoothDevice) {
-        mHearingDevice = cachedBluetoothDevice;
-    }
-
     @Override
     protected int[] getSupportedAttributeList() {
         return HearingAidAudioRoutingConstants.SYSTEM_SOUNDS_ROUTING_ATTRIBUTES;
@@ -51,11 +42,6 @@
     }
 
     @Override
-    protected CachedBluetoothDevice getHearingDevice() {
-        return mHearingDevice;
-    }
-
-    @Override
     protected void saveRoutingValue(Context context, int routingValue) {
         Settings.Secure.putInt(context.getContentResolver(),
                 Settings.Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING, routingValue);
diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
index 2011725..1270671 100644
--- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
@@ -249,12 +249,18 @@
         super.onProcessArguments(arguments);
     }
 
-    private void addAlwaysOnSetting(PreferenceCategory generalCategory) {
-        if (!DeviceConfig.getBoolean(
+    private boolean isAlwaysOnSettingEnabled() {
+        final boolean defaultValue = getContext().getResources().getBoolean(
+                com.android.internal.R.bool.config_magnification_always_on_enabled);
+
+        return DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_WINDOW_MANAGER,
                 "AlwaysOnMagnifier__enable_always_on_magnifier",
-                false
-        )) {
+                defaultValue
+        );
+    }
+    private void addAlwaysOnSetting(PreferenceCategory generalCategory) {
+        if (!isAlwaysOnSettingEnabled()) {
             return;
         }
 
diff --git a/src/com/android/settings/accounts/ContactSearchPreferenceController.java b/src/com/android/settings/accounts/ContactSearchPreferenceController.java
index 5e4ef48..87dabd8 100644
--- a/src/com/android/settings/accounts/ContactSearchPreferenceController.java
+++ b/src/com/android/settings/accounts/ContactSearchPreferenceController.java
@@ -20,37 +20,38 @@
 import android.os.UserManager;
 import android.provider.Settings;
 
-import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
 import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
 
+import com.android.settings.R;
 import com.android.settings.Utils;
-import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.TogglePreferenceController;
 import com.android.settings.slices.SliceData;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.settingslib.RestrictedSwitchPreference;
 
-public class ContactSearchPreferenceController extends BasePreferenceController implements
-        Preference.OnPreferenceChangeListener {
+import org.jetbrains.annotations.NotNull;
 
-    private UserHandle mManagedUser;
+public class ContactSearchPreferenceController extends TogglePreferenceController implements
+        Preference.OnPreferenceChangeListener, DefaultLifecycleObserver,
+        ManagedProfileQuietModeEnabler.QuietModeChangeListener {
+
+    private final ManagedProfileQuietModeEnabler mQuietModeEnabler;
+    private final UserHandle mManagedUser;
+    private Preference mPreference;
 
     public ContactSearchPreferenceController(Context context, String key) {
         super(context, key);
-        // Set default managed profile for the current user, otherwise isAvailable will be false and
-        // the setting won't be searchable.
-        UserManager userManager = context.getSystemService(UserManager.class);
-        mManagedUser = Utils.getManagedProfile(userManager);
-    }
-
-    @VisibleForTesting
-    void setManagedUser(UserHandle managedUser) {
-        mManagedUser = managedUser;
+        mManagedUser = Utils.getManagedProfile(context.getSystemService(UserManager.class));
+        mQuietModeEnabler = new ManagedProfileQuietModeEnabler(context, this);
     }
 
     @Override
     public int getAvailabilityStatus() {
-        return (mManagedUser != null) ? AVAILABLE : DISABLED_FOR_USER;
+        return mQuietModeEnabler.isAvailable() ? AVAILABLE : DISABLED_FOR_USER;
     }
 
     @Override
@@ -59,6 +60,7 @@
         if (preference instanceof RestrictedSwitchPreference) {
             final RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
             pref.setChecked(isChecked());
+            pref.setEnabled(!mQuietModeEnabler.isQuietModeEnabled());
             if (mManagedUser != null) {
                 final RestrictedLockUtils.EnforcedAdmin enforcedAdmin =
                         RestrictedLockUtilsInternal.checkIfRemoteContactSearchDisallowed(
@@ -68,26 +70,48 @@
         }
     }
 
-    private boolean isChecked() {
-        if (mManagedUser == null) {
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreference = screen.findPreference(getPreferenceKey());
+        updateState(mPreference);
+    }
+
+    @Override
+    public void onStart(@NotNull LifecycleOwner lifecycleOwner) {
+        lifecycleOwner.getLifecycle().addObserver(mQuietModeEnabler);
+    }
+
+    @Override
+    public void onStop(@NotNull LifecycleOwner lifecycleOwner) {
+        lifecycleOwner.getLifecycle().removeObserver(mQuietModeEnabler);
+    }
+
+    @Override
+    public boolean isChecked() {
+        if (mManagedUser == null || mQuietModeEnabler.isQuietModeEnabled()) {
             return false;
         }
         return 0 != Settings.Secure.getIntForUser(mContext.getContentResolver(),
                 MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, mManagedUser.getIdentifier());
     }
 
-    private boolean setChecked(boolean isChecked) {
-        if (mManagedUser != null) {
-            final int value = isChecked ? 1 : 0;
-            Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                    MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, value, mManagedUser.getIdentifier());
+    @Override
+    public boolean setChecked(boolean isChecked) {
+        if (mManagedUser == null || mQuietModeEnabler.isQuietModeEnabled()) {
+            return false;
         }
+        final int value = isChecked ? 1 : 0;
+        Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, value, mManagedUser.getIdentifier());
         return true;
     }
 
     @Override
-    public final boolean onPreferenceChange(Preference preference, Object newValue) {
-        return setChecked((boolean) newValue);
+    public void onQuietModeChanged() {
+        if (mPreference != null) {
+            updateState(mPreference);
+        }
     }
 
     @Override
@@ -95,4 +119,9 @@
     public int getSliceType() {
         return SliceData.SliceType.SWITCH;
     }
-}
\ No newline at end of file
+
+    @Override
+    public int getSliceHighlightMenuRes() {
+        return R.string.menu_key_accounts;
+    }
+}
diff --git a/src/com/android/settings/accounts/ManagedProfileQuietModeEnabler.java b/src/com/android/settings/accounts/ManagedProfileQuietModeEnabler.java
new file mode 100644
index 0000000..989be09
--- /dev/null
+++ b/src/com/android/settings/accounts/ManagedProfileQuietModeEnabler.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accounts;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
+
+import com.android.settings.Utils;
+
+import javax.annotation.Nullable;
+
+/**
+ * A class that controls the managed profile's quiet mode, listens to quiet mode changes and
+ * modifies managed profile settings. The user facing term for quiet mode is "work apps".
+ */
+final class ManagedProfileQuietModeEnabler implements DefaultLifecycleObserver {
+
+    private static final String TAG = "QuietModeEnabler";
+    private final Context mContext;
+    private final QuietModeChangeListener mListener;
+    @Nullable private final UserHandle mManagedProfile;
+    private final UserManager mUserManager;
+
+    public interface QuietModeChangeListener {
+        /** Called when quiet mode has changed. */
+        void onQuietModeChanged();
+    }
+
+    ManagedProfileQuietModeEnabler(Context context, QuietModeChangeListener listener) {
+        mContext = context;
+        mListener = listener;
+        mUserManager = context.getSystemService(UserManager.class);
+        mManagedProfile = Utils.getManagedProfile(mUserManager);
+    }
+
+    public void setQuietModeEnabled(boolean enabled) {
+        if (mManagedProfile != null) {
+            mUserManager.requestQuietModeEnabled(enabled, mManagedProfile);
+        }
+    }
+
+    public boolean isQuietModeEnabled() {
+        return mManagedProfile != null && mUserManager.isQuietModeEnabled(mManagedProfile);
+    }
+
+    @Override
+    public void onStart(@NonNull LifecycleOwner owner) {
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+        intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+        mContext.registerReceiver(mReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED);
+    }
+
+    @Override
+    public void onStop(@NonNull LifecycleOwner owner) {
+        mContext.unregisterReceiver(mReceiver);
+    }
+
+    public boolean isAvailable() {
+        return (mManagedProfile != null);
+    }
+
+    private void refreshQuietMode() {
+        if (mListener != null) {
+            mListener.onQuietModeChanged();
+        }
+    }
+
+    /**
+     * Receiver that listens to {@link Intent#ACTION_MANAGED_PROFILE_AVAILABLE} and
+     * {@link Intent#ACTION_MANAGED_PROFILE_UNAVAILABLE}, and updates the work mode
+     */
+    @VisibleForTesting
+    final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent == null) {
+                return;
+            }
+            String action = intent.getAction();
+            Log.v(TAG, "Received broadcast: " + action);
+
+            if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)
+                    || Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
+                int intentUserIdentifier = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                        UserHandle.USER_NULL);
+                if (intentUserIdentifier == mManagedProfile.getIdentifier()) {
+                    refreshQuietMode();
+                } else {
+                    Log.w(TAG, "Managed profile broadcast ID: " + intentUserIdentifier
+                            + " does not match managed user: " + mManagedProfile);
+                }
+            } else {
+                Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction());
+            }
+        }
+    };
+}
diff --git a/src/com/android/settings/accounts/WorkModePreferenceController.java b/src/com/android/settings/accounts/WorkModePreferenceController.java
index 1941de4..a261afc 100644
--- a/src/com/android/settings/accounts/WorkModePreferenceController.java
+++ b/src/com/android/settings/accounts/WorkModePreferenceController.java
@@ -1,165 +1,90 @@
 /*
  * Copyright (C) 2018 The Android Open Source Project
  *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
+ * 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.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 package com.android.settings.accounts;
 
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SETTING_OFF_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SETTING_ON_SUMMARY;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
 
-import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
 import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-import androidx.preference.TwoStatePreference;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
-import com.android.settings.Utils;
-import com.android.settings.core.BasePreferenceController;
 import com.android.settings.slices.SliceData;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnStart;
-import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settings.widget.SettingsMainSwitchPreferenceController;
+import com.android.settingslib.widget.MainSwitchPreference;
 
-public class WorkModePreferenceController extends BasePreferenceController implements
-        Preference.OnPreferenceChangeListener, LifecycleObserver, OnStart, OnStop {
+import org.jetbrains.annotations.NotNull;
 
-    private static final String TAG = "WorkModeController";
 
-    private UserManager mUserManager;
-    private UserHandle mManagedUser;
-    private DevicePolicyManager mDevicePolicyManager;
+public class WorkModePreferenceController extends SettingsMainSwitchPreferenceController
+        implements Preference.OnPreferenceChangeListener, DefaultLifecycleObserver,
+        ManagedProfileQuietModeEnabler.QuietModeChangeListener {
 
-    private Preference mPreference;
-    private IntentFilter mIntentFilter;
+    private final ManagedProfileQuietModeEnabler mQuietModeEnabler;
 
     public WorkModePreferenceController(Context context, String key) {
         super(context, key);
-        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-        mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
-        mIntentFilter = new IntentFilter();
-        mIntentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
-        mIntentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
-        // Set default managed profile for the current user, otherwise isAvailable will be false and
-        // the setting won't be searchable.
-        mManagedUser = Utils.getManagedProfile(mUserManager);
-    }
-
-    @VisibleForTesting
-    void setManagedUser(UserHandle managedUser) {
-        mManagedUser = managedUser;
-    }
-
-    @Override
-    public void onStart() {
-        mContext.registerReceiver(mReceiver, mIntentFilter,
-                Context.RECEIVER_EXPORTED_UNAUDITED);
-    }
-
-    @Override
-    public void onStop() {
-        mContext.unregisterReceiver(mReceiver);
+        mQuietModeEnabler = new ManagedProfileQuietModeEnabler(context, this);
     }
 
     @Override
     public int getAvailabilityStatus() {
-        return (mManagedUser != null) ? AVAILABLE : DISABLED_FOR_USER;
+        return (mQuietModeEnabler.isAvailable()) ? AVAILABLE : DISABLED_FOR_USER;
     }
 
     @Override
-    public void displayPreference(PreferenceScreen screen) {
-        super.displayPreference(screen);
-        mPreference = screen.findPreference(getPreferenceKey());
+    public void onStart(@NotNull LifecycleOwner lifecycleOwner) {
+        lifecycleOwner.getLifecycle().addObserver(mQuietModeEnabler);
     }
 
     @Override
-    public CharSequence getSummary() {
-        if (isChecked()) {
-            return mDevicePolicyManager.getResources().getString(
-                    WORK_PROFILE_SETTING_ON_SUMMARY,
-                    () -> mContext.getString(R.string.work_mode_on_summary));
-        }
-
-        return mDevicePolicyManager.getResources().getString(
-                WORK_PROFILE_SETTING_OFF_SUMMARY,
-                        () -> mContext.getString(R.string.work_mode_off_summary));
+    public void onStop(@NotNull LifecycleOwner lifecycleOwner) {
+        lifecycleOwner.getLifecycle().removeObserver(mQuietModeEnabler);
     }
 
-    private boolean isChecked() {
-        boolean isWorkModeOn = false;
-        if (mUserManager != null && mManagedUser != null) {
-            isWorkModeOn = !mUserManager.isQuietModeEnabled(mManagedUser);
-        }
-        return isWorkModeOn;
+    @Override
+    public boolean isChecked() {
+        return !mQuietModeEnabler.isQuietModeEnabled();
     }
 
-    private boolean setChecked(boolean isChecked) {
-        if (mUserManager != null && mManagedUser != null) {
-            final boolean quietModeEnabled = !isChecked;
-            mUserManager.requestQuietModeEnabled(quietModeEnabled, mManagedUser);
-        }
+    @Override
+    public boolean setChecked(boolean isChecked) {
+        mQuietModeEnabler.setQuietModeEnabled(!isChecked);
         return true;
     }
 
     @Override
-    public void updateState(Preference preference) {
-        super.updateState(preference);
-        if (preference instanceof TwoStatePreference) {
-            ((TwoStatePreference) preference).setChecked(isChecked());
-        }
+    public void onQuietModeChanged() {
+        updateState(mSwitchPreference);
     }
 
     @Override
-    public final boolean onPreferenceChange(Preference preference, Object newValue) {
-        return setChecked((boolean) newValue);
-    }
-
-    /**
-     * Receiver that listens to {@link Intent#ACTION_MANAGED_PROFILE_AVAILABLE} and
-     * {@link Intent#ACTION_MANAGED_PROFILE_UNAVAILABLE}, and updates the work mode
-     */
-    @VisibleForTesting
-    final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (intent == null) {
-                return;
-            }
-            final String action = intent.getAction();
-            Log.v(TAG, "Received broadcast: " + action);
-
-            if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)
-                    || Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
-                if (intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
-                        UserHandle.USER_NULL) == mManagedUser.getIdentifier()) {
-                    updateState(mPreference);
-                }
-                return;
-            }
-            Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction());
-        }
-    };
-
-    @Override
     @SliceData.SliceType
     public int getSliceType() {
         return SliceData.SliceType.SWITCH;
     }
-}
\ No newline at end of file
+
+    @Override
+    public int getSliceHighlightMenuRes() {
+        return R.string.menu_key_accounts;
+    }
+
+    @VisibleForTesting
+    void setPreference(MainSwitchPreference preference) {
+        mSwitchPreference = preference;
+    }
+}
diff --git a/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java b/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java
index ae890f8..67d56e0 100644
--- a/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java
+++ b/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java
@@ -97,16 +97,24 @@
      * </ul>
      */
     public static boolean isEmbeddingActivityEnabled(Context context) {
-        boolean isFlagEnabled = FeatureFlagUtils.isEnabled(context,
-                FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN);
-        boolean isSettingsSplitSupported = isSettingsSplitEnabled(context);
-        boolean isUserSetupComplete = WizardManagerHelper.isUserSetupComplete(context);
-
-        Log.d(TAG, "isFlagEnabled = " + isFlagEnabled);
-        Log.d(TAG, "isSettingsSplitSupported = " + isSettingsSplitSupported);
-        Log.d(TAG, "isUserSetupComplete = " + isUserSetupComplete);
-
-        return isFlagEnabled && isSettingsSplitSupported && isUserSetupComplete;
+        // Activity Embedding feature is not enabled if Settings doesn't enable large screen
+        // optimization or the device is not supported.
+        if (!isSettingsSplitEnabled(context)) {
+            Log.d(TAG, "isSettingsSplitSupported = false");
+            return false;
+        }
+        // Activity Embedding feature is not enabled if a user chooses to disable the feature.
+        if (!FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN)) {
+            Log.d(TAG, "isFlagEnabled = false");
+            return false;
+        }
+        // Don't enable Activity embedding for setup wizard.
+        if (!WizardManagerHelper.isUserSetupComplete(context)) {
+            Log.d(TAG, "isUserSetupComplete = false");
+            return false;
+        }
+        Log.d(TAG, "isEmbeddingActivityEnabled = true");
+        return true;
     }
 
     /** Whether to show the regular or simplified homepage layout. */
@@ -120,8 +128,7 @@
      * Check if activity is already embedded
      */
     public static boolean isAlreadyEmbedded(Activity activity) {
-        return ActivityEmbeddingController
-                .getInstance(activity)
-                .isActivityEmbedded(activity);
+        return isEmbeddingActivityEnabled(activity) && ActivityEmbeddingController.getInstance(
+                activity).isActivityEmbedded(activity);
     }
 }
diff --git a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
index 07a737d..80d3947 100644
--- a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
+++ b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
@@ -16,10 +16,6 @@
 
 package com.android.settings.applications;
 
-import static android.Manifest.permission.RUN_USER_INITIATED_JOBS;
-import static android.app.AppOpsManager.OP_RUN_USER_INITIATED_JOBS;
-import static android.app.AppOpsManager.opToPermission;
-
 import android.Manifest;
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
@@ -345,7 +341,9 @@
 
     @Override
     public boolean isLongBackgroundTaskPermissionToggleSupported() {
-        return TextUtils.equals(RUN_USER_INITIATED_JOBS,
-                opToPermission(OP_RUN_USER_INITIATED_JOBS));
+        // Since the RUN_USER_INITIATED_JOBS permission related to this controller is a normal
+        // app-op permission allowed by default, this should always return false - if it is ever
+        // converted to a special app-op permission, this should be updated.
+        return false;
     }
 }
diff --git a/src/com/android/settings/applications/ClonedAppsPreferenceController.java b/src/com/android/settings/applications/ClonedAppsPreferenceController.java
index a8a79f4..332df18 100644
--- a/src/com/android/settings/applications/ClonedAppsPreferenceController.java
+++ b/src/com/android/settings/applications/ClonedAppsPreferenceController.java
@@ -75,6 +75,9 @@
     }
 
     private void updatePreferenceSummary() {
+        if (!isAvailable()) {
+            return;
+        }
         new AsyncTask<Void, Void, Integer[]>() {
 
             @Override
diff --git a/src/com/android/settings/applications/credentials/CombinedProviderInfo.java b/src/com/android/settings/applications/credentials/CombinedProviderInfo.java
index 1fd3075..074fb7b 100644
--- a/src/com/android/settings/applications/credentials/CombinedProviderInfo.java
+++ b/src/com/android/settings/applications/credentials/CombinedProviderInfo.java
@@ -51,7 +51,7 @@
             @Nullable List<CredentialProviderInfo> cpis,
             @Nullable AutofillServiceInfo asi,
             boolean isDefaultAutofillProvider,
-            boolean IsPrimaryCredmanProvider) {
+            boolean isPrimaryCredmanProvider) {
         if (cpis == null) {
             mCredentialProviderInfos = new ArrayList<>();
         } else {
@@ -59,11 +59,11 @@
         }
         mAutofillServiceInfo = asi;
         mIsDefaultAutofillProvider = isDefaultAutofillProvider;
-        mIsPrimaryCredmanProvider = IsPrimaryCredmanProvider;
+        mIsPrimaryCredmanProvider = isPrimaryCredmanProvider;
     }
 
     /** Returns the credential provider info. */
-    @Nullable
+    @NonNull
     public List<CredentialProviderInfo> getCredentialProviderInfos() {
         return mCredentialProviderInfos;
     }
@@ -85,11 +85,13 @@
     /** Returns the app icon. */
     @Nullable
     public Drawable getAppIcon(@NonNull Context context, int userId) {
-        IconDrawableFactory factory = IconDrawableFactory.newInstance(context);
+        final IconDrawableFactory factory = IconDrawableFactory.newInstance(context);
+        final ServiceInfo brandingService = getBrandingService();
+        final ApplicationInfo appInfo = getApplicationInfo();
+
         Drawable icon = null;
-        ServiceInfo brandingService = getBrandingService();
-        if (brandingService != null) {
-            icon = factory.getBadgedIcon(brandingService, getApplicationInfo(), userId);
+        if (brandingService != null && appInfo != null) {
+            icon = factory.getBadgedIcon(brandingService, appInfo, userId);
         }
 
         // If the branding service gave us a icon then use that.
@@ -98,7 +100,10 @@
         }
 
         // Otherwise fallback to the app icon and then the package name.
-        return factory.getBadgedIcon(getApplicationInfo(), userId);
+        if (appInfo != null) {
+            return factory.getBadgedIcon(appInfo, userId);
+        }
+        return null;
     }
 
     /** Returns the app name. */
@@ -116,11 +121,14 @@
         }
 
         // Otherwise fallback to the app label and then the package name.
-        name = getApplicationInfo().loadLabel(context.getPackageManager());
-        if (TextUtils.isEmpty(name)) {
-            name = getApplicationInfo().packageName;
+        final ApplicationInfo appInfo = getApplicationInfo();
+        if (appInfo != null) {
+            name = appInfo.loadLabel(context.getPackageManager());
+            if (TextUtils.isEmpty(name)) {
+                return appInfo.packageName;
+            }
         }
-        return name;
+        return "";
     }
 
     /** Gets the service to use for branding (name, icons). */
@@ -245,8 +253,10 @@
         // Now go through and build the joint datasets.
         List<CombinedProviderInfo> cmpi = new ArrayList<>();
         for (String packageName : packageNames) {
-            List<AutofillServiceInfo> asi = autofillServices.get(packageName);
-            List<CredentialProviderInfo> cpi = credmanServices.get(packageName);
+            List<AutofillServiceInfo> asi =
+                    autofillServices.getOrDefault(packageName, new ArrayList<>());
+            List<CredentialProviderInfo> cpi =
+                    credmanServices.getOrDefault(packageName, new ArrayList<>());
 
             // If there are multiple autofill services then pick the first one.
             AutofillServiceInfo selectedAsi = null;
diff --git a/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java b/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java
index 742faf1..59c33b2 100644
--- a/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java
+++ b/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java
@@ -35,6 +35,7 @@
 import com.android.settings.applications.defaultapps.DefaultAppPreferenceController;
 import com.android.settingslib.applications.DefaultAppInfo;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class DefaultCombinedPreferenceController extends DefaultAppPreferenceController {
@@ -110,15 +111,19 @@
     private List<CombinedProviderInfo> getAllProviders(int userId) {
         final List<AutofillServiceInfo> autofillProviders =
                 AutofillServiceInfo.getAvailableServices(mContext, userId);
-        final List<CredentialProviderInfo> credManProviders =
-                mCredentialManager.getCredentialProviderServices(
-                        userId, CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY);
         final String selectedAutofillProvider =
                 Settings.Secure.getStringForUser(
                         mContext.getContentResolver(),
                         DefaultCombinedPicker.AUTOFILL_SETTING,
                         userId);
 
+        final List<CredentialProviderInfo> credManProviders = new ArrayList<>();
+        if (mCredentialManager != null) {
+            credManProviders.addAll(
+                    mCredentialManager.getCredentialProviderServices(
+                            userId, CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY));
+        }
+
         return CombinedProviderInfo.buildMergedList(
                 autofillProviders, credManProviders, selectedAutofillProvider);
     }
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index a6e6ac4..e0f1b5f 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -16,8 +16,6 @@
 
 package com.android.settings.applications.manageapplications;
 
-import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_SPA;
-
 import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_DRAGGING;
 import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;
 
@@ -67,7 +65,6 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.ArraySet;
-import android.util.FeatureFlagUtils;
 import android.util.IconDrawableFactory;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -728,9 +725,6 @@
                         R.string.long_background_tasks_label);
                 break;
             case LIST_TYPE_CLONED_APPS:
-                if (!FeatureFlagUtils.isEnabled(getContext(), SETTINGS_ENABLE_SPA)) {
-                    return;
-                }
                 int userId = UserHandle.getUserId(mCurrentUid);
                 UserInfo userInfo = mUserManager.getUserInfo(userId);
                 if (userInfo != null && !userInfo.isCloneProfile()) {
diff --git a/src/com/android/settings/applications/specialaccess/applications/LongBackgroundTaskController.java b/src/com/android/settings/applications/specialaccess/applications/LongBackgroundTaskController.java
index 586980c..ccfa9c8 100644
--- a/src/com/android/settings/applications/specialaccess/applications/LongBackgroundTaskController.java
+++ b/src/com/android/settings/applications/specialaccess/applications/LongBackgroundTaskController.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -37,6 +37,6 @@
     @Override
     public int getAvailabilityStatus() {
         return mAppFeatureProvider.isLongBackgroundTaskPermissionToggleSupported()
-                ?  AVAILABLE : UNSUPPORTED_ON_DEVICE;
+                ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
     }
 }
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingController.java b/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingController.java
deleted file mode 100644
index 91221a3..0000000
--- a/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingController.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.bluetooth;
-
-import static com.android.settings.bluetooth.BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.util.FeatureFlagUtils;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceFragmentCompat;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.R;
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-
-/**
- * The controller of the audio routing in the bluetooth detail settings.
- */
-public class BluetoothDetailsAudioRoutingController extends BluetoothDetailsController  {
-
-    private static final String KEY_DEVICE_CONTROLS_SPECIFIC_GROUP = "device_controls_specific";
-    @VisibleForTesting
-    static final String KEY_AUDIO_ROUTING = "audio_routing";
-
-    public BluetoothDetailsAudioRoutingController(Context context,
-            PreferenceFragmentCompat fragment, CachedBluetoothDevice device, Lifecycle lifecycle) {
-        super(context, fragment, device, lifecycle);
-    }
-
-    @Override
-    public boolean isAvailable() {
-        return mCachedDevice.isHearingAidDevice() && FeatureFlagUtils.isEnabled(mContext,
-                FeatureFlagUtils.SETTINGS_AUDIO_ROUTING);
-    }
-
-    @Override
-    protected void init(PreferenceScreen screen) {
-        if (!mCachedDevice.isHearingAidDevice()) {
-            return;
-        }
-
-        final PreferenceCategory prefCategory = screen.findPreference(getPreferenceKey());
-        final Preference pref = createAudioRoutingPreference(prefCategory.getContext());
-        prefCategory.addPreference(pref);
-    }
-
-    @Override
-    protected void refresh() {}
-
-    @Override
-    public String getPreferenceKey() {
-        return KEY_DEVICE_CONTROLS_SPECIFIC_GROUP;
-    }
-
-    private Preference createAudioRoutingPreference(Context context) {
-        final Preference preference = new Preference(context);
-
-        preference.setKey(KEY_AUDIO_ROUTING);
-        preference.setTitle(context.getString(R.string.bluetooth_audio_routing_title));
-        preference.setSummary(context.getString(R.string.bluetooth_audio_routing_summary));
-        final Bundle extras = preference.getExtras();
-        extras.putString(KEY_DEVICE_ADDRESS, mCachedDevice.getAddress());
-        preference.setFragment(BluetoothDetailsAudioRoutingFragment.class.getName());
-
-        return preference;
-    }
-}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragment.java b/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragment.java
deleted file mode 100644
index 6c435a2..0000000
--- a/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragment.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.bluetooth;
-
-import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
-
-import static com.android.settings.bluetooth.BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS;
-
-import android.app.settings.SettingsEnums;
-import android.bluetooth.BluetoothDevice;
-import android.content.Context;
-import android.util.Log;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.settings.R;
-import com.android.settings.dashboard.RestrictedDashboardFragment;
-import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.LocalBluetoothManager;
-
-/** Settings fragment containing bluetooth audio routing. */
-public class BluetoothDetailsAudioRoutingFragment extends RestrictedDashboardFragment {
-
-    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
-            new BaseSearchIndexProvider(R.xml.bluetooth_audio_routing_fragment);
-    private static final String TAG = "BluetoothDetailsAudioRoutingFragment";
-    @VisibleForTesting
-    CachedBluetoothDevice mCachedDevice;
-
-    public BluetoothDetailsAudioRoutingFragment() {
-        super(DISALLOW_CONFIG_BLUETOOTH);
-    }
-
-    @Override
-    public void onAttach(Context context) {
-        super.onAttach(context);
-        final LocalBluetoothManager localBtMgr = Utils.getLocalBtManager(context);
-        final CachedBluetoothDeviceManager cachedDeviceMgr = localBtMgr.getCachedDeviceManager();
-        final BluetoothDevice bluetoothDevice = localBtMgr.getBluetoothAdapter().getRemoteDevice(
-                getArguments().getString(KEY_DEVICE_ADDRESS));
-
-        mCachedDevice = cachedDeviceMgr.findDevice(bluetoothDevice);
-        if (mCachedDevice == null) {
-            // Close this page if device is null with invalid device mac address
-            Log.w(TAG, "onAttach() CachedDevice is null! Can not find address: "
-                    + bluetoothDevice.getAnonymizedAddress());
-            finish();
-            return;
-        }
-
-        use(HearingDeviceRingtoneRoutingPreferenceController.class).init(mCachedDevice);
-        use(HearingDeviceCallRoutingPreferenceController.class).init(mCachedDevice);
-        use(HearingDeviceMediaRoutingPreferenceController.class).init(mCachedDevice);
-        use(HearingDeviceSystemSoundsRoutingPreferenceController.class).init(mCachedDevice);
-    }
-
-    @Override
-    public int getMetricsCategory() {
-        return SettingsEnums.BLUETOOTH_AUDIO_ROUTING;
-    }
-
-    @Override
-    protected int getPreferenceScreenResId() {
-        return R.xml.bluetooth_audio_routing_fragment;
-    }
-
-    @Override
-    protected String getLogTag() {
-        return TAG;
-    }
-}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java
index a3b1105..c4a4221 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java
@@ -34,7 +34,7 @@
 import com.google.common.annotations.VisibleForTesting;
 
 /**
- * The controller of the hearing device controls in the bluetooth detail settings.
+ * The controller of the hearing device settings to launch Hearing device page.
  */
 public class BluetoothDetailsHearingDeviceControlsController extends BluetoothDetailsController
         implements Preference.OnPreferenceClickListener {
@@ -87,6 +87,7 @@
         final Preference preference = new Preference(context);
         preference.setKey(KEY_HEARING_DEVICE_CONTROLS);
         preference.setTitle(context.getString(R.string.bluetooth_device_controls_title));
+        preference.setSummary(context.getString(R.string.bluetooth_device_controls_summary));
         preference.setOnPreferenceClickListener(this);
 
         return preference;
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 2a94b1e..99f3e31 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -314,8 +314,6 @@
                     lifecycle));
             controllers.add(new BluetoothDetailsHearingDeviceControlsController(context, this,
                     mCachedDevice, lifecycle));
-            controllers.add(new BluetoothDetailsAudioRoutingController(context, this, mCachedDevice,
-                    lifecycle));
         }
         return controllers;
     }
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
index 17c5f36..2935c67 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
@@ -35,8 +35,10 @@
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -125,7 +127,7 @@
                 update(cachedBluetoothDevice);
             }
         } else {
-          removeAllDevicesFromPreference();
+            removeAllDevicesFromPreference();
         }
     }
 
@@ -252,7 +254,7 @@
             btPreference.setOnGearClickListener(mDeviceProfilesListener);
             if (this instanceof Preference.OnPreferenceClickListener) {
                 btPreference.setOnPreferenceClickListener(
-                        (Preference.OnPreferenceClickListener)this);
+                        (Preference.OnPreferenceClickListener) this);
             }
             mPreferenceMap.put(device, btPreference);
             mDevicePreferenceCallback.onDeviceAdded(btPreference);
@@ -266,17 +268,20 @@
         final BluetoothDevice device = cachedDevice.getDevice();
         final CachedBluetoothDevice subCachedDevice = cachedDevice.getSubDevice();
         if (mPreferenceMap.containsKey(device)) {
-            mDevicePreferenceCallback.onDeviceRemoved(mPreferenceMap.get(device));
-            mPreferenceMap.remove(device);
+            removePreference(device);
         } else if (subCachedDevice != null) {
             // When doing remove, to check if preference maps to sub device.
             // This would happen when connection state is changed in detail page that there is no
             // callback from SettingsLib.
             final BluetoothDevice subDevice = subCachedDevice.getDevice();
-            if (mPreferenceMap.containsKey(subDevice)) {
-                mDevicePreferenceCallback.onDeviceRemoved(mPreferenceMap.get(subDevice));
-                mPreferenceMap.remove(subDevice);
-            }
+            removePreference(subDevice);
+        }
+    }
+
+    private void removePreference(BluetoothDevice device) {
+        if (mPreferenceMap.containsKey(device)) {
+            mDevicePreferenceCallback.onDeviceRemoved(mPreferenceMap.get(device));
+            mPreferenceMap.remove(device);
         }
     }
 
@@ -324,14 +329,38 @@
      * Update the attributes of {@link Preference}.
      */
     public void refreshPreference() {
-        for (Preference preference : mPreferenceMap.values()) {
-            ((BluetoothDevicePreference) preference).onPreferenceAttributesChanged();
+        List<BluetoothDevice> removeList = new ArrayList<>();
+        mPreferenceMap.forEach((key, preference) -> {
+            if (isDeviceOfMapInCachedDevicesList(key)) {
+                ((BluetoothDevicePreference) preference).onPreferenceAttributesChanged();
+            } else {
+                // If the BluetoothDevice of preference is not in the CachedDevices List, then
+                // remove this preference.
+                removeList.add(key);
+            }
+        });
+
+        for (BluetoothDevice bluetoothDevice : removeList) {
+            Log.d(getLogTag(), "removePreference key: " + bluetoothDevice.getAnonymizedAddress());
+            removePreference(bluetoothDevice);
         }
     }
 
-    protected boolean isDeviceInCachedDevicesList(CachedBluetoothDevice cachedDevice){
+    protected boolean isDeviceInCachedDevicesList(CachedBluetoothDevice cachedDevice) {
         return mLocalManager.getCachedDeviceManager().getCachedDevicesCopy().contains(cachedDevice);
     }
+
+    private boolean isDeviceOfMapInCachedDevicesList(BluetoothDevice inputBluetoothDevice) {
+        Collection<CachedBluetoothDevice> cachedDevices =
+                mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();
+        if (cachedDevices == null || cachedDevices.isEmpty()) {
+            return false;
+        }
+        return cachedDevices.stream()
+                .anyMatch(cachedBluetoothDevice -> cachedBluetoothDevice.getDevice() != null
+                        && cachedBluetoothDevice.getDevice().equals(inputBluetoothDevice));
+    }
+
     protected String getLogTag() {
         return TAG;
     }
diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
index 777e428..79e0194 100644
--- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
@@ -343,7 +343,7 @@
         final String stateString;
         final String footerString;
 
-        if (!mBatteryOptimizeUtils.isValidPackageName()) {
+        if (mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()) {
             // Present optimized only string when the package name is invalid.
             stateString = context.getString(R.string.manager_battery_usage_optimized_only);
             footerString = context.getString(
diff --git a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
index 79df57a..66ffc90 100644
--- a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
+++ b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
@@ -25,17 +25,20 @@
 import android.content.SharedPreferences;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
+import android.os.Build;
 import android.os.IDeviceIdleController;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 
 import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
 
 import java.io.IOException;
@@ -49,13 +52,22 @@
 public final class BatteryBackupHelper implements BackupHelper {
     /** An inditifier for {@link BackupHelper}. */
     public static final String TAG = "BatteryBackupHelper";
+    // Definition for the device build information.
+    public static final String KEY_BUILD_BRAND = "device_build_brand";
+    public static final String KEY_BUILD_PRODUCT = "device_build_product";
+    public static final String KEY_BUILD_MANUFACTURER = "device_build_manufacture";
+    public static final String KEY_BUILD_FINGERPRINT = "device_build_fingerprint";
+    // Customized fields for device extra information.
+    public static final String KEY_BUILD_METADATA_1 = "device_build_metadata_1";
+    public static final String KEY_BUILD_METADATA_2 = "device_build_metadata_2";
+
     private static final String DEVICE_IDLE_SERVICE = "deviceidle";
     private static final String BATTERY_OPTIMIZE_BACKUP_FILE_NAME =
             "battery_optimize_backup_historical_logs";
+    private static final int DEVICE_BUILD_INFO_SIZE = 6;
 
     static final String DELIMITER = ",";
     static final String DELIMITER_MODE = ":";
-    static final String KEY_FULL_POWER_LIST = "full_power_list";
     static final String KEY_OPTIMIZATION_LIST = "optimization_mode_list";
 
     @VisibleForTesting
@@ -70,7 +82,13 @@
     @VisibleForTesting
     BatteryOptimizeUtils mBatteryOptimizeUtils;
 
+    private byte[] mOptimizationModeBytes;
+    private boolean mVerifyMigrateConfiguration = false;
+
     private final Context mContext;
+    // Device information map from the restoreEntity() method.
+    private final ArrayMap<String, String> mDeviceBuildInfoMap =
+            new ArrayMap<>(DEVICE_BUILD_INFO_SIZE);
 
     public BatteryBackupHelper(Context context) {
         mContext = context.getApplicationContext();
@@ -83,37 +101,58 @@
             Log.w(TAG, "ignore performBackup() for non-owner or empty data");
             return;
         }
-        final List<String> allowlistedApps = backupFullPowerList(data);
-        if (allowlistedApps != null) {
-            backupOptimizationMode(data, allowlistedApps);
+        final List<String> allowlistedApps = getFullPowerList();
+        if (allowlistedApps == null) {
+            return;
         }
+
+        writeBackupData(data, KEY_BUILD_BRAND, Build.BRAND);
+        writeBackupData(data, KEY_BUILD_PRODUCT, Build.PRODUCT);
+        writeBackupData(data, KEY_BUILD_MANUFACTURER, Build.MANUFACTURER);
+        writeBackupData(data, KEY_BUILD_FINGERPRINT, Build.FINGERPRINT);
+        // Add customized device build metadata fields.
+        final PowerUsageFeatureProvider provider = FeatureFactory.getFactory(mContext)
+                .getPowerUsageFeatureProvider(mContext);
+        writeBackupData(data, KEY_BUILD_METADATA_1, provider.getBuildMetadata1(mContext));
+        writeBackupData(data, KEY_BUILD_METADATA_2, provider.getBuildMetadata2(mContext));
+
+        backupOptimizationMode(data, allowlistedApps);
     }
 
     @Override
     public void restoreEntity(BackupDataInputStream data) {
-        BatterySettingsMigrateChecker.verifyConfiguration(mContext);
+        // Ensure we only verify the migrate configuration one time.
+        if (!mVerifyMigrateConfiguration) {
+            mVerifyMigrateConfiguration = true;
+            BatterySettingsMigrateChecker.verifySaverConfiguration(mContext);
+        }
         if (!isOwner() || data == null || data.size() == 0) {
             Log.w(TAG, "ignore restoreEntity() for non-owner or empty data");
             return;
         }
-        if (KEY_OPTIMIZATION_LIST.equals(data.getKey())) {
-            final int dataSize = data.size();
-            final byte[] dataBytes = new byte[dataSize];
-            try {
-                data.read(dataBytes, 0 /*offset*/, dataSize);
-            } catch (IOException e) {
-                Log.e(TAG, "failed to load BackupDataInputStream", e);
-                return;
-            }
-            restoreOptimizationMode(dataBytes);
+        final String dataKey = data.getKey();
+        switch (dataKey) {
+            case KEY_BUILD_BRAND:
+            case KEY_BUILD_PRODUCT:
+            case KEY_BUILD_MANUFACTURER:
+            case KEY_BUILD_FINGERPRINT:
+            case KEY_BUILD_METADATA_1:
+            case KEY_BUILD_METADATA_2:
+                restoreBackupData(dataKey, data);
+                break;
+            case KEY_OPTIMIZATION_LIST:
+                // Hold the optimization mode data until all conditions are matched.
+                mOptimizationModeBytes = getBackupData(dataKey, data);
+                break;
         }
+        performRestoreIfNeeded();
     }
 
     @Override
     public void writeNewStateDescription(ParcelFileDescriptor newState) {
     }
 
-    private List<String> backupFullPowerList(BackupDataOutput data) {
+    private List<String> getFullPowerList() {
         final long timestamp = System.currentTimeMillis();
         String[] allowlistedApps;
         try {
@@ -127,10 +166,7 @@
             Log.w(TAG, "no data found in the getFullPowerList()");
             return new ArrayList<>();
         }
-
-        final String allowedApps = String.join(DELIMITER, allowlistedApps);
-        writeBackupData(data, KEY_FULL_POWER_LIST, allowedApps);
-        Log.d(TAG, String.format("backup getFullPowerList() size=%d in %d/ms",
+        Log.d(TAG, String.format("getFullPowerList() size=%d in %d/ms",
                 allowlistedApps.length, (System.currentTimeMillis() - timestamp)));
         return Arrays.asList(allowlistedApps);
     }
@@ -175,17 +211,17 @@
     }
 
     @VisibleForTesting
-    void restoreOptimizationMode(byte[] dataBytes) {
+    int restoreOptimizationMode(byte[] dataBytes) {
         final long timestamp = System.currentTimeMillis();
         final String dataContent = new String(dataBytes, StandardCharsets.UTF_8);
         if (dataContent == null || dataContent.isEmpty()) {
             Log.w(TAG, "no data found in the restoreOptimizationMode()");
-            return;
+            return 0;
         }
         final String[] appConfigurations = dataContent.split(BatteryBackupHelper.DELIMITER);
         if (appConfigurations == null || appConfigurations.length == 0) {
             Log.w(TAG, "no data found from the split() processing");
-            return;
+            return 0;
         }
         int restoreCount = 0;
         for (int index = 0; index < appConfigurations.length; index++) {
@@ -217,6 +253,24 @@
         }
         Log.d(TAG, String.format("restoreOptimizationMode() count=%d in %d/ms",
                 restoreCount, (System.currentTimeMillis() - timestamp)));
+        return restoreCount;
+    }
+
+    private void performRestoreIfNeeded() {
+        if (mOptimizationModeBytes == null || mOptimizationModeBytes.length == 0) {
+            return;
+        }
+        final PowerUsageFeatureProvider provider = FeatureFactory.getFactory(mContext)
+                .getPowerUsageFeatureProvider(mContext);
+        if (!provider.isValidToRestoreOptimizationMode(mDeviceBuildInfoMap)) {
+            return;
+        }
+        // Start to restore the app optimization mode data.
+        final int restoreCount = restoreOptimizationMode(mOptimizationModeBytes);
+        if (restoreCount > 0) {
+            BatterySettingsMigrateChecker.verifyOptimizationModes(mContext);
+        }
+        mOptimizationModeBytes = null; // clear data
     }
 
     /** Dump the app optimization mode backup history data. */
@@ -225,6 +279,23 @@
                 getSharedPreferences(context), writer);
     }
 
+    static boolean isOwner() {
+        return UserHandle.myUserId() == UserHandle.USER_SYSTEM;
+    }
+
+    static BatteryOptimizeUtils newBatteryOptimizeUtils(
+            Context context, String packageName, BatteryOptimizeUtils testOptimizeUtils) {
+        final int uid = BatteryUtils.getInstance(context).getPackageUid(packageName);
+        if (uid == BatteryUtils.UID_NULL) {
+            return null;
+        }
+        final BatteryOptimizeUtils batteryOptimizeUtils =
+                testOptimizeUtils != null
+                        ? testOptimizeUtils /*testing only*/
+                        : new BatteryOptimizeUtils(context, uid, packageName);
+        return batteryOptimizeUtils;
+    }
+
     @VisibleForTesting
     static SharedPreferences getSharedPreferences(Context context) {
         return context.getSharedPreferences(
@@ -233,14 +304,11 @@
 
     private void restoreOptimizationMode(
             String packageName, @BatteryOptimizeUtils.OptimizationMode int mode) {
-        final int uid = BatteryUtils.getInstance(mContext).getPackageUid(packageName);
-        if (uid == BatteryUtils.UID_NULL) {
+        final BatteryOptimizeUtils batteryOptimizeUtils =
+                newBatteryOptimizeUtils(mContext, packageName, mBatteryOptimizeUtils);
+        if (batteryOptimizeUtils == null) {
             return;
         }
-        final BatteryOptimizeUtils batteryOptimizeUtils =
-                mBatteryOptimizeUtils != null
-                        ? mBatteryOptimizeUtils /*testing only*/
-                        : new BatteryOptimizeUtils(mContext, uid, packageName);
         batteryOptimizeUtils.setAppUsageState(
                 mode, BatteryOptimizeHistoricalLogEntry.Action.RESTORE);
         Log.d(TAG, String.format("restore:%s mode=%d", packageName, mode));
@@ -284,8 +352,33 @@
         return BatteryOptimizeUtils.getInstalledApplications(mContext, getIPackageManager());
     }
 
+    private void restoreBackupData(String dataKey, BackupDataInputStream data) {
+        final byte[] dataBytes = getBackupData(dataKey, data);
+        if (dataBytes == null || dataBytes.length == 0) {
+            return;
+        }
+        final String dataContent = new String(dataBytes, StandardCharsets.UTF_8);
+        mDeviceBuildInfoMap.put(dataKey, dataContent);
+        Log.d(TAG, String.format("restore:%s:%s", dataKey, dataContent));
+    }
+
+    private static byte[] getBackupData(String dataKey, BackupDataInputStream data) {
+        final int dataSize = data.size();
+        final byte[] dataBytes = new byte[dataSize];
+        try {
+            data.read(dataBytes, 0 /*offset*/, dataSize);
+        } catch (IOException e) {
+            Log.e(TAG, "failed to getBackupData() " + dataKey, e);
+            return null;
+        }
+        return dataBytes;
+    }
+
     private static void writeBackupData(
             BackupDataOutput data, String dataKey, String dataContent) {
+        if (dataContent == null || dataContent.isEmpty()) {
+            return;
+        }
         final byte[] dataContentBytes = dataContent.getBytes();
         try {
             data.writeEntityHeader(dataKey, dataContentBytes.length);
@@ -293,9 +386,6 @@
         } catch (IOException e) {
             Log.e(TAG, "writeBackupData() is failed for " + dataKey, e);
         }
-    }
-
-    private static boolean isOwner() {
-        return UserHandle.myUserId() == UserHandle.USER_SYSTEM;
+        Log.d(TAG, String.format("backup:%s:%s", dataKey, dataContent));
     }
 }
diff --git a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
index 81a15ca..79ecd40 100644
--- a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
@@ -34,24 +34,20 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * Use this broadcastReceiver to listen to the battery change, and it will invoke
- * {@link OnBatteryChangedListener} if any of the following has been changed:
- *
- * 1. Battery level(e.g. 100%->99%)
- * 2. Battery status(e.g. plugged->unplugged)
- * 3. Battery saver(e.g. off->on)
- * 4. Battery health(e.g. good->overheat)
+ * Use this broadcastReceiver to listen to the battery change and it will invoke
+ * {@link OnBatteryChangedListener}
  */
 public class BatteryBroadcastReceiver extends BroadcastReceiver {
 
     private static final String TAG = "BatteryBroadcastRcvr";
     /**
-     * Callback when the following has been changed:
+     * Callback if any of the monitored fields has been changed:
      *
      * Battery level(e.g. 100%->99%)
      * Battery status(e.g. plugged->unplugged)
      * Battery saver(e.g. off->on)
      * Battery health(e.g. good->overheat)
+     * Battery charging status(e.g. default->long life)
      */
     public interface OnBatteryChangedListener {
         void onBatteryChanged(@BatteryUpdateType int type);
@@ -63,6 +59,7 @@
             BatteryUpdateType.BATTERY_SAVER,
             BatteryUpdateType.BATTERY_STATUS,
             BatteryUpdateType.BATTERY_HEALTH,
+            BatteryUpdateType.CHARGING_STATUS,
             BatteryUpdateType.BATTERY_NOT_PRESENT})
     public @interface BatteryUpdateType {
         int MANUAL = 0;
@@ -70,7 +67,8 @@
         int BATTERY_SAVER = 2;
         int BATTERY_STATUS = 3;
         int BATTERY_HEALTH = 4;
-        int BATTERY_NOT_PRESENT = 5;
+        int CHARGING_STATUS = 5;
+        int BATTERY_NOT_PRESENT = 6;
     }
 
     @VisibleForTesting
@@ -78,6 +76,8 @@
     @VisibleForTesting
     String mBatteryStatus;
     @VisibleForTesting
+    int mChargingStatus;
+    @VisibleForTesting
     int mBatteryHealth;
     private OnBatteryChangedListener mBatteryListener;
     private Context mContext;
@@ -121,21 +121,27 @@
             final String batteryLevel = Utils.getBatteryPercentage(intent);
             final String batteryStatus =
                     Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false);
+            final int chargingStatus = intent.getIntExtra(
+                    BatteryManager.EXTRA_CHARGING_STATUS, BatteryManager.CHARGING_POLICY_DEFAULT);
             final int batteryHealth = intent.getIntExtra(
                     BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN);
             Log.d(
                     TAG,
-                    "Battery changed: level="
+                    "Battery changed: level: "
                             + batteryLevel
-                            + ", status="
+                            + "| status: "
                             + batteryStatus
-                            + ", health="
+                            + "| chargingStatus: "
+                            + chargingStatus
+                            + "| health: "
                             + batteryHealth);
             if (!Utils.isBatteryPresent(intent)) {
                 Log.w(TAG, "Problem reading the battery meter.");
                 mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_NOT_PRESENT);
             } else if (forceUpdate) {
                 mBatteryListener.onBatteryChanged(BatteryUpdateType.MANUAL);
+            } else if (chargingStatus != mChargingStatus) {
+                mBatteryListener.onBatteryChanged(BatteryUpdateType.CHARGING_STATUS);
             } else if (batteryHealth != mBatteryHealth) {
                 mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_HEALTH);
             } else if(!batteryLevel.equals(mBatteryLevel)) {
@@ -145,6 +151,7 @@
             }
             mBatteryLevel = batteryLevel;
             mBatteryStatus = batteryStatus;
+            mChargingStatus = chargingStatus;
             mBatteryHealth = batteryHealth;
         } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
             mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_SAVER);
diff --git a/src/com/android/settings/fuelgauge/BatteryInfo.java b/src/com/android/settings/fuelgauge/BatteryInfo.java
index 9824044..27d7154 100644
--- a/src/com/android/settings/fuelgauge/BatteryInfo.java
+++ b/src/com/android/settings/fuelgauge/BatteryInfo.java
@@ -51,7 +51,7 @@
     public int batteryStatus;
     public int pluggedStatus;
     public boolean discharging = true;
-    public boolean isOverheated;
+    public boolean isBatteryDefender;
     public long remainingTimeUs = 0;
     public long averageTimeToDischarge = EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN;
     public String batteryPercentString;
@@ -257,9 +257,9 @@
         info.pluggedStatus = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
         info.mCharging = info.pluggedStatus != 0;
         info.averageTimeToDischarge = estimate.getAverageDischargeTime();
-        info.isOverheated = batteryBroadcast.getIntExtra(
-                BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN)
-                == BatteryManager.BATTERY_HEALTH_OVERHEAT;
+        info.isBatteryDefender = batteryBroadcast.getIntExtra(
+                BatteryManager.EXTRA_CHARGING_STATUS, BatteryManager.CHARGING_POLICY_DEFAULT)
+                == BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE;
 
         info.statusLabel = Utils.getBatteryStatus(context, batteryBroadcast, isCompactStatus);
         info.batteryStatus = batteryBroadcast.getIntExtra(
@@ -283,7 +283,7 @@
         info.discharging = false;
         info.suggestionLabel = null;
         int dockDefenderMode = BatteryUtils.getCurrentDockDefenderMode(context, info);
-        if ((info.isOverheated && status != BatteryManager.BATTERY_STATUS_FULL
+        if ((info.isBatteryDefender && status != BatteryManager.BATTERY_STATUS_FULL
                 && dockDefenderMode == BatteryUtils.DockDefenderMode.DISABLED)
                 || dockDefenderMode == BatteryUtils.DockDefenderMode.ACTIVE) {
             // Battery defender active, battery charging paused
@@ -322,18 +322,11 @@
         final long drainTimeUs = PowerUtil.convertMsToUs(estimate.getEstimateMillis());
         if (drainTimeUs > 0) {
             info.remainingTimeUs = drainTimeUs;
-            info.remainingLabel = PowerUtil.getBatteryRemainingStringFormatted(
+            info.remainingLabel = PowerUtil.getBatteryRemainingShortStringFormatted(
                     context,
-                    PowerUtil.convertUsToMs(drainTimeUs),
-                    null /* percentageString */,
-                    false /* basedOnUsage */
+                    PowerUtil.convertUsToMs(drainTimeUs)
             );
-            info.chargeLabel = PowerUtil.getBatteryRemainingStringFormatted(
-                    context,
-                    PowerUtil.convertUsToMs(drainTimeUs),
-                    info.batteryPercentString,
-                    estimate.isBasedOnUsage() && !shortString
-            );
+            info.chargeLabel = info.remainingLabel;
             info.suggestionLabel = PowerUtil.getBatteryTipStringFormatted(
                     context, PowerUtil.convertUsToMs(drainTimeUs));
         } else {
diff --git a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java
index b9ac64d..589e1fd 100644
--- a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java
@@ -31,11 +31,14 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.settings.R;
 import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
 import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.List;
 
 /** A utility class for application usage operation. */
 public class BatteryOptimizeUtils {
@@ -125,11 +128,10 @@
                 mContext, mode, mUid, mPackageName, mBatteryUtils, mPowerAllowListBackend, action);
     }
 
-    /**
-     * Return {@code true} if package name is valid (can get an uid).
-     */
-    public boolean isValidPackageName() {
-        return mBatteryUtils.getPackageUid(mPackageName) != BatteryUtils.UID_NULL;
+    /** Return {@code true} if it is disabled for default optimized mode only. */
+    public boolean isDisabledForOptimizeModeOnly() {
+        return getAllowList(mContext).contains(mPackageName)
+                || mBatteryUtils.getPackageUid(mPackageName) == BatteryUtils.UID_NULL;
     }
 
     /**
@@ -214,6 +216,11 @@
                 || powerAllowlistBackend.isDefaultActiveApp(packageName, uid);
     }
 
+    static List<String> getAllowList(Context context) {
+        return Arrays.asList(context.getResources().getStringArray(
+                R.array.config_disable_optimization_mode_apps));
+    }
+
     private static void setAppUsageStateInternal(
             Context context, @OptimizationMode int mode, int uid, String packageName,
             BatteryUtils batteryUtils, PowerAllowlistBackend powerAllowlistBackend,
diff --git a/src/com/android/settings/fuelgauge/BatterySettingsMigrateChecker.java b/src/com/android/settings/fuelgauge/BatterySettingsMigrateChecker.java
index c54e6d8..4b9e6ef 100644
--- a/src/com/android/settings/fuelgauge/BatterySettingsMigrateChecker.java
+++ b/src/com/android/settings/fuelgauge/BatterySettingsMigrateChecker.java
@@ -23,16 +23,27 @@
 import android.provider.Settings;
 import android.util.Log;
 
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.R;
+import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry;
 import com.android.settings.fuelgauge.batterysaver.BatterySaverScheduleRadioButtonsController;
 import com.android.settingslib.fuelgauge.BatterySaverUtils;
 
+import java.util.List;
+
 /** Execute battery settings migration tasks in the device booting stage. */
 public final class BatterySettingsMigrateChecker extends BroadcastReceiver {
     private static final String TAG = "BatterySettingsMigrateChecker";
 
+    @VisibleForTesting
+    static BatteryOptimizeUtils sBatteryOptimizeUtils = null;
+
     @Override
     public void onReceive(Context context, Intent intent) {
-        if (intent != null && Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
+        if (intent != null
+                && Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())
+                && BatteryBackupHelper.isOwner()) {
             verifyConfiguration(context);
         }
     }
@@ -40,9 +51,35 @@
     static void verifyConfiguration(Context context) {
         context = context.getApplicationContext();
         verifySaverConfiguration(context);
+        verifyOptimizationModes(context);
     }
 
-    private static void verifySaverConfiguration(Context context) {
+    /** Avoid users set important apps into the unexpected battery optimize modes */
+    static void verifyOptimizationModes(Context context) {
+        Log.d(TAG, "invoke verifyOptimizationModes()");
+        verifyOptimizationModes(context, BatteryOptimizeUtils.getAllowList(context));
+    }
+
+    @VisibleForTesting
+    static void verifyOptimizationModes(Context context, List<String> allowList) {
+        allowList.forEach(packageName -> {
+            final BatteryOptimizeUtils batteryOptimizeUtils =
+                    BatteryBackupHelper.newBatteryOptimizeUtils(context, packageName,
+                            /* testOptimizeUtils */ sBatteryOptimizeUtils);
+            if (batteryOptimizeUtils == null) {
+                return;
+            }
+            if (batteryOptimizeUtils.getAppOptimizationMode() !=
+                    BatteryOptimizeUtils.MODE_OPTIMIZED) {
+                Log.w(TAG, "Reset optimization mode for: " + packageName);
+                batteryOptimizeUtils.setAppUsageState(BatteryOptimizeUtils.MODE_OPTIMIZED,
+                        BatteryOptimizeHistoricalLogEntry.Action.FORCE_RESET);
+            }
+        });
+    }
+
+    static void verifySaverConfiguration(Context context) {
+        Log.d(TAG, "invoke verifySaverConfiguration()");
         final ContentResolver resolver = context.getContentResolver();
         final int threshold = Settings.Global.getInt(resolver,
                 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index 72d84ef..12760b1 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -18,7 +18,6 @@
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.InstallSourceInfo;
 import android.content.pm.PackageInfo;
@@ -322,10 +321,10 @@
     }
 
     /**
-     * Return {@code true} if battery is overheated and charging.
+     * Return {@code true} if battery defender is on and charging.
      */
     public static boolean isBatteryDefenderOn(BatteryInfo batteryInfo) {
-        return batteryInfo.isOverheated && !batteryInfo.discharging;
+        return batteryInfo.isBatteryDefender && !batteryInfo.discharging;
     }
 
     /**
@@ -627,11 +626,11 @@
             if (Settings.Global.getInt(context.getContentResolver(),
                     SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0) == 1) {
                 return DockDefenderMode.TEMPORARILY_BYPASSED;
-            } else if (batteryInfo.isOverheated && FeatureFactory.getFactory(context)
+            } else if (batteryInfo.isBatteryDefender && FeatureFactory.getFactory(context)
                     .getPowerUsageFeatureProvider(context)
                     .isExtraDefend()) {
                 return DockDefenderMode.ACTIVE;
-            } else if (!batteryInfo.isOverheated) {
+            } else if (!batteryInfo.isBatteryDefender) {
                 return DockDefenderMode.FUTURE_BYPASS;
             }
         }
diff --git a/src/com/android/settings/fuelgauge/OptimizedPreferenceController.java b/src/com/android/settings/fuelgauge/OptimizedPreferenceController.java
index 88241b6..ca75b0e 100644
--- a/src/com/android/settings/fuelgauge/OptimizedPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/OptimizedPreferenceController.java
@@ -46,8 +46,8 @@
 
     @Override
     public void updateState(Preference preference) {
-        if (!mBatteryOptimizeUtils.isValidPackageName()) {
-            Log.d(TAG, "invalid package name, optimized states only");
+        if (mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()) {
+            Log.d(TAG, "disable preference for " + mBatteryOptimizeUtils.getPackageName());
             preference.setEnabled(true);
             ((SelectorWithWidgetPreference) preference).setChecked(true);
             return;
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index 9f30473..0b0e243 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.util.ArrayMap;
 import android.util.SparseIntArray;
 
 import com.android.settingslib.fuelgauge.Estimate;
@@ -166,4 +167,19 @@
      * Returns {@link Set} for ignoring task root class names for screen on time
      */
     Set<String> getIgnoreScreenOnTimeTaskRootSet();
+
+    /**
+     * Returns the customized device build information for data backup
+     */
+    String getBuildMetadata1(Context context);
+
+    /**
+     * Returns the customized device build information for data backup
+     */
+    String getBuildMetadata2(Context context);
+
+    /**
+     * Whether the app optimization mode is valid to restore
+     */
+    boolean isValidToRestoreOptimizationMode(ArrayMap<String, String> deviceInfoMap);
 }
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index d65c212..1d0ba18 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.os.Process;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.SparseIntArray;
 
@@ -188,4 +189,19 @@
     public Set<String> getIgnoreScreenOnTimeTaskRootSet() {
         return new ArraySet<>();
     }
+
+    @Override
+    public String getBuildMetadata1(Context context) {
+        return null;
+    }
+
+    @Override
+    public String getBuildMetadata2(Context context) {
+        return null;
+    }
+
+    @Override
+    public boolean isValidToRestoreOptimizationMode(ArrayMap<String, String> deviceInfoMap) {
+        return false;
+    }
 }
diff --git a/src/com/android/settings/fuelgauge/RestrictedPreferenceController.java b/src/com/android/settings/fuelgauge/RestrictedPreferenceController.java
index fe896a6..7db77f1 100644
--- a/src/com/android/settings/fuelgauge/RestrictedPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/RestrictedPreferenceController.java
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-
 package com.android.settings.fuelgauge;
 
 import android.content.Context;
@@ -43,8 +42,8 @@
     @Override
     public void updateState(Preference preference) {
 
-        if (!mBatteryOptimizeUtils.isValidPackageName()) {
-            Log.d(TAG, "invalid package name, disable pref");
+        if (mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()) {
+            Log.d(TAG, "disable preference for " + mBatteryOptimizeUtils.getPackageName());
             preference.setEnabled(false);
             return;
         } else {
diff --git a/src/com/android/settings/fuelgauge/UnrestrictedPreferenceController.java b/src/com/android/settings/fuelgauge/UnrestrictedPreferenceController.java
index be4091c..4578723 100644
--- a/src/com/android/settings/fuelgauge/UnrestrictedPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/UnrestrictedPreferenceController.java
@@ -42,8 +42,8 @@
     @Override
     public void updateState(Preference preference) {
 
-        if (!mBatteryOptimizeUtils.isValidPackageName()) {
-            Log.d(TAG, "invalid package name, disable pref");
+        if (mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()) {
+            Log.d(TAG, "disable preference for " + mBatteryOptimizeUtils.getPackageName());
             preference.setEnabled(false);
             return;
         } else {
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
index 2dc057e..8b7d4c1 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
@@ -37,13 +37,12 @@
 
     @Override
     public BatteryTip detect() {
-      final boolean isBasicBatteryDefend = mBatteryInfo.isOverheated
-              && !FeatureFactory.getFactory(mContext)
-                          .getPowerUsageFeatureProvider(mContext)
-                          .isExtraDefend();
-      final int state = isBasicBatteryDefend
-              ? BatteryTip.StateType.NEW : BatteryTip.StateType.INVISIBLE;
-      final boolean isPluggedIn = mBatteryInfo.pluggedStatus != 0;
-      return new BatteryDefenderTip(state, isPluggedIn);
+        final boolean isBasicBatteryDefend = mBatteryInfo.isBatteryDefender
+                && !FeatureFactory.getFactory(mContext).getPowerUsageFeatureProvider(mContext)
+                .isExtraDefend();
+        final int state = isBasicBatteryDefend
+                ? BatteryTip.StateType.NEW : BatteryTip.StateType.INVISIBLE;
+        final boolean isPluggedIn = mBatteryInfo.pluggedStatus != 0;
+        return new BatteryDefenderTip(state, isPluggedIn);
     }
 }
diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java
index 03bc1b3..829a89c 100644
--- a/src/com/android/settings/homepage/SettingsHomepageActivity.java
+++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java
@@ -57,7 +57,6 @@
 import androidx.fragment.app.FragmentActivity;
 import androidx.fragment.app.FragmentManager;
 import androidx.fragment.app.FragmentTransaction;
-import androidx.window.embedding.ActivityEmbeddingController;
 import androidx.window.embedding.SplitRule;
 
 import com.android.settings.R;
@@ -108,7 +107,6 @@
     private View mTwoPaneSuggestionView;
     private CategoryMixin mCategoryMixin;
     private Set<HomepageLoadedListener> mLoadedListeners;
-    private ActivityEmbeddingController mActivityEmbeddingController;
     private boolean mIsEmbeddingActivityEnabled;
     private boolean mIsTwoPane;
     // A regular layout shows icons on homepage, whereas a simplified layout doesn't.
@@ -200,8 +198,7 @@
         setupEdgeToEdge();
         setContentView(R.layout.settings_homepage_container);
 
-        mActivityEmbeddingController = ActivityEmbeddingController.getInstance(this);
-        mIsTwoPane = mActivityEmbeddingController.isActivityEmbedded(this);
+        mIsTwoPane = ActivityEmbeddingUtils.isAlreadyEmbedded(this);
 
         updateAppBarMinHeight();
         initHomepageContainer();
@@ -242,7 +239,7 @@
 
         // Settings app may be launched on an existing task. Reset SplitPairRule of SubSettings here
         // to prevent SplitPairRule of an existing task applied on a new started Settings app.
-        if (ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this)
+        if (mIsEmbeddingActivityEnabled
                 && (getIntent().getFlags() & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
             initSplitPairRules();
         }
@@ -284,7 +281,7 @@
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        final boolean newTwoPaneState = mActivityEmbeddingController.isActivityEmbedded(this);
+        final boolean newTwoPaneState = ActivityEmbeddingUtils.isAlreadyEmbedded(this);
         if (mIsTwoPane != newTwoPaneState) {
             mIsTwoPane = newTwoPaneState;
             updateHomepageAppBar();
@@ -427,8 +424,9 @@
     }
 
     private boolean shouldLaunchDeepLinkIntentToRight() {
-        if (!FeatureFlagUtils.isEnabled(this, FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN)
-                || !ActivityEmbeddingUtils.isSettingsSplitEnabled(this)) {
+        if (!ActivityEmbeddingUtils.isSettingsSplitEnabled(this)
+                || !FeatureFlagUtils.isEnabled(this,
+                        FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN)) {
             return false;
         }
 
diff --git a/src/com/android/settings/localepicker/LocaleDialogFragment.java b/src/com/android/settings/localepicker/LocaleDialogFragment.java
index 2dc09bd..ad9e10f 100644
--- a/src/com/android/settings/localepicker/LocaleDialogFragment.java
+++ b/src/com/android/settings/localepicker/LocaleDialogFragment.java
@@ -21,8 +21,8 @@
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.Intent;
 import android.os.Bundle;
-import android.os.ResultReceiver;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -35,7 +35,6 @@
 
 import com.android.internal.app.LocaleStore;
 import com.android.settings.R;
-import com.android.settings.RestrictedSettingsFragment;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -46,49 +45,19 @@
 public class LocaleDialogFragment extends InstrumentedDialogFragment {
     private static final String TAG = LocaleDialogFragment.class.getSimpleName();
 
-    static final int DIALOG_CONFIRM_SYSTEM_DEFAULT = 0;
-    static final int DIALOG_NOT_AVAILABLE_LOCALE = 1;
+    static final int DIALOG_CONFIRM_SYSTEM_DEFAULT = 1;
+    static final int DIALOG_NOT_AVAILABLE_LOCALE = 2;
 
     static final String ARG_DIALOG_TYPE = "arg_dialog_type";
     static final String ARG_TARGET_LOCALE = "arg_target_locale";
-    static final String ARG_RESULT_RECEIVER = "arg_result_receiver";
+    static final String ARG_SHOW_DIALOG = "arg_show_dialog";
+
+    private boolean mShouldKeepDialog;
 
     public static LocaleDialogFragment newInstance() {
         return new LocaleDialogFragment();
     }
 
-    /**
-     * Show dialog
-     */
-    public void show(
-            @NonNull RestrictedSettingsFragment fragment,
-            int dialogType,
-            LocaleStore.LocaleInfo localeInfo) {
-        if (!isAdded()) {
-            return;
-        }
-        show(fragment, dialogType, localeInfo, null);
-    }
-
-    /**
-     * Show dialog
-     */
-    public void show(
-            @NonNull RestrictedSettingsFragment fragment,
-            int dialogType,
-            LocaleStore.LocaleInfo localeInfo,
-            ResultReceiver resultReceiver) {
-        FragmentManager manager = fragment.getChildFragmentManager();
-        Bundle args = new Bundle();
-        args.putInt(ARG_DIALOG_TYPE, dialogType);
-        args.putSerializable(ARG_TARGET_LOCALE, localeInfo);
-        args.putParcelable(ARG_RESULT_RECEIVER, resultReceiver);
-
-        LocaleDialogFragment localeDialogFragment = new LocaleDialogFragment();
-        localeDialogFragment.setArguments(args);
-        localeDialogFragment.show(manager, TAG);
-    }
-
     @Override
     public int getMetricsCategory() {
         int dialogType = getArguments().getInt(ARG_DIALOG_TYPE);
@@ -103,8 +72,28 @@
     }
 
     @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putBoolean(ARG_SHOW_DIALOG, mShouldKeepDialog);
+    }
+
+    @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
-        LocaleDialogController controller = new LocaleDialogController(this);
+        if (savedInstanceState != null) {
+            Bundle arguments = getArguments();
+            int type = arguments.getInt(ARG_DIALOG_TYPE);
+            mShouldKeepDialog = savedInstanceState.getBoolean(ARG_SHOW_DIALOG, false);
+            // Keep the dialog if user rotates the device, otherwise close the confirm system
+            // default dialog only when user changes the locale.
+            if (type == DIALOG_CONFIRM_SYSTEM_DEFAULT && !mShouldKeepDialog) {
+                dismiss();
+            }
+        }
+
+        mShouldKeepDialog = true;
+        LocaleListEditor parentFragment = (LocaleListEditor) getParentFragment();
+        LocaleDialogController controller = getLocaleDialogController(getContext(), this,
+                parentFragment);
         LocaleDialogController.DialogContent dialogContent = controller.getDialogContent();
         ViewGroup viewGroup = (ViewGroup) LayoutInflater.from(getContext()).inflate(
                 R.layout.locale_dialog, null);
@@ -140,47 +129,57 @@
         textView.setText(content);
     }
 
-    static class LocaleDialogController implements DialogInterface.OnClickListener {
+    @VisibleForTesting
+    LocaleDialogController getLocaleDialogController(Context context,
+            LocaleDialogFragment dialogFragment, LocaleListEditor parentFragment) {
+        return new LocaleDialogController(context, dialogFragment, parentFragment);
+    }
+
+    class LocaleDialogController implements DialogInterface.OnClickListener {
         private final Context mContext;
         private final int mDialogType;
         private final LocaleStore.LocaleInfo mLocaleInfo;
-        private final ResultReceiver mResultReceiver;
         private final MetricsFeatureProvider mMetricsFeatureProvider;
 
+        private LocaleListEditor mParent;
+
         LocaleDialogController(
-                @NonNull Context context, @NonNull LocaleDialogFragment dialogFragment) {
+                @NonNull Context context, @NonNull LocaleDialogFragment dialogFragment,
+                LocaleListEditor parentFragment) {
             mContext = context;
             Bundle arguments = dialogFragment.getArguments();
             mDialogType = arguments.getInt(ARG_DIALOG_TYPE);
-            mLocaleInfo = (LocaleStore.LocaleInfo) arguments.getSerializable(
-                    ARG_TARGET_LOCALE);
-            mResultReceiver = (ResultReceiver) arguments.getParcelable(ARG_RESULT_RECEIVER);
+            mLocaleInfo = (LocaleStore.LocaleInfo) arguments.getSerializable(ARG_TARGET_LOCALE);
             mMetricsFeatureProvider = FeatureFactory.getFactory(
                     mContext).getMetricsFeatureProvider();
+            mParent = parentFragment;
         }
 
-        LocaleDialogController(@NonNull LocaleDialogFragment dialogFragment) {
-            this(dialogFragment.getContext(), dialogFragment);
+        LocaleDialogController(@NonNull LocaleDialogFragment dialogFragment,
+                LocaleListEditor parent) {
+            this(dialogFragment.getContext(), dialogFragment, parent);
         }
 
         @Override
         public void onClick(DialogInterface dialog, int which) {
-            if (mResultReceiver != null && mDialogType == DIALOG_CONFIRM_SYSTEM_DEFAULT) {
+            if (mDialogType == DIALOG_CONFIRM_SYSTEM_DEFAULT) {
+                int result = Activity.RESULT_CANCELED;
+                if (which == DialogInterface.BUTTON_POSITIVE) {
+                    result = Activity.RESULT_OK;
+                }
+                Intent intent = new Intent();
                 Bundle bundle = new Bundle();
                 bundle.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT);
-                if (which == DialogInterface.BUTTON_POSITIVE) {
-                    mResultReceiver.send(Activity.RESULT_OK, bundle);
-                } else if (which == DialogInterface.BUTTON_NEGATIVE) {
-                    mResultReceiver.send(Activity.RESULT_CANCELED, bundle);
-                }
+                intent.putExtras(bundle);
+                mParent.onActivityResult(DIALOG_CONFIRM_SYSTEM_DEFAULT, result, intent);
                 mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_CHANGE_LANGUAGE);
             }
+            mShouldKeepDialog = false;
         }
 
         @VisibleForTesting
         DialogContent getDialogContent() {
-            DialogContent
-                    dialogContent = new DialogContent();
+            DialogContent dialogContent = new DialogContent();
             switch (mDialogType) {
                 case DIALOG_CONFIRM_SYSTEM_DEFAULT:
                     dialogContent.mTitle = String.format(mContext.getString(
diff --git a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
index 2223db0..edd3026 100644
--- a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
+++ b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
@@ -16,14 +16,11 @@
 
 package com.android.settings.localepicker;
 
-import android.app.Activity;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.LocaleList;
-import android.os.Looper;
-import android.os.ResultReceiver;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.LayoutInflater;
@@ -52,15 +49,20 @@
 
     private static final String TAG = "LocaleDragAndDropAdapter";
     private static final String CFGKEY_SELECTED_LOCALES = "selectedLocales";
+    private static final String CFGKEY_DRAG_LOCALE = "dragLocales";
+    private static final String CFGKEY_DRAG_LOCALES_TO_POSITION = "dragLocales_end";
+
     private final Context mContext;
+    private final ItemTouchHelper mItemTouchHelper;
+
     private List<LocaleStore.LocaleInfo> mFeedItemList;
     private List<LocaleStore.LocaleInfo> mCacheItemList;
-    private final ItemTouchHelper mItemTouchHelper;
     private RecyclerView mParentView = null;
     private LocaleListEditor mParent;
     private boolean mRemoveMode = false;
     private boolean mDragEnabled = true;
     private NumberFormat mNumberFormatter = NumberFormat.getNumberInstance();
+    private LocaleStore.LocaleInfo mDragLocale;
 
     class CustomViewHolder extends RecyclerView.ViewHolder implements View.OnTouchListener {
         private final LocaleDragCell mLocaleDragCell;
@@ -87,8 +89,7 @@
         }
     }
 
-    LocaleDragAndDropAdapter(LocaleListEditor parent,
-            List<LocaleStore.LocaleInfo> feedItemList) {
+    LocaleDragAndDropAdapter(LocaleListEditor parent, List<LocaleStore.LocaleInfo> feedItemList) {
         mFeedItemList = feedItemList;
         mParent = parent;
         mCacheItemList = new ArrayList<>(feedItemList);
@@ -202,6 +203,7 @@
             final LocaleStore.LocaleInfo saved = mFeedItemList.get(fromPosition);
             mFeedItemList.remove(fromPosition);
             mFeedItemList.add(toPosition, saved);
+            mDragLocale = saved;
         } else {
             // TODO: It looks like sometimes the RecycleView tries to swap item -1
             // I did not see it in a while, but if it happens, investigate and file a bug.
@@ -317,43 +319,20 @@
         });
     }
 
-    public void doTheUpdateWithMovingLocaleItem() {
-        LocaleStore.LocaleInfo localeInfo = mFeedItemList.get(0);
-        final LocaleDialogFragment fragment = LocaleDialogFragment.newInstance();
-        if (!localeInfo.getLocale().equals(LocalePicker.getLocales().get(0))) {
-            fragment.show(mParent,
-                    LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT,
-                    localeInfo,
-                    new ResultReceiver(new Handler(Looper.getMainLooper())) {
-                        @Override
-                        protected void onReceiveResult(int resultCode, Bundle resultData) {
-                            super.onReceiveResult(resultCode, resultData);
-                            int type = resultData.getInt(LocaleDialogFragment.ARG_DIALOG_TYPE);
-                            if (type == LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT) {
-                                if (resultCode == Activity.RESULT_OK) {
-                                    doTheUpdate();
-                                    if (!localeInfo.isTranslated()) {
-                                        fragment.show(mParent,
-                                                        LocaleDialogFragment
-                                                                .DIALOG_NOT_AVAILABLE_LOCALE,
-                                                        localeInfo);
-                                    }
-                                } else {
-                                    if (!localeInfo.getLocale()
-                                            .equals(mCacheItemList.get(0).getLocale())) {
-                                        mFeedItemList = new ArrayList<>(mCacheItemList);
-                                        notifyDataSetChanged();
-                                    }
-                                }
-                                mCacheItemList = new ArrayList<>(mFeedItemList);
-                            }
-                        }
-                    });
-        } else {
-            doTheUpdate();
+    public void notifyListChanged(LocaleStore.LocaleInfo localeInfo) {
+        if (!localeInfo.getLocale().equals(mCacheItemList.get(0).getLocale())) {
+            mFeedItemList = new ArrayList<>(mCacheItemList);
+            notifyDataSetChanged();
         }
     }
 
+    public void setCacheItemList() {
+        mCacheItemList = new ArrayList<>(mFeedItemList);
+    }
+
+    public List<LocaleStore.LocaleInfo> getFeedItemList() {
+        return mFeedItemList;
+    }
     private void setDragEnabled(boolean enabled) {
         mDragEnabled = enabled;
     }
@@ -373,6 +352,8 @@
                 }
             }
             outInstanceState.putStringArrayList(CFGKEY_SELECTED_LOCALES, selectedLocales);
+            // Save the dragged locale before rotation
+            outInstanceState.putSerializable(CFGKEY_DRAG_LOCALE, mDragLocale);
         }
     }
 
@@ -381,18 +362,30 @@
      * (for instance when the device is rotated)
      *
      * @param savedInstanceState Bundle with the data saved by {@link #saveState(Bundle)}
+     * @param isDialogShowing A flag indicating whether the dialog is showing or not.
      */
-    public void restoreState(Bundle savedInstanceState) {
-        if (savedInstanceState != null && mRemoveMode) {
-            final ArrayList<String> selectedLocales =
-                    savedInstanceState.getStringArrayList(CFGKEY_SELECTED_LOCALES);
-            if (selectedLocales == null || selectedLocales.isEmpty()) {
-                return;
+    public void restoreState(Bundle savedInstanceState, boolean isDialogShowing) {
+        if (savedInstanceState != null) {
+            if (mRemoveMode) {
+                final ArrayList<String> selectedLocales =
+                        savedInstanceState.getStringArrayList(CFGKEY_SELECTED_LOCALES);
+                if (selectedLocales == null || selectedLocales.isEmpty()) {
+                    return;
+                }
+                for (LocaleStore.LocaleInfo li : mFeedItemList) {
+                    li.setChecked(selectedLocales.contains(li.getId()));
+                }
+                notifyItemRangeChanged(0, mFeedItemList.size());
+            } else if (isDialogShowing) {
+                // After rotation, the dragged position will be restored to original. Restore the
+                // drag locale's original position to the top.
+                mDragLocale = (LocaleStore.LocaleInfo) savedInstanceState.getSerializable(
+                        CFGKEY_DRAG_LOCALE);
+                mFeedItemList.removeIf(
+                        localeInfo -> TextUtils.equals(localeInfo.getId(), mDragLocale.getId()));
+                mFeedItemList.add(0, mDragLocale);
+                notifyItemRangeChanged(0, mFeedItemList.size());
             }
-            for (LocaleStore.LocaleInfo li : mFeedItemList) {
-                li.setChecked(selectedLocales.contains(li.getId()));
-            }
-            notifyItemRangeChanged(0, mFeedItemList.size());
         }
     }
 }
diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java
index 6317f24..7ec08f7 100644
--- a/src/com/android/settings/localepicker/LocaleListEditor.java
+++ b/src/com/android/settings/localepicker/LocaleListEditor.java
@@ -18,6 +18,8 @@
 
 import static android.os.UserManager.DISALLOW_CONFIG_LOCALE;
 
+import static com.android.settings.localepicker.LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT;
+
 import android.app.Activity;
 import android.app.settings.SettingsEnums;
 import android.content.Context;
@@ -32,12 +34,14 @@
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.FragmentManager;
 import androidx.preference.PreferenceScreen;
 import androidx.recyclerview.widget.RecyclerView;
 
@@ -60,7 +64,7 @@
  * Drag-and-drop editor for the user-ordered locale lists.
  */
 @SearchIndexable
-public class LocaleListEditor extends RestrictedSettingsFragment {
+public class LocaleListEditor extends RestrictedSettingsFragment implements View.OnTouchListener {
 
     protected static final String INTENT_LOCALE_KEY = "localeInfo";
     private static final String CFGKEY_REMOVE_MODE = "localeRemoveMode";
@@ -70,6 +74,8 @@
 
     private static final String INDEX_KEY_ADD_LANGUAGE = "add_language";
     private static final String KEY_LANGUAGES_PICKER = "languages_picker";
+    private static final String TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT = "dialog_confirm_system_default";
+    private static final String TAG_DIALOG_NOT_AVAILABLE = "dialog_not_available_locale";
 
     private LocaleDragAndDropAdapter mAdapter;
     private Menu mMenu;
@@ -80,6 +86,7 @@
 
     private LayoutPreference mLocalePickerPreference;
     private LocaleHelperPreferenceController mLocaleHelperPreferenceController;
+    private FragmentManager mFragmentManager;
 
     public LocaleListEditor() {
         super(DISALLOW_CONFIG_LOCALE);
@@ -106,6 +113,7 @@
         LocaleStore.fillCache(this.getContext());
         final List<LocaleStore.LocaleInfo> feedsList = getUserLocaleList();
         mAdapter = new LocaleDragAndDropAdapter(this, feedsList);
+        mFragmentManager = getChildFragmentManager();
     }
 
     @Override
@@ -141,7 +149,15 @@
             mShowingRemoveDialog = savedInstanceState.getBoolean(CFGKEY_REMOVE_DIALOG, false);
         }
         setRemoveMode(mRemoveMode);
-        mAdapter.restoreState(savedInstanceState);
+
+        final LocaleDialogFragment dialogFragment =
+                (LocaleDialogFragment) mFragmentManager.findFragmentByTag(
+                        TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT);
+        boolean isDialogShowing = false;
+        if (dialogFragment != null && dialogFragment.isAdded()) {
+            isDialogShowing = true;
+        }
+        mAdapter.restoreState(savedInstanceState, isDialogShowing);
 
         if (mShowingRemoveDialog) {
             showRemoveLocaleWarningDialog();
@@ -178,17 +194,32 @@
 
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        LocaleStore.LocaleInfo localeInfo;
         if (requestCode == REQUEST_LOCALE_PICKER && resultCode == Activity.RESULT_OK
                 && data != null) {
-            final LocaleStore.LocaleInfo localeInfo =
-                    (LocaleStore.LocaleInfo) data.getSerializableExtra(
-                            INTENT_LOCALE_KEY);
-
+            localeInfo = (LocaleStore.LocaleInfo) data.getSerializableExtra(INTENT_LOCALE_KEY);
             String preferencesTags = Settings.System.getString(
                     getContext().getContentResolver(), Settings.System.LOCALE_PREFERENCES);
 
             mAdapter.addLocale(mayAppendUnicodeTags(localeInfo, preferencesTags));
             updateVisibilityOfRemoveMenu();
+        } else if (requestCode == DIALOG_CONFIRM_SYSTEM_DEFAULT) {
+            localeInfo = mAdapter.getFeedItemList().get(0);
+            if (resultCode == Activity.RESULT_OK) {
+                mAdapter.doTheUpdate();
+                if (!localeInfo.isTranslated()) {
+                    Bundle args = new Bundle();
+                    args.putInt(LocaleDialogFragment.ARG_DIALOG_TYPE,
+                            LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE);
+                    args.putSerializable(LocaleDialogFragment.ARG_TARGET_LOCALE, localeInfo);
+                    LocaleDialogFragment localeDialogFragment = LocaleDialogFragment.newInstance();
+                    localeDialogFragment.setArguments(args);
+                    localeDialogFragment.show(mFragmentManager, TAG_DIALOG_NOT_AVAILABLE);
+                }
+            } else {
+                mAdapter.notifyListChanged(localeInfo);
+            }
+            mAdapter.setCacheItemList();
         }
         super.onActivityResult(requestCode, resultCode, data);
     }
@@ -332,6 +363,7 @@
         list.setNestedScrollingEnabled(false);
         mAdapter.setRecyclerView(list);
         list.setAdapter(mAdapter);
+        list.setOnTouchListener(this);
 
         mAddLanguage = layout.findViewById(R.id.add_language);
         mAddLanguage.setOnClickListener(new View.OnClickListener() {
@@ -348,6 +380,26 @@
         });
     }
 
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        if (event.getAction() == MotionEvent.ACTION_UP
+                || event.getAction() == MotionEvent.ACTION_CANCEL) {
+            LocaleStore.LocaleInfo localeInfo = mAdapter.getFeedItemList().get(0);
+            if (!localeInfo.getLocale().equals(LocalePicker.getLocales().get(0))) {
+                final LocaleDialogFragment localeDialogFragment =
+                        LocaleDialogFragment.newInstance();
+                Bundle args = new Bundle();
+                args.putInt(LocaleDialogFragment.ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT);
+                args.putSerializable(LocaleDialogFragment.ARG_TARGET_LOCALE, localeInfo);
+                localeDialogFragment.setArguments(args);
+                localeDialogFragment.show(mFragmentManager, TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT);
+            } else {
+                mAdapter.doTheUpdate();
+            }
+        }
+        return false;
+    }
+
     // Hide the "Remove" menu if there is only one locale in the list, show it otherwise
     // This is called when the menu is first created, and then one add / remove locale
     private void updateVisibilityOfRemoveMenu() {
diff --git a/src/com/android/settings/localepicker/LocaleRecyclerView.java b/src/com/android/settings/localepicker/LocaleRecyclerView.java
index 5d469bf..4a5f28b 100644
--- a/src/com/android/settings/localepicker/LocaleRecyclerView.java
+++ b/src/com/android/settings/localepicker/LocaleRecyclerView.java
@@ -34,15 +34,4 @@
     public LocaleRecyclerView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
     }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent e) {
-        if (e.getAction() == MotionEvent.ACTION_UP || e.getAction() == MotionEvent.ACTION_CANCEL) {
-            LocaleDragAndDropAdapter adapter = (LocaleDragAndDropAdapter) this.getAdapter();
-            if (adapter != null) {
-                adapter.doTheUpdateWithMovingLocaleItem();
-            }
-        }
-        return super.onTouchEvent(e);
-    }
 }
diff --git a/src/com/android/settings/network/tether/TetherSettings.java b/src/com/android/settings/network/tether/TetherSettings.java
index ba19d1c..9fa8730 100644
--- a/src/com/android/settings/network/tether/TetherSettings.java
+++ b/src/com/android/settings/network/tether/TetherSettings.java
@@ -171,6 +171,8 @@
             return;
         }
 
+        setupTetherPreference();
+
         final Activity activity = getActivity();
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
         if (adapter != null) {
@@ -184,7 +186,6 @@
                     new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
         }
 
-        setupTetherPreference();
         setTopIntroPreferenceTitle();
 
         mDataSaverBackend.addListener(this);
@@ -605,6 +606,7 @@
                 public void onServiceConnected(int profile, BluetoothProfile proxy) {
                     if (mBluetoothPan.get() == null) {
                         mBluetoothPan.set((BluetoothPan) proxy);
+                        updateBluetoothState();
                     }
                 }
 
diff --git a/src/com/android/settings/password/BiometricFragment.java b/src/com/android/settings/password/BiometricFragment.java
index d364c71..4ad04a1 100644
--- a/src/com/android/settings/password/BiometricFragment.java
+++ b/src/com/android/settings/password/BiometricFragment.java
@@ -141,6 +141,7 @@
                 .setDisallowBiometricsIfPolicyExists(
                         promptInfo.isDisallowBiometricsIfPolicyExists())
                 .setReceiveSystemEvents(true)
+                .setAllowBackgroundAuthentication(true)
                 .build();
     }
 
diff --git a/src/com/android/settings/regionalpreferences/FirstDayOfWeekController.java b/src/com/android/settings/regionalpreferences/FirstDayOfWeekController.java
index 1ebd166..574e62f 100644
--- a/src/com/android/settings/regionalpreferences/FirstDayOfWeekController.java
+++ b/src/com/android/settings/regionalpreferences/FirstDayOfWeekController.java
@@ -19,6 +19,8 @@
 import android.content.Context;
 import android.provider.Settings;
 
+import androidx.core.text.util.LocalePreferences;
+
 import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
 
diff --git a/src/com/android/settings/regionalpreferences/LocalePreferences.java b/src/com/android/settings/regionalpreferences/LocalePreferences.java
deleted file mode 100644
index 2006221..0000000
--- a/src/com/android/settings/regionalpreferences/LocalePreferences.java
+++ /dev/null
@@ -1,605 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.regionalpreferences;
-import android.icu.number.LocalizedNumberFormatter;
-import android.icu.number.NumberFormatter;
-import android.icu.text.DateFormat;
-import android.icu.text.DateTimePatternGenerator;
-import android.icu.util.MeasureUnit;
-import android.os.Build.VERSION;
-
-import androidx.annotation.DoNotInline;
-import androidx.annotation.NonNull;
-import androidx.annotation.OptIn;
-import androidx.annotation.RestrictTo;
-import androidx.annotation.StringDef;
-import androidx.core.os.BuildCompat;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Locale;
-import java.util.Locale.Category;
-
-/**
- * TODO(b/263861083) This is a temp file and will replace it to Androidx version.
- * Provides friendly APIs to get the user's locale preferences. The data can refer to
- * external/cldr/common/main/en.xml.
- */
-public final class LocalePreferences {
-    private static final String TAG = LocalePreferences.class.getSimpleName();
-
-    /** APIs to get the user's preference of the hour cycle. */
-    public static class HourCycle {
-        private static final String U_EXTENSION_OF_HOUR_CYCLE = "hc";
-
-        /** 12 Hour System (0-11) */
-        public static final String H11 = "h11";
-        /** 12 Hour System (1-12) */
-        public static final String H12 = "h12";
-        /** 24 Hour System (0-23) */
-        public static final String H23 = "h23";
-        /** 24 Hour System (1-24) */
-        public static final String H24 = "h24";
-        /** Default hour cycle for the locale */
-        public static final String DEFAULT = "";
-
-        /** @hide */
-        @RestrictTo(RestrictTo.Scope.LIBRARY)
-        @StringDef({
-                H11,
-                H12,
-                H23,
-                H24,
-                DEFAULT
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface HourCycleTypes {
-        }
-
-        private HourCycle() {
-        }
-    }
-
-    /**
-     * Return the user's preference of the hour cycle which is from
-     * {@link Locale#getDefault(Locale.Category)}. The returned result is resolved and
-     * bases on the {@code Locale#getDefault(Locale.Category)}. E.g. "h23"
-     */
-    @NonNull
-    @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
-    @HourCycle.HourCycleTypes
-    public static String getHourCycle() {
-        return getHourCycle(true);
-    }
-
-    /**
-     * Return the hour cycle setting of the inputted {@link Locale}. The returned result is resolved
-     * and bases on the inputted {@code Locale}.
-     * E.g. "h23"
-     */
-    @NonNull
-    @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
-    @HourCycle.HourCycleTypes
-    public static String getHourCycle(@NonNull Locale locale) {
-        return getHourCycle(locale, true);
-    }
-
-    /**
-     * Return the user's preference of the hour cycle which is from
-     * {@link Locale#getDefault(Locale.Category)}. E.g. "h23"
-     *
-     * @param resolved If the {@code Locale#getDefault(Locale.Category)} contains hour cycle subtag,
-     *                 this argument is ignored. If the
-     *                 {@code Locale#getDefault(Locale.Category)} doesn't contain hour cycle subtag
-     *                 and the resolved argument is true, this function tries to find the default
-     *                 hour cycle for the {@code Locale#getDefault(Locale.Category)}. If the
-     *                 {@code Locale#getDefault(Locale.Category)} doesn't contain hour cycle subtag
-     *                 and the resolved argument is false, this function returns empty string
-     *                 i.e. HourCycle.Default.
-     * @return {@link HourCycle.HourCycleTypes} If the malformed hour cycle format was specified
-     * in the hour cycle subtag, e.g. en-US-u-hc-h32, this function returns empty string
-     * i.e. HourCycle.Default.
-     */
-    @NonNull
-    @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
-    @HourCycle.HourCycleTypes
-    public static String getHourCycle(
-            boolean resolved) {
-        return getHourCycle(Api33Impl.getDefaultLocale(), resolved);
-    }
-
-    /**
-     * Return the hour cycle setting of the inputted {@link Locale}. E.g. "en-US-u-hc-h23".
-     *
-     * @param locale   The {@code Locale} to get the hour cycle.
-     * @param resolved If the given {@code Locale} contains hour cycle subtag, this argument is
-     *                 ignored. If the given {@code Locale} doesn't contain hour cycle subtag and
-     *                 the resolved argument is true, this function tries to find the default
-     *                 hour cycle for the given {@code Locale}. If the given {@code Locale} doesn't
-     *                 contain hour cycle subtag and the resolved argument is false, this function
-     *                 return empty string i.e. HourCycle.Default.
-     * @return {@link HourCycle.HourCycleTypes} If the malformed hour cycle format was specified
-     * in the hour cycle subtag, e.g. en-US-u-hc-h32, this function returns empty string
-     * i.e. HourCycle.Default.
-     */
-    @NonNull
-    @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
-    @HourCycle.HourCycleTypes
-    public static String getHourCycle(@NonNull Locale locale, boolean resolved) {
-        if (!BuildCompat.isAtLeastT()) {
-            throw new IllegalArgumentException("not a valid extension: " + VERSION.SDK_INT);
-        }
-        return Api33Impl.getHourCycle(locale, resolved);
-    }
-
-    /** APIs to get the user's preference of Calendar. */
-    public static class CalendarType {
-        private static final String U_EXTENSION_OF_CALENDAR = "ca";
-        /** Chinese Calendar */
-        public static final String CHINESE = "chinese";
-        /** Dangi Calendar (Korea Calendar) */
-        public static final String DANGI = "dangi";
-        /** Gregorian Calendar */
-        public static final String GREGORIAN = "gregorian";
-        /** Hebrew Calendar */
-        public static final String HEBREW = "hebrew";
-        /** Indian National Calendar */
-        public static final String INDIAN = "indian";
-        /** Islamic Calendar */
-        public static final String ISLAMIC = "islamic";
-        /** Islamic Calendar (tabular, civil epoch) */
-        public static final String ISLAMIC_CIVIL = "islamic-civil";
-        /** Islamic Calendar (Saudi Arabia, sighting) */
-        public static final String ISLAMIC_RGSA = "islamic-rgsa";
-        /** Islamic Calendar (tabular, astronomical epoch) */
-        public static final String ISLAMIC_TBLA = "islamic-tbla";
-        /** Islamic Calendar (Umm al-Qura) */
-        public static final String ISLAMIC_UMALQURA = "islamic-umalqura";
-        /** Persian Calendar */
-        public static final String PERSIAN = "persian";
-        /** Default calendar for the locale */
-        public static final String DEFAULT = "";
-
-        /** @hide */
-        @RestrictTo(RestrictTo.Scope.LIBRARY)
-        @StringDef({
-                CHINESE,
-                DANGI,
-                GREGORIAN,
-                HEBREW,
-                INDIAN,
-                ISLAMIC,
-                ISLAMIC_CIVIL,
-                ISLAMIC_RGSA,
-                ISLAMIC_TBLA,
-                ISLAMIC_UMALQURA,
-                PERSIAN,
-                DEFAULT
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface CalendarTypes {
-        }
-
-        private CalendarType() {
-        }
-    }
-
-    /**
-     * Return the user's preference of the calendar type which is from {@link
-     * Locale#getDefault(Locale.Category)}. The returned result is resolved and bases on
-     * the {@code Locale#getDefault(Locale.Category)} settings. E.g. "chinese"
-     */
-    @NonNull
-    @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
-    @CalendarType.CalendarTypes
-    public static String getCalendarType() {
-        return getCalendarType(true);
-    }
-
-    /**
-     * Return the calendar type of the inputted {@link Locale}. The returned result is resolved and
-     * bases on the inputted {@link Locale} settings.
-     * E.g. "chinese"
-     */
-    @NonNull
-    @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
-    @CalendarType.CalendarTypes
-    public static String getCalendarType(@NonNull Locale locale) {
-        return getCalendarType(locale, true);
-    }
-
-    /**
-     * Return the user's preference of the calendar type which is from {@link
-     * Locale#getDefault(Locale.Category)}. E.g. "chinese"
-     *
-     * @param resolved If the {@code Locale#getDefault(Locale.Category)} contains calendar type
-     *                 subtag, this argument is ignored. If the
-     *                 {@code Locale#getDefault(Locale.Category)} doesn't contain calendar type
-     *                 subtag and the resolved argument is true, this function tries to find
-     *                 the default calendar type for the
-     *                 {@code Locale#getDefault(Locale.Category)}. If the
-     *                 {@code Locale#getDefault(Locale.Category)} doesn't contain calendar type
-     *                 subtag and the resolved argument is false, this function returns empty string
-     *                 i.e. CalendarTypes.Default.
-     * @return {@link CalendarType.CalendarTypes} If the malformed calendar type format was
-     * specified in the calendar type subtag, e.g. en-US-u-ca-calendar, this function returns
-     * empty string i.e. CalendarTypes.Default.
-     */
-    @NonNull
-    @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
-    @CalendarType.CalendarTypes
-    public static String getCalendarType(boolean resolved) {
-        return getCalendarType(Api33Impl.getDefaultLocale(), resolved);
-    }
-
-    /**
-     * Return the calendar type of the inputted {@link Locale}. E.g. "chinese"
-     *
-     * @param locale   The {@link Locale} to get the calendar type.
-     * @param resolved If the given {@code Locale} contains calendar type subtag, this argument is
-     *                 ignored. If the given {@code Locale} doesn't contain calendar type subtag and
-     *                 the resolved argument is true, this function tries to find the default
-     *                 calendar type for the given {@code Locale}. If the given {@code Locale}
-     *                 doesn't contain calendar type subtag and the resolved argument is false, this
-     *                 function return empty string i.e. CalendarTypes.Default.
-     * @return {@link CalendarType.CalendarTypes} If the malformed calendar type format was
-     * specified in the calendar type subtag, e.g. en-US-u-ca-calendar, this function returns
-     * empty string i.e. CalendarTypes.Default.
-     */
-    @NonNull
-    @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
-    @CalendarType.CalendarTypes
-    public static String getCalendarType(@NonNull Locale locale, boolean resolved) {
-        if (!BuildCompat.isAtLeastT()) {
-            throw new IllegalArgumentException("not a valid extension: " + VERSION.SDK_INT);
-        }
-        return Api33Impl.getCalendarType(locale, resolved);
-    }
-
-    /** APIs to get the user's preference of temperature unit. */
-    public static class TemperatureUnit {
-        private static final String U_EXTENSION_OF_TEMPERATURE_UNIT = "mu";
-        /** Celsius */
-        public static final String CELSIUS = "celsius";
-        /** Fahrenheit */
-        public static final String FAHRENHEIT = "fahrenhe";
-        /** Kelvin */
-        public static final String KELVIN = "kelvin";
-        /** Default Temperature for the locale */
-        public static final String DEFAULT = "";
-
-        /** @hide */
-        @RestrictTo(RestrictTo.Scope.LIBRARY)
-        @StringDef({
-                CELSIUS,
-                FAHRENHEIT,
-                KELVIN,
-                DEFAULT
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface TemperatureUnits {
-        }
-
-        private TemperatureUnit() {
-        }
-    }
-
-    /**
-     * Return the user's preference of the temperature unit which is from {@link
-     * Locale#getDefault(Locale.Category)}. The returned result is resolved and bases on the
-     * {@code Locale#getDefault(Locale.Category)} settings. E.g. "fahrenhe"
-     */
-    @NonNull
-    @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
-    @TemperatureUnit.TemperatureUnits
-    public static String getTemperatureUnit() {
-        return getTemperatureUnit(true);
-    }
-
-    /**
-     * Return the temperature unit of the inputted {@link Locale}. The returned result is resolved
-     * and bases on the inputted {@code Locale} settings. E.g. "fahrenhe"
-     */
-    @NonNull
-    @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
-    @TemperatureUnit.TemperatureUnits
-    public static String getTemperatureUnit(
-            @NonNull Locale locale) {
-        return getTemperatureUnit(locale, true);
-    }
-
-    /**
-     * Return the user's preference of the temperature unit which is from {@link
-     * Locale#getDefault(Locale.Category)}. E.g. "fahrenhe"
-     *
-     * @param resolved If the {@code Locale#getDefault(Locale.Category)} contains temperature unit
-     *                 subtag, this argument is ignored. If the
-     *                 {@code Locale#getDefault(Locale.Category)} doesn't contain temperature unit
-     *                 subtag and the resolved argument is true, this function tries to find
-     *                 the default temperature unit for the
-     *                 {@code Locale#getDefault(Locale.Category)}. If the
-     *                 {@code Locale#getDefault(Locale.Category)} doesn't contain temperature unit
-     *                 subtag and the resolved argument is false, this function returns empty string
-     *                 i.e. TemperatureUnits.Default.
-     * @return {@link TemperatureUnit.TemperatureUnits} If the malformed temperature unit format was
-     * specified in the temperature unit subtag, e.g. en-US-u-mu-temperature, this function returns
-     * empty string i.e. TemperatureUnits.Default.
-     */
-    @NonNull
-    @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
-    @TemperatureUnit.TemperatureUnits
-    public static String getTemperatureUnit(boolean resolved) {
-        return getTemperatureUnit(Api33Impl.getDefaultLocale(), resolved);
-    }
-
-    /**
-     * Return the temperature unit of the inputted {@link Locale}. E.g. "fahrenheit"
-     *
-     * @param locale   The {@link Locale} to get the temperature unit.
-     * @param resolved If the given {@code Locale} contains temperature unit subtag, this argument
-     *                 is ignored. If the given {@code Locale} doesn't contain temperature unit
-     *                 subtag and the resolved argument is true, this function tries to find
-     *                 the default temperature unit for the given {@code Locale}. If the given
-     *                 {@code Locale} doesn't contain temperature unit subtag and the resolved
-     *                 argument is false, this function return empty string
-     *                 i.e. TemperatureUnits.Default.
-     * @return {@link TemperatureUnit.TemperatureUnits} If the malformed temperature unit format was
-     * specified in the temperature unit subtag, e.g. en-US-u-mu-temperature, this function returns
-     * empty string i.e. TemperatureUnits.Default.
-     */
-    @NonNull
-    @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
-    @TemperatureUnit.TemperatureUnits
-    public static String getTemperatureUnit(@NonNull Locale locale, boolean resolved) {
-        if (!BuildCompat.isAtLeastT()) {
-            throw new IllegalArgumentException("not a valid extension: " + VERSION.SDK_INT);
-        }
-        return Api33Impl.getTemperatureUnit(locale, resolved);
-    }
-
-    /** APIs to get the user's preference of the first day of week. */
-    public static class FirstDayOfWeek {
-        private static final String U_EXTENSION_OF_FIRST_DAY_OF_WEEK = "fw";
-        /** Sunday */
-        public static final String SUNDAY = "sun";
-        /** Monday */
-        public static final String MONDAY = "mon";
-        /** Tuesday */
-        public static final String TUESDAY = "tue";
-        /** Wednesday */
-        public static final String WEDNESDAY = "wed";
-        /** Thursday */
-        public static final String THURSDAY = "thu";
-        /** Friday */
-        public static final String FRIDAY = "fri";
-        /** Saturday */
-        public static final String SATURDAY = "sat";
-        /** Default first day of week for the locale */
-        public static final String DEFAULT = "";
-
-        /** @hide */
-        @RestrictTo(RestrictTo.Scope.LIBRARY)
-        @StringDef({
-                SUNDAY,
-                MONDAY,
-                TUESDAY,
-                WEDNESDAY,
-                THURSDAY,
-                FRIDAY,
-                SATURDAY,
-                DEFAULT
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface Days {
-        }
-
-        private FirstDayOfWeek() {
-        }
-    }
-
-    /**
-     * Return the user's preference of the first day of week which is from
-     * {@link Locale#getDefault(Locale.Category)}. The returned result is resolved and bases on the
-     * {@code Locale#getDefault(Locale.Category)} settings. E.g. "sun"
-     */
-    @NonNull
-    @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
-    @FirstDayOfWeek.Days
-    public static String getFirstDayOfWeek() {
-        return getFirstDayOfWeek(true);
-    }
-
-    /**
-     * Return the first day of week of the inputted {@link Locale}. The returned result is resolved
-     * and bases on the inputted {@code Locale} settings.
-     * E.g. "sun"
-     */
-    @NonNull
-    @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
-    public static @FirstDayOfWeek.Days String getFirstDayOfWeek(@NonNull Locale locale) {
-        return getFirstDayOfWeek(locale, true);
-    }
-
-    /**
-     * Return the user's preference of the first day of week which is from {@link
-     * Locale#getDefault(Locale.Category)}. E.g. "sun"
-     *
-     * @param resolved If the {@code Locale#getDefault(Locale.Category)} contains first day of week
-     *                 subtag, this argument is ignored. If the
-     *                 {@code Locale#getDefault(Locale.Category)} doesn't contain first day of week
-     *                 subtag and the resolved argument is true, this function tries to find
-     *                 the default first day of week for the
-     *                 {@code Locale#getDefault(Locale.Category)}. If the
-     *                 {@code Locale#getDefault(Locale.Category)} doesn't contain first day of week
-     *                 subtag and the resolved argument is false, this function returns empty string
-     *                 i.e. Days.Default.
-     * @return {@link FirstDayOfWeek.Days} If the malformed first day of week format was specified
-     * in the first day of week subtag, e.g. en-US-u-fw-days, this function returns empty string
-     * i.e. Days.Default.
-     */
-    @NonNull
-    @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
-    @FirstDayOfWeek.Days
-    public static String getFirstDayOfWeek(boolean resolved) {
-        return getFirstDayOfWeek(Api33Impl.getDefaultLocale(), resolved);
-    }
-
-    /**
-     * Return the first day of week of the inputted {@link Locale}. E.g. "sun"
-     *
-     * @param locale   The {@link Locale} to get the first day of week.
-     * @param resolved If the given {@code Locale} contains first day of week subtag, this argument
-     *                 is ignored. If the given {@code Locale} doesn't contain first day of week
-     *                 subtag and the resolved argument is true, this function tries to find
-     *                 the default first day of week for the given {@code Locale}. If the given
-     *                 {@code Locale} doesn't contain first day of week subtag and the resolved
-     *                 argument is false, this function return empty string i.e. Days.Default.
-     * @return {@link FirstDayOfWeek.Days} If the malformed first day of week format was
-     * specified in the first day of week subtag, e.g. en-US-u-fw-days, this function returns
-     * empty string i.e. Days.Default.
-     */
-    @NonNull
-    @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
-    @FirstDayOfWeek.Days
-    public static String getFirstDayOfWeek(
-            @NonNull Locale locale, boolean resolved) {
-        if (!BuildCompat.isAtLeastT()) {
-            throw new IllegalArgumentException("not a valid extension: " + VERSION.SDK_INT);
-        }
-
-        return Api33Impl.getFirstDayOfWeek(locale, resolved);
-    }
-
-    private static class Api33Impl {
-        @DoNotInline
-        @HourCycle.HourCycleTypes
-        static String getHourCycle(@NonNull Locale locale,
-                boolean resolved) {
-            String hc = locale.getUnicodeLocaleType(HourCycle.U_EXTENSION_OF_HOUR_CYCLE);
-            if (hc != null) {
-                return hc;
-            }
-            if (!resolved) {
-                return HourCycle.DEFAULT;
-            }
-
-            return getHourCycleType(
-                    DateTimePatternGenerator.getInstance(locale).getDefaultHourCycle());
-
-        }
-
-        @DoNotInline
-        @CalendarType.CalendarTypes
-        static String getCalendarType(@NonNull Locale locale, boolean resolved) {
-            String ca = locale.getUnicodeLocaleType(CalendarType.U_EXTENSION_OF_CALENDAR);
-            if (ca != null) {
-                return ca;
-            }
-            if (!resolved) {
-                return CalendarType.DEFAULT;
-            }
-
-            return android.icu.util.Calendar.getInstance(locale).getType();
-        }
-
-        @DoNotInline
-        @TemperatureUnit.TemperatureUnits
-        static String getTemperatureUnit(@NonNull Locale locale, boolean resolved) {
-            String mu =
-                    locale.getUnicodeLocaleType(TemperatureUnit.U_EXTENSION_OF_TEMPERATURE_UNIT);
-            if (mu != null) {
-                return mu;
-            }
-            if (!resolved) {
-                return TemperatureUnit.DEFAULT;
-            }
-
-            return getResolvedTemperatureUnit(locale);
-        }
-
-        @DoNotInline
-        @FirstDayOfWeek.Days
-        static String getFirstDayOfWeek(@NonNull Locale locale, boolean resolved) {
-            String mu =
-                    locale.getUnicodeLocaleType(FirstDayOfWeek.U_EXTENSION_OF_FIRST_DAY_OF_WEEK);
-            if (mu != null) {
-                return mu;
-            }
-            if (!resolved) {
-                return FirstDayOfWeek.DEFAULT;
-            }
-            // TODO(b/262294472) Use {@code android.icu.util.Calendar} instead of
-            //  {@code java.util.Calendar}.
-            return getStringOfFirstDayOfWeek(
-                    java.util.Calendar.getInstance(locale).getFirstDayOfWeek());
-        }
-
-        @DoNotInline
-        static Locale getDefaultLocale() {
-            return Locale.getDefault(Category.FORMAT);
-        }
-
-        private static String getStringOfFirstDayOfWeek(int fw) {
-            String[] arrDays = {
-                    FirstDayOfWeek.SUNDAY,
-                    FirstDayOfWeek.MONDAY,
-                    FirstDayOfWeek.TUESDAY,
-                    FirstDayOfWeek.WEDNESDAY,
-                    FirstDayOfWeek.THURSDAY,
-                    FirstDayOfWeek.FRIDAY,
-                    FirstDayOfWeek.SATURDAY};
-
-            return fw >= 1 && fw <= 7 ? arrDays[fw - 1] : FirstDayOfWeek.DEFAULT;
-        }
-
-        @HourCycle.HourCycleTypes
-        private static String getHourCycleType(
-                DateFormat.HourCycle hourCycle) {
-            switch (hourCycle) {
-                case HOUR_CYCLE_11:
-                    return HourCycle.H11;
-                case HOUR_CYCLE_12:
-                    return HourCycle.H12;
-                case HOUR_CYCLE_23:
-                    return HourCycle.H23;
-                case HOUR_CYCLE_24:
-                    return HourCycle.H24;
-                default:
-                    return HourCycle.DEFAULT;
-            }
-        }
-
-        @TemperatureUnit.TemperatureUnits
-        private static String getResolvedTemperatureUnit(@NonNull Locale locale) {
-            LocalizedNumberFormatter nf = NumberFormatter.with()
-                    .usage("temperature")
-                    .unit(MeasureUnit.CELSIUS)
-                    .locale(locale);
-            String unit = nf.format(1).getOutputUnit().getIdentifier();
-            if (unit.contains(TemperatureUnit.FAHRENHEIT)) {
-                return TemperatureUnit.FAHRENHEIT;
-            }
-            return unit;
-        }
-
-        private Api33Impl() {
-        }
-    }
-
-    private LocalePreferences() {
-    }
-}
diff --git a/src/com/android/settings/regionalpreferences/RegionalPreferenceListBasePreferenceController.java b/src/com/android/settings/regionalpreferences/RegionalPreferenceListBasePreferenceController.java
index 823f5bb..1e39fff 100644
--- a/src/com/android/settings/regionalpreferences/RegionalPreferenceListBasePreferenceController.java
+++ b/src/com/android/settings/regionalpreferences/RegionalPreferenceListBasePreferenceController.java
@@ -63,7 +63,9 @@
             pref.setKey(item);
             pref.setOnPreferenceClickListener(clickedPref -> {
                 setSelected(pref);
-                RegionalPreferencesDataUtils.savePreference(mContext, getExtensionTypes(), item);
+                RegionalPreferencesDataUtils.savePreference(mContext, getExtensionTypes(),
+                        item.equals(RegionalPreferencesDataUtils.DEFAULT_VALUE)
+                                ? null : item);
                 mMetricsFeatureProvider.action(mContext, getMetricsActionKey());
                 return true;
             });
diff --git a/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtils.java b/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtils.java
index 32e00b4..d1ae40b 100644
--- a/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtils.java
+++ b/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtils.java
@@ -22,6 +22,8 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 
+import androidx.core.text.util.LocalePreferences;
+
 import com.android.internal.app.LocalePicker;
 import com.android.settings.R;
 
diff --git a/src/com/android/settings/regionalpreferences/TemperatureUnitController.java b/src/com/android/settings/regionalpreferences/TemperatureUnitController.java
index 9fbf69b..4b0f22c 100644
--- a/src/com/android/settings/regionalpreferences/TemperatureUnitController.java
+++ b/src/com/android/settings/regionalpreferences/TemperatureUnitController.java
@@ -19,6 +19,8 @@
 import android.content.Context;
 import android.provider.Settings;
 
+import androidx.core.text.util.LocalePreferences;
+
 import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
 
diff --git a/src/com/android/settings/slices/SlicePreferenceController.java b/src/com/android/settings/slices/SlicePreferenceController.java
index df28304..eb10bd4 100644
--- a/src/com/android/settings/slices/SlicePreferenceController.java
+++ b/src/com/android/settings/slices/SlicePreferenceController.java
@@ -44,6 +44,7 @@
     LiveData<Slice> mLiveData;
     @VisibleForTesting
     SlicePreference mSlicePreference;
+    private boolean mIsObservering = false;
     private Uri mUri;
 
     public SlicePreferenceController(Context context, String preferenceKey) {
@@ -68,25 +69,31 @@
         });
 
         //TODO(b/120803703): figure out why we need to remove observer first
-        mLiveData.removeObserver(this);
+        removeLiveDataObserver();
     }
 
     @Override
     public void onStart() {
-        if (mLiveData != null) {
+        if (mLiveData != null && !mIsObservering) {
+            mIsObservering = true;
             mLiveData.observeForever(this);
         }
     }
 
     @Override
     public void onStop() {
-        if (mLiveData != null) {
-            mLiveData.removeObserver(this);
-        }
+        removeLiveDataObserver();
     }
 
     @Override
     public void onChanged(Slice slice) {
         mSlicePreference.onSliceUpdated(slice);
     }
+
+    private void removeLiveDataObserver() {
+        if (mLiveData != null && mIsObservering && mLiveData.hasActiveObservers()) {
+            mIsObservering = false;
+            mLiveData.removeObserver(this);
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java
index 5ee7ab3..c68e90b 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java
@@ -24,25 +24,22 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.app.Activity;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHapClient;
 import android.bluetooth.BluetoothHearingAid;
 import android.bluetooth.BluetoothProfile;
 import android.content.BroadcastReceiver;
+import android.content.Context;
 import android.content.Intent;
 
-import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.FragmentActivity;
 import androidx.preference.Preference;
+import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.R;
 import com.android.settings.bluetooth.Utils;
-import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
 import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
-import com.android.settings.utils.ActivityControllerWrapper;
 import com.android.settingslib.bluetooth.BluetoothEventManager;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
@@ -55,11 +52,12 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.Robolectric;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadow.api.Shadow;
@@ -74,6 +72,9 @@
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class})
 public class AccessibilityHearingAidPreferenceControllerTest {
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+
     private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
     private static final String TEST_DEVICE_ADDRESS_2 = "00:A2:A2:A2:A2:A2";
     private static final String TEST_DEVICE_NAME = "TEST_HEARING_AID_BT_DEVICE_NAME";
@@ -82,7 +83,8 @@
     private BluetoothAdapter mBluetoothAdapter;
     private ShadowBluetoothAdapter mShadowBluetoothAdapter;
     private BluetoothDevice mBluetoothDevice;
-    private Activity mContext;
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+
     private Preference mHearingAidPreference;
     private AccessibilityHearingAidPreferenceController mPreferenceController;
     private ShadowApplication mShadowApplication;
@@ -106,11 +108,7 @@
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
         mShadowApplication = ShadowApplication.getInstance();
-
-        mContext = spy((Activity) ActivityControllerWrapper.setup(
-                Robolectric.buildActivity(Activity.class)).get());
         setupEnvironment();
 
         mHearingAidPreference = new Preference(mContext);
@@ -275,65 +273,6 @@
     }
 
     @Test
-    public void onSupportHearingAidProfile_isAvailable() {
-        mShadowBluetoothAdapter.clearSupportedProfiles();
-        mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
-        mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext,
-                HEARING_AID_PREFERENCE);
-        mPreferenceController.setPreference(mHearingAidPreference);
-
-        assertThat(mPreferenceController.isAvailable()).isTrue();
-    }
-
-    @Test
-    public void onSupportHapClientProfile_isAvailable() {
-        mShadowBluetoothAdapter.clearSupportedProfiles();
-        mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HAP_CLIENT);
-        mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext,
-                HEARING_AID_PREFERENCE);
-        mPreferenceController.setPreference(mHearingAidPreference);
-
-        assertThat(mPreferenceController.isAvailable()).isTrue();
-    }
-
-    @Test
-    public void onNotSupportAnyHearingAidRelatedProfile_isNotAvailable() {
-        mShadowBluetoothAdapter.clearSupportedProfiles();
-        mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext,
-                HEARING_AID_PREFERENCE);
-        mPreferenceController.setPreference(mHearingAidPreference);
-
-        assertThat(mPreferenceController.isAvailable()).isFalse();
-    }
-
-    @Test
-    public void getConnectedHearingAidDevice_doNotReturnSubDevice() {
-        when(mHearingAidProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
-        when(mLocalBluetoothManager.getCachedDeviceManager().isSubDevice(mBluetoothDevice))
-                .thenReturn(true);
-
-        assertThat(mPreferenceController.getConnectedHearingAidDevice()).isNull();
-    }
-
-    @Test
-    @Config(shadows = ShadowAlertDialogCompat.class)
-    public void onActiveDeviceChanged_hearingAidProfile_launchHearingAidPairingDialog() {
-        final FragmentActivity mActivity = Robolectric.setupActivity(FragmentActivity.class);
-        when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
-        when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
-                HearingAidInfo.DeviceMode.MODE_BINAURAL);
-        when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
-                HearingAidInfo.DeviceSide.SIDE_LEFT);
-        mPreferenceController.setFragmentManager(mActivity.getSupportFragmentManager());
-
-        mPreferenceController.onActiveDeviceChanged(mCachedBluetoothDevice,
-                BluetoothProfile.HEARING_AID);
-
-        final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
-        assertThat(dialog.isShowing()).isTrue();
-    }
-
-    @Test
     public void onServiceConnected_onHearingAidProfileConnected_updateSummary() {
         when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
                 HearingAidInfo.DeviceSide.SIDE_LEFT);
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceControllerTest.java
new file mode 100644
index 0000000..d16bc43
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceControllerTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+/** Tests for {@link HearingAidAudioRoutingPreferenceController}. */
+@RunWith(RobolectricTestRunner.class)
+public class HearingAidAudioRoutingPreferenceControllerTest {
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+
+    private HearingAidAudioRoutingPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        mController = new HearingAidAudioRoutingPreferenceController(mContext, "test_key");
+    }
+
+    @Test
+    public void getAvailabilityStatus_audioRoutingNotSupported_returnUnsupported() {
+        FeatureFlagUtils.setEnabled(mContext,
+                FeatureFlagUtils.SETTINGS_AUDIO_ROUTING, false);
+
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+    }
+
+    @Test
+    public void getAvailabilityStatus_audioRoutingNotSupported_available() {
+        FeatureFlagUtils.setEnabled(mContext,
+                FeatureFlagUtils.SETTINGS_AUDIO_ROUTING, true);
+
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidHelperTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidHelperTest.java
new file mode 100644
index 0000000..194b766
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidHelperTest.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.bluetooth.Utils;
+import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
+import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.HapClientProfile;
+import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/** Tests for {@link HearingAidHelper}. */
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class})
+public class HearingAidHelperTest {
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+    private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
+
+    @Mock
+    private LocalBluetoothManager mLocalBluetoothManager;
+    @Mock
+    private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
+    @Mock
+    private CachedBluetoothDeviceManager mCachedDeviceManager;
+    @Mock
+    private CachedBluetoothDevice mCachedBluetoothDevice;
+    @Mock
+    private HearingAidProfile mHearingAidProfile;
+    @Mock
+    private HapClientProfile mHapClientProfile;
+    private ShadowBluetoothAdapter mShadowBluetoothAdapter;
+    private BluetoothAdapter mBluetoothAdapter;
+    private BluetoothDevice mBluetoothDevice;
+    private HearingAidHelper mHelper;
+
+    @Before
+    public void setUp() {
+        ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
+        mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
+        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+        mShadowBluetoothAdapter = Shadow.extract(mBluetoothAdapter);
+        mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
+        when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
+        when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
+        when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedBluetoothDevice);
+        when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
+        when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
+        when(mLocalBluetoothProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile);
+
+        mHelper = new HearingAidHelper(mContext);
+    }
+
+    @Test
+    public void isHearingAidSupported_supported_returnTrue() {
+        mBluetoothAdapter.enable();
+        mShadowBluetoothAdapter.clearSupportedProfiles();
+        mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+
+        assertThat(mHelper.isHearingAidSupported()).isTrue();
+    }
+
+    @Test
+    public void isHearingAidSupported_bluetoothOff_returnFalse() {
+        mShadowBluetoothAdapter.clearSupportedProfiles();
+        mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+        mBluetoothAdapter.disable();
+
+        assertThat(mHelper.isHearingAidSupported()).isFalse();
+    }
+
+
+    @Test
+    public void isAllHearingAidRelatedProfilesReady_allReady_returnTrue() {
+        when(mHearingAidProfile.isProfileReady()).thenReturn(true);
+        when(mHapClientProfile.isProfileReady()).thenReturn(true);
+
+        assertThat(mHelper.isAllHearingAidRelatedProfilesReady()).isTrue();
+    }
+
+    @Test
+    public void isAllHearingAidRelatedProfilesReady_notFullReady_returnFalse() {
+        when(mHearingAidProfile.isProfileReady()).thenReturn(false);
+        when(mHapClientProfile.isProfileReady()).thenReturn(true);
+
+        assertThat(mHelper.isAllHearingAidRelatedProfilesReady()).isFalse();
+    }
+
+    @Test
+    public void getConnectedHearingAidDeviceList_oneDeviceAdded_getOneDevice() {
+        mBluetoothAdapter.enable();
+        mShadowBluetoothAdapter.clearSupportedProfiles();
+        mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+        when(mHearingAidProfile.getConnectedDevices()).thenReturn(new ArrayList<>(
+                Collections.singletonList(mBluetoothDevice)));
+
+        assertThat(mHelper.getConnectedHearingAidDeviceList().size()).isEqualTo(1);
+    }
+
+    @Test
+    public void getConnectedHearingAidDeviceList_oneSubDeviceAdded_getZeroDevice() {
+        mBluetoothAdapter.enable();
+        mShadowBluetoothAdapter.clearSupportedProfiles();
+        mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+        when(mHearingAidProfile.getConnectedDevices()).thenReturn(new ArrayList<>(
+                Collections.singletonList(mBluetoothDevice)));
+        when(mLocalBluetoothManager.getCachedDeviceManager().isSubDevice(
+                mBluetoothDevice)).thenReturn(true);
+
+        assertThat(mHelper.getConnectedHearingAidDeviceList().size()).isEqualTo(0);
+    }
+
+    @Test
+    public void getConnectedHearingAidDevice_getExpectedCachedBluetoothDevice() {
+        mBluetoothAdapter.enable();
+        mShadowBluetoothAdapter.clearSupportedProfiles();
+        mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+        when(mHearingAidProfile.getConnectedDevices()).thenReturn(new ArrayList<>(
+                Collections.singletonList(mBluetoothDevice)));
+
+        assertThat(mHelper.getConnectedHearingAidDevice()).isEqualTo(mCachedBluetoothDevice);
+        assertThat(mCachedBluetoothDevice.getAddress()).isEqualTo(mBluetoothDevice.getAddress());
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceControllerTest.java
similarity index 70%
rename from tests/robotests/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceControllerTest.java
rename to tests/robotests/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceControllerTest.java
index 105da65..4decf68 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceControllerTest.java
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -37,9 +38,15 @@
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.R;
+import com.android.settings.bluetooth.Utils;
+import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
+import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
 import com.android.settingslib.bluetooth.HearingAidAudioRoutingConstants;
 import com.android.settingslib.bluetooth.HearingAidAudioRoutingHelper;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -50,11 +57,13 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 import java.util.List;
 
 /** Tests for {@link HearingDeviceAudioRoutingBasePreferenceController}. */
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class})
 public class HearingDeviceAudioRoutingBasePreferenceControllerTest {
 
     @Rule
@@ -63,17 +72,25 @@
     @Spy
     private final Context mContext = ApplicationProvider.getApplicationContext();
     private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
-    private static final String FAKE_KEY = "fake_key";
+    private final ListPreference mListPreference = new ListPreference(mContext);
 
     @Mock
+    private LocalBluetoothManager mLocalBluetoothManager;
+    @Mock
+    private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
+    @Mock
+    private CachedBluetoothDeviceManager mCachedDeviceManager;
+    @Mock
     private AudioProductStrategy mAudioProductStrategyMedia;
     @Mock
     private CachedBluetoothDevice mCachedBluetoothDevice;
     @Mock
     private BluetoothDevice mBluetoothDevice;
     @Spy
-    private HearingAidAudioRoutingHelper mHelper = new HearingAidAudioRoutingHelper(mContext);
-    private final ListPreference mListPreference = new ListPreference(mContext);
+    private HearingAidAudioRoutingHelper mAudioRoutingHelper =
+            new HearingAidAudioRoutingHelper(mContext);
+    @Mock
+    private HearingAidHelper mHearingAidHelper;
     private TestHearingDeviceAudioRoutingBasePreferenceController mController;
 
     @Before
@@ -83,19 +100,23 @@
                 AudioDeviceInfo.TYPE_HEARING_AID,
                 TEST_DEVICE_ADDRESS);
 
+        ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
+        mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
+        when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
+        when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         when(mBluetoothDevice.getAnonymizedAddress()).thenReturn(TEST_DEVICE_ADDRESS);
         when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
-        when(mHelper.getMatchedHearingDeviceAttributes(any())).thenReturn(hearingDeviceAttribute);
+        doReturn(hearingDeviceAttribute).when(
+                mAudioRoutingHelper).getMatchedHearingDeviceAttributes(any());
         when(mAudioProductStrategyMedia.getAudioAttributesForLegacyStreamType(
-                AudioManager.STREAM_MUSIC))
-                .thenReturn((new AudioAttributes.Builder()).build());
-        when(mHelper.getAudioProductStrategies()).thenReturn(List.of(mAudioProductStrategyMedia));
+                AudioManager.STREAM_MUSIC)).thenReturn((new AudioAttributes.Builder()).build());
+        when(mAudioRoutingHelper.getAudioProductStrategies()).thenReturn(
+                List.of(mAudioProductStrategyMedia));
 
-        mController = new TestHearingDeviceAudioRoutingBasePreferenceController(mContext, FAKE_KEY,
-                mHelper);
-        TestHearingDeviceAudioRoutingBasePreferenceController.setupForTesting(
-                mCachedBluetoothDevice);
+        mController = new TestHearingDeviceAudioRoutingBasePreferenceController(mContext,
+                "test_key",
+                mAudioRoutingHelper, mHearingAidHelper);
         mListPreference.setEntries(R.array.bluetooth_audio_routing_titles);
         mListPreference.setEntryValues(R.array.bluetooth_audio_routing_values);
         mListPreference.setSummary("%s");
@@ -122,20 +143,21 @@
 
     @Test
     public void onPreferenceChange_noMatchedDeviceAttributes_notCallSetStrategies() {
-        when(mHelper.getMatchedHearingDeviceAttributes(any())).thenReturn(null);
+        when(mAudioRoutingHelper.getMatchedHearingDeviceAttributes(any())).thenReturn(null);
 
-        verify(mHelper, never()).setPreferredDeviceRoutingStrategies(any(), isNull(), anyInt());
+        verify(mAudioRoutingHelper, never()).setPreferredDeviceRoutingStrategies(any(), isNull(),
+                anyInt());
     }
 
     private static class TestHearingDeviceAudioRoutingBasePreferenceController extends
             HearingDeviceAudioRoutingBasePreferenceController {
 
-        private static CachedBluetoothDevice sCachedBluetoothDevice;
         private static int sSavedRoutingValue;
 
         TestHearingDeviceAudioRoutingBasePreferenceController(Context context,
-                String preferenceKey, HearingAidAudioRoutingHelper helper) {
-            super(context, preferenceKey, helper);
+                String preferenceKey, HearingAidAudioRoutingHelper audioRoutingHelper,
+                HearingAidHelper hearingAidHelper) {
+            super(context, preferenceKey, audioRoutingHelper, hearingAidHelper);
         }
 
         @Override
@@ -144,11 +166,6 @@
         }
 
         @Override
-        protected CachedBluetoothDevice getHearingDevice() {
-            return sCachedBluetoothDevice;
-        }
-
-        @Override
         protected void saveRoutingValue(Context context, int routingValue) {
             sSavedRoutingValue = routingValue;
         }
@@ -157,9 +174,5 @@
         protected int restoreRoutingValue(Context context) {
             return sSavedRoutingValue;
         }
-
-        public static void setupForTesting(CachedBluetoothDevice cachedBluetoothDevice) {
-            sCachedBluetoothDevice = cachedBluetoothDevice;
-        }
     }
 }
diff --git a/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceControllerTest.java
similarity index 97%
rename from tests/robotests/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceControllerTest.java
rename to tests/robotests/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceControllerTest.java
index dec4cc4..8eed294 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceControllerTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
 
 import static com.android.settings.core.BasePreferenceController.AVAILABLE;
 import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
diff --git a/tests/robotests/src/com/android/settings/accounts/ContactSearchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/ContactSearchPreferenceControllerTest.java
index c8606e1..bc65563 100644
--- a/tests/robotests/src/com/android/settings/accounts/ContactSearchPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/ContactSearchPreferenceControllerTest.java
@@ -20,13 +20,19 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.content.pm.UserInfo;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 
+import androidx.test.core.app.ApplicationProvider;
+
 import com.android.settingslib.RestrictedSwitchPreference;
 
 import org.junit.Before;
@@ -35,39 +41,51 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
+
+import java.util.Collections;
 
 @RunWith(RobolectricTestRunner.class)
 public class ContactSearchPreferenceControllerTest {
 
     private static final String PREF_KEY = "contacts_search";
-
-    @Mock
-    private UserHandle mManagedUser;
+    private static final int MANAGED_USER_ID = 10;
 
     private Context mContext;
     private ContactSearchPreferenceController mController;
     private RestrictedSwitchPreference mPreference;
 
+    @Mock
+    private UserHandle mManagedUser;
+    @Mock
+    private UserManager mUserManager;
+    @Mock
+    private UserInfo mUserInfo;
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
-        mController = new ContactSearchPreferenceController(mContext, PREF_KEY);
-        mController.setManagedUser(mManagedUser);
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
         mPreference = spy(new RestrictedSwitchPreference(mContext));
+        when(mUserInfo.isManagedProfile()).thenReturn(true);
+        when(mUserManager.getUserInfo(anyInt())).thenReturn(mUserInfo);
+        when(mUserManager.getProcessUserId()).thenReturn(0);
+        when(mUserManager.getUserProfiles()).thenReturn(Collections.singletonList(mManagedUser));
+        when(mManagedUser.getIdentifier()).thenReturn(MANAGED_USER_ID);
+        mController = new ContactSearchPreferenceController(mContext, PREF_KEY);
     }
 
     @Test
     public void getAvailabilityStatus_noManagedUser_DISABLED() {
-        mController.setManagedUser(null);
+        when(mUserManager.getProcessUserId()).thenReturn(MANAGED_USER_ID);
+        mController = new ContactSearchPreferenceController(mContext, PREF_KEY);
+
         assertThat(mController.getAvailabilityStatus())
                 .isNotEqualTo(ContactSearchPreferenceController.AVAILABLE);
     }
 
     @Test
     public void getAvailabilityStatus_hasManagedUser_AVAILABLE() {
-        mController.setManagedUser(mManagedUser);
         assertThat(mController.getAvailabilityStatus())
                 .isEqualTo(ContactSearchPreferenceController.AVAILABLE);
     }
@@ -75,32 +93,96 @@
     @Test
     public void updateState_shouldRefreshContent() {
         Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, mManagedUser.getIdentifier());
+                MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, MANAGED_USER_ID);
+
         mController.updateState(mPreference);
+
         assertThat(mPreference.isChecked()).isFalse();
 
         Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, mManagedUser.getIdentifier());
+                MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, MANAGED_USER_ID);
+
         mController.updateState(mPreference);
+
         assertThat(mPreference.isChecked()).isTrue();
     }
 
     @Test
     public void updateState_preferenceShouldBeDisabled() {
         mController.updateState(mPreference);
+
         verify(mPreference).setDisabledByAdmin(any());
     }
 
     @Test
     public void onPreferenceChange_shouldUpdateProviderValue() {
         mController.onPreferenceChange(mPreference, false);
+
         assertThat(Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, mManagedUser.getIdentifier()))
+                MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, MANAGED_USER_ID))
                 .isEqualTo(0);
 
         mController.onPreferenceChange(mPreference, true);
+
         assertThat(Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, mManagedUser.getIdentifier()))
+                MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, MANAGED_USER_ID))
                 .isEqualTo(1);
     }
-}
\ No newline at end of file
+
+    @Test
+    public void onQuietModeDisabled_preferenceEnabled() {
+        when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.isEnabled()).isTrue();
+    }
+
+    @Test
+    public void onQuietModeEnabled_preferenceDisabledAndUnchecked() {
+        when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(true);
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.isEnabled()).isFalse();
+        assertThat(mPreference.isChecked()).isFalse();
+    }
+
+    @Test
+    public void afterQuietModeTurnedOnAndOffWhenPreferenceChecked_toggleCheckedAndEnabled() {
+        Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, MANAGED_USER_ID);
+        when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(true);
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.isEnabled()).isFalse();
+        assertThat(mPreference.isChecked()).isFalse();
+
+        when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.isEnabled()).isTrue();
+        assertThat(mPreference.isChecked()).isTrue();
+    }
+
+    @Test
+    public void afterQuietModeTurnedOnAndOffWhenPreferenceUnchecked_toggleUncheckedAndEnabled() {
+        Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, MANAGED_USER_ID);
+        when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(true);
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.isEnabled()).isFalse();
+        assertThat(mPreference.isChecked()).isFalse();
+
+        when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.isEnabled()).isTrue();
+        assertThat(mPreference.isChecked()).isFalse();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accounts/ManagedProfileQuietModeEnablerTest.java b/tests/robotests/src/com/android/settings/accounts/ManagedProfileQuietModeEnablerTest.java
new file mode 100644
index 0000000..2698efa
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accounts/ManagedProfileQuietModeEnablerTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accounts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.Collections;
+
+
+@RunWith(RobolectricTestRunner.class)
+public class ManagedProfileQuietModeEnablerTest {
+    private static final int MANAGED_USER_ID = 10;
+    private Context mContext;
+    private ManagedProfileQuietModeEnabler mQuietModeEnabler;
+    private LifecycleOwner mLifecycleOwner = new LifecycleOwner() {
+        public LifecycleRegistry registry = new LifecycleRegistry(this);
+
+        @Override
+        public Lifecycle getLifecycle() {
+            return registry;
+        }
+    };
+
+    @Mock
+    private ManagedProfileQuietModeEnabler.QuietModeChangeListener mOnQuietModeChangeListener;
+    @Mock
+    private UserManager mUserManager;
+    @Mock
+    private UserHandle mManagedUser;
+    @Mock
+    private UserInfo mUserInfo;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+        when(mUserInfo.isManagedProfile()).thenReturn(true);
+        when(mUserManager.getUserInfo(anyInt())).thenReturn(mUserInfo);
+        when(mUserManager.getProcessUserId()).thenReturn(0);
+        when(mManagedUser.getIdentifier()).thenReturn(MANAGED_USER_ID);
+        when(mUserManager.getUserProfiles()).thenReturn(Collections.singletonList(mManagedUser));
+        mQuietModeEnabler = new ManagedProfileQuietModeEnabler(mContext,
+                mOnQuietModeChangeListener);
+    }
+
+    @Test
+    public void onSetQuietMode_shouldRequestQuietModeEnabled() {
+        mQuietModeEnabler.setQuietModeEnabled(false);
+        verify(mUserManager).requestQuietModeEnabled(false, mManagedUser);
+        mQuietModeEnabler.setQuietModeEnabled(true);
+        verify(mUserManager).requestQuietModeEnabled(true, mManagedUser);
+    }
+
+    @Test
+    public void onIsQuietModeEnabled_shouldCallIsQuietModeEnabled() {
+        assertThat(mQuietModeEnabler.isQuietModeEnabled()).isEqualTo(
+                verify(mUserManager).isQuietModeEnabled(any()));
+    }
+
+    @Test
+    public void onQuietModeChanged_listenerNotified() {
+        mQuietModeEnabler.onStart(mLifecycleOwner);
+        mContext.sendBroadcast(new Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE).putExtra(
+                Intent.EXTRA_USER_HANDLE, MANAGED_USER_ID));
+        mContext.sendBroadcast(new Intent(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE).putExtra(
+                Intent.EXTRA_USER_HANDLE, MANAGED_USER_ID));
+        verify(mOnQuietModeChangeListener, times(2)).onQuietModeChanged();
+    }
+
+    @Test
+    public void onStart_shouldRegisterReceiver() {
+        mQuietModeEnabler.onStart(mLifecycleOwner);
+        verify(mContext).registerReceiver(eq(mQuietModeEnabler.mReceiver), any(), anyInt());
+    }
+
+    @Test
+    public void onStop_shouldUnregisterReceiver() {
+        // register it first
+        mContext.registerReceiver(mQuietModeEnabler.mReceiver, null,
+                Context.RECEIVER_EXPORTED/*UNAUDITED*/);
+
+        mQuietModeEnabler.onStop(mLifecycleOwner);
+        verify(mContext).unregisterReceiver(mQuietModeEnabler.mReceiver);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java
index 2a28318..e862d10 100644
--- a/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java
@@ -19,18 +19,18 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.content.pm.UserInfo;
 import android.os.UserHandle;
 import android.os.UserManager;
 
-import androidx.preference.SwitchPreference;
+import androidx.test.core.app.ApplicationProvider;
 
-import com.android.settings.R;
+import com.android.settingslib.widget.MainSwitchPreference;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -38,43 +38,51 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
+
+import java.util.Collections;
 
 @RunWith(RobolectricTestRunner.class)
 public class WorkModePreferenceControllerTest {
 
     private static final String PREF_KEY = "work_mode";
+    private static final int MANAGED_USER_ID = 10;
+
+    private Context mContext;
+    private WorkModePreferenceController mController;
+    private MainSwitchPreference mPreference;
 
     @Mock
     private UserManager mUserManager;
     @Mock
     private UserHandle mManagedUser;
-
-    private Context mContext;
-    private WorkModePreferenceController mController;
-    private SwitchPreference mPreference;
+    @Mock
+    private UserInfo mUserInfo;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mContext = spy(RuntimeEnvironment.application);
-        when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
-
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+        mPreference = new MainSwitchPreference(mContext);
+        when(mUserInfo.isManagedProfile()).thenReturn(true);
+        when(mUserManager.getUserInfo(anyInt())).thenReturn(mUserInfo);
+        when(mUserManager.getProcessUserId()).thenReturn(0);
+        when(mUserManager.getUserProfiles()).thenReturn(Collections.singletonList(mManagedUser));
+        when(mManagedUser.getIdentifier()).thenReturn(MANAGED_USER_ID);
         mController = new WorkModePreferenceController(mContext, PREF_KEY);
-        mController.setManagedUser(mManagedUser);
-        mPreference = new SwitchPreference(mContext);
     }
 
     @Test
     public void getAvailabilityStatus_noManagedUser_DISABLED() {
-        mController.setManagedUser(null);
+        when(mUserManager.getProcessUserId()).thenReturn(MANAGED_USER_ID);
+        mController = new WorkModePreferenceController(mContext, PREF_KEY);
+
         assertThat(mController.getAvailabilityStatus())
                 .isNotEqualTo(WorkModePreferenceController.AVAILABLE);
     }
 
     @Test
     public void getAvailabilityStatus_hasManagedUser_AVAILABLE() {
-        mController.setManagedUser(mManagedUser);
         assertThat(mController.getAvailabilityStatus())
                 .isEqualTo(WorkModePreferenceController.AVAILABLE);
     }
@@ -83,41 +91,29 @@
     public void updateState_shouldRefreshContent() {
         when(mUserManager.isQuietModeEnabled(any(UserHandle.class)))
                 .thenReturn(false);
+
         mController.updateState(mPreference);
+
         assertThat(mPreference.isChecked()).isTrue();
-        assertThat(mPreference.getSummary())
-                .isEqualTo(mContext.getText(R.string.work_mode_on_summary));
 
         when(mUserManager.isQuietModeEnabled(any(UserHandle.class)))
                 .thenReturn(true);
+
         mController.updateState(mPreference);
+
         assertThat(mPreference.isChecked()).isFalse();
-        assertThat(mPreference.getSummary())
-                .isEqualTo(mContext.getText(R.string.work_mode_off_summary));
     }
 
     @Test
     public void onPreferenceChange_shouldRequestQuietModeEnabled() {
+        mController.setPreference(mPreference);
+
         mController.onPreferenceChange(mPreference, true);
+
         verify(mUserManager).requestQuietModeEnabled(false, mManagedUser);
 
         mController.onPreferenceChange(mPreference, false);
+
         verify(mUserManager).requestQuietModeEnabled(true, mManagedUser);
     }
-
-    @Test
-    public void onStart_shouldRegisterReceiver() {
-        mController.onStart();
-        verify(mContext).registerReceiver(eq(mController.mReceiver), any(), anyInt());
-    }
-
-    @Test
-    public void onStop_shouldUnregisterReceiver() {
-        // register it first
-        mContext.registerReceiver(mController.mReceiver, null,
-                Context.RECEIVER_EXPORTED/*UNAUDITED*/);
-
-        mController.onStop();
-        verify(mContext).unregisterReceiver(mController.mReceiver);
-    }
 }
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingControllerTest.java
deleted file mode 100644
index ea65856..0000000
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingControllerTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.bluetooth;
-
-import static com.android.settings.bluetooth.BluetoothDetailsAudioRoutingController.KEY_AUDIO_ROUTING;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.util.FeatureFlagUtils;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-import org.robolectric.RobolectricTestRunner;
-
-/** Tests for {@link BluetoothDetailsAudioRoutingController}. */
-@RunWith(RobolectricTestRunner.class)
-public class BluetoothDetailsAudioRoutingControllerTest extends
-        BluetoothDetailsControllerTestBase {
-    @Rule
-    public final MockitoRule mockito = MockitoJUnit.rule();
-
-    private static final String TEST_ADDRESS = "55:66:77:88:99:AA";
-
-    private BluetoothDetailsAudioRoutingController mController;
-
-    @Override
-    public void setUp() {
-        super.setUp();
-
-        mController = new BluetoothDetailsAudioRoutingController(mContext, mFragment, mCachedDevice,
-                mLifecycle);
-        final PreferenceCategory preferenceCategory = new PreferenceCategory(mContext);
-        preferenceCategory.setKey(mController.getPreferenceKey());
-        mScreen.addPreference(preferenceCategory);
-    }
-
-    @Test
-    public void isAvailable_isHearingAidDevice_available() {
-        FeatureFlagUtils.setEnabled(mContext,
-                FeatureFlagUtils.SETTINGS_AUDIO_ROUTING, true);
-        when(mCachedDevice.isHearingAidDevice()).thenReturn(true);
-
-        assertThat(mController.isAvailable()).isTrue();
-    }
-
-    @Test
-    public void isAvailable_isNotHearingAidDevice_notAvailable() {
-        FeatureFlagUtils.setEnabled(mContext,
-                FeatureFlagUtils.SETTINGS_AUDIO_ROUTING, true);
-        when(mCachedDevice.isHearingAidDevice()).thenReturn(false);
-
-        assertThat(mController.isAvailable()).isFalse();
-    }
-
-    @Test
-    public void init_isHearingAidDevice_expectedAudioRoutingPreference() {
-        when(mCachedDevice.isHearingAidDevice()).thenReturn(true);
-        when(mCachedDevice.getAddress()).thenReturn(TEST_ADDRESS);
-
-        mController.init(mScreen);
-        final Preference preference = mScreen.findPreference(KEY_AUDIO_ROUTING);
-        final String address = preference.getExtras().getString(
-                BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS);
-        final String fragment = preference.getFragment();
-
-        assertThat(address).isEqualTo(TEST_ADDRESS);
-        assertThat(fragment).isEqualTo(BluetoothDetailsAudioRoutingFragment.class.getName());
-
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragmentTest.java
deleted file mode 100644
index 9bd4f1b..0000000
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragmentTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.bluetooth;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.bluetooth.BluetoothDevice;
-import android.content.Context;
-import android.os.Bundle;
-
-import androidx.test.core.app.ApplicationProvider;
-
-import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
-import com.android.settingslib.bluetooth.LocalBluetoothManager;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-/** Tests for {@link BluetoothDetailsAudioRoutingFragment}. */
-@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowBluetoothUtils.class})
-public class BluetoothDetailsAudioRoutingFragmentTest {
-
-    @Rule
-    public MockitoRule mMockitoRule = MockitoJUnit.rule();
-
-    private static final String TEST_ADDRESS = "55:66:77:88:99:AA";
-
-    private final Context mContext = ApplicationProvider.getApplicationContext();
-
-    private BluetoothDetailsAudioRoutingFragment mFragment;
-    @Mock
-    private LocalBluetoothManager mLocalBluetoothManager;
-    @Mock
-    private CachedBluetoothDeviceManager mCachedDeviceManager;
-    @Mock
-    private LocalBluetoothAdapter mLocalBluetoothAdapter;
-    @Mock
-    private BluetoothDevice mBluetoothDevice;
-    @Mock
-    private CachedBluetoothDevice mCachedDevice;
-
-    @Before
-    public void setUp() {
-        setupEnvironment();
-
-        when(mLocalBluetoothAdapter.getRemoteDevice(TEST_ADDRESS)).thenReturn(mBluetoothDevice);
-        when(mCachedDevice.getAddress()).thenReturn(TEST_ADDRESS);
-        when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice);
-
-        mFragment = new BluetoothDetailsAudioRoutingFragment();
-    }
-
-    @Test
-    public void onAttach_setArgumentsWithAddress_expectedCachedDeviceWithAddress() {
-        final Bundle args = new Bundle();
-        args.putString(BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS, TEST_ADDRESS);
-        mFragment.setArguments(args);
-
-        mFragment.onAttach(mContext);
-
-        assertThat(mFragment.mCachedDevice.getAddress()).isEqualTo(TEST_ADDRESS);
-    }
-
-    private void setupEnvironment() {
-        ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
-        when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
-        when(mLocalBluetoothManager.getBluetoothAdapter()).thenReturn(mLocalBluetoothAdapter);
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
index 0278553..5e9fb73 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
@@ -710,7 +710,7 @@
 
     @Test
     public void initPreferenceForTriState_isValidPackageName_hasCorrectString() {
-        when(mBatteryOptimizeUtils.isValidPackageName()).thenReturn(false);
+        when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
 
         mFragment.initPreferenceForTriState(mContext);
 
@@ -720,7 +720,7 @@
 
     @Test
     public void initPreferenceForTriState_isSystemOrDefaultApp_hasCorrectString() {
-        when(mBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+        when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
         when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
 
         mFragment.initPreferenceForTriState(mContext);
@@ -731,7 +731,7 @@
 
     @Test
     public void initPreferenceForTriState_hasCorrectString() {
-        when(mBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+        when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
         when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(false);
 
         mFragment.initPreferenceForTriState(mContext);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
index 8970730..b8c72ee 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
@@ -28,6 +28,7 @@
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.inOrder;
@@ -45,6 +46,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.UserInfo;
+import android.os.Build;
 import android.os.IDeviceIdleController;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -53,6 +55,7 @@
 
 import com.android.settings.TestUtils;
 import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
+import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
 
 import org.junit.After;
@@ -89,6 +92,7 @@
     private PrintWriter mPrintWriter;
     private StringWriter mStringWriter;
     private BatteryBackupHelper mBatteryBackupHelper;
+    private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
 
     @Mock
     private PackageManager mPackageManager;
@@ -112,6 +116,8 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+        mPowerUsageFeatureProvider =
+                FakeFeatureFactory.setupForTest().powerUsageFeatureProvider;
         mContext = spy(RuntimeEnvironment.application);
         mStringWriter = new StringWriter();
         mPrintWriter = new PrintWriter(mStringWriter);
@@ -136,19 +142,11 @@
     }
 
     @Test
-    public void performBackup_nullPowerList_notBackupPowerList() throws Exception {
-        doReturn(null).when(mDeviceController).getFullPowerWhitelist();
-        mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null);
-
-        verify(mBackupDataOutput, never()).writeEntityHeader(anyString(), anyInt());
-    }
-
-    @Test
-    public void performBackup_emptyPowerList_notBackupPowerList() throws Exception {
+    public void performBackup_emptyPowerList_backupPowerList() throws Exception {
         doReturn(new String[0]).when(mDeviceController).getFullPowerWhitelist();
         mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null);
 
-        verify(mBackupDataOutput, never()).writeEntityHeader(anyString(), anyInt());
+        verify(mBackupDataOutput, atLeastOnce()).writeEntityHeader(anyString(), anyInt());
     }
 
     @Test
@@ -160,34 +158,6 @@
     }
 
     @Test
-    public void performBackup_oneFullPowerListElement_backupFullPowerListData()
-            throws Exception {
-        final String[] fullPowerList = {"com.android.package"};
-        doReturn(fullPowerList).when(mDeviceController).getFullPowerWhitelist();
-
-        mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null);
-
-        final byte[] expectedBytes = fullPowerList[0].getBytes();
-        verify(mBackupDataOutput).writeEntityHeader(
-                BatteryBackupHelper.KEY_FULL_POWER_LIST, expectedBytes.length);
-        verify(mBackupDataOutput).writeEntityData(expectedBytes, expectedBytes.length);
-    }
-
-    @Test
-    public void performBackup_backupFullPowerListData() throws Exception {
-        final String[] fullPowerList = {"com.android.package1", "com.android.package2"};
-        doReturn(fullPowerList).when(mDeviceController).getFullPowerWhitelist();
-
-        mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null);
-
-        final String expectedResult = fullPowerList[0] + DELIMITER + fullPowerList[1];
-        final byte[] expectedBytes = expectedResult.getBytes();
-        verify(mBackupDataOutput).writeEntityHeader(
-                BatteryBackupHelper.KEY_FULL_POWER_LIST, expectedBytes.length);
-        verify(mBackupDataOutput).writeEntityData(expectedBytes, expectedBytes.length);
-    }
-
-    @Test
     public void performBackup_nonOwner_ignoreAllBackupAction() throws Exception {
         ShadowUserHandle.setUid(1);
         final String[] fullPowerList = {"com.android.package"};
@@ -283,7 +253,7 @@
 
     @Test
     public void restoreEntity_incorrectDataKey_notReadBackupData() throws Exception {
-        final String incorrectDataKey = BatteryBackupHelper.KEY_FULL_POWER_LIST;
+        final String incorrectDataKey = "incorrect_data_key";
         mockBackupData(30 /*dataSize*/, incorrectDataKey);
 
         mBatteryBackupHelper.restoreEntity(mBackupDataInputStream);
@@ -314,6 +284,20 @@
     }
 
     @Test
+    public void restoreEntity_verifyConfigurationOneTimeOnly() {
+        final int invalidScheduledLevel = 5;
+        TestUtils.setScheduledLevel(mContext, invalidScheduledLevel);
+        mBatteryBackupHelper.restoreEntity(mBackupDataInputStream);
+        TestUtils.setScheduledLevel(mContext, invalidScheduledLevel);
+
+        // Invoke the restoreEntity() method 2nd time.
+        mBatteryBackupHelper.restoreEntity(mBackupDataInputStream);
+
+        assertThat(TestUtils.getScheduledLevel(mContext))
+                .isEqualTo(invalidScheduledLevel);
+    }
+
+    @Test
     public void restoreOptimizationMode_nullBytesData_skipRestore() throws Exception {
         mBatteryBackupHelper.restoreOptimizationMode(new byte[0]);
         verifyNoInteractions(mBatteryOptimizeUtils);
@@ -358,6 +342,26 @@
                 .setAppUsageState(MODE_RESTRICTED, Action.RESTORE);
     }
 
+    @Test
+    public void performBackup_backupDeviceBuildInformation() throws Exception {
+        final String[] fullPowerList = {"com.android.package"};
+        doReturn(fullPowerList).when(mDeviceController).getFullPowerWhitelist();
+        doReturn(null).when(mPowerUsageFeatureProvider).getBuildMetadata1(mContext);
+        final String deviceMetadata = "device.metadata.test_device";
+        doReturn(deviceMetadata).when(mPowerUsageFeatureProvider).getBuildMetadata2(mContext);
+
+        mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null);
+
+        final InOrder inOrder = inOrder(mBackupDataOutput);
+        verifyBackupData(inOrder, BatteryBackupHelper.KEY_BUILD_BRAND, Build.BRAND);
+        verifyBackupData(inOrder, BatteryBackupHelper.KEY_BUILD_PRODUCT, Build.PRODUCT);
+        verifyBackupData(inOrder, BatteryBackupHelper.KEY_BUILD_MANUFACTURER, Build.MANUFACTURER);
+        verifyBackupData(inOrder, BatteryBackupHelper.KEY_BUILD_FINGERPRINT, Build.FINGERPRINT);
+        inOrder.verify(mBackupDataOutput, never()).writeEntityHeader(
+                eq(BatteryBackupHelper.KEY_BUILD_METADATA_1), anyInt());
+        verifyBackupData(inOrder, BatteryBackupHelper.KEY_BUILD_METADATA_2, deviceMetadata);
+    }
+
     private void mockUid(int uid, String packageName) throws Exception {
         doReturn(uid).when(mPackageManager)
                 .getPackageUid(packageName, PackageManager.GET_META_DATA);
@@ -429,6 +433,13 @@
                 new ArraySet<>(Arrays.asList(applicationInfo1, applicationInfo2, applicationInfo3));
     }
 
+    private void verifyBackupData(
+            InOrder inOrder, String dataKey, String dataContent) throws Exception {
+        final byte[] expectedBytes = dataContent.getBytes();
+        inOrder.verify(mBackupDataOutput).writeEntityHeader(dataKey, expectedBytes.length);
+        inOrder.verify(mBackupDataOutput).writeEntityData(expectedBytes, expectedBytes.length);
+    }
+
     @Implements(UserHandle.class)
     public static class ShadowUserHandle {
         // Sets the default as thte OWNER role.
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
index a829c40..62f812d 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
@@ -69,6 +69,7 @@
         mBatteryBroadcastReceiver.mBatteryLevel = BATTERY_INIT_LEVEL;
         mBatteryBroadcastReceiver.mBatteryStatus = BATTERY_INIT_STATUS;
         mBatteryBroadcastReceiver.mBatteryHealth = BatteryManager.BATTERY_HEALTH_UNKNOWN;
+        mBatteryBroadcastReceiver.mChargingStatus = BatteryManager.CHARGING_POLICY_DEFAULT;
         mBatteryBroadcastReceiver.setBatteryChangedListener(mBatteryListener);
 
         mChargingIntent = new Intent(Intent.ACTION_BATTERY_CHANGED);
@@ -91,8 +92,8 @@
 
     @Test
     public void onReceive_batteryHealthChanged_dataUpdated() {
-        mChargingIntent
-                .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
+        mChargingIntent.putExtra(
+                BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
         mBatteryBroadcastReceiver.onReceive(mContext, mChargingIntent);
 
         assertThat(mBatteryBroadcastReceiver.mBatteryHealth)
@@ -101,6 +102,17 @@
     }
 
     @Test
+    public void onReceive_chargingStatusChanged_dataUpdated() {
+        mChargingIntent.putExtra(BatteryManager.EXTRA_CHARGING_STATUS,
+                BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE);
+        mBatteryBroadcastReceiver.onReceive(mContext, mChargingIntent);
+
+        assertThat(mBatteryBroadcastReceiver.mChargingStatus)
+                .isEqualTo(BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE);
+        verify(mBatteryListener).onBatteryChanged(BatteryUpdateType.CHARGING_STATUS);
+    }
+
+    @Test
     public void onReceive_batteryNotPresent_shouldShowHelpMessage() {
         mChargingIntent.putExtra(BatteryManager.EXTRA_PRESENT, false);
 
@@ -131,6 +143,8 @@
         assertThat(mBatteryBroadcastReceiver.mBatteryStatus).isEqualTo(batteryStatus);
         assertThat(mBatteryBroadcastReceiver.mBatteryHealth)
                 .isEqualTo(BatteryManager.BATTERY_HEALTH_UNKNOWN);
+        assertThat(mBatteryBroadcastReceiver.mChargingStatus)
+                .isEqualTo(BatteryManager.CHARGING_POLICY_DEFAULT);
         verify(mBatteryListener, never()).onBatteryChanged(anyInt());
     }
 
@@ -163,6 +177,8 @@
                 Utils.getBatteryStatus(mContext, mChargingIntent, /* compactStatus= */ false));
         assertThat(mBatteryBroadcastReceiver.mBatteryHealth)
                 .isEqualTo(BatteryManager.BATTERY_HEALTH_UNKNOWN);
+        assertThat(mBatteryBroadcastReceiver.mChargingStatus)
+                .isEqualTo(BatteryManager.CHARGING_POLICY_DEFAULT);
         // 2 times because register will force update the battery
         verify(mBatteryListener, times(2)).onBatteryChanged(BatteryUpdateType.MANUAL);
     }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
index f94e5bf..2779e0a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
@@ -290,8 +290,8 @@
     }
 
     @Test
-    public void updatePreference_isOverheat_showEmptyText() {
-        mBatteryInfo.isOverheated = true;
+    public void updatePreference_isBatteryDefender_showEmptyText() {
+        mBatteryInfo.isBatteryDefender = true;
 
         mController.updateHeaderPreference(mBatteryInfo);
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
index eb4b598..b0d6da6 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
@@ -43,7 +43,6 @@
 import com.android.settings.testutils.BatteryTestUtils;
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.widget.UsageView;
-import com.android.settingslib.R;
 import com.android.settingslib.fuelgauge.Estimate;
 
 import org.junit.Before;
@@ -164,26 +163,6 @@
     }
 
     @Test
-    public void testGetBatteryInfo_basedOnUsageTrueLessThanSevenMinutes_usesCorrectString() {
-        Estimate estimate = new Estimate(Duration.ofMinutes(7).toMillis(),
-                true /* isBasedOnUsage */,
-                1000 /* averageDischargeTime */);
-        BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
-                mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000,
-                false /* shortString */);
-        BatteryInfo info2 = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
-                mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000,
-                true /* shortString */);
-
-        // These should be identical in either case
-        assertThat(info.remainingLabel.toString()).isEqualTo(
-                mContext.getString(R.string.power_remaining_duration_only_shutdown_imminent));
-        assertThat(info2.remainingLabel.toString()).isEqualTo(
-                mContext.getString(R.string.power_remaining_duration_only_shutdown_imminent));
-        assertThat(info2.suggestionLabel).contains(BATTERY_RUN_OUT_PREFIX);
-    }
-
-    @Test
     @Ignore
     public void getBatteryInfo_MoreThanOneDay_suggestionLabelIsCorrectString() {
         Estimate estimate = new Estimate(Duration.ofDays(3).toMillis(),
@@ -197,25 +176,6 @@
     }
 
     @Test
-    public void
-    testGetBatteryInfo_basedOnUsageTrueBetweenSevenAndFifteenMinutes_usesCorrectString() {
-        Estimate estimate = new Estimate(Duration.ofMinutes(10).toMillis(),
-                true /* isBasedOnUsage */,
-                1000 /* averageDischargeTime */);
-        BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
-                mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000,
-                false /* shortString */);
-
-        // Check that strings are showing less than 15 minutes remaining regardless of exact time.
-        assertThat(info.chargeLabel.toString()).isEqualTo(
-                mContext.getString(R.string.power_remaining_less_than_duration,
-                        FIFTEEN_MIN_FORMATTED, TEST_BATTERY_LEVEL_10));
-        assertThat(info.remainingLabel.toString()).isEqualTo(
-                mContext.getString(R.string.power_remaining_less_than_duration_only,
-                        FIFTEEN_MIN_FORMATTED));
-    }
-
-    @Test
     public void testGetBatteryInfo_basedOnUsageFalse_usesDefaultString() {
         BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
                 mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
@@ -254,18 +214,18 @@
     }
 
     @Test
-    public void testGetBatteryInfo_chargingWithOverheated_updateChargeLabel() {
+    public void testGetBatteryInfo_chargingWithDefender_updateChargeLabel() {
         doReturn(TEST_CHARGE_TIME_REMAINING)
                 .when(mBatteryUsageStats)
                 .getChargeTimeRemainingMs();
-        mChargingBatteryBroadcast
-                .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
+        mChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_CHARGING_STATUS,
+                BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE);
 
         BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast,
                 mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
                 false /* shortString */);
 
-        assertThat(info.isOverheated).isTrue();
+        assertThat(info.isBatteryDefender).isTrue();
         assertThat(info.chargeLabel.toString()).contains(STATUS_CHARGING_PAUSED);
     }
 
@@ -278,7 +238,8 @@
                         50 /* level */,
                         100 /* scale */,
                         BatteryManager.BATTERY_STATUS_CHARGING)
-                .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
+                .putExtra(BatteryManager.EXTRA_CHARGING_STATUS,
+                        BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE);
 
         BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, intent,
                 mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
@@ -290,8 +251,8 @@
     @Test
     public void testGetBatteryInfo_dockDefenderTemporarilyBypassed_updateChargeLabel() {
         doReturn(REMAINING_TIME).when(mBatteryUsageStats).getChargeTimeRemainingMs();
-        mChargingBatteryBroadcast
-                .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_GOOD);
+        mChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_CHARGING_STATUS,
+                BatteryManager.CHARGING_POLICY_DEFAULT);
         Settings.Global.putInt(mContext.getContentResolver(),
                 BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 1);
 
@@ -309,8 +270,8 @@
     @Test
     public void testGetBatteryInfo_dockDefenderFutureBypass_updateChargeLabel() {
         doReturn(false).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
-        mChargingBatteryBroadcast
-                .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_GOOD);
+        mChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_CHARGING_STATUS,
+                BatteryManager.CHARGING_POLICY_DEFAULT);
 
         BatteryInfo info = BatteryInfo.getBatteryInfo(mContext,
                 BatteryTestUtils.getCustomBatteryIntent(BatteryManager.BATTERY_PLUGGED_DOCK,
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java
index 83a75f6..f9d3108 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java
@@ -136,16 +136,16 @@
     }
 
     @Test
-    public void testIsValidPackageName_InvalidPackageName_returnFalse() {
+    public void isDisabledForOptimizeModeOnly_invalidPackageName_returnTrue() {
         final BatteryOptimizeUtils testBatteryOptimizeUtils =
                 new BatteryOptimizeUtils(mContext, UID, null);
 
-        assertThat(testBatteryOptimizeUtils.isValidPackageName()).isFalse();
+        assertThat(testBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).isTrue();
     }
 
     @Test
-    public void testIsValidPackageName_validPackageName_returnTrue() {
-        assertThat(mBatteryOptimizeUtils.isValidPackageName()).isTrue();
+    public void isDisabledForOptimizeModeOnly_validPackageName_returnFalse() {
+        assertThat(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).isFalse();
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsMigrateCheckerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsMigrateCheckerTest.java
index dfee3e7..c34dcec 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsMigrateCheckerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsMigrateCheckerTest.java
@@ -18,35 +18,76 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.inOrder;
+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 android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.os.UserManager;
 
 import com.android.settings.TestUtils;
+import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry;
 import com.android.settings.fuelgauge.batterysaver.BatterySaverScheduleRadioButtonsController;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+import java.util.ArrayList;
+import java.util.Arrays;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {BatterySettingsMigrateCheckerTest.ShadowUserHandle.class})
 public final class BatterySettingsMigrateCheckerTest {
 
     private static final Intent BOOT_COMPLETED_INTENT =
             new Intent(Intent.ACTION_BOOT_COMPLETED);
+    private static final int UID = 2003;
+    private static final String PACKAGE_NAME = "com.android.test.app";
 
     private Context mContext;
     private BatterySettingsMigrateChecker mBatterySettingsMigrateChecker;
 
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private BatteryOptimizeUtils mBatteryOptimizeUtils;
+
     @Before
-    public void setUp() {
+    public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
+        mContext = spy(RuntimeEnvironment.application);
+        doReturn(mContext).when(mContext).getApplicationContext();
+        doReturn(mPackageManager).when(mContext).getPackageManager();
+        doReturn(UID).when(mPackageManager)
+                .getPackageUid(PACKAGE_NAME, PackageManager.GET_META_DATA);
+        BatterySettingsMigrateChecker.sBatteryOptimizeUtils = mBatteryOptimizeUtils;
         mBatterySettingsMigrateChecker = new BatterySettingsMigrateChecker();
     }
 
+    @After
+    public void resetShadows() {
+        ShadowUserHandle.reset();
+    }
+
     @Test
     public void onReceive_invalidScheduledLevel_resetScheduledValue() {
         final int invalidScheduledLevel = 5;
@@ -98,6 +139,54 @@
         assertThat(getScheduledLevel()).isEqualTo(invalidScheduledLevel);
     }
 
+    @Test
+    public void onReceive_nonOwner_noAction() {
+        ShadowUserHandle.setUid(1);
+        final int invalidScheduledLevel = 5;
+        setScheduledLevel(invalidScheduledLevel);
+
+        mBatterySettingsMigrateChecker.onReceive(mContext, BOOT_COMPLETED_INTENT);
+
+        assertThat(getScheduledLevel()).isEqualTo(invalidScheduledLevel);
+    }
+
+    @Test
+    public void verifyOptimizationModes_inAllowList_resetOptimizationMode() throws Exception {
+        doReturn(BatteryOptimizeUtils.MODE_RESTRICTED).when(mBatteryOptimizeUtils)
+                .getAppOptimizationMode();
+
+        mBatterySettingsMigrateChecker.verifyOptimizationModes(
+                mContext, Arrays.asList(PACKAGE_NAME));
+
+        final InOrder inOrder = inOrder(mBatteryOptimizeUtils);
+        inOrder.verify(mBatteryOptimizeUtils).getAppOptimizationMode();
+        inOrder.verify(mBatteryOptimizeUtils).setAppUsageState(
+                BatteryOptimizeUtils.MODE_OPTIMIZED,
+                BatteryOptimizeHistoricalLogEntry.Action.FORCE_RESET);
+    }
+
+    @Test
+    public void verifyOptimizationModes_optimizedMode_noAction() throws Exception {
+        doReturn(BatteryOptimizeUtils.MODE_OPTIMIZED).when(mBatteryOptimizeUtils)
+                .getAppOptimizationMode();
+
+        mBatterySettingsMigrateChecker.verifyOptimizationModes(
+                mContext, Arrays.asList(PACKAGE_NAME));
+
+        verify(mBatteryOptimizeUtils, never()).setAppUsageState(anyInt(), any());
+    }
+
+    @Test
+    public void verifyOptimizationModes_notInAllowList_noAction() throws Exception {
+        doReturn(BatteryOptimizeUtils.MODE_RESTRICTED).when(mBatteryOptimizeUtils)
+                .getAppOptimizationMode();
+
+        mBatterySettingsMigrateChecker.verifyOptimizationModes(
+                mContext, new ArrayList<String>());
+
+        verifyNoInteractions(mBatteryOptimizeUtils);
+    }
+
     private void setScheduledLevel(int scheduledLevel) {
         TestUtils.setScheduledLevel(mContext, scheduledLevel);
     }
@@ -105,4 +194,24 @@
     private int getScheduledLevel() {
         return TestUtils.getScheduledLevel(mContext);
     }
+
+    @Implements(UserHandle.class)
+    public static class ShadowUserHandle {
+        // Sets the default as thte OWNER role.
+        private static int sUid = 0;
+
+        public static void setUid(int uid) {
+            sUid = uid;
+        }
+
+        @Implementation
+        public static int myUserId() {
+            return sUid;
+        }
+
+        @Resetter
+        public static void reset() {
+            sUid = 0;
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
index b5f8149..2fe0cec 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
@@ -487,32 +487,32 @@
     }
 
     @Test
-    public void testIsBatteryDefenderOn_isOverheatedAndIsCharging_returnTrue() {
-        mBatteryInfo.isOverheated = true;
+    public void testIsBatteryDefenderOn_isDefenderAndIsCharging_returnTrue() {
+        mBatteryInfo.isBatteryDefender = true;
         mBatteryInfo.discharging = false;
 
         assertThat(mBatteryUtils.isBatteryDefenderOn(mBatteryInfo)).isTrue();
     }
 
     @Test
-    public void testIsBatteryDefenderOn_isOverheatedAndDischarging_returnFalse() {
-        mBatteryInfo.isOverheated = true;
+    public void testIsBatteryDefenderOn_isDefenderAndDischarging_returnFalse() {
+        mBatteryInfo.isBatteryDefender = true;
         mBatteryInfo.discharging = true;
 
         assertThat(mBatteryUtils.isBatteryDefenderOn(mBatteryInfo)).isFalse();
     }
 
     @Test
-    public void testIsBatteryDefenderOn_notOverheatedAndDischarging_returnFalse() {
-        mBatteryInfo.isOverheated = false;
+    public void testIsBatteryDefenderOn_notDefenderAndDischarging_returnFalse() {
+        mBatteryInfo.isBatteryDefender = false;
         mBatteryInfo.discharging = true;
 
         assertThat(mBatteryUtils.isBatteryDefenderOn(mBatteryInfo)).isFalse();
     }
 
     @Test
-    public void testIsBatteryDefenderOn_notOverheatedAndIsCharging_returnFalse() {
-        mBatteryInfo.isOverheated = false;
+    public void testIsBatteryDefenderOn_notDefenderAndIsCharging_returnFalse() {
+        mBatteryInfo.isBatteryDefender = false;
         mBatteryInfo.discharging = false;
 
         assertThat(mBatteryUtils.isBatteryDefenderOn(mBatteryInfo)).isFalse();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/OptimizedPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/OptimizedPreferenceControllerTest.java
index 1fec92a..71bb998 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/OptimizedPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/OptimizedPreferenceControllerTest.java
@@ -52,7 +52,7 @@
 
     @Test
     public void testUpdateState_invalidPackage_prefEnabled() {
-        when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(false);
+        when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
 
         mController.updateState(mPreference);
 
@@ -62,7 +62,7 @@
 
     @Test
     public void testUpdateState_isSystemOrDefaultAppAndOptimizeStates_prefChecked() {
-        when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+        when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
         when(mockBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
         when(mockBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
                 BatteryOptimizeUtils.MODE_OPTIMIZED);
@@ -74,7 +74,7 @@
 
     @Test
     public void testUpdateState_isSystemOrDefaultApp_prefUnchecked() {
-        when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+        when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
         when(mockBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
 
         mController.updateState(mPreference);
@@ -85,7 +85,7 @@
 
     @Test
     public void testUpdateState_isOptimizedStates_prefChecked() {
-        when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+        when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
         when(mockBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
                 BatteryOptimizeUtils.MODE_OPTIMIZED);
 
@@ -96,7 +96,7 @@
 
     @Test
     public void testUpdateState_prefUnchecked() {
-        when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+        when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
 
         mController.updateState(mPreference);
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/RestrictedPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/RestrictedPreferenceControllerTest.java
index 944376c..bcddbc2 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/RestrictedPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/RestrictedPreferenceControllerTest.java
@@ -52,7 +52,7 @@
 
     @Test
     public void testUpdateState_isValidPackage_prefEnabled() {
-        when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+        when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
 
         mController.updateState(mPreference);
 
@@ -61,7 +61,7 @@
 
     @Test
     public void testUpdateState_invalidPackage_prefDisabled() {
-        when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(false);
+        when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
 
         mController.updateState(mPreference);
 
@@ -70,7 +70,7 @@
 
     @Test
     public void testUpdateState_isSystemOrDefaultAppAndRestrictedStates_prefChecked() {
-        when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+        when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
         when(mockBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
         when(mockBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
                 BatteryOptimizeUtils.MODE_RESTRICTED);
@@ -82,7 +82,7 @@
 
     @Test
     public void testUpdateState_isSystemOrDefaultApp_prefUnchecked() {
-        when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+        when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
         when(mockBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
 
         mController.updateState(mPreference);
@@ -93,7 +93,7 @@
 
     @Test
     public void testUpdateState_isRestrictedStates_prefChecked() {
-        when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+        when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
         when(mockBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
                 BatteryOptimizeUtils.MODE_RESTRICTED);
 
@@ -104,7 +104,7 @@
 
     @Test
     public void testUpdateState_prefUnchecked() {
-        when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+        when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
 
         mController.updateState(mPreference);
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/UnrestrictedPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/UnrestrictedPreferenceControllerTest.java
index c5642df..9bed9ba 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/UnrestrictedPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/UnrestrictedPreferenceControllerTest.java
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-
 package com.android.settings.fuelgauge;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -53,7 +52,7 @@
 
     @Test
     public void testUpdateState_isValidPackage_prefEnabled() {
-        when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+        when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
 
         mController.updateState(mPreference);
 
@@ -62,7 +61,7 @@
 
     @Test
     public void testUpdateState_invalidPackage_prefDisabled() {
-        when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(false);
+        when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
 
         mController.updateState(mPreference);
 
@@ -71,7 +70,7 @@
 
     @Test
     public void testUpdateState_isSystemOrDefaultAppAndUnrestrictedStates_prefChecked() {
-        when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+        when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
         when(mockBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
         when(mockBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
                 BatteryOptimizeUtils.MODE_UNRESTRICTED);
@@ -83,7 +82,7 @@
 
     @Test
     public void testUpdateState_isSystemOrDefaultApp_prefUnchecked() {
-        when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+        when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
         when(mockBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
 
         mController.updateState(mPreference);
@@ -94,7 +93,7 @@
 
     @Test
     public void testUpdateState_isUnrestrictedStates_prefChecked() {
-        when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+        when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
         when(mockBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
                 BatteryOptimizeUtils.MODE_UNRESTRICTED);
 
@@ -105,7 +104,7 @@
 
     @Test
     public void testUpdateState_prefUnchecked() {
-        when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+        when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
 
         mController.updateState(mPreference);
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
index f81a4be..64d5d04 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
@@ -60,32 +60,32 @@
     }
 
     @Test
-    public void testDetect_notOverheatedNotExtraDefend_tipInvisible() {
-        mBatteryInfo.isOverheated = false;
+    public void testDetect_notDefenderNotExtraDefend_tipInvisible() {
+        mBatteryInfo.isBatteryDefender = false;
         when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(false);
 
         assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
     }
 
     @Test
-    public void testDetect_notOverheatedIsExtraDefend_tipInvisible() {
-        mBatteryInfo.isOverheated = false;
+    public void testDetect_notDefenderIsExtraDefend_tipInvisible() {
+        mBatteryInfo.isBatteryDefender = false;
         when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(true);
 
         assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
     }
 
     @Test
-    public void testDetect_isOverheatedIsExtraDefend_tipInvisible() {
-        mBatteryInfo.isOverheated = false;
+    public void testDetect_isDefenderIsExtraDefend_tipInvisible() {
+        mBatteryInfo.isBatteryDefender = false;
         when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(true);
 
         assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
     }
 
     @Test
-    public void testDetect_isOverheatedNotExtraDefend_tipNew() {
-        mBatteryInfo.isOverheated = true;
+    public void testDetect_isDefenderNotExtraDefend_tipNew() {
+        mBatteryInfo.isBatteryDefender = true;
         when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(false);
 
         assertThat(mBatteryDefenderDetector.detect().getState())
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java
index 9652a00..bd2c5d1 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java
@@ -83,7 +83,7 @@
 
     @Test
     public void testDetect_dockDefenderActive() {
-        mBatteryInfo.isOverheated = true;
+        mBatteryInfo.isBatteryDefender = true;
         doReturn(true).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
 
         BatteryTip batteryTip = mDockDefenderDetector.detect();
@@ -95,7 +95,7 @@
 
     @Test
     public void testDetect_dockDefenderFutureBypass() {
-        mBatteryInfo.isOverheated = false;
+        mBatteryInfo.isBatteryDefender = false;
         doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
 
         BatteryTip batteryTip = mDockDefenderDetector.detect();
@@ -107,7 +107,7 @@
 
     @Test
     public void testDetect_overheatedTrue_dockDefenderDisabled() {
-        mBatteryInfo.isOverheated = true;
+        mBatteryInfo.isBatteryDefender = true;
         doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
 
         BatteryTip batteryTip = mDockDefenderDetector.detect();
@@ -131,7 +131,7 @@
     @Test
     public void testDetect_overheatedTrueAndDockDefenderNotTriggered_dockDefenderDisabled() {
         doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
-        mBatteryInfo.isOverheated = true;
+        mBatteryInfo.isBatteryDefender = true;
 
         BatteryTip batteryTip = mDockDefenderDetector.detect();
 
diff --git a/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java b/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java
index 111ee5a..16d51be 100644
--- a/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java
+++ b/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java
@@ -18,19 +18,32 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.Activity;
+import android.app.IActivityManager;
 import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.LocaleList;
+import android.view.MotionEvent;
 import android.view.View;
 import android.widget.TextView;
 
 import androidx.appcompat.app.AlertDialog;
 import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentTransaction;
 
 import com.android.internal.app.LocaleStore;
 import com.android.settings.R;
 import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.shadow.ShadowActivityManager;
 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
 
 import org.junit.After;
@@ -45,22 +58,42 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.util.ReflectionHelpers;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Locale;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowAlertDialogCompat.class)
+@Config(shadows = {ShadowAlertDialogCompat.class, ShadowActivityManager.class})
 public class LocaleListEditorTest {
 
+    private static final String ARG_DIALOG_TYPE = "arg_dialog_type";
+    private static final String TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT = "dialog_confirm_system_default";
+    private static final String TAG_DIALOG_NOT_AVAILABLE = "dialog_not_available_locale";
+    private static final int DIALOG_CONFIRM_SYSTEM_DEFAULT = 1;
+    private static final int REQUEST_CONFIRM_SYSTEM_DEFAULT = 1;
+
     private LocaleListEditor mLocaleListEditor;
 
     private Context mContext;
     private FragmentActivity mActivity;
+    private List mLocaleList;
+    private Intent mIntent = new Intent();
 
     @Mock
     private LocaleDragAndDropAdapter mAdapter;
+    @Mock
+    private LocaleStore.LocaleInfo mLocaleInfo;
+    @Mock
+    private FragmentManager mFragmentManager;
+    @Mock
+    private FragmentTransaction mFragmentTransaction;
+    @Mock
+    private View mView;
+    @Mock
+    private IActivityManager mActivityService;
 
     @Before
-    public void setUp() {
+    public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         mContext = RuntimeEnvironment.application;
         mLocaleListEditor = spy(new LocaleListEditor());
@@ -74,6 +107,8 @@
         ReflectionHelpers.setField(mLocaleListEditor, "mUserManager",
                 RuntimeEnvironment.application.getSystemService(Context.USER_SERVICE));
         ReflectionHelpers.setField(mLocaleListEditor, "mAdapter", mAdapter);
+        ReflectionHelpers.setField(mLocaleListEditor, "mFragmentManager", mFragmentManager);
+        when(mFragmentManager.beginTransaction()).thenReturn(mFragmentTransaction);
         FakeFeatureFactory.setupForTest();
     }
 
@@ -174,4 +209,65 @@
         assertThat(result.getLocale().getUnicodeLocaleType("fw")).isEqualTo("wed");
         assertThat(result.getLocale().getUnicodeLocaleType("mu")).isEqualTo("celsius");
     }
+
+    @Test
+    public void onActivityResult_ResultCodeIsOk_showNotAvailableDialog() {
+        Bundle bundle = new Bundle();
+        bundle.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT);
+        mIntent.putExtras(bundle);
+        setUpLocaleConditions();
+        mLocaleListEditor.onActivityResult(REQUEST_CONFIRM_SYSTEM_DEFAULT, Activity.RESULT_OK,
+                mIntent);
+
+        verify(mFragmentTransaction).add(any(LocaleDialogFragment.class),
+                eq(TAG_DIALOG_NOT_AVAILABLE));
+    }
+
+    @Test
+    public void onActivityResult_ResultCodeIsCancel_notifyAdapterListChanged() {
+        Bundle bundle = new Bundle();
+        bundle.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT);
+        mIntent.putExtras(bundle);
+        setUpLocaleConditions();
+        mLocaleListEditor.onActivityResult(REQUEST_CONFIRM_SYSTEM_DEFAULT, Activity.RESULT_CANCELED,
+                mIntent);
+
+        verify(mAdapter).notifyListChanged(mLocaleInfo);
+    }
+
+    @Test
+    public void onTouch_dragDifferentLocaleToTop_showConfirmDialog() throws Exception {
+        MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0.0f, 0.0f, 0);
+        setUpLocaleConditions();
+        final Configuration config = new Configuration();
+        config.setLocales((LocaleList.forLanguageTags("zh-TW,en-US")));
+        when(mActivityService.getConfiguration()).thenReturn(config);
+        when(mAdapter.getFeedItemList()).thenReturn(mLocaleList);
+        mLocaleListEditor.onTouch(mView, event);
+
+        verify(mFragmentTransaction).add(any(LocaleDialogFragment.class),
+                eq(TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT));
+    }
+
+    @Test
+    public void onTouch_dragSameLocaleToTop_updateAdapter() throws Exception {
+        MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0.0f, 0.0f, 0);
+        setUpLocaleConditions();
+        final Configuration config = new Configuration();
+        config.setLocales((LocaleList.forLanguageTags("en-US,zh-TW")));
+        when(mActivityService.getConfiguration()).thenReturn(config);
+        when(mAdapter.getFeedItemList()).thenReturn(mLocaleList);
+        mLocaleListEditor.onTouch(mView, event);
+
+        verify(mAdapter).doTheUpdate();
+    }
+
+    private void setUpLocaleConditions() {
+        ShadowActivityManager.setService(mActivityService);
+        mLocaleList = new ArrayList<>();
+        mLocaleList.add(mLocaleInfo);
+        when(mLocaleInfo.getFullNameNative()).thenReturn("English");
+        when(mLocaleInfo.getLocale()).thenReturn(LocaleList.forLanguageTags("en-US").get(0));
+        when(mAdapter.getFeedItemList()).thenReturn(mLocaleList);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
index 5310ae0..8d6d2d9 100644
--- a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
@@ -133,18 +133,12 @@
         assertThat(mController.isAvailable()).isFalse();
     }
 
-    @Ignore
     @Test
-    public void getSummary_noSubscriptions_correctSummaryAndClickHandler() {
+    public void getSummary_noSubscriptions_returnSummaryCorrectly() {
         mController.displayPreference(mPreferenceScreen);
         mController.onResume();
-        assertThat(mController.getSummary()).isEqualTo("Add a network");
 
-        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
-        doNothing().when(mContext).startActivity(intentCaptor.capture());
-        mPreference.getOnPreferenceClickListener().onPreferenceClick(mPreference);
-        assertThat(intentCaptor.getValue().getAction()).isEqualTo(
-                EuiccManager.ACTION_PROVISION_EMBEDDED_SUBSCRIPTION);
+        assertThat(mController.getSummary()).isEqualTo("Add a network");
     }
 
     @Test
@@ -300,15 +294,13 @@
         assertThat(captor.getValue()).isFalse();
     }
 
-    @Ignore
     @Test
-    public void onResume_noSubscriptionEsimDisabled_isDisabled() {
+    public void onAvailableSubInfoChanged_noSubscriptionEsimDisabled_isDisabled() {
         Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
-        SubscriptionUtil.setAvailableSubscriptionsForTesting(null);
         when(mEuiccManager.isEnabled()).thenReturn(false);
         mController.displayPreference(mPreferenceScreen);
 
-        mController.onResume();
+        mController.onAvailableSubInfoChanged(null);
 
         assertThat(mPreference.isEnabled()).isFalse();
     }
diff --git a/tests/robotests/src/com/android/settings/slices/SlicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/slices/SlicePreferenceControllerTest.java
index 65eaddd..e8bd27d 100644
--- a/tests/robotests/src/com/android/settings/slices/SlicePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SlicePreferenceControllerTest.java
@@ -18,8 +18,10 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.net.Uri;
@@ -43,11 +45,11 @@
     private LiveData<Slice> mLiveData;
     @Mock
     private SlicePreference mSlicePreference;
+
     private Context mContext;
     private SlicePreferenceController mController;
     private Uri mUri;
 
-
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
@@ -78,11 +80,31 @@
 
     @Test
     public void onStop_unregisterObserver() {
+        when(mLiveData.hasActiveObservers()).thenReturn(true);
+        mController.onStart();
+
         mController.onStop();
         verify(mLiveData).removeObserver(mController);
     }
 
     @Test
+    public void onStop_noActiveObservers_notUnregisterObserver() {
+        when(mLiveData.hasActiveObservers()).thenReturn(false);
+        mController.onStart();
+
+        mController.onStop();
+        verify(mLiveData, never()).removeObserver(mController);
+    }
+
+    @Test
+    public void onStop_notRegisterObserver_notUnregisterObserver() {
+        when(mLiveData.hasActiveObservers()).thenReturn(true);
+
+        mController.onStop();
+        verify(mLiveData, never()).removeObserver(mController);
+    }
+
+    @Test
     public void onChanged_nullSlice_updateSlice() {
         mController.onChanged(null);
 
diff --git a/tests/unit/src/com/android/settings/biometrics/face/FaceUpdaterTest.java b/tests/unit/src/com/android/settings/biometrics/face/FaceUpdaterTest.java
index a49b4a6..66514ac 100644
--- a/tests/unit/src/com/android/settings/biometrics/face/FaceUpdaterTest.java
+++ b/tests/unit/src/com/android/settings/biometrics/face/FaceUpdaterTest.java
@@ -39,6 +39,7 @@
 import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -152,6 +153,7 @@
         verify(mSafetyCenterManagerWrapper, never()).isEnabled(any());
     }
 
+    @Ignore("b/282413778")
     @Test
     public void enroll_secondVersion_onEnrollmentCallbacks_triggerGivenCallback() {
         ArgumentCaptor<FaceManager.EnrollmentCallback> callbackCaptor =
@@ -180,6 +182,7 @@
                 .onEnrollmentFrame(HELP_CODE, HELP_MESSAGE, CELL, STAGE, PAN, TILT, DISTANCE);
     }
 
+    @Ignore("b/282413778")
     @Test
     public void enroll_secondVersion_onEnrollmentSuccess_invokedInteractionWithSafetyCenter() {
         ArgumentCaptor<FaceManager.EnrollmentCallback> callbackCaptor =
@@ -201,6 +204,7 @@
         verify(mSafetyCenterManagerWrapper).isEnabled(mContext);
     }
 
+    @Ignore("b/282413778")
     @Test
     public void enroll_secondVersion_onEnrollmentNotYetFinished_didntInvokeInteractionWithSafetyCenter() {
         ArgumentCaptor<FaceManager.EnrollmentCallback> callbackCaptor =
diff --git a/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java b/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java
index b0998c0..824954d 100644
--- a/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java
+++ b/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java
@@ -17,8 +17,8 @@
 package com.android.settings.localepicker;
 
 import static com.android.settings.localepicker.LocaleDialogFragment.ARG_DIALOG_TYPE;
-import static com.android.settings.localepicker.LocaleDialogFragment.ARG_RESULT_RECEIVER;
 import static com.android.settings.localepicker.LocaleDialogFragment.ARG_TARGET_LOCALE;
+import static com.android.settings.localepicker.LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -27,12 +27,9 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
-import android.app.Activity;
 import android.app.settings.SettingsEnums;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.os.Bundle;
-import android.os.ResultReceiver;
 
 import androidx.test.annotation.UiThreadTest;
 import androidx.test.core.app.ApplicationProvider;
@@ -55,6 +52,7 @@
     public final MockitoRule mockito = MockitoJUnit.rule();
 
     private Context mContext;
+    private LocaleListEditor mLocaleListEditor;
     private LocaleDialogFragment mDialogFragment;
     private FakeFeatureFactory mFeatureFactory;
 
@@ -62,30 +60,30 @@
     public void setUp() throws Exception {
         mContext = ApplicationProvider.getApplicationContext();
         mDialogFragment = new LocaleDialogFragment();
+        mLocaleListEditor = spy(new LocaleListEditor());
         mFeatureFactory = FakeFeatureFactory.setupForTest();
     }
 
-    private void setArgument(
-            int type, ResultReceiver receiver) {
+    private void setArgument(int type) {
         LocaleStore.LocaleInfo localeInfo = LocaleStore.getLocaleInfo(Locale.ENGLISH);
         Bundle args = new Bundle();
         args.putInt(ARG_DIALOG_TYPE, type);
         args.putSerializable(ARG_TARGET_LOCALE, localeInfo);
-        args.putParcelable(ARG_RESULT_RECEIVER, receiver);
         mDialogFragment.setArguments(args);
     }
 
     @Test
     public void getDialogContent_confirmSystemDefault_has2ButtonText() {
-        setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, null);
+        setArgument(DIALOG_CONFIRM_SYSTEM_DEFAULT);
         LocaleDialogFragment.LocaleDialogController controller =
-                new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
+                mDialogFragment.getLocaleDialogController(mContext, mDialogFragment,
+                        mLocaleListEditor);
 
         LocaleDialogFragment.LocaleDialogController.DialogContent dialogContent =
                 controller.getDialogContent();
 
         assertEquals(ResourcesUtils.getResourcesString(
-                mContext, "button_label_confirmation_of_system_locale_change"),
+                        mContext, "button_label_confirmation_of_system_locale_change"),
                 dialogContent.mPositiveButton);
         assertEquals(ResourcesUtils.getResourcesString(mContext, "cancel"),
                 dialogContent.mNegativeButton);
@@ -93,9 +91,10 @@
 
     @Test
     public void getDialogContent_unavailableLocale_has1ButtonText() {
-        setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE, null);
+        setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE);
         LocaleDialogFragment.LocaleDialogController controller =
-                new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
+                mDialogFragment.getLocaleDialogController(mContext, mDialogFragment,
+                        mLocaleListEditor);
 
         LocaleDialogFragment.LocaleDialogController.DialogContent dialogContent =
                 controller.getDialogContent();
@@ -106,37 +105,8 @@
     }
 
     @Test
-    public void onClick_clickPositiveButton_sendOK() {
-        ResultReceiver resultReceiver = spy(new ResultReceiver(null));
-        setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, resultReceiver);
-        LocaleDialogFragment.LocaleDialogController controller =
-                new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
-
-        controller.onClick(null, DialogInterface.BUTTON_POSITIVE);
-
-        verify(resultReceiver).send(eq(Activity.RESULT_OK), any());
-        verify(mFeatureFactory.metricsFeatureProvider).action(
-                mContext, SettingsEnums.ACTION_CHANGE_LANGUAGE, true);
-    }
-
-    @Test
-    public void onClick_clickNegativeButton_sendCancel() {
-        ResultReceiver resultReceiver = spy(new ResultReceiver(null));
-        setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, resultReceiver);
-        LocaleDialogFragment.LocaleDialogController controller =
-                new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
-
-        controller.onClick(null, DialogInterface.BUTTON_NEGATIVE);
-
-        verify(resultReceiver).send(eq(Activity.RESULT_CANCELED), any());
-        verify(mFeatureFactory.metricsFeatureProvider).action(
-                mContext, SettingsEnums.ACTION_CHANGE_LANGUAGE, false);
-    }
-
-    @Test
     public void getMetricsCategory_systemLocaleChange() {
-        setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, null);
-
+        setArgument(DIALOG_CONFIRM_SYSTEM_DEFAULT);
         int result = mDialogFragment.getMetricsCategory();
 
         assertEquals(SettingsEnums.DIALOG_SYSTEM_LOCALE_CHANGE, result);
@@ -144,8 +114,7 @@
 
     @Test
     public void getMetricsCategory_unavailableLocale() {
-        setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE, null);
-
+        setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE);
         int result = mDialogFragment.getMetricsCategory();
 
         assertEquals(SettingsEnums.DIALOG_SYSTEM_LOCALE_UNAVAILABLE, result);
diff --git a/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtilsTest.java b/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtilsTest.java
index 85272e4..c9571be 100644
--- a/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtilsTest.java
+++ b/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtilsTest.java
@@ -22,6 +22,7 @@
 import android.os.LocaleList;
 import android.provider.Settings;
 
+import androidx.core.text.util.LocalePreferences;
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.internal.app.LocalePicker;