Refactor data layer of device details page
1. Consolidate repository layer api
2. Use shared model in repository response
BUG: 343317785
Test: atest DeviceSettingRepositoryTest
Flag: com.android.settings.flags.enable_bluetooth_device_details_polish
Change-Id: I3d90dd9695868743f4c7656a4e838e85a7918319
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
index 9ff5c43..326bb31 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
@@ -19,37 +19,39 @@
import android.bluetooth.BluetoothAdapter
import android.content.Context
import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.bluetooth.devicesettings.ActionSwitchPreference
import com.android.settingslib.bluetooth.devicesettings.DeviceSetting
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
-import com.android.settingslib.bluetooth.devicesettings.DeviceSettingPreferenceState
+import com.android.settingslib.bluetooth.devicesettings.DeviceSettingItem
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingsConfig
-import java.util.concurrent.ConcurrentHashMap
+import com.android.settingslib.bluetooth.devicesettings.MultiTogglePreference
+import com.android.settingslib.bluetooth.devicesettings.ToggleInfo
+import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
+import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigModel
+import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingModel
+import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingStateModel
+import com.android.settingslib.bluetooth.devicesettings.shared.model.ToggleModel
+import com.google.common.cache.CacheBuilder
+import com.google.common.cache.CacheLoader
+import com.google.common.cache.LoadingCache
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
/** Provides functionality to control bluetooth device settings. */
interface DeviceSettingRepository {
/** Gets config for the bluetooth device, returns null if failed. */
- suspend fun getDeviceSettingsConfig(cachedDevice: CachedBluetoothDevice): DeviceSettingsConfig?
-
- /** Gets all device settings for the bluetooth device. */
- fun getDeviceSettingList(
- cachedDevice: CachedBluetoothDevice,
- ): Flow<List<DeviceSetting>?>
+ suspend fun getDeviceSettingsConfig(
+ cachedDevice: CachedBluetoothDevice
+ ): DeviceSettingConfigModel?
/** Gets device setting for the bluetooth device. */
fun getDeviceSetting(
cachedDevice: CachedBluetoothDevice,
@DeviceSettingId settingId: Int
- ): Flow<DeviceSetting?>
-
- /** Updates device setting for the bluetooth device. */
- suspend fun updateDeviceSettingState(
- cachedDevice: CachedBluetoothDevice,
- @DeviceSettingId deviceSettingId: Int,
- deviceSettingPreferenceState: DeviceSettingPreferenceState,
- )
+ ): Flow<DeviceSettingModel?>
}
class DeviceSettingRepositoryImpl(
@@ -58,40 +60,94 @@
private val coroutineScope: CoroutineScope,
private val backgroundCoroutineContext: CoroutineContext,
) : DeviceSettingRepository {
- private val deviceSettings =
- ConcurrentHashMap<CachedBluetoothDevice, DeviceSettingServiceConnection>()
+ private val connectionCache:
+ LoadingCache<CachedBluetoothDevice, DeviceSettingServiceConnection> =
+ CacheBuilder.newBuilder()
+ .weakValues()
+ .build(
+ object : CacheLoader<CachedBluetoothDevice, DeviceSettingServiceConnection>() {
+ override fun load(
+ cachedDevice: CachedBluetoothDevice
+ ): DeviceSettingServiceConnection =
+ DeviceSettingServiceConnection(
+ cachedDevice,
+ context,
+ bluetoothAdaptor,
+ coroutineScope,
+ backgroundCoroutineContext,
+ )
+ }
+ )
override suspend fun getDeviceSettingsConfig(
cachedDevice: CachedBluetoothDevice
- ): DeviceSettingsConfig? = createConnectionIfAbsent(cachedDevice).getDeviceSettingsConfig()
-
- override fun getDeviceSettingList(
- cachedDevice: CachedBluetoothDevice
- ): Flow<List<DeviceSetting>?> = createConnectionIfAbsent(cachedDevice).getDeviceSettingList()
+ ): DeviceSettingConfigModel? =
+ connectionCache.get(cachedDevice).getDeviceSettingsConfig()?.toModel()
override fun getDeviceSetting(
cachedDevice: CachedBluetoothDevice,
settingId: Int
- ): Flow<DeviceSetting?> = createConnectionIfAbsent(cachedDevice).getDeviceSetting(settingId)
-
- override suspend fun updateDeviceSettingState(
- cachedDevice: CachedBluetoothDevice,
- @DeviceSettingId deviceSettingId: Int,
- deviceSettingPreferenceState: DeviceSettingPreferenceState,
- ) =
- createConnectionIfAbsent(cachedDevice)
- .updateDeviceSettings(deviceSettingId, deviceSettingPreferenceState)
-
- private fun createConnectionIfAbsent(
- cachedDevice: CachedBluetoothDevice
- ): DeviceSettingServiceConnection =
- deviceSettings.computeIfAbsent(cachedDevice) {
- DeviceSettingServiceConnection(
- cachedDevice,
- context,
- bluetoothAdaptor,
- coroutineScope,
- backgroundCoroutineContext,
- )
+ ): Flow<DeviceSettingModel?> =
+ connectionCache.get(cachedDevice).let { connection ->
+ connection.getDeviceSetting(settingId).map { it?.toModel(cachedDevice, connection) }
}
+
+ private fun DeviceSettingsConfig.toModel(): DeviceSettingConfigModel =
+ DeviceSettingConfigModel(
+ mainItems = mainContentItems.map { it.toModel() },
+ moreSettingsItems = moreSettingsItems.map { it.toModel() },
+ moreSettingsPageFooter = moreSettingsFooter
+ )
+
+ private fun DeviceSettingItem.toModel(): DeviceSettingConfigItemModel =
+ DeviceSettingConfigItemModel(settingId)
+
+ private fun DeviceSetting.toModel(
+ cachedDevice: CachedBluetoothDevice,
+ connection: DeviceSettingServiceConnection
+ ): DeviceSettingModel =
+ when (val pref = preference) {
+ is ActionSwitchPreference ->
+ DeviceSettingModel.ActionSwitchPreference(
+ cachedDevice = cachedDevice,
+ id = settingId,
+ title = pref.title,
+ summary = pref.summary,
+ icon = pref.icon,
+ isAllowedChangingState = pref.isAllowedChangingState,
+ intent = pref.intent,
+ switchState =
+ if (pref.hasSwitch()) {
+ DeviceSettingStateModel.ActionSwitchPreferenceState(pref.checked)
+ } else {
+ null
+ },
+ updateState = { newState ->
+ coroutineScope.launch(backgroundCoroutineContext) {
+ connection.updateDeviceSettings(
+ settingId,
+ newState.toParcelable(),
+ )
+ }
+ },
+ )
+ is MultiTogglePreference ->
+ DeviceSettingModel.MultiTogglePreference(
+ cachedDevice = cachedDevice,
+ id = settingId,
+ title = pref.title,
+ toggles = pref.toggleInfos.map { it.toModel() },
+ isAllowedChangingState = pref.isAllowedChangingState,
+ isActive = true,
+ state = DeviceSettingStateModel.MultiTogglePreferenceState(pref.state),
+ updateState = { newState ->
+ coroutineScope.launch(backgroundCoroutineContext) {
+ connection.updateDeviceSettings(settingId, newState.toParcelable())
+ }
+ },
+ )
+ else -> DeviceSettingModel.Unknown(cachedDevice, settingId)
+ }
+
+ private fun ToggleInfo.toModel(): ToggleModel = ToggleModel(label, icon)
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingConfigModel.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingConfigModel.kt
new file mode 100644
index 0000000..cd597ee
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingConfigModel.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.settingslib.bluetooth.devicesettings.shared.model
+
+import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
+
+/** Models a device setting config. */
+data class DeviceSettingConfigModel(
+ /** Items need to be shown in device details main page. */
+ val mainItems: List<DeviceSettingConfigItemModel>,
+ /** Items need to be shown in device details more settings page. */
+ val moreSettingsItems: List<DeviceSettingConfigItemModel>,
+ /** Footer text in more settings page. */
+ val moreSettingsPageFooter: String)
+
+/** Models a device setting item in config. */
+data class DeviceSettingConfigItemModel(
+ @DeviceSettingId val settingId: Int,
+)
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepositoryTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepositoryTest.kt
index b5457c5..fee2394 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepositoryTest.kt
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepositoryTest.kt
@@ -22,6 +22,7 @@
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
+import android.graphics.Bitmap
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.devicesettings.ActionSwitchPreference
import com.android.settingslib.bluetooth.devicesettings.ActionSwitchPreferenceState
@@ -34,6 +35,14 @@
import com.android.settingslib.bluetooth.devicesettings.IDeviceSettingsConfigProviderService
import com.android.settingslib.bluetooth.devicesettings.IDeviceSettingsListener
import com.android.settingslib.bluetooth.devicesettings.IDeviceSettingsProviderService
+import com.android.settingslib.bluetooth.devicesettings.MultiTogglePreference
+import com.android.settingslib.bluetooth.devicesettings.MultiTogglePreferenceState
+import com.android.settingslib.bluetooth.devicesettings.ToggleInfo
+import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
+import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigModel
+import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingModel
+import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingStateModel
+import com.android.settingslib.bluetooth.devicesettings.shared.model.ToggleModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
@@ -148,7 +157,7 @@
val config = underTest.getDeviceSettingsConfig(cachedDevice)
- assertThat(config).isSameInstanceAs(DEVICE_SETTING_CONFIG)
+ assertConfig(config!!, DEVICE_SETTING_CONFIG)
}
}
@@ -163,7 +172,7 @@
)
.thenReturn("".toByteArray())
- var config: DeviceSettingsConfig? = null
+ var config: DeviceSettingConfigModel? = null
val job = launch { config = underTest.getDeviceSettingsConfig(cachedDevice) }
delay(1000)
verify(bluetoothAdapter)
@@ -185,7 +194,7 @@
.thenReturn(BLUETOOTH_DEVICE_METADATA.toByteArray())
job.join()
- assertThat(config).isSameInstanceAs(DEVICE_SETTING_CONFIG)
+ assertConfig(config!!, DEVICE_SETTING_CONFIG)
}
}
@@ -202,7 +211,7 @@
}
@Test
- fun getDeviceSettingList_success() {
+ fun getDeviceSetting_actionSwitchPreference_success() {
testScope.runTest {
`when`(configService.getDeviceSettingsConfig(any())).thenReturn(DEVICE_SETTING_CONFIG)
`when`(settingProviderService1.registerDeviceSettingsListener(any(), any())).then {
@@ -211,73 +220,7 @@
.getArgument<IDeviceSettingsListener>(1)
.onDeviceSettingsChanged(listOf(DEVICE_SETTING_1))
}
- `when`(settingProviderService2.registerDeviceSettingsListener(any(), any())).then {
- input ->
- input
- .getArgument<IDeviceSettingsListener>(1)
- .onDeviceSettingsChanged(listOf(DEVICE_SETTING_2))
- }
- var settings: List<DeviceSetting>? = null
-
- underTest
- .getDeviceSettingList(cachedDevice)
- .onEach { settings = it }
- .launchIn(backgroundScope)
- runCurrent()
-
- assertThat(settings?.map { it.settingId })
- .containsExactly(
- DeviceSettingId.DEVICE_SETTING_ID_HEADER,
- DeviceSettingId.DEVICE_SETTING_ID_ANC
- )
- assertThat(settings?.map { (it.preference as ActionSwitchPreference).title })
- .containsExactly(
- "title1",
- "title2",
- )
- }
- }
-
- @Test
- fun getDeviceSetting_oneServiceFailed_returnPartialResult() {
- testScope.runTest {
- `when`(configService.getDeviceSettingsConfig(any())).thenReturn(DEVICE_SETTING_CONFIG)
- `when`(settingProviderService1.registerDeviceSettingsListener(any(), any())).then {
- input ->
- input
- .getArgument<IDeviceSettingsListener>(1)
- .onDeviceSettingsChanged(listOf(DEVICE_SETTING_1))
- }
- var settings: List<DeviceSetting>? = null
-
- underTest
- .getDeviceSettingList(cachedDevice)
- .onEach { settings = it }
- .launchIn(backgroundScope)
- runCurrent()
-
- assertThat(settings?.map { it.settingId })
- .containsExactly(
- DeviceSettingId.DEVICE_SETTING_ID_HEADER,
- )
- assertThat(settings?.map { (it.preference as ActionSwitchPreference).title })
- .containsExactly(
- "title1",
- )
- }
- }
-
- @Test
- fun getDeviceSetting_success() {
- testScope.runTest {
- `when`(configService.getDeviceSettingsConfig(any())).thenReturn(DEVICE_SETTING_CONFIG)
- `when`(settingProviderService1.registerDeviceSettingsListener(any(), any())).then {
- input ->
- input
- .getArgument<IDeviceSettingsListener>(1)
- .onDeviceSettingsChanged(listOf(DEVICE_SETTING_1))
- }
- var setting: DeviceSetting? = null
+ var setting: DeviceSettingModel? = null
underTest
.getDeviceSetting(cachedDevice, DeviceSettingId.DEVICE_SETTING_ID_HEADER)
@@ -285,13 +228,55 @@
.launchIn(backgroundScope)
runCurrent()
- assertThat(setting?.settingId).isEqualTo(DeviceSettingId.DEVICE_SETTING_ID_HEADER)
- assertThat((setting?.preference as ActionSwitchPreference).title).isEqualTo("title1")
+ assertDeviceSetting(setting!!, DEVICE_SETTING_1)
}
}
@Test
- fun updateDeviceSetting_success() {
+ fun getDeviceSetting_multiTogglePreference_success() {
+ testScope.runTest {
+ `when`(configService.getDeviceSettingsConfig(any())).thenReturn(DEVICE_SETTING_CONFIG)
+ `when`(settingProviderService2.registerDeviceSettingsListener(any(), any())).then {
+ input ->
+ input
+ .getArgument<IDeviceSettingsListener>(1)
+ .onDeviceSettingsChanged(listOf(DEVICE_SETTING_2))
+ }
+ var setting: DeviceSettingModel? = null
+
+ underTest
+ .getDeviceSetting(cachedDevice, DeviceSettingId.DEVICE_SETTING_ID_ANC)
+ .onEach { setting = it }
+ .launchIn(backgroundScope)
+ runCurrent()
+
+ assertDeviceSetting(setting!!, DEVICE_SETTING_2)
+ }
+ }
+
+ @Test
+ fun getDeviceSetting_noConfig_returnNull() {
+ testScope.runTest {
+ `when`(settingProviderService1.registerDeviceSettingsListener(any(), any())).then {
+ input ->
+ input
+ .getArgument<IDeviceSettingsListener>(1)
+ .onDeviceSettingsChanged(listOf(DEVICE_SETTING_1))
+ }
+ var setting: DeviceSettingModel? = null
+
+ underTest
+ .getDeviceSetting(cachedDevice, DeviceSettingId.DEVICE_SETTING_ID_HEADER)
+ .onEach { setting = it }
+ .launchIn(backgroundScope)
+ runCurrent()
+
+ assertThat(setting).isNull()
+ }
+ }
+
+ @Test
+ fun updateDeviceSettingState_switchState_success() {
testScope.runTest {
`when`(configService.getDeviceSettingsConfig(any())).thenReturn(DEVICE_SETTING_CONFIG)
`when`(settingProviderService1.registerDeviceSettingsListener(any(), any())).then {
@@ -300,12 +285,15 @@
.getArgument<IDeviceSettingsListener>(1)
.onDeviceSettingsChanged(listOf(DEVICE_SETTING_1))
}
+ var setting: DeviceSettingModel? = null
- underTest.updateDeviceSettingState(
- cachedDevice,
- DeviceSettingId.DEVICE_SETTING_ID_HEADER,
- ActionSwitchPreferenceState.Builder().build()
- )
+ underTest
+ .getDeviceSetting(cachedDevice, DeviceSettingId.DEVICE_SETTING_ID_HEADER)
+ .onEach { setting = it }
+ .launchIn(backgroundScope)
+ runCurrent()
+ val updateFunc = (setting as DeviceSettingModel.ActionSwitchPreference).updateState!!
+ updateFunc(DeviceSettingStateModel.ActionSwitchPreferenceState(false))
runCurrent()
verify(settingProviderService1)
@@ -313,12 +301,107 @@
DEVICE_INFO,
DeviceSettingState.Builder()
.setSettingId(DeviceSettingId.DEVICE_SETTING_ID_HEADER)
- .setPreferenceState(ActionSwitchPreferenceState.Builder().build())
+ .setPreferenceState(
+ ActionSwitchPreferenceState.Builder().setChecked(false).build()
+ )
.build()
)
}
}
+ @Test
+ fun updateDeviceSettingState_multiToggleState_success() {
+ testScope.runTest {
+ `when`(configService.getDeviceSettingsConfig(any())).thenReturn(DEVICE_SETTING_CONFIG)
+ `when`(settingProviderService2.registerDeviceSettingsListener(any(), any())).then {
+ input ->
+ input
+ .getArgument<IDeviceSettingsListener>(1)
+ .onDeviceSettingsChanged(listOf(DEVICE_SETTING_2))
+ }
+ var setting: DeviceSettingModel? = null
+
+ underTest
+ .getDeviceSetting(cachedDevice, DeviceSettingId.DEVICE_SETTING_ID_ANC)
+ .onEach { setting = it }
+ .launchIn(backgroundScope)
+ runCurrent()
+ val updateFunc = (setting as DeviceSettingModel.MultiTogglePreference).updateState
+ updateFunc(DeviceSettingStateModel.MultiTogglePreferenceState(2))
+ runCurrent()
+
+ verify(settingProviderService2)
+ .updateDeviceSettings(
+ DEVICE_INFO,
+ DeviceSettingState.Builder()
+ .setSettingId(DeviceSettingId.DEVICE_SETTING_ID_ANC)
+ .setPreferenceState(
+ MultiTogglePreferenceState.Builder().setState(2).build()
+ )
+ .build()
+ )
+ }
+ }
+
+ private fun assertDeviceSetting(actual: DeviceSettingModel, serviceResponse: DeviceSetting) {
+ assertThat(actual.id).isEqualTo(serviceResponse.settingId)
+ when (actual) {
+ is DeviceSettingModel.ActionSwitchPreference -> {
+ assertThat(serviceResponse.preference)
+ .isInstanceOf(ActionSwitchPreference::class.java)
+ val pref = serviceResponse.preference as ActionSwitchPreference
+ assertThat(actual.title).isEqualTo(pref.title)
+ assertThat(actual.summary).isEqualTo(pref.summary)
+ assertThat(actual.icon).isEqualTo(pref.icon)
+ assertThat(actual.isAllowedChangingState).isEqualTo(pref.isAllowedChangingState)
+ if (pref.hasSwitch()) {
+ assertThat(actual.switchState!!.checked).isEqualTo(pref.checked)
+ } else {
+ assertThat(actual.switchState).isNull()
+ }
+ }
+ is DeviceSettingModel.MultiTogglePreference -> {
+ assertThat(serviceResponse.preference)
+ .isInstanceOf(MultiTogglePreference::class.java)
+ val pref = serviceResponse.preference as MultiTogglePreference
+ assertThat(actual.title).isEqualTo(pref.title)
+ assertThat(actual.isAllowedChangingState).isEqualTo(pref.isAllowedChangingState)
+ assertThat(actual.toggles.size).isEqualTo(pref.toggleInfos.size)
+ for (i in 0..<actual.toggles.size) {
+ assertToggle(actual.toggles[i], pref.toggleInfos[i])
+ }
+ }
+ else -> {}
+ }
+ }
+
+ private fun assertToggle(actual: ToggleModel, serviceResponse: ToggleInfo) {
+ assertThat(actual.label).isEqualTo(serviceResponse.label)
+ assertThat(actual.icon).isEqualTo(serviceResponse.icon)
+ }
+
+ private fun assertConfig(
+ actual: DeviceSettingConfigModel,
+ serviceResponse: DeviceSettingsConfig
+ ) {
+ assertThat(actual.mainItems.size).isEqualTo(serviceResponse.mainContentItems.size)
+ for (i in 0..<actual.mainItems.size) {
+ assertConfigItem(actual.mainItems[i], serviceResponse.mainContentItems[i])
+ }
+ assertThat(actual.moreSettingsItems.size).isEqualTo(serviceResponse.moreSettingsItems.size)
+ for (i in 0..<actual.moreSettingsItems.size) {
+ assertConfigItem(actual.moreSettingsItems[i], serviceResponse.moreSettingsItems[i])
+ }
+ assertThat(actual.moreSettingsPageFooter).isEqualTo(serviceResponse.moreSettingsFooter)
+ }
+
+ private fun assertConfigItem(
+ actual: DeviceSettingConfigItemModel,
+ serviceResponse: DeviceSettingItem
+ ) {
+ assertThat(actual.settingId).isEqualTo(serviceResponse.settingId)
+ }
+
private companion object {
const val BLUETOOTH_ADDRESS = "12:34:56:78"
const val CONFIG_SERVICE_PACKAGE_NAME = "com.android.fake.configservice"
@@ -377,10 +460,21 @@
DeviceSetting.Builder()
.setSettingId(DeviceSettingId.DEVICE_SETTING_ID_ANC)
.setPreference(
- ActionSwitchPreference.Builder()
- .setTitle("title2")
- .setHasSwitch(true)
- .setAllowedChangingState(true)
+ MultiTogglePreference.Builder()
+ .setTitle("title1")
+ .setAllowChangingState(true)
+ .addToggleInfo(
+ ToggleInfo.Builder()
+ .setLabel("label1")
+ .setIcon(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888))
+ .build()
+ )
+ .addToggleInfo(
+ ToggleInfo.Builder()
+ .setLabel("label2")
+ .setIcon(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888))
+ .build()
+ )
.build()
)
.build()