Merge "Changes to the trigger segment" into main
diff --git a/aconfig/accessibility/accessibility_flags.aconfig b/aconfig/accessibility/accessibility_flags.aconfig
index 3ed618b..3092b8f 100644
--- a/aconfig/accessibility/accessibility_flags.aconfig
+++ b/aconfig/accessibility/accessibility_flags.aconfig
@@ -21,6 +21,16 @@
 }
 
 flag {
+  name: "check_prebundled_is_preinstalled"
+  namespace: "accessibility"
+  description: "Checks that all 'prebundled' components, used for grouping, are also preinstalled"
+  bug: "353888087"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
   name: "edit_shortcuts_in_full_screen"
   namespace: "accessibility"
   description: "Show the edit shorcuts screen in full screen, since the shortcut options are increasing."
diff --git a/res/layout-land/bluetooth_audio_streams_qr_code.xml b/res/layout-land/bluetooth_audio_streams_qr_code.xml
new file mode 100644
index 0000000..b35bc65
--- /dev/null
+++ b/res/layout-land/bluetooth_audio_streams_qr_code.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal"
+    android:padding="25dp"
+    android:baselineAligned="false">
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@android:id/summary"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="start"
+            android:textSize="15sp"
+            android:textColor="?android:attr/textColorPrimary" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:gravity="center"
+        android:orientation="vertical">
+
+        <ImageView
+            android:id="@+id/qrcode_view"
+            android:layout_width="@dimen/qrcode_size"
+            android:layout_height="@dimen/qrcode_size"
+            android:contentDescription="@string/audio_streams_qr_code_page_image_label"
+            android:focusable="true" />
+
+        <TextView
+            android:id="@+id/password"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="15sp"
+            android:textColor="?android:attr/textColorPrimary" />
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout-land/qrcode_scanner_fragment.xml b/res/layout-land/qrcode_scanner_fragment.xml
new file mode 100644
index 0000000..0e563e3
--- /dev/null
+++ b/res/layout-land/qrcode_scanner_fragment.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal">
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:orientation="vertical">
+            <TextView
+                android:id="@android:id/summary"
+                style="@style/QrCodeScanner"
+                android:gravity="center"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+        </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:gravity="center"
+        android:orientation="vertical">
+
+        <FrameLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top"
+            android:gravity="center"
+            android:clipChildren="true"
+            android:contentDescription="@string/audio_streams_qr_code_scanner_label"
+            android:focusable="true">
+            <TextureView
+                android:id="@+id/preview_view"
+                android:layout_marginStart="@dimen/qrcode_preview_margin"
+                android:layout_marginEnd="@dimen/qrcode_preview_margin"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/qrcode_preview_size"/>
+        </FrameLayout>
+
+        <TextView
+            android:id="@+id/error_message"
+            style="@style/TextAppearance.ErrorText"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="16dp"
+            android:gravity="center"
+            android:layout_gravity="center"
+            android:visibility="invisible"/>
+
+    </LinearLayout>
+
+
+</LinearLayout>
+
diff --git a/res/layout/advanced_bt_entity_sub.xml b/res/layout/advanced_bt_entity_sub.xml
index 90ac456..dd8e43a 100644
--- a/res/layout/advanced_bt_entity_sub.xml
+++ b/res/layout/advanced_bt_entity_sub.xml
@@ -45,7 +45,7 @@
             android:layout_gravity="center"
             android:indeterminate="false"
             app:trackColor="@android:color/transparent"
-            app:indicatorColor="@color/bluetooth_battery_ring_indicator_color"
+            app:indicatorColor="@color/settingslib_materialColorPrimary"
             app:trackThickness="4dp"
             app:indicatorSize="76dp"
             app:indicatorInset="0dp"
diff --git a/res/xml/bluetooth_audio_streams_qr_code.xml b/res/layout/bluetooth_audio_streams_qr_code.xml
similarity index 91%
rename from res/xml/bluetooth_audio_streams_qr_code.xml
rename to res/layout/bluetooth_audio_streams_qr_code.xml
index 5ec5505..fd521fe 100644
--- a/res/xml/bluetooth_audio_streams_qr_code.xml
+++ b/res/layout/bluetooth_audio_streams_qr_code.xml
@@ -47,7 +47,9 @@
             <ImageView
                 android:id="@+id/qrcode_view"
                 android:layout_width="@dimen/qrcode_size"
-                android:layout_height="@dimen/qrcode_size"/>
+                android:layout_height="@dimen/qrcode_size"
+                android:contentDescription="@string/audio_streams_qr_code_page_image_label"
+                android:focusable="true"/>
 
             <TextView
                 android:id="@+id/password"
diff --git a/res/layout/qrcode_scanner_fragment.xml b/res/layout/qrcode_scanner_fragment.xml
index 4f748c5..72049a4 100644
--- a/res/layout/qrcode_scanner_fragment.xml
+++ b/res/layout/qrcode_scanner_fragment.xml
@@ -55,7 +55,9 @@
             android:layout_height="wrap_content"
             android:layout_gravity="top"
             android:gravity="center"
-            android:clipChildren="true">
+            android:clipChildren="true"
+            android:contentDescription="@string/audio_streams_qr_code_scanner_label"
+            android:focusable="true">
             <TextureView
                 android:id="@+id/preview_view"
                 android:layout_marginStart="@dimen/qrcode_preview_margin"
diff --git a/res/values/colors.xml b/res/values/colors.xml
index b0de870..6d92526 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -218,7 +218,4 @@
 
     <!-- Switch bar disabled state color-->
     <color name="switch_bar_state_disabled_color">#1F1F1F1F</color>
-
-    <!-- Battery ring indicator color in bluetooth device details -->
-    <color name="bluetooth_battery_ring_indicator_color">#9ED582</color>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 08d29ea..84eb74f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -5477,6 +5477,8 @@
     <string name="daltonizer_mode_grayscale_title">Grayscale</string>
     <!-- Title shown for settings that controls color correction saturation level [CHAR LIMIT=45] -->
     <string name="daltonizer_saturation_title">Intensity</string>
+    <!-- The summary shown for settings that controls color correction intensity/saturation level. It is shown when intensity slider is grayed out and is not usable and it explains why it's not usable to the user. [CHAR LIMIT=NONE] -->
+    <string name="daltonizer_saturation_unavailable_summary">Unavailable for grayscale mode or when color correction is disabled</string>
     <!-- Summary shown for deuteranomaly (red-green color blindness) [CHAR LIMIT=45] -->
     <string name="daltonizer_mode_deuteranomaly_summary">Green weak, deuteranomaly</string>
     <!-- Summary shown for protanomaly (red-green color blindness) [CHAR LIMIT=45] -->
@@ -12253,16 +12255,11 @@
     <!-- Default title for the settings panel [CHAR LIMIT=NONE] -->
     <string name="settings_panel_title">Settings Panel</string>
 
-    <!-- Title for enabling freeform windows (desktop mode) developer option toggle [CHAR LIMIT=50] -->
-    <string name="enable_desktop_mode">Enable freeform windows</string>
-    <!-- Summary for enabling freeform windows (desktop mode) developer option toggle [CHAR LIMIT=NONE] -->
-    <string name="enable_desktop_mode_summary">Enable support for freeform windows.</string>
+    <!-- Title for a toggle that enables freeform windowing experiences. Freeform windowing experiences are features involving apps running in resizable windows. [CHAR LIMIT=50] -->
+    <string name="enable_desktop_mode">Enable freeform windowing experiences</string>
 
-    <!-- TODO(b/348193756): Rename resources for this toggle to indicate that it is for secondary display -->
-    <!-- Title for enabling freeform windows (desktop mode) on secondary display developer option toggle  [CHAR LIMIT=50] -->
-    <string name="force_desktop_mode">Enable freeform windowing on second display</string>
-    <!-- Summary for enabling freeform windows (desktop mode) on secondary display developer option toggle [CHAR LIMIT=NONE] -->
-    <string name="force_desktop_mode_summary">Enable freeform windows only on secondary display.</string>
+    <!-- Title for a toggle that enables desktop mode on secondary display. [CHAR LIMIT=50] -->
+    <string name="enable_desktop_mode_on_secondary_display">Enable desktop mode on secondary display</string>
 
     <!-- UI debug setting: enable non-resizables in multi window [CHAR LIMIT=60] -->
     <string name="enable_non_resizable_multi_window">Enable non-resizable in multi window</string>
@@ -13225,14 +13222,12 @@
     <!-- The content description for accessibility tools of the customize button. It specifies which screensaver the user is customizing [CHAR LIMIT=NONE] -->
     <string name="customize_button_description">Customize <xliff:g id="screensaver_name" example="Art Gallery">%1$s</xliff:g></string>
 
-    <!-- Dialog body text used to explain a reboot is required after enabling freeform support for
-    it to work [CHAR LIMIT=none] -->
-    <string name="reboot_dialog_enable_freeform_support">A reboot is required to enable legacy freeform windowing support.</string>
-    <!-- Dialog body text used to explain a reboot is required after overriding freeform windowing (desktop mode) support. [CHAR LIMIT=none] -->
-    <string name="reboot_dialog_override_desktop_mode">A reboot is required to change freeform windowing support.</string>
-    <!-- Dialog body text used to explain a reboot is required after forcing freeform windowing (desktop mode) on
-    secondary displays. [CHAR LIMIT=none] -->
-    <string name="reboot_dialog_force_desktop_mode">A reboot is required to force freeform windowing on secondary displays.</string>
+    <!-- Dialog body text used to explain a reboot is required after enabling freeform window support for it to work. Freeform window is when an app runs in a resizable window. [CHAR LIMIT=none] -->
+    <string name="reboot_dialog_enable_freeform_support">A reboot is required to enable freeform window support.</string>
+    <!-- Dialog body text used to explain a reboot is required after updating availability of freeform windowing experiences. Freeform windowing experiences are features involving apps running in resizable windows. [CHAR LIMIT=none] -->
+    <string name="reboot_dialog_override_desktop_mode">A reboot is required to update availability of freeform windowing experiences.</string>
+    <!-- Dialog body text used to explain a reboot is required after enabling desktop mode on secondary displays. [CHAR LIMIT=none] -->
+    <string name="reboot_dialog_enable_desktop_mode_on_secondary_display">A reboot is required to enable desktop mode on secondary displays.</string>
     <!-- Text on the dialog button to reboot the device now [CHAR LIMIT=50] -->
     <string name="reboot_dialog_reboot_now">Reboot now</string>
     <!-- Text on the dialog button to reboot the device later [CHAR LIMIT=50] -->
@@ -13757,6 +13752,10 @@
     <string name="audio_streams_main_page_qr_code_scanner_summary">Scan an audio stream QR code to listen with <xliff:g example="LE headset" id="device_name">%1$s</xliff:g></string>
     <!-- Le audio streams password dialog  [CHAR LIMIT=NONE] -->
     <string name="audio_streams_main_page_password_dialog_cannot_edit">Can\u0027t edit password while sharing. To change the password, first turn off audio sharing.</string>
+    <!-- Text for audio sharing qrcode image [CHAR LIMIT=none]-->
+    <string name="audio_streams_qr_code_page_image_label">QR code</string>
+    <!-- Text for audio sharing qrcode scanner [CHAR LIMIT=none]-->
+    <string name="audio_streams_qr_code_scanner_label">QR code scanner</string>
 
 
     <!-- url for learning more about bluetooth audio sharing -->
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index 9420f59..88abadb 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -739,18 +739,15 @@
 
         <SwitchPreferenceCompat
             android:key="override_desktop_mode_features"
-            android:title="@string/enable_desktop_mode"
-            android:summary="@string/enable_desktop_mode_summary" />
+            android:title="@string/enable_desktop_mode" />
 
         <SwitchPreferenceCompat
             android:key="enable_freeform_support"
-            android:title="@string/enable_freeform_support"
-            android:summary="@string/enable_freeform_support_summary" />
+            android:title="@string/enable_freeform_support" />
 
         <SwitchPreferenceCompat
             android:key="force_desktop_mode_on_external_displays"
-            android:title="@string/force_desktop_mode"
-            android:summary="@string/force_desktop_mode_summary" />
+            android:title="@string/enable_desktop_mode_on_secondary_display"/>
 
         <SwitchPreferenceCompat
             android:key="enable_non_resizable_multi_window"
diff --git a/src/com/android/settings/MainClear.java b/src/com/android/settings/MainClear.java
index 9d219d7..9dadcb9 100644
--- a/src/com/android/settings/MainClear.java
+++ b/src/com/android/settings/MainClear.java
@@ -182,10 +182,13 @@
         }
 
         if (requestCode == KEYGUARD_REQUEST) {
+            final int userId = getActivity().getUserId();
             if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(),
                     false /* biometricsSuccessfullyAuthenticated */,
-                    false /* biometricsAuthenticationRequested */)) {
-                Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRICS_REQUEST);
+                    false /* biometricsAuthenticationRequested */,
+                    userId)) {
+                Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRICS_REQUEST,
+                        userId);
                 return;
             }
         }
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index e94769a..add5604 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -1487,23 +1487,25 @@
 
     /**
      * Request biometric authentication if all requirements for mandatory biometrics is satisfied.
-     * @param context of the corresponding activity/fragment
+     *
+     * @param context                             of the corresponding activity/fragment
      * @param biometricsSuccessfullyAuthenticated if the user has already authenticated using
      *                                            biometrics
-     * @param biometricsAuthenticationRequested if the activity/fragment has already requested for
-     *                                          biometric prompt
+     * @param biometricsAuthenticationRequested   if the activity/fragment has already requested for
+     *                                            biometric prompt
+     * @param userId                              user id for the authentication request
      * @return true if all requirements for mandatory biometrics is satisfied
      */
     public static boolean requestBiometricAuthenticationForMandatoryBiometrics(
             @NonNull Context context,
             boolean biometricsSuccessfullyAuthenticated,
-            boolean biometricsAuthenticationRequested) {
+            boolean biometricsAuthenticationRequested, int userId) {
         final BiometricManager biometricManager = context.getSystemService(BiometricManager.class);
         if (biometricManager == null) {
             Log.e(TAG, "Biometric Manager is null.");
             return false;
         }
-        final int status = biometricManager.canAuthenticate(
+        final int status = biometricManager.canAuthenticate(userId,
                 BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
         return android.hardware.biometrics.Flags.mandatoryBiometrics()
                 && status == BiometricManager.BIOMETRIC_SUCCESS
@@ -1513,15 +1515,16 @@
 
     /**
      * Launch biometric prompt for mandatory biometrics. Call
-     * {@link #requestBiometricAuthenticationForMandatoryBiometrics(Context, boolean, boolean)}
+     * {@link #requestBiometricAuthenticationForMandatoryBiometrics(Context, boolean, boolean, int)}
      * to check if all requirements for mandatory biometrics is satisfied
      * before launching biometric prompt.
      *
-     * @param fragment corresponding fragment of the surface
+     * @param fragment    corresponding fragment of the surface
      * @param requestCode for starting the new activity
+     * @param userId      user id for the authentication request
      */
     public static void launchBiometricPromptForMandatoryBiometrics(@NonNull Fragment fragment,
-            int requestCode) {
+            int requestCode, int userId) {
         final Intent intent = new Intent();
         intent.putExtra(BIOMETRIC_PROMPT_AUTHENTICATORS,
                 BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
@@ -1529,8 +1532,10 @@
                 fragment.getString(R.string.cancel));
         intent.putExtra(KeyguardManager.EXTRA_DESCRIPTION,
                 fragment.getString(R.string.mandatory_biometrics_prompt_description));
+        intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_ALLOW_ANY_USER, true);
+        intent.putExtra(EXTRA_USER_ID, userId);
         intent.setClassName(SETTINGS_PACKAGE_NAME,
-                ConfirmDeviceCredentialActivity.class.getName());
+                ConfirmDeviceCredentialActivity.InternalActivity.class.getName());
         fragment.startActivityForResult(intent, requestCode);
     }
 
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index 23f8ec7..d01806a 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -75,7 +75,8 @@
     private static final String CATEGORY_AUDIO = "audio_category";
     private static final String CATEGORY_SPEECH = "speech_category";
     private static final String CATEGORY_DISPLAY = "display_category";
-    private static final String CATEGORY_DOWNLOADED_SERVICES = "user_installed_services_category";
+    @VisibleForTesting
+    static final String CATEGORY_DOWNLOADED_SERVICES = "user_installed_services_category";
     private static final String CATEGORY_KEYBOARD_OPTIONS = "physical_keyboard_options_category";
     @VisibleForTesting
     static final String CATEGORY_INTERACTION_CONTROL = "interaction_control_category";
@@ -380,6 +381,7 @@
     }
 
     protected void updateServicePreferences() {
+        final AccessibilityManager a11yManager = AccessibilityManager.getInstance(getPrefContext());
         // Since services category is auto generated we have to do a pass
         // to generate it since services can come and go and then based on
         // the global accessibility state to decided whether it is enabled.
@@ -410,8 +412,18 @@
                 AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM,
                 mCategoryToPrefCategoryMap.get(CATEGORY_INTERACTION_CONTROL));
 
