Merge "Update "bottom right tap" string to "click"." into main
diff --git a/res/layout/search_bar_unified_version.xml b/res/layout/search_bar_unified_version.xml
index 14f46ec..e9b3c10 100644
--- a/res/layout/search_bar_unified_version.xml
+++ b/res/layout/search_bar_unified_version.xml
@@ -44,7 +44,7 @@
             style="@style/TextAppearance.SearchBar"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:paddingStart="8dp"
+            android:layout_marginStart="8dp"
             android:paddingEnd="8dp"
             android:text="@string/homepage_search"/>
     </LinearLayout>
diff --git a/res/layout/settings_homepage_container_v2.xml b/res/layout/settings_homepage_container_v2.xml
index b244579..a67b743 100644
--- a/res/layout/settings_homepage_container_v2.xml
+++ b/res/layout/settings_homepage_container_v2.xml
@@ -69,7 +69,8 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:orientation="horizontal"
-            android:paddingVertical="8dp"
+            android:paddingTop="8dp"
+            android:paddingBottom="16dp"
             android:paddingStart="?android:attr/listPreferredItemPaddingStart"
             android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3bf0324..0fcb0d6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1864,6 +1864,10 @@
     <string name="device_details_title">Device details</string>
     <!-- Title for keyboard settings preferences. [CHAR LIMIT=50] -->
     <string name="bluetooth_device_keyboard_settings_preference_title">Keyboard settings</string>
+    <!-- Title for more settings preferences. [CHAR LIMIT=50] -->
+    <string name="bluetooth_device_more_settings_preference_title">More settings</string>
+    <!-- Title for more settings summary. [CHAR LIMIT=50] -->
+    <string name="bluetooth_device_more_settings_preference_summary">Firmware updates, about, and more</string>
     <!-- Title of the item to show device MAC address -->
     <string name="bluetooth_device_mac_address">Device\'s Bluetooth address: <xliff:g id="address">%1$s</xliff:g></string>
     <!-- Title of the items to show multuple devices MAC address [CHAR LIMIT=NONE]-->
@@ -1884,6 +1888,9 @@
     <!-- Bluetooth device details companion apps. In the confirmation dialog for removing an associated app, this is the label on the button that will complete the disassociate action. [CHAR LIMIT=80] -->
     <string name = "bluetooth_companion_app_remove_association_confirm_button">Disconnect app</string>
 
+    <!-- Title of device details screen [CHAR LIMIT=28]-->
+    <string name="device_details_more_settings">More settings</string>
+
     <!-- Bluetooth developer settings: Maximum number of connected audio devices -->
     <string name="bluetooth_max_connected_audio_devices_string">Maximum connected Bluetooth audio devices</string>
     <!-- Bluetooth developer settings: Maximum number of connected audio devices -->
@@ -8184,10 +8191,10 @@
         other {{effect_1}, {effect_2}, and # more}
         }
     </string>
-    <!-- Modes: setting for whether the mode should filter (silence/hide) notifications/volume streams -->
-    <string name="mode_notification_filter_title">Limit what can notify you</string>
-    <!-- Modes: subtext when a mode is not filtering (silence/hide) notifications/volume streams -->
-    <string name="mode_no_notification_filter">No interruptions are filtered</string>
+    <!-- Modes: setting for a mode to allow all notifications and sounds through -->
+    <string name="zen_mode_allow_all_notifications">Allow all notifications</string>
+    <!-- Modes: subtext when a mode is allowing all notifications and sounds (i.e. no filtering) -->
+    <string name="zen_mode_all_notifications_allowed">People, apps, and sounds can interrupt</string>
 
     <!-- Do not disturb: restrict notifications settings title [CHAR LIMIT=80] -->
     <string name="zen_mode_restrict_notifications_title">Display options for filtered
diff --git a/res/xml/bluetooth_device_more_settings_fragment.xml b/res/xml/bluetooth_device_more_settings_fragment.xml
new file mode 100644
index 0000000..4fb4aca
--- /dev/null
+++ b/res/xml/bluetooth_device_more_settings_fragment.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:key="bluetooth_device_more_settings_screen"
+    android:title="@string/device_details_more_settings">
+
+    <PreferenceCategory
+        android:key="bluetooth_profiles"/>
+</PreferenceScreen>
diff --git a/res/xml/modes_rule_settings.xml b/res/xml/modes_rule_settings.xml
index d2f573c..4f9b685 100644
--- a/res/xml/modes_rule_settings.xml
+++ b/res/xml/modes_rule_settings.xml
@@ -59,8 +59,8 @@
             android:key="modes_filters">
 
         <SwitchPreferenceCompat
-            android:key="allow_filtering"
-            android:title="@string/mode_notification_filter_title"/>
+            android:key="allow_all"
+            android:title="@string/zen_mode_allow_all_notifications"/>
 
         <com.android.settings.notification.modes.CircularIconsPreference
             android:key="zen_mode_people"
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index bd762a1..76bff57 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -48,6 +48,7 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.settings.R;
+import com.android.settings.bluetooth.ui.model.FragmentTypeModel;
 import com.android.settings.bluetooth.ui.view.DeviceDetailsFragmentFormatter;
 import com.android.settings.connecteddevice.stylus.StylusDevicesController;
 import com.android.settings.core.SettingsUIDeviceConfig;
@@ -255,8 +256,17 @@
     public void onDetach() {
         super.onDetach();
         mManager.getEventManager().unregisterCallback(mBluetoothCallback);
-        mBluetoothAdapter.removeOnMetadataChangedListener(
-                mCachedDevice.getDevice(), mExtraControlMetadataListener);
+        BluetoothDevice device = mCachedDevice.getDevice();
+        try {
+            mBluetoothAdapter.removeOnMetadataChangedListener(
+                    device, mExtraControlMetadataListener);
+        } catch (IllegalArgumentException e) {
+            Log.w(
+                    TAG,
+                    "Unable to unregister metadata change callback for "
+                            + mCachedDevice,
+                    e);
+        }
     }
 
     private void updateExtraControlUri(int viewWidth) {
@@ -343,7 +353,7 @@
     public void onCreatePreferences(@NonNull Bundle savedInstanceState, @NonNull String rootKey) {
         super.onCreatePreferences(savedInstanceState, rootKey);
         if (Flags.enableBluetoothDeviceDetailsPolish()) {
-            mFormatter.updateLayout();
+            mFormatter.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment.INSTANCE);
         }
     }
 
