Merge "Add SafeSites related content filters preference." into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index bbe7963..8f5699c 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1899,7 +1899,7 @@
 
         <activity android:name="Settings$UserAspectRatioAppListActivity"
             android:exported="true"
-            android:label="@string/aspect_ratio_experimental_title">
+            android:label="@string/aspect_ratio_title">
             <intent-filter android:priority="1">
                 <action android:name="android.settings.MANAGE_USER_ASPECT_RATIO_SETTINGS"/>
                 <category android:name="android.intent.category.DEFAULT" />
@@ -1912,7 +1912,7 @@
 
         <activity android:name="Settings$UserAspectRatioAppActivity"
                   android:exported="true"
-                  android:label="@string/aspect_ratio_experimental_title">
+                  android:label="@string/aspect_ratio_title">
             <intent-filter>
                 <action android:name="android.settings.MANAGE_USER_ASPECT_RATIO_SETTINGS" />
                 <category android:name="android.intent.category.DEFAULT" />
diff --git a/aconfig/settings_bluetooth_declarations.aconfig b/aconfig/settings_bluetooth_declarations.aconfig
index 7f30895..e2edcb5 100644
--- a/aconfig/settings_bluetooth_declarations.aconfig
+++ b/aconfig/settings_bluetooth_declarations.aconfig
@@ -58,7 +58,7 @@
 flag {
   name: "enable_remove_association_bt_unpair"
   is_exported: true
-  namespace: "companion_device_manager"
+  namespace: "companion"
   description: "Allow to disassociate when to forget a BT pair device"
   bug: "365613753"
  }
diff --git a/res/drawable/device_details_spotlight_preference_background.xml b/res/drawable/device_details_spotlight_preference_background.xml
new file mode 100644
index 0000000..58a29a1
--- /dev/null
+++ b/res/drawable/device_details_spotlight_preference_background.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2025 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="?android:colorControlHighlight">
+    <item>
+        <shape android:shape="rectangle">
+            <solid
+                android:color="@color/settingslib_materialColorSecondaryContainer" />
+            <corners
+                android:radius="28dp" />
+        </shape>
+    </item>
+</ripple>
diff --git a/res/layout/bluetooth_device_spotlight_preference.xml b/res/layout/bluetooth_device_spotlight_preference.xml
new file mode 100644
index 0000000..ee2778a
--- /dev/null
+++ b/res/layout/bluetooth_device_spotlight_preference.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2025 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingEnd="?android:attr/scrollbarSize"
+    android:background="?android:attr/selectableItemBackground">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginHorizontal="16dp"
+        android:background="@drawable/device_details_spotlight_preference_background" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="?android:attr/listPreferredItemHeight"
+        android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+        android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+        android:gravity="center_vertical">
+
+        <ImageView
+            android:id="@+android:id/icon"
+            android:layout_width="24dip"
+            android:layout_height="24dip"
+            android:layout_gravity="center"
+            android:scaleType="center"
+            android:importantForAccessibility="no" />
+
+        <RelativeLayout
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="24dp"
+            android:layout_marginEnd="6dp"
+            android:layout_marginTop="6dp"
+            android:layout_marginBottom="6dp"
+            android:layout_weight="1">
+
+            <TextView android:id="@+android:id/title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:textAppearance="?android:attr/textAppearanceLarge"
+                android:ellipsize="marquee"
+                android:fadingEdge="horizontal" />
+
+            <TextView android:id="@+android:id/summary"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_below="@android:id/title"
+                android:layout_alignStart="@android:id/title"
+                android:textAppearance="?android:attr/textAppearanceSmall"
+                android:textColor="?android:attr/textColorSecondary"
+                android:maxLines="4" />
+        </RelativeLayout>
+    </LinearLayout>
+</FrameLayout>
diff --git a/res/layout/bluetooth_pin_confirm.xml b/res/layout/bluetooth_pin_confirm.xml
index 9387d5d..69ea777 100644
--- a/res/layout/bluetooth_pin_confirm.xml
+++ b/res/layout/bluetooth_pin_confirm.xml
@@ -101,7 +101,8 @@
                     android:hyphenationFrequency="normalFast"
                     android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Caption" />
             </LinearLayout>
-            <Switch
+            <com.google.android.material.materialswitch.MaterialSwitch
+                android:theme="@style/Theme.Material3.DynamicColors.DayNight"
                 android:id="@+id/phonebook_sharing_message_confirm_pin"
                 android:layout_width="wrap_content"
                 android:layout_height="48dp"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1e8ba4e..79020f9 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -13189,6 +13189,11 @@
     <!-- [CHAR LIMIT=200] Manage applications, text for dialog when killing persistent apps-->
     <string name="stop_app_dlg_text">Application will be stopped to apply page size compat setting.</string>
 
+    <!-- Error messages for 16 KB Developer option-->
+    <string name="error_pending_updates">Kernel update failed. Check and install any pending updates.</string>
+
+    <string name="error_ota_failed">Kernel update failed. Error occurred while applying OTA.</string>
+
     <!-- DSU Loader. Do not translate. -->
 
     <string name="dsu_loader_title" translatable="false">DSU Loader</string>
@@ -13836,20 +13841,6 @@
     <!-- [CHAR LIMIT=NONE] Warning description for app info aspect ratio page -->
     <string name="app_aspect_ratio_footer">The app will restart when you change aspect ratio. You may lose unsaved changes. Some apps may not be optimized for certain aspect ratios.</string>
 
-    <!-- TODO(b/300219974): Change aspect ratio title and clean up unused titles -->
-    <!-- [CHAR LIMIT=60] Aspect ratio experimental title settings to choose app aspect ratio -->
-    <string name="aspect_ratio_experimental_title">Aspect ratio (experimental)</string>
-    <!-- [CHAR LIMIT=60] Aspect ratio experiment title settings to choose app aspect ratio -->
-    <string name="aspect_ratio_experiment_title">Aspect ratio (experiment)</string>
-    <!-- [CHAR LIMIT=60] Aspect ratio labs title settings to choose app aspect ratio -->
-    <string name="aspect_ratio_labs_title">Aspect ratio (labs)</string>
-    <!-- [CHAR LIMIT=60] Aspect ratio experimental title label -->
-    <string name="aspect_ratio_experimental_label">Experimental</string>
-    <!-- [CHAR LIMIT=60] Aspect ratio experiment title label -->
-    <string name="aspect_ratio_experiment_label">Experiment</string>
-    <!-- [CHAR LIMIT=60] Aspect ratio labs title label -->
-    <string name="aspect_ratio_labs_label">Labs</string>
-
     <!-- Accessibility label for fingerprint sensor [CHAR LIMIT=NONE] -->
     <string name="accessibility_fingerprint_label">Fingerprint sensor</string>
 
diff --git a/res/xml/apps.xml b/res/xml/apps.xml
index 77b210f..b687497 100644
--- a/res/xml/apps.xml
+++ b/res/xml/apps.xml
@@ -123,7 +123,7 @@
 
         <Preference
             android:key="aspect_ratio_apps"
-            android:title="@string/aspect_ratio_experimental_title"
+            android:title="@string/aspect_ratio_title"
             android:summary="@string/summary_placeholder"
             android:order="22"
             settings:controller="com.android.settings.applications.appcompat.UserAspectRatioAppsPreferenceController"
diff --git a/res/xml/user_aspect_ratio_details.xml b/res/xml/user_aspect_ratio_details.xml
index 24c3271..af3d2d5 100644
--- a/res/xml/user_aspect_ratio_details.xml
+++ b/res/xml/user_aspect_ratio_details.xml
@@ -19,7 +19,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:settings="http://schemas.android.com/apk/res-auto"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:title="@string/aspect_ratio_experimental_title">
+    android:title="@string/aspect_ratio_title">
 
     <com.android.settingslib.widget.TopIntroPreference
         android:key="app_aspect_ratio_summary"
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index 2c8247f..b4b1ef6 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -30,9 +30,6 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.ArrayMap;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
 import android.view.accessibility.AccessibilityManager;
 
 import androidx.annotation.NonNull;
@@ -45,6 +42,7 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.settings.R;
 import com.android.settings.accessibility.AccessibilityUtil.AccessibilityServiceFragmentType;
+import com.android.settings.accessibility.actionbar.FeedbackMenuController;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.search.BaseSearchIndexProvider;
@@ -105,8 +103,6 @@
     // presentation.
     private static final long DELAY_UPDATE_SERVICES_MILLIS = 1000;
 
-    static final int MENU_ID_SEND_FEEDBACK = 0;
-
     private final Handler mHandler = new Handler();
 
     private final Runnable mUpdateRunnable = new Runnable() {
@@ -151,8 +147,6 @@
 
     private AccessibilitySettingsContentObserver mSettingsContentObserver;
 
-    private FeedbackManager mFeedbackManager;
-
     private final Map<String, PreferenceCategory> mCategoryToPrefCategoryMap =
             new ArrayMap<>();
     private final List<Preference> mServicePreferences = new ArrayList<>();
@@ -216,6 +210,7 @@
         mNeedPreferencesUpdate = false;
         registerContentMonitors();
         registerInputDeviceListener();
+        FeedbackMenuController.init(this, SettingsEnums.ACCESSIBILITY);
     }
 
     @Override
@@ -253,24 +248,6 @@
     }
 
     @Override
-    public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
-        if (getFeedbackManager().isAvailable()) {
-            menu.add(Menu.NONE, MENU_ID_SEND_FEEDBACK, Menu.NONE,
-                    R.string.accessibility_send_feedback_title);
-        }
-        super.onCreateOptionsMenu(menu, inflater);
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
-        if (item.getItemId() == MENU_ID_SEND_FEEDBACK) {
-            getFeedbackManager().sendFeedback();
-            return true;
-        }
-        return super.onOptionsItemSelected(item);
-    }
-
-    @Override
     protected int getPreferenceScreenResId() {
         return R.xml.accessibility_settings;
     }
@@ -280,18 +257,6 @@
         return TAG;
     }
 
-    @VisibleForTesting
-    void setFeedbackManager(FeedbackManager feedbackManager) {
-        this.mFeedbackManager = feedbackManager;
-    }
-
-    private FeedbackManager getFeedbackManager() {
-        if (mFeedbackManager == null) {
-            mFeedbackManager = new FeedbackManager(getActivity(), SettingsEnums.ACCESSIBILITY);
-        }
-        return mFeedbackManager;
-    }
-
     /**
      * Returns the summary for the current state of this accessibilityService.
      *
diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
index d8c3985..367f557 100644
--- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
@@ -40,9 +40,6 @@
 import android.text.Html;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityManager;
@@ -63,6 +60,7 @@
 import com.android.internal.accessibility.util.ShortcutUtils;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
+import com.android.settings.accessibility.actionbar.FeedbackMenuController;
 import com.android.settings.accessibility.shortcuts.EditShortcutsPreferenceFragment;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.flags.Flags;
@@ -94,7 +92,6 @@
     // <img src="R.drawable.fileName"/>, a11y settings will get the resources successfully.
     private static final String IMG_PREFIX = "R.drawable.";
     private static final String DRAWABLE_FOLDER = "drawable";
-    static final int MENU_ID_SEND_FEEDBACK = 0;
 
     protected TopIntroPreference mTopIntroPreference;
     protected SettingsMainSwitchPreference mToggleServiceSwitchPreference;
@@ -108,7 +105,6 @@
     protected Intent mSettingsIntent;
     // The mComponentName maybe null, such as Magnify
     protected ComponentName mComponentName;
-    @Nullable private FeedbackManager mFeedbackManager;
     protected CharSequence mFeatureName;
     protected Uri mImageUri;
     protected CharSequence mHtmlDescription;
@@ -142,6 +138,8 @@
 
         mSettingsContentObserver = new AccessibilitySettingsContentObserver(new Handler());
         registerKeysToObserverCallback(mSettingsContentObserver);
+
+        FeedbackMenuController.init(this, getFeedbackCategory());
     }
 
     protected void registerKeysToObserverCallback(
@@ -248,24 +246,6 @@
     }
 
     @Override
-    public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
-        if (getFeedbackManager().isAvailable()) {
-            menu.add(Menu.NONE, MENU_ID_SEND_FEEDBACK, Menu.NONE,
-                    R.string.accessibility_send_feedback_title);
-        }
-        super.onCreateOptionsMenu(menu, inflater);
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
-        if (item.getItemId() == MENU_ID_SEND_FEEDBACK) {
-            getFeedbackManager().sendFeedback();
-            return true;
-        }
-        return super.onOptionsItemSelected(item);
-    }
-
-    @Override
     public int getDialogMetricsCategory(int dialogId) {
         switch (dialogId) {
             case DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL:
@@ -280,6 +260,18 @@
         return SettingsEnums.ACCESSIBILITY_SERVICE;
     }
 
+    /**
+     * Returns the category of the feedback page.
+     *
+     * <p>By default, this method returns {@link SettingsEnums#PAGE_UNKNOWN}. This indicates that
+     * the feedback category is unknown, and the absence of a feedback menu.
+     *
+     * @return The feedback category, which is {@link SettingsEnums#PAGE_UNKNOWN} by default.
+     */
+    protected int getFeedbackCategory() {
+        return SettingsEnums.PAGE_UNKNOWN;
+    }
+
     @Override
     public int getHelpResource() {
         return 0;
@@ -785,28 +777,4 @@
                 super.onCreateRecyclerView(inflater, parent, savedInstanceState);
         return AccessibilityFragmentUtils.addCollectionInfoToAccessibilityDelegate(recyclerView);
     }