-        final List<RestrictedPreference> preferenceList = getInstalledAccessibilityList(
-                getPrefContext());
+        final List<AccessibilityShortcutInfo> installedShortcutList =
+                a11yManager.getInstalledAccessibilityShortcutListAsUser(getPrefContext(),
+                        UserHandle.myUserId());
+        final List<AccessibilityServiceInfo> modifiableInstalledServiceList =
+                new ArrayList<>(a11yManager.getInstalledAccessibilityServiceList());
+        final List<RestrictedPreference> preferenceList = getInstalledAccessibilityPreferences(
+                getPrefContext(), installedShortcutList, modifiableInstalledServiceList);
+
+        if (Flags.checkPrebundledIsPreinstalled()) {
+            removeNonPreinstalledComponents(mPreBundledServiceComponentToCategoryMap,
+                    installedShortcutList, modifiableInstalledServiceList);
+        }
 
         final PreferenceCategory downloadedServicesCategory =
                 mCategoryToPrefCategoryMap.get(CATEGORY_DOWNLOADED_SERVICES);
@@ -456,13 +468,21 @@
         updatePreferenceCategoryVisibility(CATEGORY_KEYBOARD_OPTIONS);
     }
 
-    private List<RestrictedPreference> getInstalledAccessibilityList(Context context) {
-        final AccessibilityManager a11yManager = AccessibilityManager.getInstance(context);
+    /**
+     * Gets a list of {@link RestrictedPreference}s for the provided a11y shortcuts and services.
+     *
+     * <p>{@code modifiableInstalledServiceList} may be modified to remove any entries with
+     * matching package name and label as an entry in {@code installedShortcutList}.
+     *
+     * @param installedShortcutList          A list of installed {@link AccessibilityShortcutInfo}s.
+     * @param modifiableInstalledServiceList A modifiable list of installed
+     *                                       {@link AccessibilityServiceInfo}s.
+     */
+    private List<RestrictedPreference> getInstalledAccessibilityPreferences(Context context,
+            List<AccessibilityShortcutInfo> installedShortcutList,
+            List<AccessibilityServiceInfo> modifiableInstalledServiceList) {
         final RestrictedPreferenceHelper preferenceHelper = new RestrictedPreferenceHelper(context);
 
-        final List<AccessibilityShortcutInfo> installedShortcutList =
-                a11yManager.getInstalledAccessibilityShortcutListAsUser(context,
-                        UserHandle.myUserId());
         final List<AccessibilityActivityPreference> activityList =
                 preferenceHelper.createAccessibilityActivityPreferenceList(installedShortcutList);
         final Set<Pair<String, CharSequence>> packageLabelPairs =
@@ -471,16 +491,14 @@
                                 a11yActivityPref.getPackageName(), a11yActivityPref.getLabel())
                         ).collect(Collectors.toSet());
 
-        // Remove duplicate item here, new a ArrayList to copy unmodifiable list result
-        // (getInstalledAccessibilityServiceList).
-        final List<AccessibilityServiceInfo> installedServiceList = new ArrayList<>(
-                a11yManager.getInstalledAccessibilityServiceList());
+        // Remove duplicate A11yServices that are already shown as A11yActivities.
         if (!packageLabelPairs.isEmpty()) {
-            installedServiceList.removeIf(
+            modifiableInstalledServiceList.removeIf(
                     target -> containsPackageAndLabelInList(packageLabelPairs, target));
         }
         final List<RestrictedPreference> serviceList =
-                preferenceHelper.createAccessibilityServicePreferenceList(installedServiceList);
+                preferenceHelper.createAccessibilityServicePreferenceList(
+                        modifiableInstalledServiceList);
 
         final List<RestrictedPreference> preferenceList = new ArrayList<>();
         preferenceList.addAll(activityList);
@@ -489,6 +507,22 @@
         return preferenceList;
     }
 
+    private static void removeNonPreinstalledComponents(
+            Map<ComponentName, PreferenceCategory> componentToCategory,
+            List<AccessibilityShortcutInfo> shortcutInfos,
+            List<AccessibilityServiceInfo> serviceInfos) {
+        for (AccessibilityShortcutInfo info : shortcutInfos) {
+            if (!info.getActivityInfo().applicationInfo.isSystemApp()) {
+                componentToCategory.remove(info.getComponentName());
+            }
+        }
+        for (AccessibilityServiceInfo info : serviceInfos) {
+            if (!info.getResolveInfo().serviceInfo.applicationInfo.isSystemApp()) {
+                componentToCategory.remove(info.getComponentName());
+            }
+        }
+    }
+
     private boolean containsPackageAndLabelInList(
             Set<Pair<String, CharSequence>> packageLabelPairs,
             AccessibilityServiceInfo targetServiceInfo) {
diff --git a/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceController.java b/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceController.java
index 7dcd661..2997185 100644
--- a/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceController.java
+++ b/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceController.java
@@ -17,26 +17,50 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.Looper;
 import android.provider.Settings;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
 import com.android.server.accessibility.Flags;
+import com.android.settings.R;
 import com.android.settings.core.SliderPreferenceController;
 import com.android.settings.widget.SeekBarPreference;
 
 /**
  * The controller of the seekbar preference for the saturation level of color correction.
  */
-public class DaltonizerSaturationSeekbarPreferenceController extends SliderPreferenceController {
+public class DaltonizerSaturationSeekbarPreferenceController
+        extends SliderPreferenceController
+        implements DefaultLifecycleObserver {
 
     private static final int DEFAULT_SATURATION_LEVEL = 7;
     private static final int SATURATION_MAX = 10;
-    private static final int SATURATION_MIN = 0;
+    private static final int SATURATION_MIN = 1;
 
     private int mSliderPosition;
     private final ContentResolver mContentResolver;
 
+    @Nullable
+    private SeekBarPreference mPreference;
+
+    public final ContentObserver mContentObserver = new ContentObserver(
+            new Handler(Looper.getMainLooper())) {
+        @Override
+        public void onChange(boolean selfChange) {
+            if (mPreference != null) {
+                updateState(mPreference);
+            }
+        }
+    };
+
     public DaltonizerSaturationSeekbarPreferenceController(Context context,
             String preferenceKey) {
         super(context, preferenceKey);
@@ -50,9 +74,32 @@
     }
 
     @Override
+    public void onStart(@NonNull LifecycleOwner owner) {
+        if (!isAvailable()) return;
+        mContentResolver.registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER),
+                true,
+                mContentObserver
+        );
+        mContentResolver.registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
+                true,
+                mContentObserver
+        );
+    }
+
+    @Override
+    public void onStop(@NonNull LifecycleOwner owner) {
+        if (!isAvailable()) return;
+        mContentResolver.unregisterContentObserver(mContentObserver);
+        mPreference = null;
+    }
+
+    @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
         SeekBarPreference preference = screen.findPreference(getPreferenceKey());
+        mPreference = preference;
         preference.setMax(getMax());
         preference.setMin(getMin());
         preference.setProgress(mSliderPosition);
@@ -62,7 +109,7 @@
     @Override
     public int getAvailabilityStatus() {
         if (Flags.enableColorCorrectionSaturation()) {
-            return AVAILABLE;
+            return shouldSeekBarEnabled() ? AVAILABLE : DISABLED_DEPENDENT_SETTING;
         }
         return CONDITIONALLY_UNAVAILABLE;
     }
@@ -86,6 +133,21 @@
     }
 
     @Override