@@ -400,7 +410,9 @@
     @Override
     protected void addPreferenceController(AbstractPreferenceController controller) {
         if (Flags.enableBluetoothDeviceDetailsPolish()) {
-            List<String> keys = mFormatter.getVisiblePreferenceKeysForMainPage();
+            List<String> keys =
+                    mFormatter.getVisiblePreferenceKeys(
+                            FragmentTypeModel.DeviceDetailsMainFragment.INSTANCE);
             Lifecycle lifecycle = getSettingsLifecycle();
             if (keys == null || keys.contains(controller.getPreferenceKey())) {
                 super.addPreferenceController(controller);
diff --git a/src/com/android/settings/bluetooth/ui/composable/MultiTogglePreferenceGroup.kt b/src/com/android/settings/bluetooth/ui/composable/MultiTogglePreferenceGroup.kt
index 8fe3c25..d29795e 100644
--- a/src/com/android/settings/bluetooth/ui/composable/MultiTogglePreferenceGroup.kt
+++ b/src/com/android/settings/bluetooth/ui/composable/MultiTogglePreferenceGroup.kt
@@ -66,15 +66,14 @@
 import androidx.compose.ui.unit.sp
 import androidx.compose.ui.window.DialogProperties
 import com.android.settings.R
+import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
 import com.android.settings.bluetooth.ui.composable.Icon as DeviceSettingComposeIcon
-import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingModel
-import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingStateModel
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.widget.dialog.getDialogWidth
 
 @Composable
 fun MultiTogglePreferenceGroup(
-    preferenceModels: List<DeviceSettingModel.MultiTogglePreference>,
+    preferenceModels: List<DeviceSettingPreferenceModel.MultiTogglePreference>,
 ) {
     var settingIdForPopUp by remember { mutableStateOf<Int?>(null) }
 
@@ -115,7 +114,7 @@
                                 colors = getButtonColors(preferenceModel.isActive),
                                 contentPadding = PaddingValues(0.dp)) {
                                     DeviceSettingComposeIcon(
-                                        preferenceModel.toggles[preferenceModel.state.selectedIndex]
+                                        preferenceModel.toggles[preferenceModel.selectedIndex]
                                             .icon,
                                         modifier = Modifier.size(24.dp))
                                 }
@@ -144,7 +143,7 @@
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 private fun dialog(
-    multiTogglePreference: DeviceSettingModel.MultiTogglePreference,
+    multiTogglePreference: DeviceSettingPreferenceModel.MultiTogglePreference,
     onDismiss: () -> Unit
 ) {
     BasicAlertDialog(
@@ -179,7 +178,7 @@
 }
 
 @Composable
-private fun dialogContent(multiTogglePreference: DeviceSettingModel.MultiTogglePreference) {
+private fun dialogContent(multiTogglePreference: DeviceSettingPreferenceModel.MultiTogglePreference) {
     Column {
         Row(
             modifier = Modifier.fillMaxWidth().height(24.dp),
@@ -219,7 +218,7 @@
                 }
                 Row {
                     for ((idx, toggle) in multiTogglePreference.toggles.withIndex()) {
-                        val selected = idx == multiTogglePreference.state.selectedIndex
+                        val selected = idx == multiTogglePreference.selectedIndex
                         Column(
                             modifier =
                                 Modifier.weight(1f)
@@ -237,8 +236,7 @@
                         ) {
                             Button(
                                 onClick = {
-                                    multiTogglePreference.updateState(
-                                        DeviceSettingStateModel.MultiTogglePreferenceState(idx))
+                                    multiTogglePreference.onSelectedChange(idx)
                                 },
                                 modifier = Modifier.fillMaxSize(),
                                 colors =
diff --git a/src/com/android/settings/bluetooth/ui/model/DeviceSettingPreferenceModel.kt b/src/com/android/settings/bluetooth/ui/model/DeviceSettingPreferenceModel.kt
new file mode 100644
index 0000000..6612591
--- /dev/null
+++ b/src/com/android/settings/bluetooth/ui/model/DeviceSettingPreferenceModel.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.model
+
+import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
+import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
+import com.android.settingslib.bluetooth.devicesettings.shared.model.ToggleModel
+
+/** Models a device setting preference. */
+sealed interface DeviceSettingPreferenceModel {
+    @DeviceSettingId
+    val id: Int
+
+    /** Models a plain preference. */
+    data class PlainPreference(
+        @DeviceSettingId override val id: Int,
+        val title: String,
+        val summary: String? = null,
+        val icon: DeviceSettingIcon? = null,
+        val onClick: (() -> Unit)? = null,
+    ) : DeviceSettingPreferenceModel
+
+    /** Models a switch preference. */
+    data class SwitchPreference(
+        @DeviceSettingId override val id: Int,
+        val title: String,
+        val summary: String? = null,
+        val icon: DeviceSettingIcon? = null,
+        val checked: Boolean,
+        val onCheckedChange: ((Boolean) -> Unit),
+        val onPrimaryClick: (() -> Unit)? = null,
+    ) : DeviceSettingPreferenceModel
+
+    /** Models a multi-toggle preference. */
+    data class MultiTogglePreference(
+        @DeviceSettingId override val id: Int,
+        val title: String,
+        val toggles: List<ToggleModel>,
+        val isActive: Boolean,
+        val selectedIndex: Int,
+        val isAllowedChangingState: Boolean,
+        val onSelectedChange: (Int) -> Unit,
+    ) : DeviceSettingPreferenceModel
+
+    /** Models a footer preference. */
+    data class FooterPreference(
+        @DeviceSettingId override val id: Int,
+        val footerText: String,
+    ) : DeviceSettingPreferenceModel
+
+    /** Models a preference which could navigate to more settings fragment. */
+    data class MoreSettingsPreference(
+        @DeviceSettingId override val id: Int,
+    ) : DeviceSettingPreferenceModel
+}
diff --git a/src/com/android/settings/bluetooth/ui/model/FragmentTypeModel.kt b/src/com/android/settings/bluetooth/ui/model/FragmentTypeModel.kt
new file mode 100644
index 0000000..19858c4
--- /dev/null
+++ b/src/com/android/settings/bluetooth/ui/model/FragmentTypeModel.kt
@@ -0,0 +1,25 @@
+/*
+ * 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.model
+
+/** Models a device details fragment type. */
+sealed interface FragmentTypeModel {
+    /** Device details main page. */
+    data object DeviceDetailsMainFragment : FragmentTypeModel
+    /** Device details more settings page. */
+    data object DeviceDetailsMoreSettingsFragment : FragmentTypeModel
+}
diff --git a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
index b75579d..c933c75 100644
--- a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
+++ b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
@@ -19,47 +19,52 @@
 import android.bluetooth.BluetoothAdapter
 import android.content.Context
 import android.media.AudioManager
-import android.util.Log
+import android.os.Bundle
 import androidx.compose.foundation.layout.size
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import androidx.lifecycle.lifecycleScope
 import androidx.preference.Preference
+import com.android.settings.R
 import com.android.settings.SettingsPreferenceFragment
 import com.android.settings.bluetooth.ui.composable.Icon
 import com.android.settings.bluetooth.ui.composable.MultiTogglePreferenceGroup
 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
 import com.android.settings.bluetooth.ui.viewmodel.BluetoothDeviceDetailsViewModel
+import com.android.settings.core.SubSettingLauncher
 import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
 import com.android.settings.spa.preference.ComposePreference
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
 import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
-import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingModel
-import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingStateModel
+import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
 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 kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.runBlocking
-import com.android.settingslib.spa.widget.preference.Preference as SpaPreference
-
 
 /** Handles device details fragment layout according to config. */
 interface DeviceDetailsFragmentFormatter {
     /** Gets keys of visible preferences in built-in preference in xml. */
-    fun getVisiblePreferenceKeysForMainPage(): List<String>?
+    fun getVisiblePreferenceKeys(fragmentType: FragmentTypeModel): List<String>?
 
     /** Updates device details fragment layout. */
-    fun updateLayout()
+    fun updateLayout(fragmentType: FragmentTypeModel)
 }
 
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -79,23 +84,25 @@
         ViewModelProvider(
                 fragment,
                 BluetoothDeviceDetailsViewModel.Factory(
+                    fragment.requireActivity().application,
                     repository,
                     spatialAudioInteractor,
                     cachedDevice,
                 ))
             .get(BluetoothDeviceDetailsViewModel::class.java)
 
-    override fun getVisiblePreferenceKeysForMainPage(): List<String>? = runBlocking {
-        viewModel
-            .getItems()
-            ?.filterIsInstance<DeviceSettingConfigItemModel.BuiltinItem>()
-            ?.mapNotNull { it.preferenceKey }
-    }
+    override fun getVisiblePreferenceKeys(fragmentType: FragmentTypeModel): List<String>? =
+        runBlocking {
+            viewModel
+                .getItems(fragmentType)
+                ?.filterIsInstance<DeviceSettingConfigItemModel.BuiltinItem>()
+                ?.mapNotNull { it.preferenceKey }
+        }
 
     /** Updates bluetooth device details fragment layout. */
-    override fun updateLayout() = runBlocking {
-        val items = viewModel.getItems() ?: return@runBlocking
-        val layout = viewModel.getLayout() ?: return@runBlocking
+    override fun updateLayout(fragmentType: FragmentTypeModel) = runBlocking {
+        val items = viewModel.getItems(fragmentType) ?: return@runBlocking
+        val layout = viewModel.getLayout(fragmentType) ?: return@runBlocking
         val prefKeyToSettingId =
             items
                 .filterIsInstance<DeviceSettingConfigItemModel.BuiltinItem>()
@@ -124,6 +131,8 @@
                 fragment.preferenceScreen.addPreference(pref)
             }
         }
+        // TODO(b/343317785): figure out how to remove the foot preference.
+        fragment.preferenceScreen.addPreference(Preference(context).apply { order = 10000 })
     }
 
     @Composable
@@ -132,7 +141,7 @@
             remember(row) {
                     layout.rows[row].settingIds.flatMapLatest { settingIds ->
                         if (settingIds.isEmpty()) {
-                            flowOf(emptyList<DeviceSettingModel>())
+                            flowOf(emptyList<DeviceSettingPreferenceModel>())
                         } else {
                             combine(
                                 settingIds.map { settingId ->
@@ -150,72 +159,104 @@
             0 -> {}
             1 -> {
                 when (val setting = settings[0]) {
-                    is DeviceSettingModel.ActionSwitchPreference -> {
-                        buildActionSwitchPreference(setting)
+                    is DeviceSettingPreferenceModel.PlainPreference -> {
+                        buildPlainPreference(setting)
                     }
-                    is DeviceSettingModel.MultiTogglePreference -> {
+                    is DeviceSettingPreferenceModel.SwitchPreference -> {
+                        buildSwitchPreference(setting)
+                    }
+                    is DeviceSettingPreferenceModel.MultiTogglePreference -> {
                         buildMultiTogglePreference(listOf(setting))
                     }
-                    null -> {}
-                    else -> {
-                        Log.w(TAG, "Unknown preference type ${setting.id}, skip.")
+                    is DeviceSettingPreferenceModel.FooterPreference -> {
+                        buildFooterPreference(setting)
                     }
+                    is DeviceSettingPreferenceModel.MoreSettingsPreference -> {
+                        buildMoreSettingsPreference()
+                    }
+                    null -> {}
                 }
             }
             else -> {
-                if (!settings.all { it is DeviceSettingModel.MultiTogglePreference }) {
+                if (!settings.all { it is DeviceSettingPreferenceModel.MultiTogglePreference }) {
                     return
                 }
                 buildMultiTogglePreference(
-                    settings.filterIsInstance<DeviceSettingModel.MultiTogglePreference>())
+                    settings.filterIsInstance<DeviceSettingPreferenceModel.MultiTogglePreference>())
             }
         }
     }
 
     @Composable
-    private fun buildMultiTogglePreference(prefs: List<DeviceSettingModel.MultiTogglePreference>) {
+    private fun buildMultiTogglePreference(
+        prefs: List<DeviceSettingPreferenceModel.MultiTogglePreference>
+    ) {
         MultiTogglePreferenceGroup(prefs)
     }
 
     @Composable
-    private fun buildActionSwitchPreference(model: DeviceSettingModel.ActionSwitchPreference) {
-        if (model.switchState != null) {
-            val switchPrefModel =
-                object : SwitchPreferenceModel {
-                    override val title = model.title
-                    override val summary = { model.summary ?: "" }
-                    override val checked = { model.switchState?.checked }
-                    override val onCheckedChange = { newChecked: Boolean ->
-                        model.updateState?.invoke(
-                            DeviceSettingStateModel.ActionSwitchPreferenceState(newChecked))
-                        Unit
-                    }
-                    override val icon = @Composable { deviceSettingIcon(model) }
+    private fun buildSwitchPreference(model: DeviceSettingPreferenceModel.SwitchPreference) {
+        val switchPrefModel =
+            object : SwitchPreferenceModel {
+                override val title = model.title
+                override val summary = { model.summary ?: "" }
+                override val checked = { model.checked }
+                override val onCheckedChange = { newChecked: Boolean ->
+                    model.onCheckedChange(newChecked)
                 }
-            if (model.intent != null) {
-                TwoTargetSwitchPreference(switchPrefModel) { context.startActivity(model.intent) }
-            } else {
-                SwitchPreference(switchPrefModel)
+                override val icon = @Composable { deviceSettingIcon(model.icon) }
             }
+        if (model.onPrimaryClick != null) {
+            TwoTargetSwitchPreference(
+                switchPrefModel, primaryOnClick = model.onPrimaryClick::invoke)
         } else {
-            SpaPreference(
-                object : PreferenceModel {
-                    override val title = model.title
-                    override val summary = { model.summary ?: "" }
-                    override val onClick = {
-                        model.intent?.let { context.startActivity(it) }
-                        Unit
-                    }
-                    override val icon = @Composable { deviceSettingIcon(model) }
-                })
+            SwitchPreference(switchPrefModel)
         }
     }
 
     @Composable
-    private fun deviceSettingIcon(model: DeviceSettingModel.ActionSwitchPreference) {
-        model.icon?.let { icon ->
-            Icon(icon, modifier = Modifier.size(SettingsDimension.itemIconSize))
-        }
+    private fun buildPlainPreference(model: DeviceSettingPreferenceModel.PlainPreference) {
+        SpaPreference(
+            object : PreferenceModel {
+                override val title = model.title
+                override val summary = { model.summary ?: "" }
+                override val onClick = {
+                    model.onClick?.invoke()
+                    Unit
+                }
+                override val icon = @Composable { deviceSettingIcon(model.icon) }
+            })
+    }
+
+    @Composable
+    fun buildMoreSettingsPreference() {
+        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 = {
+                    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(null) }
+            })
+    }
+
+    @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 getPreferenceKey(settingId: Int) = "DEVICE_SETTING_${settingId}"
diff --git a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt
new file mode 100644
index 0000000..c648a3e
--- /dev/null
+++ b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt
@@ -0,0 +1,92 @@
+/*
+ * 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.view
+
+import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothManager
+import android.content.Context
+import android.os.Bundle
+import com.android.settings.R
+import com.android.settings.bluetooth.BluetoothDetailsProfilesController
+import com.android.settings.bluetooth.Utils
+import com.android.settings.bluetooth.ui.model.FragmentTypeModel
+import com.android.settings.dashboard.DashboardFragment
+import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.settingslib.core.AbstractPreferenceController
+import com.android.settingslib.core.lifecycle.LifecycleObserver
+
+class DeviceDetailsMoreSettingsFragment : DashboardFragment() {
+    private lateinit var formatter: DeviceDetailsFragmentFormatter
+    private lateinit var localBluetoothManager: LocalBluetoothManager
+    private lateinit var cachedDevice: CachedBluetoothDevice
+
+    // TODO(b/343317785): add metrics category
+    override fun getMetricsCategory(): Int = 0
+
+    override fun getPreferenceScreenResId(): Int {
+        return R.xml.bluetooth_device_more_settings_fragment
+    }
+
+    override fun addPreferenceController(controller: AbstractPreferenceController) {
+        val keys: List<String>? =
+            formatter.getVisiblePreferenceKeys(FragmentTypeModel.DeviceDetailsMoreSettingsFragment)
+        val lifecycle = settingsLifecycle
+        if (keys == null || keys.contains(controller.preferenceKey)) {
+            super.addPreferenceController(controller)
+        } else if (controller is LifecycleObserver) {
+            lifecycle.removeObserver((controller as LifecycleObserver))
+        }
+    }
+
+    private fun getCachedDevice(): CachedBluetoothDevice? {
+        val bluetoothAddress = arguments?.getString(KEY_DEVICE_ADDRESS) ?: return null
+        localBluetoothManager = Utils.getLocalBtManager(context) ?: return null
+        val remoteDevice: BluetoothDevice =
+            localBluetoothManager.bluetoothAdapter.getRemoteDevice(bluetoothAddress) ?: return null
+        return Utils.getLocalBtManager(context).cachedDeviceManager.findDevice(remoteDevice)
+    }
+
+    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
+        super.onCreatePreferences(savedInstanceState, rootKey)
+        formatter.updateLayout(FragmentTypeModel.DeviceDetailsMoreSettingsFragment)
+    }
+
+    override fun createPreferenceControllers(context: Context): List<AbstractPreferenceController> {
+        val bluetoothManager = context.getSystemService(BluetoothManager::class.java)
+        cachedDevice =
+            getCachedDevice()
+                ?: run {
+                    finish()
+                    return emptyList()
+                }
+        formatter =
+            featureFactory.bluetoothFeatureProvider.getDeviceDetailsFragmentFormatter(
+                requireContext(), this, bluetoothManager.adapter, cachedDevice)
+        return listOf(
+            BluetoothDetailsProfilesController(
+                context, this, localBluetoothManager, cachedDevice, settingsLifecycle))
+    }
+
+    override fun getLogTag(): String = TAG
+
+    companion object {
+        const val TAG: String = "DeviceMoreSettingsFrg"
+        const val KEY_DEVICE_ADDRESS: String = "device_address"
+    }
+}
diff --git a/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt b/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt
index befff83..c85015c 100644
--- a/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt
+++ b/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt
@@ -16,17 +16,22 @@
 
 package com.android.settings.bluetooth.ui.viewmodel
 
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.viewModelScope
 import com.android.settings.bluetooth.domain.interactor.SpatialAudioInteractor
 import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
 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.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.DeviceSettingConfigItemModel
 import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingModel
+import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingStateModel
 import kotlinx.coroutines.CoroutineStart
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.async
@@ -38,30 +43,81 @@
 import kotlinx.coroutines.flow.stateIn
 
 class BluetoothDeviceDetailsViewModel(
+    private val application: Application,
     private val deviceSettingRepository: DeviceSettingRepository,
     private val spatialAudioInteractor: SpatialAudioInteractor,
     private val cachedDevice: CachedBluetoothDevice,
-) : ViewModel() {
+) : AndroidViewModel(application){
+
     private val items =
         viewModelScope.async(Dispatchers.IO, start = CoroutineStart.LAZY) {
             deviceSettingRepository.getDeviceSettingsConfig(cachedDevice)
         }
 
-    suspend fun getItems(): List<DeviceSettingConfigItemModel>? = items.await()?.mainItems
+    suspend fun getItems(fragment: FragmentTypeModel): List<DeviceSettingConfigItemModel>? =
+        when (fragment) {
+            is FragmentTypeModel.DeviceDetailsMainFragment -> items.await()?.mainItems
+            is FragmentTypeModel.DeviceDetailsMoreSettingsFragment ->
+                items.await()?.moreSettingsItems
+        }
 
     fun getDeviceSetting(
         cachedDevice: CachedBluetoothDevice,
         @DeviceSettingId settingId: Int
-    ): Flow<DeviceSettingModel?> {
+    ): Flow<DeviceSettingPreferenceModel?> {
+        if (settingId == DeviceSettingId.DEVICE_SETTING_ID_MORE_SETTINGS) {
+            return flowOf(DeviceSettingPreferenceModel.MoreSettingsPreference(settingId))
+        }
         return when (settingId) {
             DeviceSettingId.DEVICE_SETTING_ID_SPATIAL_AUDIO_MULTI_TOGGLE ->
                 spatialAudioInteractor.getDeviceSetting(cachedDevice)
             else -> deviceSettingRepository.getDeviceSetting(cachedDevice, settingId)
+        }.map { it?.toPreferenceModel() }
+    }
+
+    private fun DeviceSettingModel.toPreferenceModel(): DeviceSettingPreferenceModel? {
+        return when (this) {
+            is DeviceSettingModel.ActionSwitchPreference -> {
+                if (switchState != null) {
+                    DeviceSettingPreferenceModel.SwitchPreference(
+                        id = id,
+                        title = title,
+                        summary = summary,
+                        icon = icon,
+                        checked = switchState?.checked ?: false,
+                        onCheckedChange = { newState ->
+                            updateState?.invoke(
+                                DeviceSettingStateModel.ActionSwitchPreferenceState(newState))
+                        },
+                        onPrimaryClick = { intent?.let { application.startActivity(it) } })
+                } else {
+                    DeviceSettingPreferenceModel.PlainPreference(
+                        id = id,
+                        title = title,
+                        summary = summary,
+                        icon = icon,
+                        onClick = { intent?.let { application.startActivity(it) } })
+                }
+            }
+            is DeviceSettingModel.FooterPreference ->
+                DeviceSettingPreferenceModel.FooterPreference(id = id, footerText = footerText)
+            is DeviceSettingModel.MultiTogglePreference ->
+                DeviceSettingPreferenceModel.MultiTogglePreference(
+                    id = id,
+                    title = title,
+                    toggles = toggles,
+                    isActive = isActive,
+                    selectedIndex = state.selectedIndex,
+                    isAllowedChangingState = isAllowedChangingState,
+                    onSelectedChange = { newState ->
+                        updateState(DeviceSettingStateModel.MultiTogglePreferenceState(newState))
+                    })
+            is DeviceSettingModel.Unknown -> null
         }
     }
 
-    suspend fun getLayout(): DeviceSettingLayout? {
-        val configItems = getItems() ?: return null
+    suspend fun getLayout(fragment: FragmentTypeModel): DeviceSettingLayout? {
+        val configItems = getItems(fragment) ?: return null
         val idToDeviceSetting =
             configItems
                 .filterIsInstance<DeviceSettingConfigItemModel.AppProvidedItem>()
@@ -80,7 +136,7 @@
                         if (!isXmlPreference && setting == null) {
                             continue
                         }
-                        if (setting !is DeviceSettingModel.MultiTogglePreference) {
+                        if (setting !is DeviceSettingPreferenceModel.MultiTogglePreference) {
                             multiToggleSettingIds = null
                             positionMapping[i] = listOf(configItem.settingId)
                             continue
@@ -103,6 +159,7 @@
     }
 
     class Factory(
+        private val application: Application,
         private val deviceSettingRepository: DeviceSettingRepository,
         private val spatialAudioInteractor: SpatialAudioInteractor,
         private val cachedDevice: CachedBluetoothDevice,
@@ -110,7 +167,7 @@
         override fun <T : ViewModel> create(modelClass: Class<T>): T {
             @Suppress("UNCHECKED_CAST")
             return BluetoothDeviceDetailsViewModel(
-                deviceSettingRepository, spatialAudioInteractor, cachedDevice)
+                application, deviceSettingRepository, spatialAudioInteractor, cachedDevice)
                 as T
         }
     }
diff --git a/src/com/android/settings/notification/modes/InterruptionFilterPreferenceController.java b/src/com/android/settings/notification/modes/InterruptionFilterPreferenceController.java
index 9d4a172..d69b317 100644
--- a/src/com/android/settings/notification/modes/InterruptionFilterPreferenceController.java
+++ b/src/com/android/settings/notification/modes/InterruptionFilterPreferenceController.java
@@ -45,20 +45,21 @@
     @Override
     public void updateState(Preference preference, @NonNull ZenMode zenMode) {
         preference.setEnabled(zenMode.isEnabled());
-        boolean filteringNotifications = zenMode.getRule().getInterruptionFilter()
-                != INTERRUPTION_FILTER_ALL;
-        ((TwoStatePreference) preference).setChecked(filteringNotifications);
-        preference.setSummary(filteringNotifications ? "" :
-                mContext.getResources().getString(R.string.mode_no_notification_filter));
+        boolean allowingAll = zenMode.getRule().getInterruptionFilter() == INTERRUPTION_FILTER_ALL;
+
+        ((TwoStatePreference) preference).setChecked(allowingAll);
+        preference.setSummary(allowingAll
+                ? mContext.getString(R.string.zen_mode_all_notifications_allowed)
+                : "");
     }
 
     @Override
-    public boolean onPreferenceChange(Preference preference, Object newValue) {
-        final boolean filterNotifications = ((Boolean) newValue);
+    public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) {
+        final boolean allowAll = ((Boolean) newValue);
         return saveMode(zenMode -> {
-            zenMode.getRule().setInterruptionFilter(filterNotifications
-                    ? INTERRUPTION_FILTER_PRIORITY
-                    : INTERRUPTION_FILTER_ALL);
+            zenMode.getRule().setInterruptionFilter(allowAll
+                    ? INTERRUPTION_FILTER_ALL
+                    : INTERRUPTION_FILTER_PRIORITY);
             return zenMode;
         });
     }
diff --git a/src/com/android/settings/notification/modes/ZenModeFragment.java b/src/com/android/settings/notification/modes/ZenModeFragment.java
index 13aabd3..6889cac 100644
--- a/src/com/android/settings/notification/modes/ZenModeFragment.java
+++ b/src/com/android/settings/notification/modes/ZenModeFragment.java
@@ -77,7 +77,7 @@
                 new ZenModeTriggerAddPreferenceController(context, "zen_add_automatic_trigger",
                         this, mBackend));
         prefControllers.add(new InterruptionFilterPreferenceController(
-                context, "allow_filtering", mBackend));
+                context, "allow_all", mBackend));
         prefControllers.add(new ManualDurationPreferenceController(
                 context, "mode_manual_duration", this, mBackend));
         return prefControllers;
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
index 19d0edd..c84d42c 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
@@ -50,6 +50,7 @@
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.R;
+import com.android.settings.bluetooth.ui.model.FragmentTypeModel;
 import com.android.settings.bluetooth.ui.view.DeviceDetailsFragmentFormatter;
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -117,7 +118,9 @@
         FakeFeatureFactory fakeFeatureFactory = FakeFeatureFactory.setupForTest();
         when(fakeFeatureFactory.mBluetoothFeatureProvider.getDeviceDetailsFragmentFormatter(any(),
                 any(), any(), eq(mCachedDevice))).thenReturn(mFormatter);
-        when(mFormatter.getVisiblePreferenceKeysForMainPage()).thenReturn(null);
+        when(mFormatter.getVisiblePreferenceKeys(
+                        FragmentTypeModel.DeviceDetailsMainFragment.INSTANCE))
+                .thenReturn(null);
 
         mFragment = setupFragment();
         mFragment.onAttach(mContext);
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 609d767..251b814 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
@@ -26,6 +26,7 @@
 import androidx.preference.PreferenceScreen
 import androidx.test.core.app.ApplicationProvider
 import com.android.settings.bluetooth.domain.interactor.SpatialAudioInteractor
+import com.android.settings.bluetooth.ui.model.FragmentTypeModel
 import com.android.settings.dashboard.DashboardFragment
 import com.android.settings.testutils.FakeFeatureFactory
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
@@ -45,7 +46,6 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
 import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
 import org.mockito.Mockito.any
@@ -111,10 +111,9 @@
                             DeviceSettingConfigItemModel.BuiltinItem(
                                 DeviceSettingId.DEVICE_SETTING_ID_ACTION_BUTTONS, "action_buttons"),
                         ),
-                        listOf(),
-                        "footer"))
+                        listOf()))
 
-            val keys = underTest.getVisiblePreferenceKeysForMainPage()
+            val keys = underTest.getVisiblePreferenceKeys(FragmentTypeModel.DeviceDetailsMainFragment)
 
             assertThat(keys).containsExactly("bluetooth_device_header", "action_buttons")
         }
@@ -125,7 +124,7 @@
         testScope.runTest {
             `when`(repository.getDeviceSettingsConfig(cachedDevice)).thenReturn(null)
 
-            val keys = underTest.getVisiblePreferenceKeysForMainPage()
+            val keys = underTest.getVisiblePreferenceKeys(FragmentTypeModel.DeviceDetailsMainFragment)
 
             assertThat(keys).isNull()
         }
@@ -136,9 +135,9 @@
         testScope.runTest {
             `when`(repository.getDeviceSettingsConfig(cachedDevice)).thenReturn(null)
 
-            underTest.updateLayout()
+            underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
 
-            assertThat(getDisplayedPreferences().map { it.key })
+            assertThat(getDisplayedPreferences().mapNotNull { it.key })
                 .containsExactly("bluetooth_device_header", "action_buttons", "keyboard_settings")
         }
     }
@@ -157,12 +156,11 @@
                                 DeviceSettingId.DEVICE_SETTING_ID_KEYBOARD_SETTINGS,
                                 "keyboard_settings"),
                         ),
-                        listOf(),
-                        "footer"))
+                        listOf()))
 
-            underTest.updateLayout()
+            underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
 
-            assertThat(getDisplayedPreferences().map { it.key })
+            assertThat(getDisplayedPreferences().mapNotNull { it.key })
                 .containsExactly("bluetooth_device_header", "keyboard_settings")
         }
     }
@@ -183,8 +181,7 @@
                                 DeviceSettingId.DEVICE_SETTING_ID_KEYBOARD_SETTINGS,
                                 "keyboard_settings"),
                         ),
-                        listOf(),
-                        "footer"))
+                        listOf()))
             `when`(repository.getDeviceSetting(cachedDevice, DeviceSettingId.DEVICE_SETTING_ID_ANC))
                 .thenReturn(
                     flowOf(
@@ -209,9 +206,9 @@
                             isAllowedChangingState = true,
                             updateState = {})))
 
-            underTest.updateLayout()
+            underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
 
-            assertThat(getDisplayedPreferences().map { it.key })
+            assertThat(getDisplayedPreferences().mapNotNull { it.key })
                 .containsExactly(
                     "bluetooth_device_header",
                     "DEVICE_SETTING_${DeviceSettingId.DEVICE_SETTING_ID_ANC}",
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 a1fadb8..378f363 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
@@ -16,12 +16,14 @@
 
 package com.android.settings.bluetooth.ui.viewmodel
 
+import android.app.Application
 import android.bluetooth.BluetoothAdapter
-import android.content.Context
 import android.graphics.Bitmap
 import androidx.test.core.app.ApplicationProvider
 import com.android.settings.bluetooth.domain.interactor.SpatialAudioInteractor
 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
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
 import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
@@ -44,8 +46,6 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
@@ -73,26 +73,23 @@
 
     @Before
     fun setUp() {
-        val context = ApplicationProvider.getApplicationContext<Context>()
+        val application = ApplicationProvider.getApplicationContext<Application>()
         featureFactory = FakeFeatureFactory.setupForTest()
-        `when`(
-                featureFactory.bluetoothFeatureProvider.getDeviceSettingRepository(
-                    eq(context), eq(bluetoothAdapter), any()))
-            .thenReturn(repository)
 
         underTest =
-            BluetoothDeviceDetailsViewModel(repository, spatialAudioInteractor, cachedDevice)
+            BluetoothDeviceDetailsViewModel(
+                application, repository, spatialAudioInteractor, cachedDevice)
     }
 
     @Test
-    fun getItems_returnConfigMainItems() {
+    fun getItems_returnConfigMainMainItems() {
         testScope.runTest {
             `when`(repository.getDeviceSettingsConfig(cachedDevice))
                 .thenReturn(
                     DeviceSettingConfigModel(
-                        listOf(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2), listOf(), "footer"))
+                        listOf(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2), listOf()))
 
-            val keys = underTest.getItems()
+            val keys = underTest.getItems(FragmentTypeModel.DeviceDetailsMainFragment)
 
             assertThat(keys).containsExactly(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2)
         }
@@ -110,19 +107,18 @@
                             BUILTIN_SETTING_ITEM_1,
                             buildRemoteSettingItem(remoteSettingId1),
                         ),
-                        listOf(),
-                        "footer"))
+                        listOf()))
             `when`(repository.getDeviceSetting(cachedDevice, remoteSettingId1))
                 .thenReturn(flowOf(pref))
 
-            var deviceSetting: DeviceSettingModel? = null
+            var deviceSettingPreference: DeviceSettingPreferenceModel? = null
             underTest
                 .getDeviceSetting(cachedDevice, remoteSettingId1)
-                .onEach { deviceSetting = it }
+                .onEach { deviceSettingPreference = it }
                 .launchIn(testScope.backgroundScope)
             runCurrent()
 
-            assertThat(deviceSetting).isSameInstanceAs(pref)
+            assertThat(deviceSettingPreference?.id).isEqualTo(pref.id)
             verify(repository, times(1)).getDeviceSetting(cachedDevice, remoteSettingId1)
         }
     }
@@ -141,19 +137,18 @@
                             buildRemoteSettingItem(
                                 DeviceSettingId.DEVICE_SETTING_ID_SPATIAL_AUDIO_MULTI_TOGGLE),
                         ),
-                        listOf(),
-                        "footer"))
+                        listOf()))
             `when`(spatialAudioInteractor.getDeviceSetting(cachedDevice)).thenReturn(flowOf(pref))
 
-            var deviceSetting: DeviceSettingModel? = null
+            var deviceSettingPreference: DeviceSettingPreferenceModel? = null
             underTest
                 .getDeviceSetting(
                     cachedDevice, DeviceSettingId.DEVICE_SETTING_ID_SPATIAL_AUDIO_MULTI_TOGGLE)
-                .onEach { deviceSetting = it }
+                .onEach { deviceSettingPreference = it }
                 .launchIn(testScope.backgroundScope)
             runCurrent()
 
-            assertThat(deviceSetting).isSameInstanceAs(pref)
+            assertThat(deviceSettingPreference?.id).isEqualTo(pref.id)
             verify(spatialAudioInteractor, times(1)).getDeviceSetting(cachedDevice)
         }
     }
@@ -164,9 +159,9 @@
             `when`(repository.getDeviceSettingsConfig(cachedDevice))
                 .thenReturn(
                     DeviceSettingConfigModel(
-                        listOf(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2), listOf(), "footer"))
+                        listOf(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2), listOf()))
 
-            val layout = underTest.getLayout()!!
+            val layout = underTest.getLayout(FragmentTypeModel.DeviceDetailsMainFragment)!!
 
             assertThat(getLatestLayout(layout))
                 .isEqualTo(
@@ -191,8 +186,7 @@
                             buildRemoteSettingItem(remoteSettingId2),
                             buildRemoteSettingItem(remoteSettingId3),
                         ),
-                        listOf(),
-                        "footer"))
+                        listOf()))
             `when`(repository.getDeviceSetting(cachedDevice, remoteSettingId1))
                 .thenReturn(flowOf(buildMultiTogglePreference(remoteSettingId1)))
             `when`(repository.getDeviceSetting(cachedDevice, remoteSettingId2))
@@ -200,7 +194,7 @@
             `when`(repository.getDeviceSetting(cachedDevice, remoteSettingId3))
                 .thenReturn(flowOf(buildActionSwitchPreference(remoteSettingId3)))
 
-            val layout = underTest.getLayout()!!
+            val layout = underTest.getLayout(FragmentTypeModel.DeviceDetailsMainFragment)!!
 
             assertThat(getLatestLayout(layout))
                 .isEqualTo(
diff --git a/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java
index 0c3f8e1..777d213 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java
@@ -87,7 +87,7 @@
                 .build();
         mController.updateZenMode(preference, zenMode);
 
-        verify(preference).setChecked(false);
+        verify(preference).setChecked(true);
     }
 
     @Test
@@ -99,7 +99,7 @@
 
         mController.updateZenMode(preference, zenMode);
 
-        mController.onPreferenceChange(preference, true);
+        mController.onPreferenceChange(preference, false);
 
         ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
         verify(mBackend).updateMode(captor.capture());
@@ -118,7 +118,7 @@
                 .build();
         mController.updateZenMode(preference, zenMode);
 
-        verify(preference).setChecked(true);
+        verify(preference).setChecked(false);
     }
 
     @Test
@@ -131,7 +131,7 @@
 
         mController.updateZenMode(preference, zenMode);
 
-        mController.onPreferenceChange(preference, false);
+        mController.onPreferenceChange(preference, true);
 
         ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
         verify(mBackend).updateMode(captor.capture());
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ManualDurationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ManualDurationPreferenceControllerTest.java
index 29fdfdd..4edb0d5 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ManualDurationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ManualDurationPreferenceControllerTest.java
@@ -18,11 +18,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import android.app.AutomaticZenRule;
 import android.app.Flags;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.net.Uri;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
@@ -31,7 +29,6 @@
 import androidx.preference.Preference;
 
 import com.android.settingslib.notification.modes.TestModeBuilder;
-import com.android.settingslib.notification.modes.ZenMode;
 import com.android.settingslib.notification.modes.ZenModesBackend;
 
 import org.junit.Before;
@@ -73,10 +70,8 @@
     @Test
     public void testIsAvailable_onlyForManualDnd() {
         assertThat(mPrefController.isAvailable(TestModeBuilder.EXAMPLE)).isFalse();
-
-        ZenMode manualDnd = ZenMode.manualDndMode(
-                new AutomaticZenRule.Builder("id", Uri.EMPTY).build(), false);
-        assertThat(mPrefController.isAvailable(manualDnd)).isTrue();
+        assertThat(mPrefController.isAvailable(TestModeBuilder.MANUAL_DND_ACTIVE)).isTrue();
+        assertThat(mPrefController.isAvailable(TestModeBuilder.MANUAL_DND_INACTIVE)).isTrue();
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeButtonPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeButtonPreferenceControllerTest.java
index 47078b0..159dada 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeButtonPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeButtonPreferenceControllerTest.java
@@ -23,11 +23,9 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.app.AutomaticZenRule;
 import android.app.Flags;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.net.Uri;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
@@ -192,8 +190,7 @@
         Button button = new Button(mContext);
         LayoutPreference pref = mock(LayoutPreference.class);
         when(pref.findViewById(anyInt())).thenReturn(button);
-        ZenMode zenMode = ZenMode.manualDndMode(
-                new AutomaticZenRule.Builder("manual", Uri.EMPTY).build(), false);
+        ZenMode zenMode = TestModeBuilder.MANUAL_DND_INACTIVE;
 
         mController.updateZenMode(pref, zenMode);
         button.callOnClick();
@@ -207,8 +204,7 @@
         Button button = new Button(mContext);
         LayoutPreference pref = mock(LayoutPreference.class);
         when(pref.findViewById(anyInt())).thenReturn(button);
-        ZenMode zenMode = ZenMode.manualDndMode(
-                new AutomaticZenRule.Builder("manual", Uri.EMPTY).build(), false);
+        ZenMode zenMode = TestModeBuilder.MANUAL_DND_INACTIVE;
 
         mController.updateZenMode(pref, zenMode);
         button.callOnClick();
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceControllerTest.java
index a56e723..0d20b19 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceControllerTest.java
@@ -19,7 +19,6 @@
 import static android.app.AutomaticZenRule.TYPE_OTHER;
 import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
 import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
 import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
 
 import static com.android.settings.notification.modes.CharSequenceTruth.assertThat;
@@ -28,7 +27,6 @@
 
 import static org.mockito.Mockito.verify;
 
-import android.app.AutomaticZenRule;
 import android.app.Flags;
 import android.content.Context;
 import android.net.Uri;
@@ -125,12 +123,7 @@
 
     @Test
     public void isAvailable_manualDND_false() {
-        ZenMode manualMode = ZenMode.manualDndMode(new AutomaticZenRule.Builder("Do Not Disturb",
-                Uri.parse("manual"))
-                .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
-                .build(), /* isActive= */ false);
-
-        mController.setZenMode(manualMode);
+        mController.setZenMode(TestModeBuilder.MANUAL_DND_INACTIVE);
         assertThat(mController.isAvailable()).isFalse();
     }
 
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerCategoryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerCategoryPreferenceControllerTest.java
index 4510e20..bcafe47 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerCategoryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerCategoryPreferenceControllerTest.java
@@ -18,15 +18,12 @@
 
 import static android.app.AutomaticZenRule.TYPE_OTHER;
 import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
 import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
 
 import static com.google.common.truth.Truth.assertThat;
 
-import android.app.AutomaticZenRule;
 import android.app.Flags;
 import android.content.Context;
-import android.net.Uri;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.service.notification.SystemZenRules;
@@ -116,12 +113,7 @@
 
     @Test
     public void isAvailable_manualDND_false() {
-        ZenMode manualMode = ZenMode.manualDndMode(new AutomaticZenRule.Builder("Do Not Disturb",
-                Uri.parse("manual"))
-                .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
-                .build(), /* isActive= */ false);
-
-        mController.setZenMode(manualMode);
+        mController.setZenMode(TestModeBuilder.MANUAL_DND_INACTIVE);
         assertThat(mController.isAvailable()).isFalse();
     }
 }
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java
index 80d314c..b7af71b 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java
@@ -19,7 +19,6 @@
 import static android.app.AutomaticZenRule.TYPE_OTHER;
 import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
 import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
 import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
 
 import static com.android.settings.notification.modes.CharSequenceTruth.assertThat;
@@ -35,13 +34,11 @@
 import static org.robolectric.Shadows.shadowOf;
 
 import android.app.AlertDialog;
-import android.app.AutomaticZenRule;
 import android.app.Flags;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.net.Uri;
 import android.os.Looper;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
@@ -149,12 +146,7 @@
 
     @Test
     public void isAvailable_manualDND_false() {
-        ZenMode manualMode = ZenMode.manualDndMode(new AutomaticZenRule.Builder("Do Not Disturb",
-                Uri.parse("manual"))
-                .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
-                .build(), /* isActive= */ false);
-
-        mController.setZenMode(manualMode);
+        mController.setZenMode(TestModeBuilder.MANUAL_DND_INACTIVE);
         assertThat(mController.isAvailable()).isFalse();
     }
 
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModesListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModesListPreferenceControllerTest.java
index 4c16f26..4fa8b8a 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModesListPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModesListPreferenceControllerTest.java
@@ -18,6 +18,8 @@
 
 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
 
+import static com.android.settingslib.notification.modes.TestModeBuilder.MANUAL_DND_INACTIVE;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.when;
@@ -71,13 +73,6 @@
                     .build())
             .build();
 
-    private static final ZenMode TEST_MANUAL_MODE = ZenMode.manualDndMode(
-            new AutomaticZenRule.Builder("Do Not Disturb", Uri.EMPTY)
-                    .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
-                    .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
-                    .build(),
-            false);
-
     @Rule
     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(
             SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT);
@@ -152,7 +147,7 @@
     @DisableFlags(Flags.FLAG_MODES_UI)
     public void testModesUiOff_notAvailableAndNoSearchData() {
         // There exist modes
-        when(mBackend.getModes()).thenReturn(List.of(TEST_MANUAL_MODE, TEST_MODE));
+        when(mBackend.getModes()).thenReturn(List.of(MANUAL_DND_INACTIVE, TEST_MODE));
 
         assertThat(mPrefController.isAvailable()).isFalse();
         List<SearchIndexableRaw> data = new ArrayList<>();
@@ -187,20 +182,20 @@
 
         // Changing mode data so there's a different one mode doesn't keep any previous data
         // (and setting that state up in the caller)
-        when(mBackend.getModes()).thenReturn(List.of(TEST_MANUAL_MODE));
+        when(mBackend.getModes()).thenReturn(List.of(MANUAL_DND_INACTIVE));
         List<SearchIndexableRaw> newData = new ArrayList<>();
         mPrefController.updateDynamicRawDataToIndex(newData);
         assertThat(newData).hasSize(1);
 
         SearchIndexableRaw newItem = newData.get(0);
-        assertThat(newItem.key).isEqualTo(TEST_MANUAL_MODE.getId());
+        assertThat(newItem.key).isEqualTo(MANUAL_DND_INACTIVE.getId());
         assertThat(newItem.title).isEqualTo("Do Not Disturb");  // set above
     }
 
     @Test
     @EnableFlags(Flags.FLAG_MODES_UI)
     public void testUpdateDynamicRawDataToIndex_multipleModes() {
-        when(mBackend.getModes()).thenReturn(List.of(TEST_MANUAL_MODE, TEST_MODE));
+        when(mBackend.getModes()).thenReturn(List.of(MANUAL_DND_INACTIVE, TEST_MODE));
 
         List<SearchIndexableRaw> data = new ArrayList<>();
         mPrefController.updateDynamicRawDataToIndex(data);
@@ -208,7 +203,7 @@
 
         // Should keep the order presented by getModes()
         SearchIndexableRaw item0 = data.get(0);
-        assertThat(item0.key).isEqualTo(TEST_MANUAL_MODE.getId());
+        assertThat(item0.key).isEqualTo(MANUAL_DND_INACTIVE.getId());
         assertThat(item0.title).isEqualTo("Do Not Disturb");  // set above
 
         SearchIndexableRaw item1 = data.get(1);