-
-    @VisibleForTesting
-    void setFeedbackManager(FeedbackManager feedbackManager) {
-        this.mFeedbackManager = feedbackManager;
-    }
-
-    private FeedbackManager getFeedbackManager() {
-        if (mFeedbackManager == null) {
-            mFeedbackManager = new FeedbackManager(getActivity(), getFeedbackCategory());
-        }
-        return mFeedbackManager;
-    }
-
-    /**
-     * Returns the category of the feedback page.
-     *
-     * <p>By default, this method returns {@link SettingsEnums#PAGE_UNKNOWN}. This indicates that
-     * the feedback category is unknown, and the absence of a feedback menu.
-     *
-     * @return The feedback category, which is {@link SettingsEnums#PAGE_UNKNOWN} by default.
-     */
-    protected int getFeedbackCategory() {
-        return SettingsEnums.PAGE_UNKNOWN;
-    }
 }
diff --git a/src/com/android/settings/accessibility/VibrationMainSwitchPreference.kt b/src/com/android/settings/accessibility/VibrationMainSwitchPreference.kt
index c488e27..4008cee 100644
--- a/src/com/android/settings/accessibility/VibrationMainSwitchPreference.kt
+++ b/src/com/android/settings/accessibility/VibrationMainSwitchPreference.kt
@@ -25,7 +25,7 @@
 import com.android.settings.contract.KEY_VIBRATION_HAPTICS
 import com.android.settings.metrics.PreferenceActionMetricsProvider
 import com.android.settingslib.datastore.KeyValueStore
-import com.android.settingslib.datastore.KeyedObservableDelegate
+import com.android.settingslib.datastore.KeyValueStoreDelegate
 import com.android.settingslib.datastore.SettingsSystemStore
 import com.android.settingslib.metadata.BooleanValuePreference
 import com.android.settingslib.metadata.PreferenceMetadata
@@ -96,18 +96,13 @@
 class VibrationMainSwitchStore(
     context: Context,
     private val settingsStore: KeyValueStore = SettingsSystemStore.get(context),
-) : KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
+) : KeyValueStoreDelegate {
 
-    override fun contains(key: String) = settingsStore.contains(key)
+    override val keyValueStoreDelegate
+        get() = settingsStore
 
     override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) = DEFAULT_VALUE as T
 
-    override fun <T : Any> getValue(key: String, valueType: Class<T>) =
-        settingsStore.getValue(key, valueType) ?: getDefaultValue(key, valueType)
-
-    override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) =
-        settingsStore.setValue(key, valueType, value)
-
     companion object {
         private const val DEFAULT_VALUE = true
     }
diff --git a/src/com/android/settings/accessibility/actionbar/FeedbackMenuController.java b/src/com/android/settings/accessibility/actionbar/FeedbackMenuController.java
new file mode 100644
index 0000000..ee08276
--- /dev/null
+++ b/src/com/android/settings/accessibility/actionbar/FeedbackMenuController.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility.actionbar;
+
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+
+import androidx.annotation.NonNull;
+
+import com.android.settings.R;
+import com.android.settings.accessibility.FeedbackManager;
+import com.android.settings.core.InstrumentedPreferenceFragment;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnCreateOptionsMenu;
+import com.android.settingslib.core.lifecycle.events.OnOptionsItemSelected;
+
+/**
+ * A controller that adds feedback menu to any Settings page.
+ */
+public class FeedbackMenuController implements LifecycleObserver, OnCreateOptionsMenu,
+        OnOptionsItemSelected {
+
+    /**
+     * The menu item ID for the feedback menu option.
+     */
+    public static final int MENU_FEEDBACK = Menu.FIRST + 10;
+
+    /**
+     * The menu item ID for the feedback menu option.
+     */
+    private final FeedbackManager mFeedbackManager;
+
+    /**
+     * Initializes the FeedbackMenuController for an InstrumentedPreferenceFragment with a provided
+     * pade ID.
+     *
+     * @param host The InstrumentedPreferenceFragment to which the menu controller will be added.
+     * @param pageId The page ID used for feedback tracking.
+     */
+    public static void init(@NonNull InstrumentedPreferenceFragment host, int pageId) {
+        host.getSettingsLifecycle().addObserver(
+                new FeedbackMenuController(
+                        new FeedbackManager(host.getActivity(), pageId)));
+    }
+
+    /**
+     * Initializes the FeedbackMenuController for an InstrumentedPreferenceFragment with a provided
+     * FeedbackManager.
+     *
+     * @param host The InstrumentedPreferenceFragment to which the menu controller will be added.
+     * @param feedbackManager The FeedbackManager to use for handling feedback actions.
+     */
+    public static void init(@NonNull InstrumentedPreferenceFragment host,
+            @NonNull FeedbackManager feedbackManager) {
+        host.getSettingsLifecycle().addObserver(
+                new FeedbackMenuController(feedbackManager));
+    }
+
+    @Override
+    public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
+        if (!mFeedbackManager.isAvailable()) {
+            return;
+        }
+        menu.add(Menu.NONE, MENU_FEEDBACK, Menu.NONE, R.string.accessibility_send_feedback_title);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(@NonNull MenuItem menuItem) {
+        if (menuItem.getItemId() == MENU_FEEDBACK) {
+            mFeedbackManager.sendFeedback();
+            return true;
+        }
+        return false;
+    }
+
+    private FeedbackMenuController(@NonNull FeedbackManager feedbackManager) {
+        mFeedbackManager = feedbackManager;
+    }
+}
diff --git a/src/com/android/settings/biometrics/combination/CombinedBiometricSettings.java b/src/com/android/settings/biometrics/combination/CombinedBiometricSettings.java
index 9fe4794..6be6a38 100644
--- a/src/com/android/settings/biometrics/combination/CombinedBiometricSettings.java
+++ b/src/com/android/settings/biometrics/combination/CombinedBiometricSettings.java
@@ -204,5 +204,11 @@
     }
 
     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
-            new CombinedBiometricSearchIndexProvider(R.xml.security_settings_combined_biometric);
+            new CombinedBiometricSearchIndexProvider(R.xml.security_settings_combined_biometric) {
+                @Override
+                protected boolean isPageSearchEnabled(Context context) {
+                    return super.isPageSearchEnabled(context)
+                            && !Flags.biometricsOnboardingEducation();
+                }
+            };
 }
diff --git a/src/com/android/settings/biometrics/face/FaceEnroll.kt b/src/com/android/settings/biometrics/face/FaceEnroll.kt
index 2ed628d..74f1613 100644
--- a/src/com/android/settings/biometrics/face/FaceEnroll.kt
+++ b/src/com/android/settings/biometrics/face/FaceEnroll.kt
@@ -23,7 +23,6 @@
 import androidx.appcompat.app.AppCompatActivity
 import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED
 import com.android.settings.biometrics.combination.CombinedBiometricStatusUtils
-
 import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
 
 class FaceEnroll: AppCompatActivity() {
@@ -39,18 +38,33 @@
     private val enrollActivityProvider: FaceEnrollActivityClassProvider
         get() = featureFactory.faceFeatureProvider.enrollActivityClassProvider
 
+    private var isLaunched = false
+
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
-        /**
-         *  Logs the next activity to be launched, creates an intent for that activity,
-         *  adds flags to forward the result, includes any existing extras from the current intent,
-         *  starts the new activity and then finishes the current one
-         */
-        Log.d("FaceEnroll", "forward to $nextActivityClass")
-        val nextIntent = Intent(this, nextActivityClass)
-        nextIntent.putExtras(intent)
-        startActivityForResult(nextIntent, 0)
+        if (savedInstanceState != null) {
+            isLaunched = savedInstanceState.getBoolean(KEY_IS_LAUNCHED, isLaunched)
+        }
+
+        if (!isLaunched) {
+            /**
+             *  Logs the next activity to be launched, creates an intent for that activity,
+             *  adds flags to forward the result, includes any existing extras from the current intent,
+             *  starts the new activity and then finishes the current one
+             */
+            Log.d("FaceEnroll", "forward to $nextActivityClass")
+            val nextIntent = Intent(this, nextActivityClass)
+            nextIntent.putExtras(intent)
+            startActivityForResult(nextIntent, 0)
+
+            isLaunched = true
+        }
+    }
+
+    override fun onSaveInstanceState(outState: Bundle) {
+        outState.putBoolean(KEY_IS_LAUNCHED, isLaunched)
+        super.onSaveInstanceState(outState)
     }
 
     override fun onActivityResult(
@@ -60,6 +74,7 @@
         caller: ComponentCaller
     ) {
         super.onActivityResult(requestCode, resultCode, data, caller)
+        isLaunched = false
         if (intent.getBooleanExtra(
                 CombinedBiometricStatusUtils.EXTRA_LAUNCH_FROM_SAFETY_SOURCE_ISSUE, false)
             && resultCode != RESULT_FINISHED) {
@@ -68,4 +83,8 @@
         setResult(resultCode, data)
         finish()
     }
-}
\ No newline at end of file
+
+    private companion object {
+        const val KEY_IS_LAUNCHED = "isLaunched"
+    }
+}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnroll.kt b/src/com/android/settings/biometrics/fingerprint/FingerprintEnroll.kt
index 795be13..229f6c4 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnroll.kt
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnroll.kt
@@ -62,18 +62,33 @@
     protected val enrollActivityProvider: FingerprintEnrollActivityClassProvider
         get() = featureFactory.fingerprintFeatureProvider.getEnrollActivityClassProvider(this)
 