+    public void updateState(Preference preference) {
+        if (preference == null) {
+            return;
+        }
+
+        var shouldSeekbarEnabled = shouldSeekBarEnabled();
+        // setSummary not working yet on SeekBarPreference.
+        String summary = shouldSeekbarEnabled
+                ? ""
+                : mContext.getString(R.string.daltonizer_saturation_unavailable_summary);
+        preference.setSummary(summary);
+        preference.setEnabled(shouldSeekbarEnabled);
+    }
+
+    @Override
     public int getMax() {
         return SATURATION_MAX;
     }
@@ -94,4 +156,16 @@
     public int getMin() {
         return SATURATION_MIN;
     }
+
+    private boolean shouldSeekBarEnabled() {
+        int enabled = Settings.Secure.getInt(
+                mContentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0);
+        int mode = Settings.Secure.getInt(
+                mContentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, -1);
+
+        // enabled == 0 is disabled and also default.
+        // mode == 0 is gray scale where saturation level isn't applicable.
+        // mode == -1 is disabled and also default.
+        return enabled != 0 && mode != -1 && mode != 0;
+    }
 }
diff --git a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
index b9a0b93..835f3a8 100644
--- a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
+++ b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
@@ -144,9 +144,10 @@
             launchChooseOrConfirmLock();
         } else if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(
                 getActivity(), mBiometricsSuccessfullyAuthenticated,
-                mBiometricsAuthenticationRequested)) {
+                mBiometricsAuthenticationRequested, mUserId)) {
             mBiometricsAuthenticationRequested = true;
-            Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST);
+            Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST,
+                    mUserId);
         }
 
         updateUnlockPhonePreferenceSummary();
@@ -161,10 +162,11 @@
     public void onResume() {
         super.onResume();
         if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(),
-                mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested)
+                mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested, mUserId)
                 && mGkPwHandle != 0L) {
             mBiometricsAuthenticationRequested = true;
-            Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST);
+            Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST,
+                    mUserId);
         }
         if (!mConfirmCredential) {
             mDoNotFinishActivity = false;
diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java
index 2a0dd83..305d670 100644
--- a/src/com/android/settings/biometrics/face/FaceSettings.java
+++ b/src/com/android/settings/biometrics/face/FaceSettings.java
@@ -289,9 +289,11 @@
                 finish();
             }
         } else if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(),
-                mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested)) {
+                mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested,
+                mUserId)) {
             mBiometricsAuthenticationRequested = true;
-            Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST);
+            Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST,
+                    mUserId);
         } else {
             mAttentionController.setToken(mToken);
             mEnrollController.setToken(mToken);
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index c4bbcde..815c08e 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -485,9 +485,11 @@
                     mLaunchedConfirm = true;
                     launchChooseOrConfirmLock();
                 } else if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(),
-                        mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested)) {
+                        mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested,
+                        mUserId)) {
                     mBiometricsAuthenticationRequested = true;
-                    Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST);
+                    Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST,
+                            mUserId);
                 } else if (!mHasFirstEnrolled) {
                     mIsEnrolling = true;
                     addFirstFingerprint(null);
@@ -777,9 +779,11 @@
                     .getUdfpsEnrollCalibrator(getActivity().getApplicationContext(), null, null);
 
             if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(),
-                    mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested)) {
+                    mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested,
+                    mUserId)) {
                 mBiometricsAuthenticationRequested = true;
-                Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST);
+                Utils.launchBiometricPromptForMandatoryBiometrics(this,
+                        BIOMETRIC_AUTH_REQUEST, mUserId);
             }
         }
 
diff --git a/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt b/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt
index 215692a..9bc920a 100644
--- a/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt
@@ -16,7 +16,9 @@
 
 package com.android.settings.biometrics.fingerprint2
 
+import android.content.pm.PackageManager
 import android.hardware.fingerprint.FingerprintManager
+import android.os.ServiceManager.ServiceNotFoundException
 import android.view.MotionEvent
 import android.view.accessibility.AccessibilityManager
 import androidx.fragment.app.FragmentActivity
@@ -74,8 +76,15 @@
   private val backgroundDispatcher = executorService.asCoroutineDispatcher()
   private val applicationScope = MainScope()
   private val gateKeeperPasswordProvider = GatekeeperPasswordProvider(LockPatternUtils(context))
-  private val fingerprintManager =
-    context.getSystemService(FragmentActivity.FINGERPRINT_SERVICE) as FingerprintManager?
+  private val fingerprintManager = try {
+    if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+      context.getSystemService(FragmentActivity.FINGERPRINT_SERVICE) as FingerprintManager?
+    } else {
+      null
+    }
+  } catch (exception: ServiceNotFoundException){
+    null
+  }
 
   private val fingerprintSensorRepository: FingerprintSensorRepository =
     FingerprintSensorRepositoryImpl(fingerprintManager, backgroundDispatcher, applicationScope)
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java
index bfccdc4..0a90e7b 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java
@@ -92,6 +92,8 @@
         shareButton.setVisibility(View.VISIBLE);
         shareButton.setImageDrawable(getContext().getDrawable(R.drawable.ic_qrcode_24dp));
         shareButton.setOnClickListener(unused -> launchAudioSharingQrCodeFragment());
+        shareButton.setContentDescription(
+                getContext().getString(R.string.audio_sharing_qrcode_button_label));
     }
 
     private void configureInvisibleStateForQrCodeIcon(ImageButton shareButton, View divider) {
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragment.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragment.java
index e4c0794..47f9c75 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragment.java
@@ -55,7 +55,7 @@
     @Override
     public final View onCreateView(
             LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-        return inflater.inflate(R.xml.bluetooth_audio_streams_qr_code, container, false);
+        return inflater.inflate(R.layout.bluetooth_audio_streams_qr_code, container, false);
     }
 
     @Override
diff --git a/src/com/android/settings/development/DesktopModeSecondaryDisplayPreferenceController.java b/src/com/android/settings/development/DesktopModeSecondaryDisplayPreferenceController.java
index ff513c2..0d3d835 100644
--- a/src/com/android/settings/development/DesktopModeSecondaryDisplayPreferenceController.java
+++ b/src/com/android/settings/development/DesktopModeSecondaryDisplayPreferenceController.java
@@ -69,7 +69,8 @@
                 isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
         if (isEnabled && mFragment != null) {
             RebootConfirmationDialogFragment.show(
-                    mFragment, R.string.reboot_dialog_force_desktop_mode, this);
+                    mFragment, R.string.reboot_dialog_enable_desktop_mode_on_secondary_display,
+                    this);
         }
         return true;
     }
diff --git a/src/com/android/settings/development/FreeformWindowsPreferenceController.java b/src/com/android/settings/development/FreeformWindowsPreferenceController.java
index 7cf7738..c02ffa7 100644
--- a/src/com/android/settings/development/FreeformWindowsPreferenceController.java
+++ b/src/com/android/settings/development/FreeformWindowsPreferenceController.java
@@ -16,8 +16,9 @@
 
 package com.android.settings.development;
 
+import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
+
 import android.content.Context;
-import android.os.Build;
 import android.provider.Settings;
 
 import androidx.annotation.Nullable;
@@ -40,7 +41,8 @@
     @VisibleForTesting
     static final int SETTING_VALUE_ON = 1;
 
-    @Nullable private final DevelopmentSettingsDashboardFragment mFragment;
+    @Nullable
+    private final DevelopmentSettingsDashboardFragment mFragment;
 
     public FreeformWindowsPreferenceController(
             Context context, @Nullable DevelopmentSettingsDashboardFragment fragment) {
@@ -49,6 +51,13 @@
     }
 
     @Override
+    public boolean isAvailable() {
+        // When devices have the system feature FEATURE_FREEFORM_WINDOW_MANAGEMENT, freeform
+        // mode is enabled automatically, and this toggle is not needed.
+        return !mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT);
+    }
+
+    @Override
     public String getPreferenceKey() {
         return ENABLE_FREEFORM_SUPPORT_KEY;
     }
@@ -80,9 +89,4 @@
                 Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, SETTING_VALUE_OFF);
         ((TwoStatePreference) mPreference).setChecked(false);
     }
-
-    @VisibleForTesting
-    String getBuildType() {
-        return Build.TYPE;
-    }
 }
diff --git a/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceController.java b/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceController.java
index 23d4cc6..9f7512c 100644
--- a/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceController.java
+++ b/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceController.java
@@ -30,85 +30,184 @@
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settingslib.development.DeveloperOptionsPreferenceController;
 
+/**
+ * This preference represents the default log level for the Bluetooth stack
+ *
+ * The default log level is captured and held in an Android Log Framework log tag, using "bluetooth"
+ * as the tag name. The Log framework does not provide methods to directly write a log tag value,
+ * but instead leverages special system properties to hold the value of a log tag.
+ *
+ * This preferences aims to keep the selection in sync with the currently set log tag value. It
+ * writes directly to the system properties that hold the level associated with the bluetooth log
+ * tag. It leverages the Log.isLoggable("bluetooth", level) function to discern the current value.
+ * The default level is INFO.
+ *
+ * This value is read once at start of the Bluetooth stack. To use a new value once setting it, be
+ * sure to turn Bluetooth off and back on again.
+ */
 public class BluetoothStackLogPreferenceController extends DeveloperOptionsPreferenceController
         implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+    private static final String TAG = BluetoothStackLogPreferenceController.class.getSimpleName();
+
+    private static final String PREFERENCE_KEY = "bt_stack_log_level";
 
     /* Ensure that the indexes match with bt_stack_log_values and bt_stack_log_entries ordering */
-    private static final String PREFERENCE_KEY = "bt_stack_log_level";
-    @VisibleForTesting static final int BTSTACK_LOG_MODE_VERBOSE_INDEX = 0;
-    @VisibleForTesting static final int BTSTACK_LOG_MODE_DEBUG_INDEX = 1;
-    @VisibleForTesting static final int BTSTACK_LOG_MODE_INFO_INDEX = 2;
-    @VisibleForTesting static final int BTSTACK_LOG_MODE_WARN_INDEX = 3;
-    @VisibleForTesting static final int BTSTACK_LOG_MODE_ERROR_INDEX = 4;
+    private static final int BT_LOG_LEVEL_VERBOSE_INDEX = 0;
+    private static final int BT_LOG_LEVEL_DEBUG_INDEX = 1;
+    private static final int BT_LOG_LEVEL_INFO_INDEX = 2;
+    private static final int BT_LOG_LEVEL_WARN_INDEX = 3;
+    private static final int BT_LOG_LEVEL_ERROR_INDEX = 4;
+    @VisibleForTesting static final int BT_LOG_LEVEL_DEFAULT_INDEX = BT_LOG_LEVEL_INFO_INDEX;
 
-    @VisibleForTesting
-    static final String BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST = "persist.log.tag.bluetooth";
-    static final String BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY = "log.tag.bluetooth";
-    static final String BLUETOOTH_STRING_NAME = "bluetooth";
-    static final int DEFAULT_MODE = BTSTACK_LOG_MODE_INFO_INDEX;
+    private static final String BT_LOG_TAG = "bluetooth";
+    @VisibleForTesting static final String BT_LOG_LEVEL_PROP_PERSIST = "persist.log.tag.bluetooth";
+    @VisibleForTesting static final String BT_LOG_LEVEL_PROP = "log.tag.bluetooth";
 
-    private final String[] mListValues;
-    private final String[] mListEntries;
+    // Values represents the untranslatable log level strings that should be used for writing to
+    // system properties. Entries represents the translatable log level strings that should be used
+    // in the UI to communicate to the user their options for this preference.
+    private String[] mListValues;
+    private String[] mListEntries;
 
-
+    /**
+     * Create a BluetoothStackLogPreferenceController instance
+     */
     public BluetoothStackLogPreferenceController(@NonNull Context context) {
         super(context);
         mListValues = context.getResources().getStringArray(R.array.bt_stack_log_level_values);
         mListEntries = context.getResources().getStringArray(R.array.bt_stack_log_level_entries);
     }
 
-    /** returns default log level index of INFO */
-    public int getDefaultModeIndex() {
-        return DEFAULT_MODE;
-    }
-
+    /**
+     * Returns the preference key associated with this preference
+     *
+     * Note that this key is _usually_ a system property in and of itself, which is expected to hold
+     * the value of the preference. In this case though, this key *does not* hold the preference. It
+     * is only really used to tie this controller to the list preference defined in the XML file.
+     *
+     * @return the preference key associated with this preference
+     */
     @Override
     @Nullable
     public String getPreferenceKey() {
         return PREFERENCE_KEY;
     }
 
