Merge "Add device details more settings page" into main
This commit is contained in:
@@ -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 -->
|
||||
|
24
res/xml/bluetooth_device_more_settings_fragment.xml
Normal file
24
res/xml/bluetooth_device_more_settings_fragment.xml
Normal file
@@ -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>
|
@@ -48,6 +48,7 @@ import androidx.annotation.Nullable;
|
||||
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;
|
||||
@@ -343,7 +344,7 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
|
||||
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 +401,9 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
|
||||
@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);
|
||||
|
@@ -66,15 +66,14 @@ import androidx.compose.ui.unit.dp
|
||||
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 @@ fun MultiTogglePreferenceGroup(
|
||||
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 @@ private fun getButtonColors(isActive: Boolean) =
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun dialog(
|
||||
multiTogglePreference: DeviceSettingModel.MultiTogglePreference,
|
||||
multiTogglePreference: DeviceSettingPreferenceModel.MultiTogglePreference,
|
||||
onDismiss: () -> Unit
|
||||
) {
|
||||
BasicAlertDialog(
|
||||
@@ -179,7 +178,7 @@ private fun dialog(
|
||||
}
|
||||
|
||||
@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 @@ private fun dialogContent(multiTogglePreference: DeviceSettingModel.MultiToggleP
|
||||
}
|
||||
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 @@ private fun dialogContent(multiTogglePreference: DeviceSettingModel.MultiToggleP
|
||||
) {
|
||||
Button(
|
||||
onClick = {
|
||||
multiTogglePreference.updateState(
|
||||
DeviceSettingStateModel.MultiTogglePreferenceState(idx))
|
||||
multiTogglePreference.onSelectedChange(idx)
|
||||
},
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
colors =
|
||||
|
@@ -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
|
||||
}
|
@@ -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
|
||||
}
|
@@ -19,47 +19,52 @@ package com.android.settings.bluetooth.ui.view
|
||||
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 @@ class DeviceDetailsFragmentFormatterImpl(
|
||||
ViewModelProvider(
|
||||
fragment,
|
||||
BluetoothDeviceDetailsViewModel.Factory(
|
||||
fragment.requireActivity().application,
|
||||
repository,
|
||||
spatialAudioInteractor,
|
||||
cachedDevice,
|
||||
))
|
||||
.get(BluetoothDeviceDetailsViewModel::class.java)
|
||||
|
||||
override fun getVisiblePreferenceKeysForMainPage(): List<String>? = runBlocking {
|
||||
override fun getVisiblePreferenceKeys(fragmentType: FragmentTypeModel): List<String>? =
|
||||
runBlocking {
|
||||
viewModel
|
||||
.getItems()
|
||||
.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 @@ class DeviceDetailsFragmentFormatterImpl(
|
||||
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 @@ class DeviceDetailsFragmentFormatterImpl(
|
||||
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 @@ class DeviceDetailsFragmentFormatterImpl(
|
||||
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))
|
||||
}
|
||||
is DeviceSettingPreferenceModel.FooterPreference -> {
|
||||
buildFooterPreference(setting)
|
||||
}
|
||||
is DeviceSettingPreferenceModel.MoreSettingsPreference -> {
|
||||
buildMoreSettingsPreference()
|
||||
}
|
||||
null -> {}
|
||||
else -> {
|
||||
Log.w(TAG, "Unknown preference type ${setting.id}, skip.")
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
private fun buildSwitchPreference(model: DeviceSettingPreferenceModel.SwitchPreference) {
|
||||
val switchPrefModel =
|
||||
object : SwitchPreferenceModel {
|
||||
override val title = model.title
|
||||
override val summary = { model.summary ?: "" }
|
||||
override val checked = { model.switchState?.checked }
|
||||
override val checked = { model.checked }
|
||||
override val onCheckedChange = { newChecked: Boolean ->
|
||||
model.updateState?.invoke(
|
||||
DeviceSettingStateModel.ActionSwitchPreferenceState(newChecked))
|
||||
Unit
|
||||
model.onCheckedChange(newChecked)
|
||||
}
|
||||
override val icon = @Composable { deviceSettingIcon(model) }
|
||||
override val icon = @Composable { deviceSettingIcon(model.icon) }
|
||||
}
|
||||
if (model.intent != null) {
|
||||
TwoTargetSwitchPreference(switchPrefModel) { context.startActivity(model.intent) }
|
||||
if (model.onPrimaryClick != null) {
|
||||
TwoTargetSwitchPreference(
|
||||
switchPrefModel, primaryOnClick = model.onPrimaryClick::invoke)
|
||||
} else {
|
||||
SwitchPreference(switchPrefModel)
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun buildPlainPreference(model: DeviceSettingPreferenceModel.PlainPreference) {
|
||||
SpaPreference(
|
||||
object : PreferenceModel {
|
||||
override val title = model.title
|
||||
override val summary = { model.summary ?: "" }
|
||||
override val onClick = {
|
||||
model.intent?.let { context.startActivity(it) }
|
||||
model.onClick?.invoke()
|
||||
Unit
|
||||
}
|
||||
override val icon = @Composable { deviceSettingIcon(model) }
|
||||
override val icon = @Composable { deviceSettingIcon(model.icon) }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun deviceSettingIcon(model: DeviceSettingModel.ActionSwitchPreference) {
|
||||
model.icon?.let { icon ->
|
||||
Icon(icon, modifier = Modifier.size(SettingsDimension.itemIconSize))
|
||||
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}"
|
||||
|
@@ -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"
|
||||
}
|
||||
}
|
@@ -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.map
|
||||
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 @@ class BluetoothDeviceDetailsViewModel(
|
||||
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 BluetoothDeviceDetailsViewModel(
|
||||
}
|
||||
|
||||
class Factory(
|
||||
private val application: Application,
|
||||
private val deviceSettingRepository: DeviceSettingRepository,
|
||||
private val spatialAudioInteractor: SpatialAudioInteractor,
|
||||
private val cachedDevice: CachedBluetoothDevice,
|
||||
@@ -110,7 +167,7 @@ class BluetoothDeviceDetailsViewModel(
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return BluetoothDeviceDetailsViewModel(
|
||||
deviceSettingRepository, spatialAudioInteractor, cachedDevice)
|
||||
application, deviceSettingRepository, spatialAudioInteractor, cachedDevice)
|
||||
as T
|
||||
}
|
||||
}
|
||||
|
@@ -50,6 +50,7 @@ import androidx.fragment.app.FragmentTransaction;
|
||||
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 @@ public class BluetoothDeviceDetailsFragmentTest {
|
||||
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);
|
||||
|
@@ -26,6 +26,7 @@ import androidx.preference.PreferenceManager
|
||||
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.Before
|
||||
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 @@ class DeviceDetailsFragmentFormatterTest {
|
||||
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 @@ class DeviceDetailsFragmentFormatterTest {
|
||||
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 @@ class DeviceDetailsFragmentFormatterTest {
|
||||
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 @@ class DeviceDetailsFragmentFormatterTest {
|
||||
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 @@ class DeviceDetailsFragmentFormatterTest {
|
||||
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 @@ class DeviceDetailsFragmentFormatterTest {
|
||||
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}",
|
||||
|
@@ -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.Before
|
||||
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 @@ class BluetoothDeviceDetailsViewModelTest {
|
||||
|
||||
@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 @@ class BluetoothDeviceDetailsViewModelTest {
|
||||
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 @@ class BluetoothDeviceDetailsViewModelTest {
|
||||
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 @@ class BluetoothDeviceDetailsViewModelTest {
|
||||
`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 @@ class BluetoothDeviceDetailsViewModelTest {
|
||||
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 @@ class BluetoothDeviceDetailsViewModelTest {
|
||||
`when`(repository.getDeviceSetting(cachedDevice, remoteSettingId3))
|
||||
.thenReturn(flowOf(buildActionSwitchPreference(remoteSettingId3)))
|
||||
|
||||
val layout = underTest.getLayout()!!
|
||||
val layout = underTest.getLayout(FragmentTypeModel.DeviceDetailsMainFragment)!!
|
||||
|
||||
assertThat(getLatestLayout(layout))
|
||||
.isEqualTo(
|
||||
|
Reference in New Issue
Block a user