+    private var isLaunched = false
+
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
-        /**
-         *  Logs the next activity to be launched, creates an intent for that activity,
-         *  adds flags to forward the result, includes any existing extras from the current intent,
-         *  starts the new activity and then finishes the current one
-         */
-        Log.d("FingerprintEnroll", "forward to $nextActivityClass")
-        val nextIntent = Intent(this, nextActivityClass)
-        nextIntent.putExtras(intent)
-        startActivityForResult(nextIntent, 0)
+        if (savedInstanceState != null) {
+            isLaunched = savedInstanceState.getBoolean(KEY_IS_LAUNCHED, isLaunched)
+        }
+
+        if (!isLaunched) {
+            /**
+             *  Logs the next activity to be launched, creates an intent for that activity,
+             *  adds flags to forward the result, includes any existing extras from the current intent,
+             *  starts the new activity and then finishes the current one
+             */
+            Log.d("FingerprintEnroll", "forward to $nextActivityClass")
+            val nextIntent = Intent(this, nextActivityClass)
+            nextIntent.putExtras(intent)
+            startActivityForResult(nextIntent, 0)
+
+            isLaunched = true
+        }
+    }
+
+    override fun onSaveInstanceState(outState: Bundle) {
+        outState.putBoolean(KEY_IS_LAUNCHED, isLaunched)
+        super.onSaveInstanceState(outState)
     }
 
     override fun onActivityResult(
@@ -83,6 +98,7 @@
         caller: ComponentCaller
     ) {
         super.onActivityResult(requestCode, resultCode, data, caller)
+        isLaunched = false
         if (intent.getBooleanExtra(
                 CombinedBiometricStatusUtils.EXTRA_LAUNCH_FROM_SAFETY_SOURCE_ISSUE, false)
             && resultCode != BiometricEnrollBase.RESULT_FINISHED
@@ -92,4 +108,8 @@
         setResult(resultCode, data)
         finish()
     }
+
+    private companion object {
+        const val KEY_IS_LAUNCHED = "isLaunched"
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java b/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
index 9d54b1d..476f002 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
@@ -250,17 +250,19 @@
         TextView messageViewCaptionHint = (TextView) view.findViewById(R.id.pin_values_hint);
         TextView messageView2 = (TextView) view.findViewById(R.id.message_below_pin);
         CheckBox alphanumericPin = (CheckBox) view.findViewById(R.id.alphanumeric_pin);
-        CheckBox contactSharing = (CheckBox) view.findViewById(
-                R.id.phonebook_sharing_message_entry_pin);
-        contactSharing.setText(getString(R.string.bluetooth_pairing_shares_phonebook));
+
+        CheckBox contactSharing =
+                (CheckBox) view.findViewById(R.id.phonebook_sharing_message_entry_pin);
+        if (contactSharing != null) {
+            contactSharing.setText(getString(R.string.bluetooth_pairing_shares_phonebook));
+            contactSharing.setVisibility(
+                    mPairingController.isContactSharingVisible() ? View.VISIBLE : View.GONE);
+            mPairingController.setContactSharingState();
+            contactSharing.setOnCheckedChangeListener(mPairingController);
+            contactSharing.setChecked(mPairingController.getContactSharingState());
+        }
+
         EditText pairingView = (EditText) view.findViewById(R.id.text);
-
-        contactSharing.setVisibility(
-                mPairingController.isContactSharingVisible() ? View.VISIBLE : View.GONE);
-        mPairingController.setContactSharingState();
-        contactSharing.setOnCheckedChangeListener(mPairingController);
-        contactSharing.setChecked(mPairingController.getContactSharingState());
-
         mPairingView = pairingView;
 
         pairingView.setInputType(InputType.TYPE_CLASS_NUMBER);
diff --git a/src/com/android/settings/bluetooth/ui/layout/DeviceSettingLayout.kt b/src/com/android/settings/bluetooth/ui/layout/DeviceSettingLayout.kt
deleted file mode 100644
index 5987e5a..0000000
--- a/src/com/android/settings/bluetooth/ui/layout/DeviceSettingLayout.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.bluetooth.ui.layout
-
-import kotlinx.coroutines.flow.Flow
-
-/** Represent the layout of device settings. */
-data class DeviceSettingLayout(val rows: List<DeviceSettingLayoutRow>)
-
-/** Represent a row in the layout. */
-data class DeviceSettingLayoutRow(val columns: Flow<List<DeviceSettingLayoutColumn>>)
-
-/** Represent a column in a row. */
-data class DeviceSettingLayoutColumn(val settingId: Int, val highlighted: Boolean)
diff --git a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
index b7ec32e..0658b1d 100644
--- a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
+++ b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
@@ -21,35 +21,26 @@
 import android.bluetooth.BluetoothAdapter
 import android.content.Context
 import android.content.Intent
+import android.graphics.drawable.Drawable
 import android.os.Bundle
 import androidx.compose.animation.AnimatedVisibility
 import androidx.compose.animation.fadeIn
 import androidx.compose.animation.fadeOut
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.unit.dp
+import androidx.core.graphics.drawable.toDrawable
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import androidx.lifecycle.lifecycleScope
 import androidx.preference.Preference
+import androidx.preference.PreferenceViewHolder
+import androidx.preference.SwitchPreferenceCompat
+import androidx.preference.TwoStatePreference
 import com.android.settings.R
 import com.android.settings.bluetooth.BlockingPrefWithSliceController
 import com.android.settings.bluetooth.BluetoothDetailsProfilesController
-import com.android.settings.bluetooth.ui.composable.Icon
 import com.android.settings.bluetooth.ui.composable.MultiTogglePreference
-import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
 import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
 import com.android.settings.bluetooth.ui.model.FragmentTypeModel
 import com.android.settings.bluetooth.ui.view.DeviceDetailsMoreSettingsFragment.Companion.KEY_DEVICE_ADDRESS
@@ -58,6 +49,7 @@
 import com.android.settings.dashboard.DashboardFragment
 import com.android.settings.overlay.FeatureFactory
 import com.android.settings.spa.preference.ComposePreference
+import com.android.settingslib.PrimarySwitchPreference
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
 import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
 import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingActionModel
@@ -67,24 +59,15 @@
 import com.android.settingslib.core.lifecycle.LifecycleObserver
 import com.android.settingslib.core.lifecycle.events.OnPause
 import com.android.settingslib.core.lifecycle.events.OnStop
-import com.android.settingslib.spa.framework.theme.SettingsDimension
-import com.android.settingslib.spa.widget.preference.Preference as SpaPreference
-import com.android.settingslib.spa.widget.preference.PreferenceModel
-import com.android.settingslib.spa.widget.preference.SwitchPreference
-import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
-import com.android.settingslib.spa.widget.preference.TwoTargetSwitchPreference
-import com.android.settingslib.spa.widget.ui.Footer
+import com.android.settingslib.widget.FooterPreference
 import kotlin.coroutines.CoroutineContext
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.FlowPreview
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.emitAll
-import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flow
-import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
@@ -105,7 +88,7 @@
 @OptIn(ExperimentalCoroutinesApi::class)
 class DeviceDetailsFragmentFormatterImpl(
     private val context: Context,
-    private val fragment: DashboardFragment,
+    private val dashboardFragment: DashboardFragment,
     controllers: List<AbstractPreferenceController>,
     private val bluetoothAdapter: BluetoothAdapter,
     private val cachedDevice: CachedBluetoothDevice,
@@ -120,32 +103,30 @@
 
     private val viewModel: BluetoothDeviceDetailsViewModel =
         ViewModelProvider(
-            fragment,
-            BluetoothDeviceDetailsViewModel.Factory(
-                fragment.requireActivity().application,
-                bluetoothAdapter,
-                cachedDevice,
-                backgroundCoroutineContext,
-            ),
-        )
+                dashboardFragment,
+                BluetoothDeviceDetailsViewModel.Factory(
+                    dashboardFragment.requireActivity().application,
+                    bluetoothAdapter,
+                    cachedDevice,
+                    backgroundCoroutineContext,
+                ),
+            )
             .get(BluetoothDeviceDetailsViewModel::class.java)
 
     /** Updates bluetooth device details fragment layout. */
     override fun updateLayout(fragmentType: FragmentTypeModel) {
-        fragment.setLoading(true, false)
+        dashboardFragment.setLoading(true, false)
         isLoading = true
-        fragment.lifecycleScope.launch { updateLayoutInternal(fragmentType) }
+        dashboardFragment.lifecycleScope.launch { updateLayoutInternal(fragmentType) }
     }
 
     private suspend fun updateLayoutInternal(fragmentType: FragmentTypeModel) {
-        val items = viewModel.getItems(fragmentType) ?: run {
-            fragment.setLoading(false, false)
-            return
-        }
-        val layout = viewModel.getLayout(fragmentType) ?: run {
-            fragment.setLoading(false, false)
-            return
-        }
+        val items =
+            viewModel.getItems(fragmentType)
+                ?: run {
+                    dashboardFragment.setLoading(false, false)
+                    return
+                }
 
         val prefKeyToSettingId =
             items
@@ -153,14 +134,14 @@
                 .associateBy({ it.preferenceKey }, { it.settingId })
 
         val settingIdToXmlPreferences: MutableMap<Int, Preference> = HashMap()
-        for (i in 0 until fragment.preferenceScreen.preferenceCount) {
-            val pref = fragment.preferenceScreen.getPreference(i)
+        for (i in 0 until dashboardFragment.preferenceScreen.preferenceCount) {
+            val pref = dashboardFragment.preferenceScreen.getPreference(i)
             prefKeyToSettingId[pref.key]?.let { id -> settingIdToXmlPreferences[id] = pref }
             if (pref.key !in prefKeyToSettingId) {
                 getController(pref.key)?.let { disableController(it) }
             }
         }
-        fragment.preferenceScreen.removeAll()
+        dashboardFragment.preferenceScreen.removeAll()
         for (job in prefVisibilityJobs) {
             job.cancel()
         }
@@ -170,53 +151,83 @@
             val settingId = settingItem.settingId
             if (settingIdToXmlPreferences.containsKey(settingId)) {
                 val pref = settingIdToXmlPreferences[settingId]!!.apply { order = row }
-                fragment.preferenceScreen.addPreference(pref)
+                dashboardFragment.preferenceScreen.addPreference(pref)
             } else {
                 val prefKey = getPreferenceKey(settingId)
+
                 prefVisibilityJobs.add(
-                    getDevicesSettingForRow(layout, row)
-                        .onEach { logItemShown(prefKey, it.isNotEmpty()) }
-                        .launchIn(fragment.lifecycleScope)
+                    viewModel
+                        .getDeviceSetting(cachedDevice, settingId)
+                        .onEach { logItemShown(prefKey, it != null) }
+                        .launchIn(dashboardFragment.lifecycleScope)
                 )
-                val pref =
-                    ComposePreference(context)
-                        .apply {
-                            key = prefKey
-                            order = row
+                if (settingId == DeviceSettingId.DEVICE_SETTING_ID_ANC) {
+                    // TODO(b/399316980): replace it with SegmentedButtonPreference once it's ready.
+                    val pref =
+                        ComposePreference(context)
+                            .apply {
+                                key = prefKey
+                                order = row
+                            }
+                            .also { pref ->
+                                pref.setContent {
+                                    buildComposePreference(cachedDevice, settingId, prefKey)
+                                }
+                            }
+                    dashboardFragment.preferenceScreen.addPreference(pref)
+                } else {
+                    viewModel
+                        .getDeviceSetting(cachedDevice, settingId)
+                        .onEach {
+                            val existedPref =
+                                dashboardFragment.preferenceScreen.findPreference<Preference>(
+                                    prefKey
+                                )
+                            val item =
+                                it
+                                    ?: run {
+                                        existedPref?.let {
+                                            dashboardFragment.preferenceScreen.removePreference(
+                                                existedPref
+                                            )
+                                        }
+                                        return@onEach
+                                    }
+                            buildPreference(existedPref, item, prefKey, settingItem.highlighted)
+                                ?.apply {
+                                    key = prefKey
+                                    order = row
+                                }
+                                ?.also { dashboardFragment.preferenceScreen.addPreference(it) }
                         }
-                        .also { pref -> pref.setContent { buildPreference(layout, row, prefKey) } }
-                fragment.preferenceScreen.addPreference(pref)
+                        .launchIn(dashboardFragment.lifecycleScope)
+                }
             }
         }
-        // TODO(b/343317785): figure out how to remove the foot preference.
-        fragment.preferenceScreen.addPreference(ComposePreference(context).apply {
-            order = 10000
-            isEnabled = false
-            isSelectable = false
-            setContent { Spacer(modifier = Modifier.height(1.dp)) }
-        })
 
         for (row in items.indices) {
             val settingItem = items[row]
             val settingId = settingItem.settingId
-            if (settingIdToXmlPreferences.containsKey(settingId)) {
-                val pref = fragment.preferenceScreen.getPreference(row)
+            settingIdToXmlPreferences[settingId]?.let { pref ->
                 if (settingId == DeviceSettingId.DEVICE_SETTING_ID_BLUETOOTH_PROFILES) {
                     (getController(pref.key) as? BluetoothDetailsProfilesController)?.run {
-                        if (settingItem is DeviceSettingConfigItemModel.BuiltinItem.BluetoothProfilesItem) {
+                        if (
+                            settingItem
+                                is DeviceSettingConfigItemModel.BuiltinItem.BluetoothProfilesItem
+                        ) {
                             setInvisibleProfiles(settingItem.invisibleProfiles)
                             setHasExtraSpace(false)
                         }
                     }
                 }
-                getController(pref.key)?.displayPreference(fragment.preferenceScreen)
+                getController(pref.key)?.displayPreference(dashboardFragment.preferenceScreen)
                 logItemShown(pref.key, pref.isVisible)
             }
         }
 
-        fragment.lifecycleScope.launch {
+        dashboardFragment.lifecycleScope.launch {
             if (isLoading) {
-                fragment.setLoading(false, false)
+                dashboardFragment.setLoading(false, false)
                 isLoading = false
             }
         }
@@ -236,88 +247,171 @@
         } ?: emit(null)
     }
 
-    private fun getDevicesSettingForRow(
-        layout: DeviceSettingLayout,
-        row: Int,
-    ): Flow<List<DeviceSettingPreferenceModel>> =
-        layout.rows[row].columns.flatMapLatest { columns ->
-            if (columns.isEmpty()) {
-                flowOf(emptyList())
-            } else {
-                combine(
-                    columns.map { column ->
-                        viewModel.getDeviceSetting(cachedDevice, column.settingId)
-                    }
-                ) {
-                    it.toList().filterNotNull()
+    private fun buildPreference(
+        existedPref: Preference?,
+        model: DeviceSettingPreferenceModel,
+        prefKey: String,
+        highlighted: Boolean,
+    ): Preference? =
+        when (model) {
+            is DeviceSettingPreferenceModel.PlainPreference -> {
+                val pref =
+                    existedPref
+                        ?: run {
+                            if (highlighted) SpotlightPreference(context) else Preference(context)
+                        }
+                pref.apply {
+                    title = model.title
+                    summary = model.summary
+                    icon = getDrawable(model.icon)
+                    onPreferenceClickListener =
+                        object : Preference.OnPreferenceClickListener {
+                            override fun onPreferenceClick(p: Preference): Boolean {
+                                logItemClick(prefKey, EVENT_CLICK_PRIMARY)
+                                model.action?.let { triggerAction(it) }
+                                return true
+                            }
+                        }
                 }
             }
+            is DeviceSettingPreferenceModel.SwitchPreference ->
+                if (model.action == null) {
+                    val pref =
+                        existedPref as? SwitchPreferenceCompat ?: SwitchPreferenceCompat(context)
+                    pref.apply {
+                        title = model.title
+                        summary = model.summary
+                        icon = getDrawable(model.icon)
+                        isChecked = model.checked
+                        isEnabled = !model.disabled
+                        onPreferenceChangeListener =
+                            object : Preference.OnPreferenceChangeListener {
+                                override fun onPreferenceChange(
+                                    p: Preference,
+                                    value: Any?,
+                                ): Boolean {
+                                    (p as? TwoStatePreference)?.let { newState ->
+                                        val newState = value as? Boolean ?: return false
+                                        logItemClick(
+                                            prefKey,
+                                            if (newState) EVENT_SWITCH_ON else EVENT_SWITCH_OFF,
+                                        )
+                                        isEnabled = false
+                                        model.onCheckedChange.invoke(newState)
+                                    }
+                                    return false
+                                }
+                            }
+                    }
+                } else {
+                    val pref =
+                        existedPref as? PrimarySwitchPreference ?: PrimarySwitchPreference(context)
+                    pref.apply {
+                        title = model.title
+                        summary = model.summary
+                        icon = getDrawable(model.icon)
+                        isChecked = model.checked
+                        isEnabled = !model.disabled
+                        isSwitchEnabled = !model.disabled
+                        onPreferenceClickListener =
+                            object : Preference.OnPreferenceClickListener {
+                                override fun onPreferenceClick(p: Preference): Boolean {
+                                    logItemClick(prefKey, EVENT_CLICK_PRIMARY)
+                                    triggerAction(model.action)
+                                    return true
+                                }
+                            }
+                        onPreferenceChangeListener =
+                            object : Preference.OnPreferenceChangeListener {
+                                override fun onPreferenceChange(
+                                    p: Preference,
+                                    value: Any?,
+                                ): Boolean {
+                                    val newState = value as? Boolean ?: return false
+                                    logItemClick(
+                                        prefKey,
+                                        if (newState) EVENT_SWITCH_ON else EVENT_SWITCH_OFF,
+                                    )
+                                    isSwitchEnabled = false
+                                    model.onCheckedChange.invoke(newState)
+                                    return false
+                                }
+                            }
+                    }
+                }
+
+            is DeviceSettingPreferenceModel.MultiTogglePreference -> {
+                // TODO(b/399316980): implemented it by SegmentedButtonPreference
+                null
+            }
+            is DeviceSettingPreferenceModel.FooterPreference -> {
+                val pref = existedPref as? FooterPreference ?: FooterPreference(context)
+                pref.apply { title = model.footerText }
+            }
+            is DeviceSettingPreferenceModel.MoreSettingsPreference -> {
+                val pref = existedPref ?: Preference(context)
+                pref.apply {
+                    title =
+                        context.getString(R.string.bluetooth_device_more_settings_preference_title)
+                    summary =
+                        context.getString(
+                            R.string.bluetooth_device_more_settings_preference_summary
+                        )
+                    icon = context.getDrawable(R.drawable.ic_chevron_right_24dp)
+                    onPreferenceClickListener =
+                        object : Preference.OnPreferenceClickListener {
+                            override fun onPreferenceClick(p: Preference): Boolean {
+                                logItemClick(prefKey, EVENT_CLICK_PRIMARY)
+                                SubSettingLauncher(context)
+                                    .setDestination(
+                                        DeviceDetailsMoreSettingsFragment::class.java.name
+                                    )
+                                    .setSourceMetricsCategory(
+                                        dashboardFragment.getMetricsCategory()
+                                    )
+                                    .setArguments(
+                                        Bundle().apply {
+                                            putString(KEY_DEVICE_ADDRESS, cachedDevice.address)
+                                        }
+                                    )
+                                    .launch()
+                                return true
+                            }
+                        }
+                }
+            }
+            is DeviceSettingPreferenceModel.HelpPreference -> {
+                null
+            }
         }
 
-    @Composable
-    private fun buildPreference(layout: DeviceSettingLayout, row: Int, prefKey: String) {
-        val contents by
-        remember(row) { getDevicesSettingForRow(layout, row) }
-            .collectAsStateWithLifecycle(initialValue = listOf())
-
-        val highlighted by
-        remember(row) {
-            layout.rows[row].columns.map { columns -> columns.any { it.highlighted } }
+    private fun getDrawable(deviceSettingIcon: DeviceSettingIcon?): Drawable? =
+        when (deviceSettingIcon) {
+            is DeviceSettingIcon.BitmapIcon ->
+                deviceSettingIcon.bitmap.toDrawable(context.resources)
+            is DeviceSettingIcon.ResourceIcon -> context.getDrawable(deviceSettingIcon.resId)
+            null -> null
         }
-            .collectAsStateWithLifecycle(initialValue = false)
+
+    @Composable
+    private fun buildComposePreference(
+        cachedDevice: CachedBluetoothDevice,
+        settingId: Int,
+        prefKey: String,
+    ) {
+        val contents by
+            remember(settingId) { viewModel.getDeviceSetting(cachedDevice, settingId) }
+                .collectAsStateWithLifecycle(initialValue = null)
 
         val settings = contents
-        AnimatedVisibility(visible = settings.isNotEmpty(), enter = fadeIn(), exit = fadeOut()) {
-            Box {
-                Box(
-                    modifier =
-                        Modifier.matchParentSize()
-                            .padding(16.dp, 0.dp, 8.dp, 0.dp)
-                            .background(
-                                color =
-                                    if (highlighted) {
-                                        MaterialTheme.colorScheme.primaryContainer
-                                    } else {
-                                        Color.Transparent
-                                    },
-                                shape = RoundedCornerShape(28.dp),
-                            )
-                ) {}
-                buildPreferences(settings, prefKey)
+        AnimatedVisibility(visible = settings != null, enter = fadeIn(), exit = fadeOut()) {
+            (settings as? DeviceSettingPreferenceModel.MultiTogglePreference)?.let {
+                buildMultiTogglePreference(it, prefKey)
             }
         }
     }
 
     @Composable
-    fun buildPreferences(settings: List<DeviceSettingPreferenceModel?>, prefKey: String) {
-        when (settings.size) {
-            0 -> {}
-            1 -> {
-                when (val setting = settings[0]) {
-                    is DeviceSettingPreferenceModel.PlainPreference -> {
-                        buildPlainPreference(setting, prefKey)
-                    }
-                    is DeviceSettingPreferenceModel.SwitchPreference -> {
-                        buildSwitchPreference(setting, prefKey)
-                    }
-                    is DeviceSettingPreferenceModel.MultiTogglePreference -> {
-                        buildMultiTogglePreference(setting, prefKey)
-                    }
-                    is DeviceSettingPreferenceModel.FooterPreference -> {
-                        buildFooterPreference(setting)
-                    }
-                    is DeviceSettingPreferenceModel.MoreSettingsPreference -> {
-                        buildMoreSettingsPreference(prefKey)
-                    }
-                    is DeviceSettingPreferenceModel.HelpPreference -> {}
-                    null -> {}
-                }
-            }
-            else -> {}
-        }
-    }
-
-    @Composable
     private fun buildMultiTogglePreference(
         pref: DeviceSettingPreferenceModel.MultiTogglePreference,
         prefKey: String,
@@ -332,107 +426,6 @@
         )
     }
 
-    @Composable
-    private fun buildSwitchPreference(
-        model: DeviceSettingPreferenceModel.SwitchPreference,
-        prefKey: String,
-    ) {
-        val switchPrefModel =
-            object : SwitchPreferenceModel {
-                override val title = model.title
-                override val summary = { model.summary ?: "" }
-                override val checked = { model.checked }
-                override val onCheckedChange = { newState: Boolean ->
-                    logItemClick(prefKey, if (newState) EVENT_SWITCH_ON else EVENT_SWITCH_OFF)
-                    model.onCheckedChange(newState)
-                }
-                override val changeable = { !model.disabled }
-                override val icon: (@Composable () -> Unit)?
-                    get() {
-                        if (model.icon == null) {
-                            return null
-                        }
-                        return { deviceSettingIcon(model.icon) }
-                    }
-            }
-        if (model.action != null) {
-            TwoTargetSwitchPreference(
-                switchPrefModel,
-                primaryOnClick = {
-                    logItemClick(prefKey, EVENT_CLICK_PRIMARY)
-                    triggerAction(model.action)
-                },
-                primaryEnabled = { !model.disabled },
-            )
-        } else {
-            SwitchPreference(switchPrefModel)
-        }
-    }
-
-    @Composable
-    private fun buildPlainPreference(
-        model: DeviceSettingPreferenceModel.PlainPreference,
-        prefKey: String,
-    ) {
-        SpaPreference(
-            object : PreferenceModel {
-                override val title = model.title
-                override val summary = { model.summary ?: "" }
-                override val onClick = {
-                    logItemClick(prefKey, EVENT_CLICK_PRIMARY)
-                    model.action?.let { triggerAction(it) }
-                    Unit
-                }
-                override val icon: (@Composable () -> Unit)?
-                    get() {
-                        if (model.icon == null) {
-                            return null
-                        }
-                        return { deviceSettingIcon(model.icon) }
-                    }
-            }
-        )
-    }
-
-    @Composable
-    fun buildMoreSettingsPreference(prefKey: String) {
-        SpaPreference(
-            object : PreferenceModel {
-                override val title =
-                    stringResource(R.string.bluetooth_device_more_settings_preference_title)
-                override val summary = {
-                    context.getString(R.string.bluetooth_device_more_settings_preference_summary)
-                }
-                override val onClick = {
-                    logItemClick(prefKey, EVENT_CLICK_PRIMARY)
-                    SubSettingLauncher(context)
-                        .setDestination(DeviceDetailsMoreSettingsFragment::class.java.name)
-                        .setSourceMetricsCategory(fragment.getMetricsCategory())
-                        .setArguments(
-                            Bundle().apply { putString(KEY_DEVICE_ADDRESS, cachedDevice.address) }
-                        )
-                        .launch()
-                }
-                override val icon =
-                    @Composable {
-                        deviceSettingIcon(
-                            DeviceSettingIcon.ResourceIcon(R.drawable.ic_chevron_right_24dp)
-                        )
-                    }
-            }
-        )
-    }
-
-    @Composable
-    fun buildFooterPreference(model: DeviceSettingPreferenceModel.FooterPreference) {
-        Footer(footerText = model.footerText)
-    }
-
-    @Composable
-    private fun deviceSettingIcon(icon: DeviceSettingIcon?) {
-        icon?.let { Icon(it, modifier = Modifier.size(SettingsDimension.itemIconSize)) }
-    }
-
     private fun logItemClick(preferenceKey: String, value: Int = 0) {
         logAction(preferenceKey, SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_ITEM_CLICKED, value)
     }
@@ -452,7 +445,7 @@
                                 if (it) EVENT_VISIBLE else EVENT_INVISIBLE,
                             )
                         }
-                        .launchIn(fragment.lifecycleScope)
+                        .launchIn(dashboardFragment.lifecycleScope)
                 }
             }
             .value = visible
@@ -485,7 +478,7 @@
 
     private fun disableController(controller: AbstractPreferenceController) {
         if (controller is LifecycleObserver) {
-            fragment.settingsLifecycle.removeObserver(controller as LifecycleObserver)
+            dashboardFragment.settingsLifecycle.removeObserver(controller as LifecycleObserver)
         }
 
         if (controller is BlockingPrefWithSliceController) {
@@ -504,6 +497,19 @@
 
     private fun getPreferenceKey(settingId: Int) = "DEVICE_SETTING_${settingId}"
 
+    private class SpotlightPreference(context: Context) : Preference(context) {
+
+        init {
+            layoutResource = R.layout.bluetooth_device_spotlight_preference
+        }
+
+        override fun onBindViewHolder(holder: PreferenceViewHolder) {
+            super.onBindViewHolder(holder)
+            holder.isDividerAllowedBelow = false
+            holder.isDividerAllowedAbove = false
+        }
+    }
+
     private companion object {
         const val TAG = "DeviceDetailsFormatter"
         const val EVENT_SWITCH_OFF = 0
diff --git a/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt b/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt
index 8d3b853..5434ec9 100644
--- a/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt
+++ b/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt
@@ -23,9 +23,6 @@
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.viewModelScope
 import com.android.settings.R
-import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
-import com.android.settings.bluetooth.ui.layout.DeviceSettingLayoutColumn
-import com.android.settings.bluetooth.ui.layout.DeviceSettingLayoutRow
 import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
 import com.android.settings.bluetooth.ui.model.FragmentTypeModel
 import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
@@ -39,11 +36,8 @@
 import kotlinx.coroutines.CoroutineStart
 import kotlinx.coroutines.async
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
 
 class BluetoothDeviceDetailsViewModel(
     private val application: Application,
@@ -141,43 +135,6 @@
         }
     }
 
-    suspend fun getLayout(fragment: FragmentTypeModel): DeviceSettingLayout? {
-        val configItems = getItems(fragment) ?: return null
-        val idToDeviceSetting =
-            configItems
-                .filterIsInstance<DeviceSettingConfigItemModel.AppProvidedItem>()
-                .associateBy({ it.settingId }, { getDeviceSetting(cachedDevice, it.settingId) })
-
-        val configDeviceSetting =
-            configItems.map { idToDeviceSetting[it.settingId] ?: flowOf(null) }
-        val positionToSettingIds =
-            combine(configDeviceSetting) { settings ->
-                    val positionMapping = mutableMapOf<Int, List<DeviceSettingLayoutColumn>>()
-                    for (i in settings.indices) {
-                        val configItem = configItems[i]
-                        val setting = settings[i]
-                        val isXmlPreference = configItem is DeviceSettingConfigItemModel.BuiltinItem
-                        if (!isXmlPreference && setting == null) {
-                            continue
-                        }
-                        positionMapping[i] =
-                            listOf(
-                                DeviceSettingLayoutColumn(
-                                    configItem.settingId,
-                                    configItem.highlighted,
-                                )
-                            )
-                    }
-                    positionMapping
-                }
-                .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), initialValue = mapOf())
-        return DeviceSettingLayout(
-            configItems.indices.map { idx ->
-                DeviceSettingLayoutRow(positionToSettingIds.map { it[idx] ?: emptyList() })
-            }
-        )
-    }
-
     class Factory(
         private val application: Application,
         private val bluetoothAdapter: BluetoothAdapter,
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java
index 90ff344..c3459f5 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java
@@ -103,7 +103,7 @@
             return false;
         }
         Lifecycle.State currentState = host.getLifecycle().getCurrentState();
-        if (!currentState.isAtLeast(Lifecycle.State.STARTED)) {
+        if (!currentState.isAtLeast(Lifecycle.State.CREATED)) {
             Log.d(TAG, "Fail to show dialog with state: " + currentState);
             return false;
         }
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java
index 02c4a4c..f244f5f 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java
@@ -102,7 +102,7 @@
             return false;
         }
         Lifecycle.State currentState = host.getLifecycle().getCurrentState();
-        if (!currentState.isAtLeast(Lifecycle.State.STARTED)) {
+        if (!currentState.isAtLeast(Lifecycle.State.CREATED)) {
             Log.d(TAG, "Fail to show dialog with state: " + currentState);
             return false;
         }
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java
index 65a9ac3..8a11ac5 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java
@@ -100,7 +100,7 @@
             return false;
         }
         Lifecycle.State currentState = host.getLifecycle().getCurrentState();
-        if (!currentState.isAtLeast(Lifecycle.State.STARTED)) {
+        if (!currentState.isAtLeast(Lifecycle.State.CREATED)) {
             Log.d(TAG, "Fail to show dialog with state: " + currentState);
             return false;
         }
diff --git a/src/com/android/settings/development/Enable16kPagesPreferenceController.java b/src/com/android/settings/development/Enable16kPagesPreferenceController.java
index d8ad55f..1c1b713 100644
--- a/src/com/android/settings/development/Enable16kPagesPreferenceController.java
+++ b/src/com/android/settings/development/Enable16kPagesPreferenceController.java
@@ -186,7 +186,13 @@
                     public void onFailure(@NonNull Throwable t) {
                         hideProgressDialog();
                         Log.e(TAG, "Failed to call applyPayload of UpdateEngineStable!", t);
-                        displayToast(mContext.getString(R.string.toast_16k_update_failed_text));
+                        // installUpdate will always throw localized messages.
+                        String message = t.getMessage();
+                        if (message != null) {
+                            displayToast(message);
+                        } else {
+                            displayToast(mContext.getString(R.string.toast_16k_update_failed_text));
+                        }
                     }
                 },
                 ContextCompat.getMainExecutor(mContext));
@@ -208,10 +214,8 @@
         int status = data.getInt(SystemUpdateManager.KEY_STATUS);
         if (status != SystemUpdateManager.STATUS_UNKNOWN
                 && status != SystemUpdateManager.STATUS_IDLE) {
-            throw new RuntimeException(
-                    "System has pending update! Please restart the device to complete applying"
-                            + " pending update. If you are seeing this after using 16KB developer"
-                            + " options, please check configuration and OTA packages!");
+            Log.e(TAG, "SystemUpdateManager is not available. Status :" + status);
+            throw new RuntimeException(mContext.getString(R.string.error_pending_updates));
         }
 
         // Publish system update info
@@ -223,7 +227,11 @@
             Log.i(TAG, "Update file path is " + updateFile.getAbsolutePath());
             applyUpdateFile(updateFile);
         } catch (IOException e) {
-            throw new RuntimeException(e);
+            Log.e(TAG, "Error occurred while applying OTA ", e);
+            throw new RuntimeException(mContext.getString(R.string.error_ota_failed));
+        } catch (Exception e) {
+            Log.e(TAG, "Unknown error occurred while applying OTA ", e);
+            throw new RuntimeException(mContext.getString(R.string.toast_16k_update_failed_text));
         }
     }
 
diff --git a/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java b/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java
index 0835081..93d3a0b 100644
--- a/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java
+++ b/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java
@@ -44,7 +44,7 @@
     static final long MEMORY_MIN_BYTES = DataUnit.GIGABYTES.toBytes(4); // 4_000_000_000
 
     @VisibleForTesting
-    static final long STORAGE_MIN_BYTES = DataUnit.GIGABYTES.toBytes(64); // 64_000_000_000
+    static final long STORAGE_MIN_BYTES = DataUnit.GIGABYTES.toBytes(16); // 16_000_000_000
 
     private static final String LINUX_TERMINAL_KEY = "linux_terminal";
 
diff --git a/src/com/android/settings/display/AdaptiveSleepPreference.kt b/src/com/android/settings/display/AdaptiveSleepPreference.kt
index a38925c..32f805f 100644
--- a/src/com/android/settings/display/AdaptiveSleepPreference.kt
+++ b/src/com/android/settings/display/AdaptiveSleepPreference.kt
@@ -33,9 +33,8 @@
 import com.android.settings.restriction.PreferenceRestrictionMixin
 import com.android.settingslib.RestrictedSwitchPreference
 import com.android.settingslib.datastore.KeyValueStore
-import com.android.settingslib.datastore.KeyedObservableDelegate
+import com.android.settingslib.datastore.KeyValueStoreDelegate
 import com.android.settingslib.datastore.SettingsSecureStore
-import com.android.settingslib.datastore.SettingsStore
 import com.android.settingslib.metadata.BooleanValuePreference
 import com.android.settingslib.metadata.PreferenceAvailabilityProvider
 import com.android.settingslib.metadata.PreferenceLifecycleContext
@@ -106,16 +105,14 @@
     @Suppress("UNCHECKED_CAST")
     private class Storage(
         private val context: Context,
-        private val settingsStore: SettingsStore = SettingsSecureStore.get(context),
-    ) : KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
+        private val settingsStore: KeyValueStore = SettingsSecureStore.get(context),
+    ) : KeyValueStoreDelegate {
 
-        override fun contains(key: String) = settingsStore.contains(key)
+        override val keyValueStoreDelegate
+            get() = settingsStore
 
         override fun <T : Any> getValue(key: String, valueType: Class<T>) =
             (context.canBeEnabled() && settingsStore.getBoolean(key) == true) as T
-
-        override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) =
-            settingsStore.setBoolean(key, value as Boolean?)
     }
 
     override fun onStart(context: PreferenceLifecycleContext) {
diff --git a/src/com/android/settings/display/BatteryPercentageSwitchPreference.kt b/src/com/android/settings/display/BatteryPercentageSwitchPreference.kt
index 2ce6436..26d1c94 100644
--- a/src/com/android/settings/display/BatteryPercentageSwitchPreference.kt
+++ b/src/com/android/settings/display/BatteryPercentageSwitchPreference.kt
@@ -23,8 +23,7 @@
 import com.android.settings.contract.KEY_BATTERY_PERCENTAGE
 import com.android.settings.metrics.PreferenceActionMetricsProvider
 import com.android.settingslib.datastore.KeyValueStore
-import com.android.settingslib.datastore.KeyedObservableDelegate
-import com.android.settingslib.datastore.SettingsStore
+import com.android.settingslib.datastore.KeyValueStoreDelegate
 import com.android.settingslib.datastore.SettingsSystemStore
 import com.android.settingslib.metadata.PreferenceAvailabilityProvider
 import com.android.settingslib.metadata.ReadWritePermit
@@ -71,17 +70,11 @@
     @Suppress("UNCHECKED_CAST")
     private class BatteryPercentageStorage(
         private val context: Context,
-        private val settingsStore: SettingsStore,
-    ) : KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
+        private val settingsStore: KeyValueStore,
+    ) : KeyValueStoreDelegate {
 
-        override fun contains(key: String) = settingsStore.contains(KEY)
-
-        override fun <T : Any> getValue(key: String, valueType: Class<T>) =
-            (settingsStore.getBoolean(key) ?: getDefaultValue(key, valueType)) as T
-
-        override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
-            settingsStore.setBoolean(key, value as Boolean)
-        }
+        override val keyValueStoreDelegate
+            get() = settingsStore
 
         override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) =
             context.resources.getBoolean(
diff --git a/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java b/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java
index e38f5d4..d3950ee 100644
--- a/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java
+++ b/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java
@@ -34,6 +34,7 @@
 import com.android.settings.core.TogglePreferenceController;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager;
 import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
 import com.android.settingslib.search.SearchIndexableRaw;
 
@@ -47,8 +48,8 @@
 
     private final DeviceStateRotationLockSettingsManager mAutoRotateSettingsManager;
     private final int mOrder;
-    private final DeviceStateRotationLockSettingsManager.DeviceStateRotationLockSettingsListener
-            mDeviceStateRotationLockSettingsListener = () -> updateState(mPreference);
+    private final DeviceStateAutoRotateSettingManager.DeviceStateAutoRotateSettingListener
+            mDeviceStateAutoRotateSettingListener = () -> updateState(mPreference);
     private final int mDeviceState;
     private final String mDeviceStateDescription;
     private final MetricsFeatureProvider mMetricsFeatureProvider;
@@ -77,12 +78,12 @@
 
     @OnLifecycleEvent(ON_START)
     void onStart() {
-        mAutoRotateSettingsManager.registerListener(mDeviceStateRotationLockSettingsListener);
+        mAutoRotateSettingsManager.registerListener(mDeviceStateAutoRotateSettingListener);
     }
 
     @OnLifecycleEvent(ON_STOP)
     void onStop() {
-        mAutoRotateSettingsManager.unregisterListener(mDeviceStateRotationLockSettingsListener);
+        mAutoRotateSettingsManager.unregisterListener(mDeviceStateAutoRotateSettingListener);
     }
 
     @Override
diff --git a/src/com/android/settings/display/DeviceStateAutoRotationHelper.java b/src/com/android/settings/display/DeviceStateAutoRotationHelper.java
index 223ef1a..3bf9def 100644
--- a/src/com/android/settings/display/DeviceStateAutoRotationHelper.java
+++ b/src/com/android/settings/display/DeviceStateAutoRotationHelper.java
@@ -26,7 +26,7 @@
 import com.android.settings.core.BasePreferenceController;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
-import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager.SettableDeviceState;
+import com.android.settingslib.devicestate.SettableDeviceState;
 import com.android.settingslib.search.SearchIndexableRaw;
 
 import com.google.common.collect.ImmutableList;
diff --git a/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt b/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt
index ee538db..8f1f9b5 100644
--- a/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt
+++ b/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt
@@ -29,8 +29,7 @@
 import com.android.settings.metrics.PreferenceActionMetricsProvider
 import com.android.settingslib.datastore.HandlerExecutor
 import com.android.settingslib.datastore.KeyValueStore
-import com.android.settingslib.datastore.KeyedObservableDelegate
-import com.android.settingslib.datastore.SettingsStore
+import com.android.settingslib.datastore.KeyValueStoreDelegate
 import com.android.settingslib.datastore.SettingsSystemStore
 import com.android.settingslib.metadata.PreferenceAvailabilityProvider
 import com.android.settingslib.metadata.PreferenceLifecycleContext
@@ -112,18 +111,16 @@
     @Suppress("UNCHECKED_CAST")
     private class PeakRefreshRateStore(
         private val context: Context,
-        private val settingsStore: SettingsStore,
-    ) : KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
+        private val settingsStore: KeyValueStore,
+    ) : KeyValueStoreDelegate {
 
-        override fun contains(key: String) = settingsStore.contains(key)
+        override val keyValueStoreDelegate
+            get() = settingsStore
 
-        override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>): T? {
-            if (key != KEY) return super.getDefaultValue(key, valueType)
-            return context.defaultPeakRefreshRate.refreshRateAsBoolean(context) as T
-        }
+        override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) =
+            context.defaultPeakRefreshRate.refreshRateAsBoolean(context) as T
 
         override fun <T : Any> getValue(key: String, valueType: Class<T>): T? {
-            if (key != KEY) return null
             val refreshRate = settingsStore.getFloat(KEY) ?: context.defaultPeakRefreshRate
             return refreshRate.refreshRateAsBoolean(context) as T
         }