+    /**
+     * Update the state of the preference based on what the user has selected
+     *
+     * This function is invoked when the user has selected a new value for this preference. The new
+     * value is the entry value at the index of the list the user has selected. This value will be
+     * one of the values from the array returned in getEntryValues(). Specifically, this array is
+     * set using R.array.bt_stack_log_level_values
+     *
+     * @param preference - the preference object to set the value of
+     * @param newValue - the value the user has selected, as an Object
+     * @return True when updated successfully
+     */
     @Override
     public boolean onPreferenceChange(@NonNull Preference preference, @NonNull Object newValue) {
-        SystemProperties.set(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST, newValue.toString());
-        SystemProperties.set(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY, newValue.toString());
-        updateState(mPreference);
+        Log.v(TAG, "onPreferenceChange(pref=" + preference + "value=" + newValue.toString() + ")");
+        setBluetoothLogTag(newValue.toString());
+        setBluetoothLogLevelIndex(getBluetoothLogLevelIndex());
         return true;
     }
 
+    /**
+     * Refresh the state of this preference based on the state stored on the system
+     *
+     * Read the Bluetooth stack log level from the underlying system property/log tag, and map that
+     * level to the proper index in the values and entries array. Use those strings to set the value
+     * and summary of the preference.
+     *
+     * @param preference - the preference object to refresh the state of
+     */
     @Override
     public void updateState(@NonNull Preference preference) {
-        final ListPreference listPreference = (ListPreference) preference;
-        int index = getBluetoothLogLevelIndex();
-        listPreference.setValue(mListValues[index]);
-        listPreference.setSummary(mListEntries[index]);
+        Log.v(TAG, "updateState(pref=" + preference + "): refresh preference state");
+        setBluetoothLogLevelIndex(getBluetoothLogLevelIndex());
     }
 
     /**
-     *  Returns the current log level from Log.isLoggable().
+     * Notify this developer options preference of a change to developer options visibility
+     *
+     * We developer options are closed, we should clear out the value of this developer option
+     * preference and revert it back to the default state of INFO.
      */
-    @VisibleForTesting
-    public int getBluetoothLogLevelIndex() {
-        if (Log.isLoggable(BLUETOOTH_STRING_NAME, Log.VERBOSE)) {
-            return BTSTACK_LOG_MODE_VERBOSE_INDEX;
-        } else if (Log.isLoggable(BLUETOOTH_STRING_NAME, Log.DEBUG)) {
-            return BTSTACK_LOG_MODE_DEBUG_INDEX;
-        } else if (Log.isLoggable(BLUETOOTH_STRING_NAME, Log.INFO)) {
-            return BTSTACK_LOG_MODE_INFO_INDEX;
-        } else if (Log.isLoggable(BLUETOOTH_STRING_NAME, Log.WARN)) {
-            return BTSTACK_LOG_MODE_WARN_INDEX;
-        } else if (Log.isLoggable(BLUETOOTH_STRING_NAME, Log.ERROR)) {
-            return BTSTACK_LOG_MODE_ERROR_INDEX;
-        }
-        return BTSTACK_LOG_MODE_INFO_INDEX;
-    }
-
     @Override
     protected void onDeveloperOptionsSwitchDisabled() {
         super.onDeveloperOptionsSwitchDisabled();
-        SystemProperties.set(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST, null);
-        SystemProperties.set(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY, null);
-        ((ListPreference) mPreference).setValue(mListValues[getDefaultModeIndex()]);
-        ((ListPreference) mPreference).setSummary(mListEntries[getDefaultModeIndex()]);
+        Log.v(TAG, "onDeveloperOptionsSwitchDisabled(): Revert stack log to default");
+        setBluetoothLogTag(null);
+        setBluetoothLogLevelIndex(BT_LOG_LEVEL_DEFAULT_INDEX);
+    }
+
+    /**
+     * Set the system property values used by the Log framework to read the "bluetooth" log tag
+     *
+     * @param logLevel - the log level to set the Bluetooth stack minimum log level to
+     */
+    private void setBluetoothLogTag(@Nullable String logLevel) {
+        Log.i(TAG, "setBluetoothLogTag(logLevel=" + logLevel + "): Set properties for log tag");
+        SystemProperties.set(BT_LOG_LEVEL_PROP_PERSIST, logLevel);
+        SystemProperties.set(BT_LOG_LEVEL_PROP, logLevel);
+    }
+
+    /**
+     * Get the entry and value index corresponding to the current Bluetooth stack log level
+     *
+     * Since this preference uses an actual log tag and not a specific/private system property, we
+     * can read the value using the Log.isLoggable() function with our "bluetooth" log tag that
+     * represents the log level of the Bluetooth stack. This is safer than trying to replacate the
+     * logic used in the Log framework around the various persist, ro, and blank variants of the tag
+     *
+     * If no value is present, INFO is used.
+     *
+     * @return the entry/value index corresponding to the current log level of the tag "bluetooth"
+     */
+    @VisibleForTesting
+    public int getBluetoothLogLevelIndex() {
+        int level = BT_LOG_LEVEL_DEFAULT_INDEX;
+        if (Log.isLoggable(BT_LOG_TAG, Log.VERBOSE)) {
+            level = BT_LOG_LEVEL_VERBOSE_INDEX;
+        } else if (Log.isLoggable(BT_LOG_TAG, Log.DEBUG)) {
+            level = BT_LOG_LEVEL_DEBUG_INDEX;
+        } else if (Log.isLoggable(BT_LOG_TAG, Log.INFO)) {
+            level = BT_LOG_LEVEL_INFO_INDEX;
+        } else if (Log.isLoggable(BT_LOG_TAG, Log.WARN)) {
+            level = BT_LOG_LEVEL_WARN_INDEX;
+        } else if (Log.isLoggable(BT_LOG_TAG, Log.ERROR)) {
+            level = BT_LOG_LEVEL_ERROR_INDEX;
+        }
+        Log.v(TAG, "getBluetoothLogLevelIndex() -> " + level);
+        return level;
+    }
+
+    /**
+     * Set the current Bluetooth stack log level displayed in the list for this preference
+     *
+     * @param index - the index representing the log level choice of this preference
+     */
+    private void setBluetoothLogLevelIndex(int index) {
+        if (index < BT_LOG_LEVEL_VERBOSE_INDEX || index > BT_LOG_LEVEL_ERROR_INDEX) {
+            Log.e(TAG, "setBluetoothLogLevelIndex(index=" + index + "): Log level invalid");
+            return;
+        }
+
+        String value = mListValues[index];
+        String entryValue = mListEntries[index];
+
+        ListPreference preference = ((ListPreference) mPreference);
+        if (preference == null) {
+            Log.e(TAG, "setBluetoothLogLevelIndex(index=" + index + "): mPreference is null");
+            return;
+        }
+
+        preference.setValue(value);
+        preference.setSummary(entryValue);
+
+        Log.i(TAG, "setBluetoothLogLevelIndex(index=" + index
+                + "): Updated Bluetooth stack log level to value='" + value + "', entryValue='"
+                + entryValue + "'");
     }
 }
diff --git a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
index 7d15858..f121d0c 100644
--- a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
@@ -81,7 +81,10 @@
             return mContext.getString(
                     com.android.settingslib.R.string.battery_info_status_not_charging);
         }
-        if (BatteryUtils.isBatteryDefenderOn(info)) {
+        if (BatteryUtils.isBatteryDefenderOn(info)
+                || FeatureFactory.getFeatureFactory()
+                .getPowerUsageFeatureProvider()
+                .isExtraDefend()) {
             return mContext.getString(
                     com.android.settingslib.R.string.battery_info_status_charging_on_hold);
         }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
index bfa501c..f710c71 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
@@ -63,8 +63,8 @@
         }
         final String action = intent.getAction();
         Log.d(TAG, "onReceive:" + action);
-        if (com.android.settingslib.fuelgauge.BatteryUtils.isWorkProfile(context)) {
-            Log.w(TAG, "do nothing for work profile action=" + action);
+        if (com.android.settingslib.fuelgauge.BatteryUtils.isAdditionalProfile(context)) {
+            Log.w(TAG, "do nothing for an additional profile action=" + action);
             return;
         }
         DatabaseUtils.recordDateTime(context, action);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
index 095a65a..52010af 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
@@ -110,8 +110,8 @@
 
     @Override
     public boolean onCreate() {
-        if (BatteryUtils.isWorkProfile(getContext())) {
-            Log.w(TAG, "do not create provider for work profile");
+        if (BatteryUtils.isAdditionalProfile(getContext())) {
+            Log.w(TAG, "do not create provider for an additional profile");
             return false;
         }
         mClock = Clock.systemUTC();
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java
index b758df4..45d724f 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java
@@ -54,8 +54,8 @@
     @Override
     public void onReceive(Context context, Intent intent) {
         final String action = intent == null ? "" : intent.getAction();
-        if (BatteryUtils.isWorkProfile(context)) {
-            Log.w(TAG, "do not start job for work profile action=" + action);
+        if (BatteryUtils.isAdditionalProfile(context)) {
+            Log.w(TAG, "do not start job for an additional profile action=" + action);
             return;
         }
 
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
index 7620323..6feb815 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
@@ -70,6 +70,7 @@
 
     /** Clear memory threshold for device booting phase. */
     private static final long CLEAR_MEMORY_THRESHOLD_MS = Duration.ofMinutes(5).toMillis();
+
     private static final long CLEAR_MEMORY_DELAYED_MS = Duration.ofSeconds(2).toMillis();
     private static final long INVALID_TIMESTAMP = 0L;
 
@@ -527,9 +528,11 @@
         return startCalendar.getTimeInMillis();
     }
 
-    /** Returns the context with profile parent identity when current user is work profile. */
+    /**
+     * Returns the context with profile parent identity when current user is an additional profile.
+     */
     public static Context getParentContext(Context context) {
-        if (com.android.settingslib.fuelgauge.BatteryUtils.isWorkProfile(context)) {
+        if (com.android.settingslib.fuelgauge.BatteryUtils.isAdditionalProfile(context)) {
             try {
                 return context.createPackageContextAsUser(
                         /* packageName= */ context.getPackageName(),
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
index 5c73adb..982cf40 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
@@ -50,10 +50,10 @@
             Log.w(TAG, "receive unexpected action=" + action);
             return;
         }
-        if (BatteryUtils.isWorkProfile(context)) {
+        if (BatteryUtils.isAdditionalProfile(context)) {
             BatteryUsageLogUtils.writeLog(
-                    context, Action.SCHEDULE_JOB, "do not refresh job for work profile");
-            Log.w(TAG, "do not refresh job for work profile action=" + action);
+                    context, Action.SCHEDULE_JOB, "do not refresh job for an additional profile");
+            Log.w(TAG, "do not refresh job for an additional profile action=" + action);
             return;
         }
         BatteryUsageLogUtils.writeLog(context, Action.EXECUTE_JOB, "");
diff --git a/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java b/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java
index 7e759ee..e829a3c 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java
@@ -49,8 +49,8 @@
             Log.w(TAG, "failed to dump BatteryUsage state: null application context");
             return;
         }
-        if (BatteryUtils.isWorkProfile(context)) {
-            Log.w(TAG, "ignore battery usage states dump in the work profile");
+        if (BatteryUtils.isAdditionalProfile(context)) {
+            Log.w(TAG, "ignore battery usage states dump in the additional profile");
             return;
         }
         writer.println("dump BatteryUsage and AppUsage states:");
diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java
index b4f13e8..d5d079e 100644
--- a/src/com/android/settings/password/ChooseLockGeneric.java
+++ b/src/com/android/settings/password/ChooseLockGeneric.java
@@ -492,9 +492,10 @@
                     : null;
                 updatePreferencesOrFinish(false /* isRecreatingActivity */);
                 if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getContext(),
-                        mBiometricsAuthSuccessful, mWaitingForConfirmation)) {
+                        mBiometricsAuthSuccessful, mWaitingForConfirmation, mUserId)) {
                     mWaitingForConfirmation = true;
-                    Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST);
+                    Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST,
+                            mUserId);
                 }
             } else if (requestCode == BIOMETRIC_AUTH_REQUEST) {
                 if (resultCode == Activity.RESULT_OK) {
diff --git a/tests/robotests/src/com/android/settings/MainClearTest.java b/tests/robotests/src/com/android/settings/MainClearTest.java
index 187fce1..26a430b 100644
--- a/tests/robotests/src/com/android/settings/MainClearTest.java
+++ b/tests/robotests/src/com/android/settings/MainClearTest.java
@@ -140,8 +140,8 @@
         when(mScrollView.getChildCount()).thenReturn(1);
         doReturn(mMockActivity).when(mMainClear).getActivity();
         when(mMockActivity.getSystemService(BiometricManager.class)).thenReturn(mBiometricManager);
-        when(mBiometricManager.canAuthenticate(
-                BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+        when(mBiometricManager.canAuthenticate(anyInt(),
+                eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
                 .thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
     }
 
@@ -370,8 +370,8 @@
         when(mContext.getResources()).thenReturn(mResources);
         when(mMockActivity.getSystemService(BiometricManager.class)).thenReturn(mBiometricManager);
         when(mResources.getString(anyInt())).thenReturn(TEST_ACCOUNT_NAME);
-        when(mBiometricManager.canAuthenticate(
-                BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+        when(mBiometricManager.canAuthenticate(anyInt(),
+                eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
                 .thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
         doReturn(true).when(mMainClear).isValidRequestCode(eq(MainClear.KEYGUARD_REQUEST));
         doNothing().when(mMainClear).startActivityForResult(any(), anyInt());
diff --git a/tests/robotests/src/com/android/settings/UtilsTest.java b/tests/robotests/src/com/android/settings/UtilsTest.java
index fd97b78..b36e9d6 100644
--- a/tests/robotests/src/com/android/settings/UtilsTest.java
+++ b/tests/robotests/src/com/android/settings/UtilsTest.java
@@ -81,6 +81,7 @@
 import androidx.fragment.app.FragmentActivity;
 
 import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.password.ChooseLockSettingsHelper;
 import com.android.settings.password.ConfirmDeviceCredentialActivity;
 import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
 
@@ -532,31 +533,45 @@
         when(mContext.getSystemService(BiometricManager.class)).thenReturn(null);
         assertThat(Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext,
                 false /* biometricsSuccessfullyAuthenticated */,
-                false /* biometricsAuthenticationRequested */)).isFalse();
+                false /* biometricsAuthenticationRequested */, USER_ID)).isFalse();
     }
 
     @Test
     @EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS)
     public void testRequestBiometricAuthentication_biometricManagerReturnsSuccess_shouldReturnTrue() {
-        when(mBiometricManager.canAuthenticate(
+        when(mBiometricManager.canAuthenticate(USER_ID,
                 BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
                 .thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
-        boolean requestBiometricAuthenticationForMandatoryBiometrics =
+        final boolean requestBiometricAuthenticationForMandatoryBiometrics =
                 Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext,
-                true /* biometricsSuccessfullyAuthenticated */,
-                false /* biometricsAuthenticationRequested */);
-        assertThat(requestBiometricAuthenticationForMandatoryBiometrics).isFalse();
+                false /* biometricsSuccessfullyAuthenticated */,
+                false /* biometricsAuthenticationRequested */, USER_ID);
+        assertThat(requestBiometricAuthenticationForMandatoryBiometrics).isTrue();
     }
 
     @Test
     @EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS)
     public void testRequestBiometricAuthentication_biometricManagerReturnsError_shouldReturnFalse() {
-        when(mBiometricManager.canAuthenticate(
-                BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+        when(mBiometricManager.canAuthenticate(anyInt(),
+                eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
                 .thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
         assertThat(Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext,
                 false /* biometricsSuccessfullyAuthenticated */,
-                false /* biometricsAuthenticationRequested */)).isFalse();
+                false /* biometricsAuthenticationRequested */, USER_ID)).isFalse();
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS)
+    public void testRequestBiometricAuthentication_biometricManagerReturnsSuccessForDifferentUser_shouldReturnFalse() {
+        when(mBiometricManager.canAuthenticate(anyInt(),
+                eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
+                .thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
+        when(mBiometricManager.canAuthenticate(0 /* userId */,
+                BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+                .thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
+        assertThat(Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext,
+                false /* biometricsSuccessfullyAuthenticated */,
+                false /* biometricsAuthenticationRequested */, USER_ID)).isFalse();
     }
 
     @Test
@@ -566,7 +581,7 @@
 
         final int requestCode = 1;
         final ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
-        Utils.launchBiometricPromptForMandatoryBiometrics(mFragment, requestCode);
+        Utils.launchBiometricPromptForMandatoryBiometrics(mFragment, requestCode, USER_ID);
 
         verify(mFragment).startActivityForResult(intentArgumentCaptor.capture(), eq(requestCode));
 
@@ -576,9 +591,12 @@
                 BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
         assertThat(intent.getExtra(BIOMETRIC_PROMPT_NEGATIVE_BUTTON_TEXT)).isNotNull();
         assertThat(intent.getExtra(KeyguardManager.EXTRA_DESCRIPTION)).isNotNull();
+        assertThat(intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_ALLOW_ANY_USER, false))
+                .isTrue();
+        assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, 0)).isEqualTo(USER_ID);
         assertThat(intent.getComponent().getPackageName()).isEqualTo(SETTINGS_PACKAGE_NAME);
         assertThat(intent.getComponent().getClassName()).isEqualTo(
-                ConfirmDeviceCredentialActivity.class.getName());
+                ConfirmDeviceCredentialActivity.InternalActivity.class.getName());
     }
 
     private void setUpForConfirmCredentialString(boolean isEffectiveUserManagedProfile) {
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
index 1463cd0..cb2429c 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
@@ -26,11 +26,9 @@
 import static java.util.Collections.singletonList;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
-import android.accessibilityservice.AccessibilityShortcutInfo;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
@@ -110,9 +108,7 @@
     private final Context mContext = ApplicationProvider.getApplicationContext();
     @Spy
     private final AccessibilityServiceInfo mServiceInfo = getMockAccessibilityServiceInfo(
-            PACKAGE_NAME, CLASS_NAME);
-    @Mock
-    private AccessibilityShortcutInfo mShortcutInfo;
+            new ComponentName(PACKAGE_NAME, CLASS_NAME));
     private ShadowAccessibilityManager mShadowAccessibilityManager;
     @Mock
     private LocalBluetoothManager mLocalBluetoothManager;
@@ -125,7 +121,6 @@
         mShadowAccessibilityManager.setInstalledAccessibilityServiceList(new ArrayList<>());
         mContext.setTheme(androidx.appcompat.R.style.Theme_AppCompat);
         ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
-        setMockAccessibilityShortcutInfo(mShortcutInfo);
 
         Intent intent = new Intent();
         intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT,
@@ -398,14 +393,25 @@
     public void testAccessibilityMenuInSystem_IncludedInInteractionControl() {
         mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
                 List.of(getMockAccessibilityServiceInfo(
-                        AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM)));
+                        AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM,
+                        /*isSystemApp=*/true)));
         setupFragment();
 
-        final RestrictedPreference pref = mFragment.getPreferenceScreen().findPreference(
-                AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM.flattenToString());
-        final String prefCategory = mFragment.mServicePreferenceToPreferenceCategoryMap.get(
-                pref).getKey();
-        assertThat(prefCategory).isEqualTo(AccessibilitySettings.CATEGORY_INTERACTION_CONTROL);
+        assertThat(getPreferenceCategory(AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM))
+                .isEqualTo(AccessibilitySettings.CATEGORY_INTERACTION_CONTROL);
+    }
+
+    @Test
+    @EnableFlags(com.android.settings.accessibility.Flags.FLAG_CHECK_PREBUNDLED_IS_PREINSTALLED)
+    public void testNonPreinstalledApp_IncludedInDownloadedCategory() {
+        mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
+                List.of(getMockAccessibilityServiceInfo(
+                        AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM,
+                        /*isSystemApp=*/false)));
+        setupFragment();
+
+        assertThat(getPreferenceCategory(AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM))
+                .isEqualTo(AccessibilitySettings.CATEGORY_DOWNLOADED_SERVICES);
     }
 
     @Test
@@ -418,13 +424,20 @@
         assertThat(pref).isNull();
     }
 
-    private AccessibilityServiceInfo getMockAccessibilityServiceInfo(String packageName,
-            String className) {
-        return getMockAccessibilityServiceInfo(new ComponentName(packageName, className));
+    private String getPreferenceCategory(ComponentName componentName) {
+        return mFragment.mServicePreferenceToPreferenceCategoryMap.get(
+                        mFragment.getPreferenceScreen().findPreference(
+                                componentName.flattenToString())).getKey();
     }
 
     private AccessibilityServiceInfo getMockAccessibilityServiceInfo(ComponentName componentName) {
-        final ApplicationInfo applicationInfo = new ApplicationInfo();
+        return getMockAccessibilityServiceInfo(componentName, true);
+    }
+
+    private AccessibilityServiceInfo getMockAccessibilityServiceInfo(ComponentName componentName,
+            boolean isSystemApp) {
+        final ApplicationInfo applicationInfo = Mockito.mock(ApplicationInfo.class);
+        when(applicationInfo.isSystemApp()).thenReturn(isSystemApp);
         final ServiceInfo serviceInfo = new ServiceInfo();
         applicationInfo.packageName = componentName.getPackageName();
         serviceInfo.packageName = componentName.getPackageName();
@@ -445,16 +458,6 @@
         return null;
     }
 
-    private void setMockAccessibilityShortcutInfo(AccessibilityShortcutInfo mockInfo) {
-        final ActivityInfo activityInfo = Mockito.mock(ActivityInfo.class);
-        activityInfo.applicationInfo = new ApplicationInfo();
-        when(mockInfo.getActivityInfo()).thenReturn(activityInfo);
-        when(activityInfo.loadLabel(any())).thenReturn(DEFAULT_LABEL);
-        when(mockInfo.loadSummary(any())).thenReturn(DEFAULT_SUMMARY);
-        when(mockInfo.loadDescription(any())).thenReturn(DEFAULT_DESCRIPTION);
-        when(mockInfo.getComponentName()).thenReturn(COMPONENT_NAME);
-    }
-
     private void setInvisibleToggleFragmentType(AccessibilityServiceInfo info) {
         info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.R;
         info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON;
diff --git a/tests/robotests/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceControllerTest.java
index 98ed442..5fd11f9 100644
--- a/tests/robotests/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceControllerTest.java
@@ -16,38 +16,39 @@
 
 package com.android.settings.accessibility;
 
+import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+
 import static com.android.settings.core.BasePreferenceController.AVAILABLE;
 import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
 
 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.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
 
 import android.content.ContentResolver;
 import android.content.Context;
+import android.os.Looper;
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 
+import androidx.lifecycle.LifecycleOwner;
+import androidx.preference.PreferenceManager;
 import androidx.preference.PreferenceScreen;
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.server.accessibility.Flags;
 import com.android.settings.widget.SeekBarPreference;
+import com.android.settingslib.core.lifecycle.Lifecycle;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 
 /** Tests for {@link DaltonizerSaturationSeekbarPreferenceController}. */
@@ -60,8 +61,9 @@
     private int mOriginalSaturationLevel = -1;
 
     private PreferenceScreen mScreen;
+    private LifecycleOwner mLifecycleOwner;
+    private Lifecycle mLifecycle;
 
-    @Mock
     private SeekBarPreference mPreference;
 
     @Rule
@@ -69,7 +71,6 @@
 
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
         Context context = ApplicationProvider.getApplicationContext();
         mContentResolver = context.getContentResolver();
         mOriginalSaturationLevel = Settings.Secure.getInt(
@@ -77,10 +78,13 @@
                 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL,
                 7);
 
-        mScreen = spy(new PreferenceScreen(context, /* attrs= */ null));
-        when(mScreen.findPreference(ToggleDaltonizerPreferenceFragment.KEY_SATURATION))
-                .thenReturn(mPreference);
+        mPreference = new SeekBarPreference(context);
+        mPreference.setKey(ToggleDaltonizerPreferenceFragment.KEY_SATURATION);
+        mScreen = new PreferenceManager(context).createPreferenceScreen(context);
+        mScreen.addPreference(mPreference);
 
+        mLifecycleOwner = () -> mLifecycle;
+        mLifecycle = new Lifecycle(mLifecycleOwner);
         mController = new DaltonizerSaturationSeekbarPreferenceController(
                 context,
                 ToggleDaltonizerPreferenceFragment.KEY_SATURATION);
@@ -94,6 +98,12 @@
                 mOriginalSaturationLevel);
     }
 