diff --git a/src/com/android/settings/display/SmartAutoRotateController.java b/src/com/android/settings/display/SmartAutoRotateController.java
index b5e3af2..c99b2f8 100644
--- a/src/com/android/settings/display/SmartAutoRotateController.java
+++ b/src/com/android/settings/display/SmartAutoRotateController.java
@@ -46,6 +46,7 @@
 import com.android.settings.core.TogglePreferenceController;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager;
 import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
 
 /**
@@ -75,8 +76,8 @@
             };
 
     private final DeviceStateRotationLockSettingsManager mDeviceStateAutoRotateSettingsManager;
-    private final DeviceStateRotationLockSettingsManager.DeviceStateRotationLockSettingsListener
-            mDeviceStateRotationLockSettingsListener = () -> updateState(mPreference);
+    private final DeviceStateAutoRotateSettingManager.DeviceStateAutoRotateSettingListener
+            mDeviceStateAutoRotateSettingListener = () -> updateState(mPreference);
     private RotationPolicy.RotationPolicyListener mRotationPolicyListener;
 
     public SmartAutoRotateController(Context context, String preferenceKey) {
@@ -140,7 +141,7 @@
         }
         RotationPolicy.registerRotationPolicyListener(mContext, mRotationPolicyListener);
         mDeviceStateAutoRotateSettingsManager.registerListener(
-                mDeviceStateRotationLockSettingsListener);
+                mDeviceStateAutoRotateSettingListener);
         mPrivacyManager.addSensorPrivacyListener(CAMERA, mPrivacyChangedListener);
     }
 
@@ -152,7 +153,7 @@
             mRotationPolicyListener = null;
         }
         mDeviceStateAutoRotateSettingsManager.unregisterListener(
-                mDeviceStateRotationLockSettingsListener);
+                mDeviceStateAutoRotateSettingListener);
         mPrivacyManager.removeSensorPrivacyListener(CAMERA, mPrivacyChangedListener);
     }
 
diff --git a/src/com/android/settings/network/AdaptiveConnectivityTogglePreference.kt b/src/com/android/settings/network/AdaptiveConnectivityTogglePreference.kt
index 80f1d00..d495967 100644
--- a/src/com/android/settings/network/AdaptiveConnectivityTogglePreference.kt
+++ b/src/com/android/settings/network/AdaptiveConnectivityTogglePreference.kt
@@ -24,9 +24,8 @@
 import com.android.settings.contract.KEY_ADAPTIVE_CONNECTIVITY
 import com.android.settings.metrics.PreferenceActionMetricsProvider
 import com.android.settingslib.datastore.KeyValueStore
-import com.android.settingslib.datastore.KeyedObservableDelegate
+import com.android.settingslib.datastore.KeyValueStoreDelegate
 import com.android.settingslib.datastore.SettingsSecureStore
-import com.android.settingslib.datastore.SettingsStore
 import com.android.settingslib.metadata.MainSwitchPreference
 import com.android.settingslib.metadata.ReadWritePermit
 import com.android.settingslib.metadata.SensitivityLevel
@@ -42,7 +41,7 @@
     override fun tags(context: Context) = arrayOf(KEY_ADAPTIVE_CONNECTIVITY)
 
     override fun storage(context: Context): KeyValueStore =
-        AdaptiveConnectivityToggleStorage(context, SettingsSecureStore.get(context))
+        AdaptiveConnectivityToggleStorage(context)
 
     override fun getReadPermissions(context: Context) = SettingsSecureStore.getReadPermissions()
 
@@ -64,20 +63,20 @@
     @Suppress("UNCHECKED_CAST")
     private class AdaptiveConnectivityToggleStorage(
         private val context: Context,
-        private val settingsStore: SettingsStore,
-    ) : KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
+        private val settingsStore: KeyValueStore = SettingsSecureStore.get(context),
+    ) : KeyValueStoreDelegate {
 
-        override fun contains(key: String) = settingsStore.contains(KEY)
+        override val keyValueStoreDelegate
+            get() = settingsStore
 
         override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) =
             DEFAULT_VALUE as T
 
-        override fun <T : Any> getValue(key: String, valueType: Class<T>) =
-            (settingsStore.getBoolean(key) ?: DEFAULT_VALUE) as T
-
         override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
-            settingsStore.setBoolean(key, value as Boolean)
-            context.getSystemService(WifiManager::class.java)?.setWifiScoringEnabled(value)
+            settingsStore.setValue(key, valueType, value)
+            context
+                .getSystemService(WifiManager::class.java)
+                ?.setWifiScoringEnabled((value as Boolean?) ?: DEFAULT_VALUE)
         }
     }
 
diff --git a/src/com/android/settings/network/AirplaneModePreference.kt b/src/com/android/settings/network/AirplaneModePreference.kt
index de2eb1a..5a0dd5a 100644
--- a/src/com/android/settings/network/AirplaneModePreference.kt
+++ b/src/com/android/settings/network/AirplaneModePreference.kt
@@ -36,9 +36,8 @@
 import com.android.settings.restriction.PreferenceRestrictionMixin
 import com.android.settingslib.RestrictedSwitchPreference
 import com.android.settingslib.datastore.KeyValueStore
-import com.android.settingslib.datastore.KeyedObservableDelegate
+import com.android.settingslib.datastore.KeyValueStoreDelegate
 import com.android.settingslib.datastore.SettingsGlobalStore
-import com.android.settingslib.datastore.SettingsStore
 import com.android.settingslib.metadata.PreferenceAvailabilityProvider
 import com.android.settingslib.metadata.PreferenceLifecycleContext
 import com.android.settingslib.metadata.PreferenceLifecycleProvider
@@ -92,17 +91,15 @@
     @Suppress("UNCHECKED_CAST")
     private class AirplaneModeStorage(
         private val context: Context,
-        private val settingsStore: SettingsStore = SettingsGlobalStore.get(context),
-    ) : KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
+        private val settingsStore: KeyValueStore = SettingsGlobalStore.get(context),
+    ) : KeyValueStoreDelegate {
 
-        override fun contains(key: String) = settingsStore.contains(KEY)
+        override val keyValueStoreDelegate
+            get() = settingsStore
 
         override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) =
             DEFAULT_VALUE as T
 
-        override fun <T : Any> getValue(key: String, valueType: Class<T>): T =
-            (settingsStore.getBoolean(key) ?: DEFAULT_VALUE) as T
-
         override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
             settingsStore.setValue(key, valueType, value)
 
diff --git a/src/com/android/settings/privatespace/PrivateSpaceEducation.java b/src/com/android/settings/privatespace/PrivateSpaceEducation.java
index dfaf8b9..093d7a5 100644
--- a/src/com/android/settings/privatespace/PrivateSpaceEducation.java
+++ b/src/com/android/settings/privatespace/PrivateSpaceEducation.java
@@ -44,6 +44,8 @@
 public class PrivateSpaceEducation extends InstrumentedFragment {
     private static final String TAG = "PrivateSpaceEducation";
 
+    private boolean mIsAnimationPlaying = true;
+
     @Override
     public View onCreateView(
             LayoutInflater inflater,
@@ -73,6 +75,7 @@
                         .build());
         LottieAnimationView lottieAnimationView = rootView.findViewById(R.id.lottie_animation);
         LottieColorUtils.applyDynamicColors(getContext(), lottieAnimationView);
+        lottieAnimationView.setOnClickListener(v -> handleAnimationClick(lottieAnimationView));
 
         TextView infoTextView = rootView.findViewById(R.id.learn_more);
         Pattern pattern = Pattern.compile(infoTextView.getText().toString());
@@ -110,4 +113,13 @@
             }
         };
     }
+
+    private void handleAnimationClick(LottieAnimationView lottieAnimationView) {
+        if (mIsAnimationPlaying) {
+            lottieAnimationView.pauseAnimation();
+        } else {
+            lottieAnimationView.playAnimation();
+        }
+        mIsAnimationPlaying = !mIsAnimationPlaying;
+    }
 }
diff --git a/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java b/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java
index 28ac97f..47cf3ba 100644
--- a/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java
+++ b/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java
@@ -51,6 +51,8 @@
     private static final String TAG = "PrivateSpaceSetLockFrag";
     private static final int HEADER_TEXT_MAX_LINES = 4;
 
+    private boolean mIsAnimationPlaying = true;
+
     @Override
     public View onCreateView(
             LayoutInflater inflater,
@@ -91,6 +93,7 @@
         requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
         LottieAnimationView lottieAnimationView = rootView.findViewById(R.id.lottie_animation);
         LottieColorUtils.applyDynamicColors(getContext(), lottieAnimationView);
+        lottieAnimationView.setOnClickListener(v -> handleAnimationClick(lottieAnimationView));
 
         return rootView;
     }
@@ -130,4 +133,13 @@
             Log.w(TAG, "Private profile user handle is null");
         }
     }
+
+    private void handleAnimationClick(LottieAnimationView lottieAnimationView) {
+        if (mIsAnimationPlaying) {
+            lottieAnimationView.pauseAnimation();
+        } else {
+            lottieAnimationView.playAnimation();
+        }
+        mIsAnimationPlaying = !mIsAnimationPlaying;
+    }
 }
diff --git a/src/com/android/settings/privatespace/SetupSuccessFragment.java b/src/com/android/settings/privatespace/SetupSuccessFragment.java
index bfd9e96..538912e 100644
--- a/src/com/android/settings/privatespace/SetupSuccessFragment.java
+++ b/src/com/android/settings/privatespace/SetupSuccessFragment.java
@@ -49,6 +49,8 @@
 public class SetupSuccessFragment extends InstrumentedFragment {
     private static final String TAG = "SetupSuccessFragment";
 
+    private boolean mIsAnimationPlaying = true;
+
     @Override
     public View onCreateView(
             LayoutInflater inflater,
@@ -80,6 +82,7 @@
         requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
         LottieAnimationView lottieAnimationView = rootView.findViewById(R.id.lottie_animation);
         LottieColorUtils.applyDynamicColors(getContext(), lottieAnimationView);
+        lottieAnimationView.setOnClickListener(v -> handleAnimationClick(lottieAnimationView));
 
         return rootView;
     }
@@ -141,4 +144,13 @@
             task.finishAndRemoveTask();
         }
     }
+
+    private void handleAnimationClick(LottieAnimationView lottieAnimationView) {
+        if (mIsAnimationPlaying) {
+            lottieAnimationView.pauseAnimation();
+        } else {
+            lottieAnimationView.playAnimation();
+        }
+        mIsAnimationPlaying = !mIsAnimationPlaying;
+    }
 }
diff --git a/src/com/android/settings/sound/MediaControlsLockscreenSwitchPreference.kt b/src/com/android/settings/sound/MediaControlsLockscreenSwitchPreference.kt
index 59c1b8f..2d70b83 100644
--- a/src/com/android/settings/sound/MediaControlsLockscreenSwitchPreference.kt
+++ b/src/com/android/settings/sound/MediaControlsLockscreenSwitchPreference.kt
@@ -18,22 +18,21 @@
 
 import android.content.Context
 import android.provider.Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN
-
+import com.android.settings.R
 import com.android.settingslib.datastore.KeyValueStore
-import com.android.settingslib.datastore.KeyedObservableDelegate
+import com.android.settingslib.datastore.KeyValueStoreDelegate
 import com.android.settingslib.datastore.SettingsSecureStore
-import com.android.settingslib.datastore.SettingsStore
 import com.android.settingslib.metadata.ReadWritePermit
 import com.android.settingslib.metadata.SensitivityLevel
 import com.android.settingslib.metadata.SwitchPreference
-import com.android.settings.R
 
 // LINT.IfChange
-class MediaControlsLockscreenSwitchPreference : SwitchPreference(
-    KEY,
-    R.string.media_controls_lockscreen_title,
-    R.string.media_controls_lockscreen_description,
-) {
+class MediaControlsLockscreenSwitchPreference :
+    SwitchPreference(
+        KEY,
+        R.string.media_controls_lockscreen_title,
+        R.string.media_controls_lockscreen_description,
+    ) {
 
     override val sensitivityLevel
         get() = SensitivityLevel.NO_SENSITIVITY
@@ -52,21 +51,17 @@
         MediaControlsLockscreenStore(SettingsSecureStore.get(context))
 
     @Suppress("UNCHECKED_CAST")
-    private class MediaControlsLockscreenStore(private val settingsStore: SettingsStore) :
-        KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
-        override fun contains(key: String) = settingsStore.contains(key)
+    private class MediaControlsLockscreenStore(private val settingsStore: KeyValueStore) :
+        KeyValueStoreDelegate {
+
+        override val keyValueStoreDelegate
+            get() = settingsStore
 
         override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) = true as T
-
-        override fun <T : Any> getValue(key: String, valueType: Class<T>) =
-            settingsStore.getValue(key, valueType) ?: getDefaultValue(key, valueType)
-
-        override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) =
-            settingsStore.setValue(key, valueType, value)
     }
 
     companion object {
         const val KEY = MEDIA_CONTROLS_LOCK_SCREEN
     }
 }
-// LINT.ThenChange(MediaControlsLockScreenPreferenceController.java)
\ No newline at end of file
+// LINT.ThenChange(MediaControlsLockScreenPreferenceController.java)
diff --git a/src/com/android/settings/sound/MediaControlsScreen.kt b/src/com/android/settings/sound/MediaControlsScreen.kt
index d63259c..f9c2f64 100644
--- a/src/com/android/settings/sound/MediaControlsScreen.kt
+++ b/src/com/android/settings/sound/MediaControlsScreen.kt
@@ -17,21 +17,18 @@
 package com.android.settings.sound
 
 import android.content.Context
-
 import com.android.settings.R
 import com.android.settings.flags.Flags
 import com.android.settingslib.datastore.AbstractKeyedDataObservable
 import com.android.settingslib.datastore.HandlerExecutor
-import com.android.settingslib.datastore.KeyedObserver
 import com.android.settingslib.datastore.KeyValueStore
-import com.android.settingslib.datastore.KeyedObservableDelegate
+import com.android.settingslib.datastore.KeyValueStoreDelegate
+import com.android.settingslib.datastore.KeyedObserver
 import com.android.settingslib.datastore.SettingsSecureStore
-import com.android.settingslib.datastore.SettingsStore
 import com.android.settingslib.metadata.PreferenceChangeReason
-import com.android.settingslib.metadata.ProvidePreferenceScreen
 import com.android.settingslib.metadata.PreferenceSummaryProvider
+import com.android.settingslib.metadata.ProvidePreferenceScreen
 import com.android.settingslib.metadata.preferenceHierarchy
-
 import com.android.settingslib.preference.PreferenceScreenCreator
 
 // LINT.IfChange
@@ -83,21 +80,16 @@
         }
 
     @Suppress("UNCHECKED_CAST")
-    class MediaControlsStore(private val settingsStore: SettingsStore) :
-        KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
-        override fun contains(key: String) = settingsStore.contains(key)
+    class MediaControlsStore(private val settingsStore: KeyValueStore) : KeyValueStoreDelegate {
+
+        override val keyValueStoreDelegate
+            get() = settingsStore
 
         override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) = true as T
-
-        override fun <T : Any> getValue(key: String, valueType: Class<T>) =
-            settingsStore.getValue(key, valueType) ?: getDefaultValue(key, valueType)
-
-        override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) =
-            settingsStore.setValue(key, valueType, value)
     }
 
     companion object {
         const val KEY = "media_controls"
     }
 }
-// LINT.ThenChange(MediaControlsSettings.java)
\ No newline at end of file
+// LINT.ThenChange(MediaControlsSettings.java)
diff --git a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt
index 1e6e545..cbd9c53 100644
--- a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt
+++ b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt
@@ -45,7 +45,7 @@
         initialValue = stringResource(R.string.summary_placeholder),
     )
     Preference(object : PreferenceModel {
-        override val title = stringResource(R.string.aspect_ratio_experimental_title)
+        override val title = stringResource(R.string.aspect_ratio_title)
         override val summary = { summary }
         override val onClick = presenter::startActivity
     })
diff --git a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
index 3241d71..5902677 100644
--- a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
+++ b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
@@ -85,7 +85,7 @@
     fun EntryItem() {
         val summary = getSummary()
         Preference(object : PreferenceModel {
-            override val title = stringResource(R.string.aspect_ratio_experimental_title)
+            override val title = stringResource(R.string.aspect_ratio_title)
             override val summary = { summary }
             override val onClick = navigator(name)
         })
@@ -108,7 +108,7 @@
     = { AppList() },
 ) {
     AppListPage(
-        title = stringResource(R.string.aspect_ratio_experimental_title),
+        title = stringResource(R.string.aspect_ratio_title),
         listModel = rememberContext(::UserAspectRatioAppListModel),
         appList = appList,
         header = {
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
index 6710da9..a077e47 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
@@ -21,10 +21,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.robolectric.Shadows.shadowOf;
 
@@ -46,8 +43,6 @@
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
-import android.view.Menu;
-import android.view.MenuItem;
 import android.view.accessibility.AccessibilityManager;
 
 import androidx.fragment.app.Fragment;
@@ -112,7 +107,6 @@
     private static final String EMPTY_STRING = "";
     private static final String DEFAULT_SUMMARY = "default summary";
     private static final String DEFAULT_DESCRIPTION = "default description";
-    private static final String DEFAULT_CATEGORY = "default category";
     private static final String DEFAULT_LABEL = "default label";
     private static final Boolean SERVICE_ENABLED = true;
     private static final Boolean SERVICE_DISABLED = false;
@@ -128,10 +122,6 @@
     private ShadowAccessibilityManager mShadowAccessibilityManager;
     @Mock
     private LocalBluetoothManager mLocalBluetoothManager;
-    @Mock
-    private Menu mMenu;
-    @Mock
-    private MenuItem mMenuItem;
 
     private ActivityController<SettingsActivity> mActivityController;
 
@@ -452,58 +442,6 @@
     }
 
     @Test
-    @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
-    public void onCreateOptionsMenu_enableLowVisionGenericFeedback_shouldAddSendFeedbackMenu() {
-        setupFragment();
-        mFragment.setFeedbackManager(
-                new FeedbackManager(mFragment.getActivity(), PACKAGE_NAME, DEFAULT_CATEGORY));
-
-        mFragment.onCreateOptionsMenu(mMenu, /* inflater= */ null);
-
-        verify(mMenu).add(anyInt(), anyInt(), anyInt(), anyInt());
-    }
-
-    @Test
-    @DisableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
-    public void onCreateOptionsMenu_disableLowVisionGenericFeedback_shouldNotAddSendFeedbackMenu() {
-        setupFragment();
-        mFragment.setFeedbackManager(
-                new FeedbackManager(mFragment.getActivity(), PACKAGE_NAME, DEFAULT_CATEGORY));
-
-        mFragment.onCreateOptionsMenu(mMenu, /* inflater= */ null);
-
-        verify(mMenu, never()).add(anyInt(), anyInt(), anyInt(), anyInt());
-    }
-
-    @Test
-    @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
-    public void onOptionsItemSelected_enableLowVisionGenericFeedback_shouldStartSendFeedback() {
-        setupFragment();
-        mFragment.setFeedbackManager(
-                new FeedbackManager(mFragment.getActivity(), PACKAGE_NAME, DEFAULT_CATEGORY));
-        when(mMenuItem.getItemId()).thenReturn(AccessibilitySettings.MENU_ID_SEND_FEEDBACK);
-
-        mFragment.onOptionsItemSelected(mMenuItem);
-
-        Intent startedIntent = shadowOf(mFragment.getActivity()).getNextStartedActivity();
-        assertThat(startedIntent).isNotNull();
-    }
-
-    @Test
-    @DisableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
-    public void onOptionsItemSelected_disableLowVisionGenericFeedback_shouldNotStartSendFeedback() {
-        setupFragment();
-        mFragment.setFeedbackManager(
-                new FeedbackManager(mFragment.getActivity(), PACKAGE_NAME, DEFAULT_CATEGORY));
-        when(mMenuItem.getItemId()).thenReturn(AccessibilitySettings.MENU_ID_SEND_FEEDBACK);
-
-        mFragment.onOptionsItemSelected(mMenuItem);
-
-        Intent startedIntent = shadowOf(mFragment.getActivity()).getNextStartedActivity();
-        assertThat(startedIntent).isNull();
-    }
-
-    @Test
     public void testAccessibilityMenuInSystem_IncludedInInteractionControl() {
         mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
                 List.of(getMockAccessibilityServiceInfo(
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java
index ff73e7f..9d304ba 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java
@@ -31,6 +31,7 @@
 import android.app.settings.SettingsEnums;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.res.Resources;
 import android.os.Bundle;
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
@@ -82,6 +83,8 @@
     private PreferenceManager mPreferenceManager;
     @Mock
     private FragmentActivity mActivity;
+    @Mock
+    private Resources mResources;
 
     @Before
     public void setUpTestFragment() {
@@ -93,6 +96,7 @@
         when(mFragment.getContext()).thenReturn(mContext);
         when(mFragment.getActivity()).thenReturn(mActivity);
         when(mActivity.getContentResolver()).thenReturn(mContext.getContentResolver());
+        when(mActivity.getResources()).thenReturn(mResources);
 
         mScreen = spy(new PreferenceScreen(mContext, /* attrs= */ null));
         when(mScreen.findPreference(mFragment.getUseServicePreferenceKey()))
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java
index f72b591..cdd309f 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java
@@ -23,8 +23,6 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -38,16 +36,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.icu.text.CaseMap;
 import android.net.Uri;
 import android.os.Bundle;
-import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityManager;
@@ -107,19 +103,10 @@
             PLACEHOLDER_PACKAGE_NAME + "tile.placeholder";
     private static final ComponentName PLACEHOLDER_TILE_COMPONENT_NAME = new ComponentName(
             PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_TILE_CLASS_NAME);
-    private static final String PLACEHOLDER_TILE_TOOLTIP_CONTENT =
-            PLACEHOLDER_PACKAGE_NAME + "tooltip_content";
-    private static final String PLACEHOLDER_CATEGORY = "category";
-    private static final String PLACEHOLDER_DIALOG_TITLE = "title";
     private static final String DEFAULT_SUMMARY = "default summary";
     private static final String DEFAULT_DESCRIPTION = "default description";
     private static final String DEFAULT_TOP_INTRO = "default top intro";
 
-    private static final String SOFTWARE_SHORTCUT_KEY =
-            Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS;
-    private static final String HARDWARE_SHORTCUT_KEY =
-            Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
-
     private TestToggleFeaturePreferenceFragment mFragment;
     @Spy
     private final Context mContext = ApplicationProvider.getApplicationContext();
@@ -135,9 +122,7 @@
     @Mock
     private PackageManager mPackageManager;
     @Mock
-    private Menu mMenu;
-    @Mock
-    private MenuItem mMenuItem;
+    private Resources mResources;
 
     @Before
     public void setUpTestFragment() {
@@ -150,6 +135,7 @@
         when(mFragment.getContext()).thenReturn(mContext);
         when(mFragment.getActivity()).thenReturn(mActivity);
         when(mActivity.getContentResolver()).thenReturn(mContentResolver);
+        when(mActivity.getResources()).thenReturn(mResources);
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
         final PreferenceScreen screen = spy(new PreferenceScreen(mContext, null));
         when(screen.getPreferenceManager()).thenReturn(mPreferenceManager);
@@ -187,61 +173,6 @@
     }
 
     @Test
-    @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
-    public void onCreateOptionsMenu_enableLowVisionGenericFeedback_shouldAddSendFeedbackMenu() {
-        mFragment.setFeedbackManager(
-                new FeedbackManager(mActivity, PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CATEGORY));
-
-        mFragment.onCreateOptionsMenu(mMenu, /* inflater= */ null);
-
-        verify(mMenu).add(anyInt(), eq(ToggleFeaturePreferenceFragment.MENU_ID_SEND_FEEDBACK),
-                anyInt(), eq(R.string.accessibility_send_feedback_title));
-    }
-
-    @Test
-    @DisableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
-    public void onCreateOptionsMenu_disableLowVisionGenericFeedback_shouldNotAddSendFeedbackMenu() {
-        mFragment.setFeedbackManager(
-                new FeedbackManager(mActivity, PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CATEGORY));
-
-        mFragment.onCreateOptionsMenu(mMenu, /* inflater= */ null);
-
-        verify(mMenu, never()).add(anyInt(),
-                eq(ToggleFeaturePreferenceFragment.MENU_ID_SEND_FEEDBACK), anyInt(),
-                        eq(R.string.accessibility_send_feedback_title));
-    }
-
-    @Test
-    @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
-    public void onOptionsItemSelected_enableLowVisionGenericFeedback_shouldStartSendFeedback() {
-        mFragment.setFeedbackManager(
-                new FeedbackManager(mActivity, PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CATEGORY));
-        when(mMenuItem.getItemId()).thenReturn(
-                ToggleFeaturePreferenceFragment.MENU_ID_SEND_FEEDBACK);
-
-        mFragment.onOptionsItemSelected(mMenuItem);
-
-        verify(mActivity).startActivityForResult(
-                argThat(intent -> intent != null
-                        && Intent.ACTION_BUG_REPORT.equals(intent.getAction())), anyInt());
-    }
-
-    @Test
-    @DisableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
-    public void onOptionsItemSelected_disableLowVisionGenericFeedback_shouldNotStartSendFeedback() {
-        mFragment.setFeedbackManager(
-                new FeedbackManager(mActivity, PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CATEGORY));
-        when(mMenuItem.getItemId()).thenReturn(
-                ToggleFeaturePreferenceFragment.MENU_ID_SEND_FEEDBACK);
-
-        mFragment.onOptionsItemSelected(mMenuItem);
-
-        verify(mActivity, never()).startActivityForResult(
-                argThat(intent -> intent != null
-                        && Intent.ACTION_BUG_REPORT.equals(intent.getAction())), anyInt());
-    }
-
-    @Test
     public void updateShortcutPreferenceData_assignDefaultValueToVariable() {
         mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME;
 
diff --git a/tests/robotests/src/com/android/settings/accessibility/actionbar/FeedbackMenuControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/actionbar/FeedbackMenuControllerTest.java
new file mode 100644
index 0000000..7208f49
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/actionbar/FeedbackMenuControllerTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility.actionbar;
+
+import static com.android.settings.accessibility.actionbar.FeedbackMenuController.MENU_FEEDBACK;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
+
+import android.app.settings.SettingsEnums;
+import android.content.Intent;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.testing.EmptyFragmentActivity;
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+
+import com.android.settings.accessibility.FeedbackManager;
+import com.android.settings.core.InstrumentedPreferenceFragment;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+/** Tests for {@link FeedbackMenuController} */
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
+@RunWith(RobolectricTestRunner.class)
+public class FeedbackMenuControllerTest {
+    private static final String PACKAGE_NAME = "com.android.test";
+    private static final String DEFAULT_CATEGORY = "default category";
+
+    @Rule
+    public final MockitoRule mMocks = MockitoJUnit.rule();
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+    @Rule
+    public ActivityScenarioRule<EmptyFragmentActivity> mActivityScenario =
+            new ActivityScenarioRule<>(EmptyFragmentActivity.class);
+
+    private FragmentActivity mActivity;
+    private InstrumentedPreferenceFragment mHost;
+    private FeedbackManager mFeedbackManager;
+    @Mock
+    private Lifecycle mLifecycle;
+    @Mock
+    private Menu mMenu;
+    @Mock
+    private MenuItem mMenuItem;
+
+    @Before
+    public void setUp() {
+        mActivityScenario.getScenario().onActivity(activity -> mActivity = activity);
+        mHost = spy(new InstrumentedPreferenceFragment() {
+            @Override
+            public int getMetricsCategory() {
+                return 0;
+            }
+        });
+        when(mHost.getActivity()).thenReturn(mActivity);
+        when(mMenu.add(anyInt(), anyInt(), anyInt(), anyInt())).thenReturn(mMenuItem);
+        when(mMenuItem.getItemId()).thenReturn(MENU_FEEDBACK);
+        mFeedbackManager = new FeedbackManager(mActivity, PACKAGE_NAME, DEFAULT_CATEGORY);
+    }
+
+    @Test
+    public void init_withPageId_shouldAttachToLifecycle() {
+        when(mHost.getSettingsLifecycle()).thenReturn(mLifecycle);
+
+        FeedbackMenuController.init(mHost, SettingsEnums.ACCESSIBILITY);
+
+        verify(mLifecycle).addObserver(any(FeedbackMenuController.class));
+    }
+
+    @Test
+    public void init_withFeedbackManager_shouldAttachToLifecycle() {
+        when(mHost.getSettingsLifecycle()).thenReturn(mLifecycle);
+
+        FeedbackMenuController.init(mHost, mFeedbackManager);
+
+        verify(mLifecycle).addObserver(any(FeedbackMenuController.class));
+    }
+
+    @Test
+    @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
+    public void onCreateOptionsMenu_enableLowVisionGenericFeedback_shouldAddSendFeedbackMenu() {
+        FeedbackMenuController.init(mHost, mFeedbackManager);
+
+        mHost.getSettingsLifecycle().onCreateOptionsMenu(mMenu, /* inflater= */ null);
+
+        verify(mMenu).add(anyInt(), anyInt(), anyInt(), anyInt());
+    }
+
+    @Test
+    @DisableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
+    public void onCreateOptionsMenu_disableLowVisionGenericFeedback_shouldNotAddSendFeedbackMenu() {
+        FeedbackMenuController.init(mHost, mFeedbackManager);
+
+        mHost.getSettingsLifecycle().onCreateOptionsMenu(mMenu, /* inflater= */ null);
+
+        verify(mMenu, never()).add(anyInt(), anyInt(), anyInt(), anyInt());
+    }
+
+    @Test
+    @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
+    public void onOptionsItemSelected_enableLowVisionGenericFeedback_shouldStartSendFeedback() {
+        FeedbackMenuController.init(mHost, mFeedbackManager);
+
+        mHost.getSettingsLifecycle().onOptionsItemSelected(mMenuItem);
+
+        Intent intent = shadowOf(mActivity).getNextStartedActivity();
+        assertThat(intent.getAction()).isEqualTo(Intent.ACTION_BUG_REPORT);
+    }
+
+    @Test
+    @DisableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
+    public void onOptionsItemSelected_disableLowVisionGenericFeedback_shouldNotStartSendFeedback() {
+        FeedbackMenuController.init(mHost, mFeedbackManager);
+
+        mHost.getSettingsLifecycle().onOptionsItemSelected(mMenuItem);
+
+        Intent intent = shadowOf(mActivity).getNextStartedActivity();
+        assertThat(intent).isNull();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt b/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt
index d0bd27d..1eb15e5 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt
+++ b/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt
@@ -16,7 +16,7 @@
 
 package com.android.settings.bluetooth.ui.view
 
-import android.app.settings.SettingsEnums;
+import android.app.settings.SettingsEnums
 import android.bluetooth.BluetoothAdapter
 import android.content.Context
 import android.content.Intent
@@ -25,6 +25,7 @@
 import androidx.preference.Preference
 import androidx.preference.PreferenceManager
 import androidx.preference.PreferenceScreen
+import androidx.preference.SwitchPreferenceCompat
 import androidx.test.core.app.ApplicationProvider
 import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
 import com.android.settings.bluetooth.ui.model.FragmentTypeModel
@@ -33,6 +34,7 @@
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
 import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
 import com.android.settingslib.bluetooth.devicesettings.data.repository.DeviceSettingRepository
+import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingActionModel
 import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
 import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigModel
 import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
@@ -58,14 +60,15 @@
 import org.mockito.Mockito.any
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when`
+import org.mockito.Spy
 import org.mockito.junit.MockitoJUnit
 import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.doNothing
 import org.robolectric.Robolectric
 import org.robolectric.RobolectricTestRunner
 import org.robolectric.shadows.ShadowLooper
 import org.robolectric.shadows.ShadowLooper.shadowMainLooper
 
-
 @ExperimentalCoroutinesApi
 @RunWith(RobolectricTestRunner::class)
 class DeviceDetailsFragmentFormatterTest {
@@ -78,7 +81,7 @@
     @Mock private lateinit var headerController: AbstractPreferenceController
     @Mock private lateinit var buttonController: AbstractPreferenceController
 
-    private lateinit var context: Context
+    @Spy private val context: Context = ApplicationProvider.getApplicationContext()
     private lateinit var fragment: TestFragment
     private lateinit var underTest: DeviceDetailsFragmentFormatter
     private lateinit var featureFactory: FakeFeatureFactory
@@ -87,11 +90,15 @@
 
     @Before
     fun setUp() {
-        context = ApplicationProvider.getApplicationContext()
         featureFactory = FakeFeatureFactory.setupForTest()
+        doNothing().`when`(context).startActivity(any(Intent::class.java))
         `when`(
                 featureFactory.bluetoothFeatureProvider.getDeviceSettingRepository(
-                    eq(context), eq(bluetoothAdapter), any()))
+                    any(),
+                    eq(bluetoothAdapter),
+                    any(),
+                )
+            )
             .thenReturn(repository)
         fragmentActivity = Robolectric.setupActivity(FragmentActivity::class.java)
         assertThat(fragmentActivity.applicationContext).isNotNull()
@@ -115,7 +122,8 @@
                 listOf(profileController, headerController, buttonController),
                 bluetoothAdapter,
                 cachedDevice,
-                testScope.testScheduler)
+                testScope.testScheduler,
+            )
     }
 
     @Test
@@ -124,11 +132,16 @@
             `when`(repository.getDeviceSettingsConfig(cachedDevice))
                 .thenReturn(
                     DeviceSettingConfigModel(
-                        listOf(), listOf(), DeviceSettingConfigItemModel.AppProvidedItem(12345, false)))
-            val intent = Intent().apply {
-                setAction(Intent.ACTION_VIEW)
-                setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-            }
+                        listOf(),
+                        listOf(),
+                        DeviceSettingConfigItemModel.AppProvidedItem(12345, false),
+                    )
+                )
+            val intent =
+                Intent().apply {
+                    setAction(Intent.ACTION_VIEW)
+                    setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                }
             `when`(repository.getDeviceSetting(cachedDevice, 12345))
                 .thenReturn(
                     flowOf(
@@ -136,12 +149,15 @@
                             cachedDevice = cachedDevice,
                             id = 12345,
                             intent = intent,
-                        )))
+                        )
+                    )
+                )
 
             var helpPreference: DeviceSettingPreferenceModel.HelpPreference? = null
-            underTest.getMenuItem(FragmentTypeModel.DeviceDetailsMoreSettingsFragment).onEach {
-                helpPreference = it
-            }.launchIn(testScope.backgroundScope)
+            underTest
+                .getMenuItem(FragmentTypeModel.DeviceDetailsMoreSettingsFragment)
+                .onEach { helpPreference = it }
+                .launchIn(testScope.backgroundScope)
             delay(100)
             runCurrent()
             ShadowLooper.idleMainLooper()
@@ -171,13 +187,19 @@
                         listOf(
                             DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
                                 DeviceSettingId.DEVICE_SETTING_ID_HEADER,
-                                highlighted = false, preferenceKey = "bluetooth_device_header"),
+                                highlighted = false,
+                                preferenceKey = "bluetooth_device_header",
+                            ),
                             DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
                                 DeviceSettingId.DEVICE_SETTING_ID_BLUETOOTH_PROFILES,
-                                highlighted = false, preferenceKey = "bluetooth_profiles"),
+                                highlighted = false,
+                                preferenceKey = "bluetooth_profiles",
+                            ),
                         ),
                         listOf(),
-                        null))
+                        null,
+                    )
+                )
 
             underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
             runCurrent()
@@ -189,13 +211,17 @@
                     SettingsEnums.PAGE_UNKNOWN,
                     SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_ITEM_SHOWN,
                     0,
-                    "bluetooth_device_header", 1)
+                    "bluetooth_device_header",
+                    1,
+                )
             verify(featureFactory.metricsFeatureProvider)
                 .action(
                     SettingsEnums.PAGE_UNKNOWN,
                     SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_ITEM_SHOWN,
                     0,
-                    "bluetooth_profiles", 1)
+                    "bluetooth_profiles",
+                    1,
+                )
         }
     }
 
@@ -209,16 +235,22 @@
                             DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
                                 DeviceSettingId.DEVICE_SETTING_ID_HEADER,
                                 highlighted = false,
-                                preferenceKey = "bluetooth_device_header"),
+                                preferenceKey = "bluetooth_device_header",
+                            ),
                             DeviceSettingConfigItemModel.AppProvidedItem(
-                                DeviceSettingId.DEVICE_SETTING_ID_ANC, highlighted = false),
+                                DeviceSettingId.DEVICE_SETTING_ID_ANC,
+                                highlighted = false,
+                            ),
                             DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
                                 DeviceSettingId.DEVICE_SETTING_ID_BLUETOOTH_PROFILES,
                                 highlighted = false,
-                                preferenceKey = "bluetooth_profiles"),
+                                preferenceKey = "bluetooth_profiles",
+                            ),
                         ),
                         listOf(),
-                        null))
+                        null,
+                    )
+                )
             `when`(repository.getDeviceSetting(cachedDevice, DeviceSettingId.DEVICE_SETTING_ID_ANC))
                 .thenReturn(
                     flowOf(
@@ -231,11 +263,17 @@
                                     ToggleModel(
                                         "",
                                         DeviceSettingIcon.BitmapIcon(
-                                            Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)))),
+                                            Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
+                                        ),
+                                    )
+                                ),
                             isActive = true,
                             state = DeviceSettingStateModel.MultiTogglePreferenceState(0),
                             isAllowedChangingState = true,
-                            updateState = {})))
+                            updateState = {},
+                        )
+                    )
+                )
 
             underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
             runCurrent()
@@ -244,13 +282,119 @@
                 .containsExactly(
                     "bluetooth_device_header",
                     "DEVICE_SETTING_${DeviceSettingId.DEVICE_SETTING_ID_ANC}",
-                    "bluetooth_profiles")
+                    "bluetooth_profiles",
+                )
             verify(featureFactory.metricsFeatureProvider)
                 .action(
                     SettingsEnums.PAGE_UNKNOWN,
                     SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_ITEM_SHOWN,
                     0,
-                    "DEVICE_SETTING_${DeviceSettingId.DEVICE_SETTING_ID_ANC}", 1
+                    "DEVICE_SETTING_${DeviceSettingId.DEVICE_SETTING_ID_ANC}",
+                    1,
+                )
+        }
+    }
+
+    @Test
+    fun updateLayout_plainPreferenceClicked() {
+        testScope.runTest {
+            val settingId = 12345
+            val intent = Intent("test_intent")
+            `when`(repository.getDeviceSettingsConfig(cachedDevice))
+                .thenReturn(
+                    DeviceSettingConfigModel(
+                        listOf(
+                            DeviceSettingConfigItemModel.AppProvidedItem(
+                                settingId,
+                                highlighted = false,
+                            )
+                        ),
+                        listOf(),
+                        null,
+                    )
+                )
+
+            `when`(repository.getDeviceSetting(cachedDevice, settingId))
+                .thenReturn(
+                    flowOf(
+                        DeviceSettingModel.ActionSwitchPreference(
+                            cachedDevice = cachedDevice,
+                            id = settingId,
+                            title = "title",
+                            summary = "summary",
+                            icon = null,
+                            action = DeviceSettingActionModel.IntentAction(intent),
+                        )
+                    )
+                )
+
+            underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
+            runCurrent()
+            val displayedPrefs = getDisplayedPreferences()
+            displayedPrefs[0].performClick()
+
+            assertThat(displayedPrefs).hasSize(1)
+            verify(context).startActivity(intent)
+            verify(featureFactory.metricsFeatureProvider)
+                .action(
+                    SettingsEnums.PAGE_UNKNOWN,
+                    SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_ITEM_CLICKED,
+                    0,
+                    "DEVICE_SETTING_$settingId",
+                    2,
+                )
+        }
+    }
+
+    @Test
+    fun updateLayout_switchPreferenceClicked() {
+        val settingId = 12345
+        testScope.runTest {
+            `when`(repository.getDeviceSettingsConfig(cachedDevice))
+                .thenReturn(
+                    DeviceSettingConfigModel(
+                        listOf(
+                            DeviceSettingConfigItemModel.AppProvidedItem(
+                                settingId,
+                                highlighted = false,
+                            )
+                        ),
+                        listOf(),
+                        null,
+                    )
+                )
+
+            `when`(repository.getDeviceSetting(cachedDevice, settingId))
+                .thenReturn(
+                    flowOf(
+                        DeviceSettingModel.ActionSwitchPreference(
+                            cachedDevice = cachedDevice,
+                            id = settingId,
+                            title = "title",
+                            summary = "summary",
+                            icon = null,
+                            action = null,
+                            switchState = DeviceSettingStateModel.ActionSwitchPreferenceState(true),
+                            isAllowedChangingState = true,
+                            updateState = {},
+                        )
+                    )
+                )
+
+            underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
+            runCurrent()
+            val displayedPrefs = getDisplayedPreferences()
+            displayedPrefs[0].performClick()
+
+            assertThat(displayedPrefs).hasSize(1)
+            assertThat(displayedPrefs[0]).isInstanceOf(SwitchPreferenceCompat::class.java)
+            verify(featureFactory.metricsFeatureProvider)
+                .action(
+                    SettingsEnums.PAGE_UNKNOWN,
+                    SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_ITEM_CLICKED,
+                    0,
+                    "DEVICE_SETTING_$settingId",
+                    0,
                 )
         }
     }
diff --git a/tests/robotests/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModelTest.kt b/tests/robotests/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModelTest.kt
index caeea94..bf66a04 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModelTest.kt
+++ b/tests/robotests/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModelTest.kt
@@ -20,7 +20,6 @@
 import android.bluetooth.BluetoothAdapter
 import android.graphics.Bitmap
 import androidx.test.core.app.ApplicationProvider
-import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
 import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
 import com.android.settings.bluetooth.ui.model.FragmentTypeModel
 import com.android.settings.testutils.FakeFeatureFactory
@@ -164,74 +163,6 @@
         }
     }
 
-    @Test
-    fun getLayout_builtinDeviceSettings() {
-        testScope.runTest {
-            `when`(repository.getDeviceSettingsConfig(cachedDevice))
-                .thenReturn(
-                    DeviceSettingConfigModel(
-                        listOf(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2), listOf(), null))
-
-            val layout = underTest.getLayout(FragmentTypeModel.DeviceDetailsMainFragment)!!
-
-            assertThat(getLatestLayout(layout))
-                .isEqualTo(
-                    listOf(
-                        listOf(DeviceSettingId.DEVICE_SETTING_ID_HEADER),
-                        listOf(DeviceSettingId.DEVICE_SETTING_ID_ACTION_BUTTONS)))
-        }
-    }
-
-    @Test
-    fun getLayout_remoteDeviceSettings() {
-        val remoteSettingId1 = 10001
-        val remoteSettingId2 = 10002
-        val remoteSettingId3 = 10003
-        testScope.runTest {
-            `when`(repository.getDeviceSettingsConfig(cachedDevice))
-                .thenReturn(
-                    DeviceSettingConfigModel(
-                        listOf(
-                            BUILTIN_SETTING_ITEM_1,
-                            buildRemoteSettingItem(remoteSettingId1),
-                            buildRemoteSettingItem(remoteSettingId2),
-                            buildRemoteSettingItem(remoteSettingId3),
-                        ),
-                        listOf(),
-                        null))
-            `when`(repository.getDeviceSetting(cachedDevice, remoteSettingId1))
-                .thenReturn(flowOf(buildMultiTogglePreference(remoteSettingId1)))
-            `when`(repository.getDeviceSetting(cachedDevice, remoteSettingId2))
-                .thenReturn(flowOf(buildMultiTogglePreference(remoteSettingId2)))
-            `when`(repository.getDeviceSetting(cachedDevice, remoteSettingId3))
-                .thenReturn(flowOf(buildActionSwitchPreference(remoteSettingId3)))
-
-            val layout = underTest.getLayout(FragmentTypeModel.DeviceDetailsMainFragment)!!
-
-            assertThat(getLatestLayout(layout))
-                .isEqualTo(
-                    listOf(
-                        listOf(DeviceSettingId.DEVICE_SETTING_ID_HEADER),
-                        listOf(remoteSettingId1),
-                        listOf(remoteSettingId2),
-                        listOf(remoteSettingId3),
-                    ))
-        }
-    }
-
-    private fun getLatestLayout(layout: DeviceSettingLayout): List<List<Int>> {
-        val latestLayout = MutableList(layout.rows.size) { emptyList<Int>() }
-        for (i in layout.rows.indices) {
-            layout.rows[i]
-                .columns
-                .onEach { latestLayout[i] = it.map { c -> c.settingId } }
-                .launchIn(testScope.backgroundScope)
-        }
-
-        testScope.runCurrent()
-        return latestLayout.filter { !it.isEmpty() }.toList()
-    }
-
     private fun buildMultiTogglePreference(settingId: Int) =
         DeviceSettingModel.MultiTogglePreference(
             cachedDevice,
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt
index 15fe091..82642ee 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt
@@ -155,7 +155,7 @@
 
         composeTestRule.onNode(
             hasTextExactly(
-                context.getString(R.string.aspect_ratio_experimental_title),
+                context.getString(R.string.aspect_ratio_title),
                 context.getString(R.string.user_aspect_ratio_app_default)
             ),
         ).assertIsDisplayed().assertIsEnabled()
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
index b859df4..1549994 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
@@ -63,7 +63,7 @@
     @Test
     fun injectEntry_title() {
         setInjectEntry()
-        composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_experimental_title))
+        composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_title))
             .assertIsDisplayed()
     }
 
@@ -78,7 +78,7 @@
     @Test
     fun injectEntry_onClick_navigate() {
         setInjectEntry()
-        composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_experimental_title))
+        composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_title))
             .performClick()
         assertThat(fakeNavControllerWrapper.navigateCalledWith).isEqualTo("UserAspectRatioAppsPage")
     }
@@ -97,7 +97,7 @@
             UserAspectRatioAppList {}
         }
 
-        composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_experimental_title))
+        composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_title))
             .assertIsDisplayed()
     }