+    @Test
+    public void constructor_defaultValuesMatch() {
+        assertThat(mController.getSliderPosition()).isEqualTo(7);
+        assertThat(mController.getMax()).isEqualTo(10);
+        assertThat(mController.getMin()).isEqualTo(1);
+    }
 
     @Test
     @DisableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
@@ -103,28 +113,72 @@
 
     @Test
     @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
-    public void getAvailabilityStatus_flagEnabled_available() {
+    public void getAvailabilityStatus_flagEnabledProtanEnabled_available() {
+        setDaltonizerMode(/* enabled= */ 1, /* mode= */ 11);
         assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
     }
 
     @Test
-    public void constructor_defaultValuesMatch() {
-        assertThat(mController.getSliderPosition()).isEqualTo(7);
-        assertThat(mController.getMax()).isEqualTo(10);
-        assertThat(mController.getMin()).isEqualTo(0);
+    @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
+    public void getAvailabilityStatus_flagEnabledDeutranEnabled_available() {
+        setDaltonizerMode(/* enabled= */ 1, /* mode= */ 12);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
     }
 
     @Test
     @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
-    public void displayPreference_enabled_visible() {
+    public void getAvailabilityStatus_flagEnabledTritanEnabled_available() {
+        setDaltonizerMode(/* enabled= */ 1, /* mode= */ 13);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
+    public void getAvailabilityStatus_flagEnabledGrayScale_disabled() {
+        setDaltonizerMode(/* enabled= */ 1, /* mode= */ 0);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
+    public void getAvailabilityStatus_flagEnabledColorCorrectionDisabled_disabled() {
+        setDaltonizerMode(/* enabled= */ 0, /* mode= */ 11);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
+    public void getAvailabilityStatus_flagEnabledColorCorrectionDisabledGrayScale_disabled() {
+        setDaltonizerMode(/* enabled= */ 0, /* mode= */ 0);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
+    public void displayPreference_flagEnabledColorCorrectionEnabled_enabledWithDefaultValues() {
+        setDaltonizerMode(/* enabled= */ 1, /* mode= */ 11);
         mController.displayPreference(mScreen);
 
-        verify(mPreference).setMax(eq(10));
-        verify(mPreference).setMin(eq(0));
-        verify(mPreference).setProgress(eq(7));
-        verify(mPreference).setContinuousUpdates(eq(true));
-        verify(mPreference).setOnPreferenceChangeListener(eq(mController));
-        verify(mPreference).setVisible(eq(true));
+        assertThat(mPreference.isEnabled()).isTrue();
+        assertThat(mPreference.getMax()).isEqualTo(10);
+        assertThat(mPreference.getMin()).isEqualTo(1);
+        assertThat(mPreference.getProgress()).isEqualTo(7);
+        assertThat(mPreference.isVisible()).isTrue();
+        assertThat(mPreference.getOnPreferenceChangeListener()).isEqualTo(mController);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
+    public void displayPreference_flagEnabledColorCorrectionDisabled_disabledWithDefaultValues() {
+        setDaltonizerMode(/* enabled= */ 0, /* mode= */ 11);
+        mController.displayPreference(mScreen);
+
+        assertThat(mPreference.isEnabled()).isFalse();
+        assertThat(mPreference.getMax()).isEqualTo(10);
+        assertThat(mPreference.getMin()).isEqualTo(1);
+        assertThat(mPreference.getProgress()).isEqualTo(7);
+        assertThat(mPreference.isVisible()).isTrue();
+        assertThat(mPreference.getOnPreferenceChangeListener()).isEqualTo(mController);
     }
 
     @Test
@@ -132,12 +186,8 @@
     public void displayPreference_disabled_notVisible() {
         mController.displayPreference(mScreen);
 
-        verify(mPreference).setMax(eq(10));
-        verify(mPreference).setMin(eq(0));
-        verify(mPreference).setProgress(eq(7));
-        verify(mPreference).setContinuousUpdates(eq(true));
-        verify(mPreference, never()).setOnPreferenceChangeListener(any());
-        verify(mPreference).setVisible(eq(false));
+        assertThat(mPreference.isVisible()).isFalse();
+        assertThat(mPreference.getOnPreferenceChangeListener()).isNull();
     }
 
     @Test
@@ -153,13 +203,13 @@
 
     @Test
     public void setSliderPosition_min_secureSettingsUpdated() {
-        var isSliderSet = mController.setSliderPosition(0);
+        var isSliderSet = mController.setSliderPosition(1);
 
         assertThat(isSliderSet).isTrue();
         assertThat(Settings.Secure.getInt(
                 mContentResolver,
                 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL,
-                7)).isEqualTo(0);
+                7)).isEqualTo(1);
     }
 
     @Test
@@ -194,4 +244,140 @@
                 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL,
                 7)).isEqualTo(7);
     }
+
+    @Test
+    public void updateState_enabledProtan_preferenceEnabled() {
+        setDaltonizerMode(/* enabled= */ 1, /* mode= */ 11);
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.isEnabled()).isTrue();
+    }
+
+    @Test
+    public void updateState_enabledDeuteran_preferenceEnabled() {
+        setDaltonizerMode(/* enabled= */ 1, /* mode= */ 12);
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.isEnabled()).isTrue();
+    }
+
+    @Test
+    public void updateState_enabledTritan_preferenceEnabled() {
+        setDaltonizerMode(/* enabled= */ 1, /* mode= */ 13);
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.isEnabled()).isTrue();
+    }
+
+    @Test
+    public void updateState_disabledGrayScale_preferenceDisabled() {
+        setDaltonizerMode(/* enabled= */ 0, /* mode= */ 0);
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.isEnabled()).isFalse();
+    }
+
+    @Test
+    public void updateState_nullPreference_noError() {
+        setDaltonizerMode(/* enabled= */ 0, /* mode= */ 0);
+
+        mController.updateState(null);
+    }
+
+    @Test
+    public void updateState_enabledGrayScale_preferenceDisabled() {
+        setDaltonizerMode(/* enabled= */ 1, /* mode= */ 0);
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.isEnabled()).isFalse();
+    }
+
+    @Test
+    public void onResume_daltonizerEnabledAfterResumed_preferenceEnabled() {
+        setDaltonizerMode(/* enabled= */ 0, /* mode= */ 11);
+        mController.displayPreference(mScreen);
+        assertThat(mPreference.isEnabled()).isFalse();
+
+        mLifecycle.addObserver(mController);
+        mLifecycle.handleLifecycleEvent(ON_RESUME);
+
+        Settings.Secure.putInt(
+                mContentResolver,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
+                1);
+        shadowOf(Looper.getMainLooper()).idle();
+
+        assertThat(mPreference.isEnabled()).isTrue();
+    }
+
+    @Test
+    public void onResume_daltonizerDisabledAfterResumed_preferenceDisabled() {
+        setDaltonizerMode(/* enabled= */ 1, /* mode= */ 11);
+        mController.displayPreference(mScreen);
+        assertThat(mPreference.isEnabled()).isTrue();
+
+        mLifecycle.addObserver(mController);
+        mLifecycle.handleLifecycleEvent(ON_RESUME);
+
+        Settings.Secure.putInt(
+                mContentResolver,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
+                0);
+        shadowOf(Looper.getMainLooper()).idle();
+
+        assertThat(mPreference.isEnabled()).isFalse();
+    }
+
+    @Test
+    public void onResume_daltonizerGrayScaledAfterResumed_preferenceDisabled() {
+        setDaltonizerMode(/* enabled= */ 1, /* mode= */ 11);
+        mController.displayPreference(mScreen);
+        assertThat(mPreference.isEnabled()).isTrue();
+
+        mLifecycle.addObserver(mController);
+        mLifecycle.handleLifecycleEvent(ON_RESUME);
+
+        Settings.Secure.putInt(
+                mContentResolver,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
+                0);
+        shadowOf(Looper.getMainLooper()).idle();
+
+        assertThat(mPreference.isEnabled()).isFalse();
+    }
+
+    @Test
+    public void onStop_daltonizerEnabledAfterOnStop_preferenceNotChanged() {
+        setDaltonizerMode(/* enabled= */ 0, /* mode= */ 11);
+        mController.displayPreference(mScreen);
+        assertThat(mPreference.isEnabled()).isFalse();
+
+        mLifecycle.addObserver(mController);
+        mLifecycle.handleLifecycleEvent(ON_STOP);
+
+        // enabled.
+        Settings.Secure.putInt(
+                mContentResolver,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
+                1);
+        shadowOf(Looper.getMainLooper()).idle();
+
+        assertThat(mPreference.isEnabled()).isFalse();
+    }
+
+    private void setDaltonizerMode(int enabled, int mode) {
+        Settings.Secure.putInt(
+                mContentResolver,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
+                enabled);
+        Settings.Secure.putInt(
+                mContentResolver,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
+                mode);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java b/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java
index a775731..4f8860e 100644
--- a/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java
@@ -127,8 +127,8 @@
         mFragment = spy(new TestCombinedBiometricProfileSettings(mContext));
         doReturn(mActivity).when(mFragment).getActivity();
         doReturn(mBiometricManager).when(mActivity).getSystemService(BiometricManager.class);
-        when(mBiometricManager.canAuthenticate(
-                BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+        when(mBiometricManager.canAuthenticate(anyInt(),
+                eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
                 .thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
 
         ReflectionHelpers.setField(mFragment, "mDashboardFeatureProvider",
@@ -181,8 +181,8 @@
     public void testLaunchBiometricPrompt_onCreateFragment() {
         ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
         doNothing().when(mFragment).startActivityForResult(any(), anyInt());
-        when(mBiometricManager.canAuthenticate(
-                BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+        when(mBiometricManager.canAuthenticate(anyInt(),
+                eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
                 .thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
 
         mFragment.onAttach(mContext);
@@ -193,7 +193,7 @@
 
         Intent intent = intentArgumentCaptor.getValue();
         assertThat(intent.getComponent().getClassName()).isEqualTo(
-                ConfirmDeviceCredentialActivity.class.getName());
+                ConfirmDeviceCredentialActivity.InternalActivity.class.getName());
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
index a34b6de..29b2961 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
@@ -176,7 +176,7 @@
 
         Intent intent = intentArgumentCaptor.getValue();
         assertThat(intent.getComponent().getClassName()).isEqualTo(
-                ConfirmDeviceCredentialActivity.class.getName());
+                ConfirmDeviceCredentialActivity.InternalActivity.class.getName());
     }
 
     // Test the case when FingerprintAuthenticateSidecar receives an error callback from the
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreferenceTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreferenceTest.java
index 13e2a9d..be62414 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreferenceTest.java
@@ -117,6 +117,7 @@
         assertThat(shareButton.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(shareButton.getDrawable()).isNotNull();
         assertThat(shareButton.hasOnClickListeners()).isTrue();
+        assertThat(shareButton.getContentDescription()).isNotNull();
         assertThat(divider).isNotNull();
         assertThat(divider.getVisibility()).isEqualTo(View.VISIBLE);
 
diff --git a/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java
index bd005b3..978380e 100644
--- a/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java
@@ -16,8 +16,9 @@
 
 package com.android.settings.development;
 
-import static com.android.settings.development.FreeformWindowsPreferenceController
-        .SETTING_VALUE_OFF;
+import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
+
+import static com.android.settings.development.FreeformWindowsPreferenceController.SETTING_VALUE_OFF;
 import static com.android.settings.development.FreeformWindowsPreferenceController.SETTING_VALUE_ON;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -29,6 +30,7 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.provider.Settings;
 
 import androidx.fragment.app.FragmentActivity;
@@ -43,7 +45,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
@@ -52,9 +53,10 @@
 })
 public class FreeformWindowsPreferenceControllerTest {
 
-    private static final String ENG_BUILD_TYPE = "eng";
-    private static final String USER_BUILD_TYPE = "user";
-
+    @Mock
+    Context mContext;
+    @Mock
+    private PackageManager mPackageManager;
     @Mock
     private SwitchPreference mPreference;
     @Mock
@@ -68,33 +70,33 @@
     @Mock
     private FragmentTransaction mTransaction;
 
-    private Context mContext;
     private FreeformWindowsPreferenceController mController;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
         doReturn(mTransaction).when(mFragmentManager).beginTransaction();
         doReturn(mFragmentManager).when(mActivity).getSupportFragmentManager();
         doReturn(mActivity).when(mFragment).getActivity();
         mController = new FreeformWindowsPreferenceController(mContext, mFragment);
         when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
         mController.displayPreference(mScreen);
     }
 
     @Test
-    public void isAvailable_engBuild_shouldBeTrue() {
+    public void isAvailable_deviceHasFreeformWindowSystemFeature_returnsFalse() {
         mController = spy(mController);
-        doReturn(ENG_BUILD_TYPE).when(mController).getBuildType();
+        when(mPackageManager.hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)).thenReturn(true);
 
-        assertThat(mController.isAvailable()).isTrue();
+        assertThat(mController.isAvailable()).isFalse();
     }
 
     @Test
-    public void isAvailable_userBuild_shouldBeTrue() {
+    public void isAvailable_deviceDoesNotHaveFreeformWindowSystemFeature_returnsTrue() {
         mController = spy(mController);
-        doReturn(USER_BUILD_TYPE).when(mController).getBuildType();
+        when(mPackageManager.hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)).thenReturn(
+                false);
 
         assertThat(mController.isAvailable()).isTrue();
     }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
index b949a3e..fdb075d 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
@@ -389,6 +389,28 @@
         verify(mBatteryUsageProgressBarPref).setBottomSummary(expectedChargingString);
     }
 
+    @Test
+    public void updateBatteryStatus_dockDefend_chargingOnHold() {
+        var expected = "Charging on hold";
+        mBatteryInfo.isBatteryDefender = false;
+        when(mFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(true);
+
+        mController.updateBatteryStatus(/* label= */ null, mBatteryInfo);
+
+        verify(mBatteryUsageProgressBarPref).setBottomSummary(expected);
+    }
+
+    @Test
+    public void updateBatteryStatus_batteryDefender_chargingOnHold() {
+        var expected = "Charging on hold";
+        mBatteryInfo.isBatteryDefender = true;
+        when(mFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(false);
+
+        mController.updateBatteryStatus(/* label= */ null, mBatteryInfo);
+
+        verify(mBatteryUsageProgressBarPref).setBottomSummary(expected);
+    }
+
     private BatteryInfo arrangeUpdateBatteryStatusTestWithRemainingLabel(
             String remainingLabel,
             String statusLabel,
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java
index af0cb91..63d44d0 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java
@@ -28,9 +28,9 @@
 import android.content.pm.PackageManager;
 import android.os.BatteryManager;
 import android.os.SystemClock;
+import android.os.UserManager;
 import android.text.format.DateUtils;
 
-import com.android.settings.testutils.BatteryTestUtils;
 import com.android.settings.testutils.FakeFeatureFactory;
 
 import org.junit.Before;
@@ -49,6 +49,7 @@
     private FakeFeatureFactory mFakeFeatureFactory;
 
     @Mock private PackageManager mPackageManager;
+    @Mock private UserManager mUserManager;
 
     @Before
     public void setUp() {
@@ -57,6 +58,7 @@
         mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
         mBatteryUsageBroadcastReceiver = new BatteryUsageBroadcastReceiver();
         doReturn(mPackageManager).when(mContext).getPackageManager();
+        doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
         DatabaseUtils.getSharedPreferences(mContext).edit().clear().apply();
     }
 
@@ -69,7 +71,17 @@
 
     @Test
     public void onReceive_workProfile_doNothing() {
-        BatteryTestUtils.setWorkProfile(mContext);
+        doReturn(true).when(mUserManager).isManagedProfile();
+
+        mBatteryUsageBroadcastReceiver.onReceive(
+                mContext, new Intent(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING));
+
+        assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse();
+    }
+
+    @Test
+    public void onReceive_privateProfile_doNothing() {
+        doReturn(true).when(mUserManager).isPrivateProfile();
 
         mBatteryUsageBroadcastReceiver.onReceive(
                 mContext, new Intent(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING));
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
index 950f828..ac711a4 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
@@ -19,12 +19,16 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.UserManager;
 
 import androidx.test.core.app.ApplicationProvider;
 
@@ -39,6 +43,8 @@
 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.time.Duration;
@@ -62,9 +68,14 @@
     private Context mContext;
     private BatteryUsageContentProvider mProvider;
 
+    @Mock
+    private UserManager mUserManager;
+
     @Before
     public void setUp() {
-        mContext = ApplicationProvider.getApplicationContext();
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
         mProvider = new BatteryUsageContentProvider();
         mProvider.attachInfo(mContext, /* info= */ null);
         BatteryTestUtils.setUpBatteryStateDatabase(mContext);
@@ -77,7 +88,13 @@
 
     @Test
     public void onCreate_withWorkProfileMode_returnsFalse() {
-        BatteryTestUtils.setWorkProfile(mContext);
+        doReturn(true).when(mUserManager).isManagedProfile();
+        assertThat(mProvider.onCreate()).isFalse();
+    }
+
+    @Test
+    public void onCreate_withPrivateProfileMode_returnsFalse() {
+        doReturn(true).when(mUserManager).isPrivateProfile();
         assertThat(mProvider.onCreate()).isFalse();
     }
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java
index 704637f..f318a2b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java
@@ -18,6 +18,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 import static org.robolectric.Shadows.shadowOf;
 
 import android.app.AlarmManager;
@@ -26,6 +29,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.os.UserManager;
 
 import androidx.test.core.app.ApplicationProvider;
 
@@ -37,6 +41,8 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.Shadows;
 import org.robolectric.shadows.ShadowAlarmManager;
@@ -55,10 +61,15 @@
     private ShadowAlarmManager mShadowAlarmManager;
     private PeriodicJobManager mPeriodicJobManager;
 
+    @Mock
+    private UserManager mUserManager;
+
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
         TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
-        mContext = ApplicationProvider.getApplicationContext();
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
         mPeriodicJobManager = PeriodicJobManager.getInstance(mContext);
         mShadowAlarmManager = shadowOf(mContext.getSystemService(AlarmManager.class));
         mReceiver = new BootBroadcastReceiver();
@@ -78,7 +89,15 @@
 
     @Test
     public void onReceive_withWorkProfile_notRefreshesJob() {
-        BatteryTestUtils.setWorkProfile(mContext);
+        doReturn(true).when(mUserManager).isManagedProfile();
+        mReceiver.onReceive(mContext, new Intent(Intent.ACTION_BOOT_COMPLETED));
+
+        assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNull();
+    }
+
+    @Test
+    public void onReceive_withPrivateProfile_notRefreshesJob() {
+        doReturn(true).when(mUserManager).isPrivateProfile();
         mReceiver.onReceive(mContext, new Intent(Intent.ACTION_BOOT_COMPLETED));
 
         assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNull();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
index d89e61b..2fda277 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
@@ -47,7 +47,6 @@
 
 import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
 import com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity;
-import com.android.settings.testutils.BatteryTestUtils;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -451,6 +450,26 @@
     }
 
     @Test
+    public void getHistoryMap_withPrivateProfile_returnExpectedMap()
+            throws PackageManager.NameNotFoundException {
+        doReturn("com.fake.package").when(mContext).getPackageName();
+        doReturn(mMockContext)
+                .when(mContext)
+                .createPackageContextAsUser("com.fake.package", /* flags= */ 0, UserHandle.OWNER);
+        doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
+        doReturn(UserHandle.CURRENT).when(mContext).getUser();
+        doReturn(true).when(mUserManager).isPrivateProfile();
+        doReturn(UserHandle.SYSTEM).when(mUserManager).getProfileParent(UserHandle.CURRENT);
+
+        DatabaseUtils.sFakeSupplier = () -> getMatrixCursor();
+
+        final Map<Long, Map<String, BatteryHistEntry>> batteryHistMap =
+                DatabaseUtils.getHistoryMapSinceQueryTimestamp(mContext, 0);
+
+        assertThat(batteryHistMap).isEmpty();
+    }
+
+    @Test
     public void removeUsageSource_hasNoData() {
         DatabaseUtils.removeUsageSource(mContext);
         assertThat(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiverTest.java
index d111de2..ea3c04c 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiverTest.java
@@ -18,11 +18,15 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 import static org.robolectric.Shadows.shadowOf;
 
 import android.app.AlarmManager;
 import android.content.Context;
 import android.content.Intent;
+import android.os.UserManager;
 
 import androidx.test.core.app.ApplicationProvider;
 
@@ -34,6 +38,8 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.shadows.ShadowAlarmManager;
 
@@ -53,12 +59,17 @@
     private PeriodicJobManager mPeriodicJobManager;
     private ShadowAlarmManager mShadowAlarmManager;
 
+    @Mock
+    private UserManager mUserManager;
+
     @Before
     public void setUp() {
-        mContext = ApplicationProvider.getApplicationContext();
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(ApplicationProvider.getApplicationContext());
         mPeriodicJobManager = PeriodicJobManager.getInstance(mContext);
         mShadowAlarmManager = shadowOf(mContext.getSystemService(AlarmManager.class));
         mReceiver = new PeriodicJobReceiver();
+        when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
 
         // Inserts fake data into database for testing.
         final BatteryStateDatabase database = BatteryTestUtils.setUpBatteryStateDatabase(mContext);
@@ -114,7 +125,14 @@
 
     @Test
     public void onReceive_inWorkProfileMode_notRefreshesJob() {
-        BatteryTestUtils.setWorkProfile(mContext);
+        doReturn(true).when(mUserManager).isManagedProfile();
+        mReceiver.onReceive(mContext, JOB_UPDATE_INTENT);
+        assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNull();
+    }
+
+    @Test
+    public void onReceive_inPrivateProfileMode_notRefreshesJob() {
+        doReturn(true).when(mUserManager).isPrivateProfile();
         mReceiver.onReceive(mContext, JOB_UPDATE_INTENT);
         assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNull();
     }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java
index d998106..0dd18c5 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java
@@ -18,7 +18,11 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
 import android.content.Context;
+import android.os.UserManager;
 
 import androidx.test.core.app.ApplicationProvider;
 
@@ -27,6 +31,8 @@
 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.io.FileDescriptor;
@@ -46,11 +52,17 @@
     private StringWriter mStringWriter;
     private BugReportContentProvider mBugReportContentProvider;
 
+    @Mock
+    private UserManager mUserManager;
+
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
         mStringWriter = new StringWriter();
         mPrintWriter = new PrintWriter(mStringWriter);
-        mContext = ApplicationProvider.getApplicationContext();
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        doReturn(mContext).when(mContext).getApplicationContext();
+        doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
         mBugReportContentProvider = new BugReportContentProvider();
         mBugReportContentProvider.attachInfo(mContext, /* info= */ null);
         // Inserts fake data into database for testing.
@@ -77,7 +89,14 @@
 
     @Test
     public void dump_inWorkProfileMode_notDumpsBatteryUsageData() {
-        BatteryTestUtils.setWorkProfile(mContext);
+        doReturn(true).when(mUserManager).isManagedProfile();
+        mBugReportContentProvider.dump(FileDescriptor.out, mPrintWriter, new String[] {});
+        assertThat(mStringWriter.toString()).isEmpty();
+    }
+
+    @Test
+    public void dump_inPrivateProfileMode_notDumpsBatteryUsageData() {
+        doReturn(true).when(mUserManager).isPrivateProfile();
         mBugReportContentProvider.dump(FileDescriptor.out, mPrintWriter, new String[] {});
         assertThat(mStringWriter.toString()).isEmpty();
     }
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java
index 64a5f11..c52fe2f 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java
@@ -19,9 +19,8 @@
 import android.Manifest;
 import android.content.Context;
 import android.content.pm.CrossProfileApps;
-import android.content.pm.ICrossProfileApps;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageInfo;
 
 import androidx.annotation.NonNull;
 
@@ -35,15 +34,7 @@
 @Implements(CrossProfileApps.class)
 public class ShadowCrossProfileApps extends org.robolectric.shadows.ShadowCrossProfileApps {
     private static final Set<String> configurableInteractAcrossProfilePackages = new HashSet<>();
-    private Context mContext;
-    private PackageManager mPackageManager;
 
-    @Implementation
-    protected void __constructor__(Context context, ICrossProfileApps service) {
-        super.__constructor__(context, service);
-        this.mContext = context;
-        this.mPackageManager = context.getPackageManager();
-    }
     public void addCrossProfilePackage(String packageName) {
         configurableInteractAcrossProfilePackages.add(packageName);
     }
@@ -57,7 +48,9 @@
     protected boolean canUserAttemptToConfigureInteractAcrossProfiles(@NonNull String packageName) {
         PackageInfo packageInfo;
         try {
-            packageInfo = mPackageManager.getPackageInfo(packageName, /* flags= */ 0);
+            packageInfo = getContext().getPackageManager().getPackageInfo(
+                packageName,
+                /* flags= */ 0);
         } catch (PackageManager.NameNotFoundException e) {
             return false;
         }
diff --git a/tests/unit/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceControllerTest.java b/tests/unit/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceControllerTest.java
index ab1f469..2aa10bb 100644
--- a/tests/unit/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceControllerTest.java
@@ -16,13 +16,9 @@
 
 package com.android.settings.development.bluetooth;
 
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_VERBOSE_INDEX;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_DEBUG_INDEX;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_INFO_INDEX;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_WARN_INDEX;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_ERROR_INDEX;
+import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BT_LOG_LEVEL_DEFAULT_INDEX;
+import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BT_LOG_LEVEL_PROP;
+import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BT_LOG_LEVEL_PROP_PERSIST;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -37,18 +33,21 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 
 @RunWith(AndroidJUnit4.class)
-@Ignore("b/339148064")
 public class BluetoothStackLogPreferenceControllerTest {
-    private static final String TAG = "BluetoothStackLogPreferenceControllerTest";
+    private static final String COM_ANDROID_SETTINGS = "com.android.settings";
+    private static final String TYPE_ARRAY = "array";
 
-    @Mock private Context mContext;
+    private static final String XML_DEFINED_PREFERENCE_KEY = "bt_stack_log_level";
+    private static final String XML_DEFINED_ENTRIES_RESOURCE = "bt_stack_log_level_entries";
+    private static final String XML_DEFINED_VALUES_RESOURCE = "bt_stack_log_level_values";
+
+    private static final String PROPERTY_CLEARED = "";
+
+    private Context mContext;
 
     private ListPreference mPreference;
     private PreferenceManager mPreferenceManager;
@@ -61,7 +60,6 @@
 
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
         mContext = ApplicationProvider.getApplicationContext();
 
         if (Looper.myLooper() == null) {
@@ -71,12 +69,11 @@
         mPreferenceManager = new PreferenceManager(mContext);
         mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
         mPreference = new ListPreference(mContext);
-
         mController = new BluetoothStackLogPreferenceController(mContext);
 
         mPreference.setKey(mController.getPreferenceKey());
-        mPreference.setEntries(com.android.settings.R.array.bt_stack_log_level_entries);
-        mPreference.setEntryValues(com.android.settings.R.array.bt_stack_log_level_values);
+        mPreference.setEntries(getStringArrayResourceId(XML_DEFINED_ENTRIES_RESOURCE));
+        mPreference.setEntryValues(getStringArrayResourceId(XML_DEFINED_VALUES_RESOURCE));
 
         mPreferenceScreen.addPreference(mPreference);
         mController.displayPreference(mPreferenceScreen);
@@ -86,134 +83,109 @@
     }
 
     /**
-     * Test that default log level is set to INFO
+     * Get the resource ID associated with a resource name
+     *
+     * This looks up the resource id by name using our device's context. This way, we can avoid
+     * hardcoding a resource ID or value from the R class which may not match the resource IDs on
+     * the device under test.
+     *
+     * Usage: int valuesResId = getStringArrayResource("bt_stack_log_level_values");
+     * Usage: int entriesResId = getStringArrayResource("bt_stack_log_level_entries");
+     *
+     * @param res - The resource name to look up
+     * @return The integer resource ID corresponding to the given resource name
      */
-    @Test
-    public void verifyDefaultState_enablesDefaultLogLevelEntriesAndValuesSameSize() {
-        mController.onPreferenceChange(mPreference, mController.getDefaultModeIndex());
-        assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
-                        [BTSTACK_LOG_MODE_INFO_INDEX].toString());
-        assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
-                        [BTSTACK_LOG_MODE_INFO_INDEX].toString());
+    public int getStringArrayResourceId(String res) {
+        return mContext.getResources().getIdentifier(res, TYPE_ARRAY, COM_ANDROID_SETTINGS);
     }
 
     /**
-     * Test that log level is changed to VERBOSE when VERBOSE is selected
+     * Test that, for each possible value a user can select, our controller properly handles the
+     * value to update the underlying system property _and_ set the UI entry to the proper value.
      */
     @Test
-    public void onPreferenceChanged_enableBluetoothStackVerboseLogLevel() {
-        mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_VERBOSE_INDEX]
-                        .toString());
+    public void onPreferenceChange_withEachValue_uiSetProperlyAndAllValuesWrittenToProperties() {
+        for (int index = 0; index < mListValues.length; index++) {
+            String value = mListValues[index].toString();
+            String entry = mListEntries[index].toString();
 
-        final String persistedLogLevel = SystemProperties.get(
-                        BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
-        final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
-        assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_VERBOSE_INDEX]
-                        .toString());
-        assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_VERBOSE_INDEX].toString());
+            mController.onPreferenceChange(mPreference, value);
 
-        assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
-                        [BTSTACK_LOG_MODE_VERBOSE_INDEX].toString());
-        assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
-                        [BTSTACK_LOG_MODE_VERBOSE_INDEX].toString());
+            final String persistedLogLevel = SystemProperties.get(BT_LOG_LEVEL_PROP_PERSIST);
+            final String logLevel = SystemProperties.get(BT_LOG_LEVEL_PROP);
+            final String currentValue = mPreference.getValue().toString();
+            final String currentEntry = mPreference.getEntry().toString();
+            final String currentSummary = mPreference.getSummary().toString();
+            final int currentIndex = mPreference.findIndexOfValue(currentValue);
+
+            assertThat(persistedLogLevel).isEqualTo(value);
+            assertThat(logLevel).isEqualTo(value);
+            assertThat(currentIndex).isEqualTo(index);
+            assertThat(currentValue).isEqualTo(value);
+            assertThat(currentEntry).isEqualTo(entry);
+            assertThat(currentSummary).isEqualTo(entry);
+        }
     }
 
     /**
-     * Test that log level is changed to DEBUG when DEBUG is selected
+     * Test that, for each possible log tag log level value, our controller properly handles the
+     * value to set the UI entry to the proper value.
      */
     @Test
-    public void onPreferenceChanged_enableBluetoothStackDebugLogLevel() {
-        mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_DEBUG_INDEX]
-                        .toString());
+    public void updateState_withEachValue_uiSetProperly() {
+        for (int index = 0; index < mListValues.length; index++) {
+            String value = mListValues[index].toString();
+            String entry = mListEntries[index].toString();
 
-        final String persistedLogLevel = SystemProperties.get(
-                BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
-        final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
-        assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_DEBUG_INDEX]
-                        .toString());
-        assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_DEBUG_INDEX].toString());
+            SystemProperties.set(BT_LOG_LEVEL_PROP_PERSIST, value);
+            SystemProperties.set(BT_LOG_LEVEL_PROP, value);
 
-        assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
-                        [BTSTACK_LOG_MODE_DEBUG_INDEX].toString());
-        assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
-                        [BTSTACK_LOG_MODE_DEBUG_INDEX].toString());
+            mController.updateState(mPreference);
+
+            final String currentValue = mPreference.getValue().toString();
+            final String currentEntry = mPreference.getEntry().toString();
+            final String currentSummary = mPreference.getSummary().toString();
+            final int currentIndex = mPreference.findIndexOfValue(currentValue);
+
+            assertThat(currentIndex).isEqualTo(index);
+            assertThat(currentValue).isEqualTo(value);
+            assertThat(currentEntry).isEqualTo(entry);
+            assertThat(currentSummary).isEqualTo(entry);
+        }
     }
 
     /**
-     * Test that log level is changed to INFO when INFO is selected
+     * Test that our controller reverts the log level back to a missing/default value when we're
+     * notified that Developer Options has been disabled.
      */
     @Test
-    public void onPreferenceChanged_enableBluetoothStackInfoLogLevel() {
-        mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_INFO_INDEX]
-                        .toString());
+    public void onDeveloperOptionsSwitchDisabled_preferenceSetToDefault() {
+        mController.onDeveloperOptionsSwitchDisabled();
 
-        final String persistedLogLevel = SystemProperties.get(
-                BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
-        final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
-        assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_INFO_INDEX]
-                        .toString());
-        assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_INFO_INDEX].toString());
+        final String defaultEntry = mListEntries[BT_LOG_LEVEL_DEFAULT_INDEX].toString();
+        final String defaultValue = mListValues[BT_LOG_LEVEL_DEFAULT_INDEX].toString();
 
-        assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
-                        [BTSTACK_LOG_MODE_INFO_INDEX].toString());
-        assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
-                        [BTSTACK_LOG_MODE_INFO_INDEX].toString());
+        final String persistedLogLevel = SystemProperties.get(BT_LOG_LEVEL_PROP_PERSIST);
+        final String logLevel = SystemProperties.get(BT_LOG_LEVEL_PROP);
+        final String currentValue = mPreference.getValue().toString();
+        final String currentEntry = mPreference.getEntry().toString();
+        final String currentSummary = mPreference.getSummary().toString();
+        final int currentIndex = mPreference.findIndexOfValue(currentValue);
+
+        assertThat(persistedLogLevel).isEqualTo(PROPERTY_CLEARED);
+        assertThat(logLevel).isEqualTo(PROPERTY_CLEARED);
+        assertThat(currentIndex).isEqualTo(BT_LOG_LEVEL_DEFAULT_INDEX);
+        assertThat(currentValue).isEqualTo(defaultValue);
+        assertThat(currentEntry).isEqualTo(defaultEntry);
+        assertThat(currentSummary).isEqualTo(defaultEntry);
     }
 
     /**
-     * Test that log level is changed to WARN when WARN is selected
+     * Test that our preference key returned by our controller matches the one defined in the XML
+     * definition.
      */
     @Test
-    public void onPreferenceChanged_enableBluetoothStackWarnLogLevel() {
-        mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_WARN_INDEX]
-                        .toString());
-
-        final String persistedLogLevel = SystemProperties.get(
-                BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
-        final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
-        assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_WARN_INDEX]
-                        .toString());
-        assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_WARN_INDEX].toString());
-
-        assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
-
-                        [BTSTACK_LOG_MODE_WARN_INDEX].toString());
-        assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
-                        [BTSTACK_LOG_MODE_WARN_INDEX].toString());
-    }
-
-    /**
-     * Test that log level is changed to ERROR when ERROR is selected
-     */
-    @Test
-    public void onPreferenceChanged_enableBluetoothStackErrorLogLevel() {
-        mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_ERROR_INDEX]
-                        .toString());
-
-        final String persistedLogLevel = SystemProperties.get(
-                BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
-        final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
-        assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_ERROR_INDEX]
-                        .toString());
-        assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_ERROR_INDEX].toString());
-
-        assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
-                        [BTSTACK_LOG_MODE_ERROR_INDEX].toString());
-        assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
-                        [BTSTACK_LOG_MODE_ERROR_INDEX].toString());
-    }
-
-    /**
-     * Test that preference is disabled when developer options is disabled
-     * Log level is also reset to default
-     */
-    @Test
-    public void onDeveloperOptionsDisabled_shouldDisablePreference() {
-        mController.onDeveloperOptionsDisabled();
-        assertThat(mPreference.isEnabled()).isFalse();
-        assertThat(mPreference.getValue().toString()).isEqualTo(mListValues[mController
-                .getDefaultModeIndex()].toString());
-        assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries[mController
-                .getDefaultModeIndex()].toString());
+    public void getPreferenceKey_matchesXmlDefinedPreferenceKey() {
+        assertThat(mController.getPreferenceKey()).isEqualTo(XML_DEFINED_PREFERENCE_KEY);
     }
 }