Merge "Add help button on the top right corner of more settings page" into main

This commit is contained in:
Haijie Hong
2024-08-28 05:35:57 +00:00
committed by Android (Google) Code Review
8 changed files with 224 additions and 28 deletions

View File

@@ -1868,6 +1868,8 @@
<string name="bluetooth_device_more_settings_preference_title">More settings</string> <string name="bluetooth_device_more_settings_preference_title">More settings</string>
<!-- Title for more settings summary. [CHAR LIMIT=50] --> <!-- Title for more settings summary. [CHAR LIMIT=50] -->
<string name="bluetooth_device_more_settings_preference_summary">Firmware updates, about, and more</string> <string name="bluetooth_device_more_settings_preference_summary">Firmware updates, about, and more</string>
<!-- Title for bluetooth device tips and support. [CHAR LIMIT=50] -->
<string name="bluetooth_device_tip_support">Tips &amp; support</string>
<!-- Title of the item to show device MAC address --> <!-- 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> <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]--> <!-- Title of the items to show multuple devices MAC address [CHAR LIMIT=NONE]-->

View File

@@ -101,6 +101,12 @@ open class BluetoothFeatureProviderImpl : BluetoothFeatureProvider {
bluetoothAdapter: BluetoothAdapter, bluetoothAdapter: BluetoothAdapter,
cachedDevice: CachedBluetoothDevice cachedDevice: CachedBluetoothDevice
): DeviceDetailsFragmentFormatter { ): DeviceDetailsFragmentFormatter {
return DeviceDetailsFragmentFormatterImpl(context, fragment, bluetoothAdapter, cachedDevice) return DeviceDetailsFragmentFormatterImpl(
context,
fragment,
bluetoothAdapter,
cachedDevice,
Dispatchers.IO
)
} }
} }

View File

@@ -66,4 +66,11 @@ sealed interface DeviceSettingPreferenceModel {
data class MoreSettingsPreference( data class MoreSettingsPreference(
@DeviceSettingId override val id: Int, @DeviceSettingId override val id: Int,
) : DeviceSettingPreferenceModel ) : DeviceSettingPreferenceModel
/** Models a help button on the top right corner of the fragment. */
data class HelpPreference(
@DeviceSettingId override val id: Int,
val icon: DeviceSettingIcon,
val onClick: (() -> Unit),
) : DeviceSettingPreferenceModel
} }

View File

@@ -52,10 +52,15 @@ import com.android.settingslib.spa.widget.preference.SwitchPreference
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
import com.android.settingslib.spa.widget.preference.TwoTargetSwitchPreference import com.android.settingslib.spa.widget.preference.TwoTargetSwitchPreference
import com.android.settingslib.spa.widget.ui.Footer import com.android.settingslib.spa.widget.ui.Footer
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
/** Handles device details fragment layout according to config. */ /** Handles device details fragment layout according to config. */
@@ -65,6 +70,11 @@ interface DeviceDetailsFragmentFormatter {
/** Updates device details fragment layout. */ /** Updates device details fragment layout. */
fun updateLayout(fragmentType: FragmentTypeModel) fun updateLayout(fragmentType: FragmentTypeModel)
/** Gets the menu items of the fragment. */
fun getMenuItem(
fragmentType: FragmentTypeModel
): Flow<DeviceSettingPreferenceModel.HelpPreference?>
} }
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
@@ -72,7 +82,8 @@ class DeviceDetailsFragmentFormatterImpl(
private val context: Context, private val context: Context,
private val fragment: SettingsPreferenceFragment, private val fragment: SettingsPreferenceFragment,
bluetoothAdapter: BluetoothAdapter, bluetoothAdapter: BluetoothAdapter,
private val cachedDevice: CachedBluetoothDevice private val cachedDevice: CachedBluetoothDevice,
private val backgroundCoroutineContext: CoroutineContext,
) : DeviceDetailsFragmentFormatter { ) : DeviceDetailsFragmentFormatter {
private val repository = private val repository =
featureFactory.bluetoothFeatureProvider.getDeviceSettingRepository( featureFactory.bluetoothFeatureProvider.getDeviceSettingRepository(
@@ -88,6 +99,7 @@ class DeviceDetailsFragmentFormatterImpl(
repository, repository,
spatialAudioInteractor, spatialAudioInteractor,
cachedDevice, cachedDevice,
backgroundCoroutineContext,
)) ))
.get(BluetoothDeviceDetailsViewModel::class.java) .get(BluetoothDeviceDetailsViewModel::class.java)
@@ -135,6 +147,19 @@ class DeviceDetailsFragmentFormatterImpl(
fragment.preferenceScreen.addPreference(Preference(context).apply { order = 10000 }) fragment.preferenceScreen.addPreference(Preference(context).apply { order = 10000 })
} }
override fun getMenuItem(
fragmentType: FragmentTypeModel
): Flow<DeviceSettingPreferenceModel.HelpPreference?> = flow {
val t = viewModel.getHelpItem(fragmentType)
t?.let { item ->
emitAll(
viewModel.getDeviceSetting(cachedDevice, item.settingId).map {
it as? DeviceSettingPreferenceModel.HelpPreference
})
} ?: emit(null)
}
@Composable @Composable
private fun buildPreference(layout: DeviceSettingLayout, row: Int) { private fun buildPreference(layout: DeviceSettingLayout, row: Int) {
val contents by val contents by
@@ -174,6 +199,7 @@ class DeviceDetailsFragmentFormatterImpl(
is DeviceSettingPreferenceModel.MoreSettingsPreference -> { is DeviceSettingPreferenceModel.MoreSettingsPreference -> {
buildMoreSettingsPreference() buildMoreSettingsPreference()
} }
is DeviceSettingPreferenceModel.HelpPreference -> {}
null -> {} null -> {}
} }
} }

View File

@@ -19,26 +19,65 @@ package com.android.settings.bluetooth.ui.view
import android.bluetooth.BluetoothDevice import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothManager import android.bluetooth.BluetoothManager
import android.content.Context import android.content.Context
import android.graphics.PorterDuff
import android.os.Bundle import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import androidx.lifecycle.lifecycleScope
import com.android.settings.R import com.android.settings.R
import com.android.settings.bluetooth.BluetoothDetailsProfilesController import com.android.settings.bluetooth.BluetoothDetailsProfilesController
import com.android.settings.bluetooth.Utils import com.android.settings.bluetooth.Utils
import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
import com.android.settings.bluetooth.ui.model.FragmentTypeModel import com.android.settings.bluetooth.ui.model.FragmentTypeModel
import com.android.settings.dashboard.DashboardFragment import com.android.settings.dashboard.DashboardFragment
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
import com.android.settingslib.bluetooth.CachedBluetoothDevice import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.LocalBluetoothManager import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
import com.android.settingslib.core.AbstractPreferenceController import com.android.settingslib.core.AbstractPreferenceController
import com.android.settingslib.core.lifecycle.LifecycleObserver import com.android.settingslib.core.lifecycle.LifecycleObserver
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
class DeviceDetailsMoreSettingsFragment : DashboardFragment() { class DeviceDetailsMoreSettingsFragment : DashboardFragment() {
private lateinit var formatter: DeviceDetailsFragmentFormatter private lateinit var formatter: DeviceDetailsFragmentFormatter
private lateinit var localBluetoothManager: LocalBluetoothManager private lateinit var localBluetoothManager: LocalBluetoothManager
private lateinit var cachedDevice: CachedBluetoothDevice private lateinit var cachedDevice: CachedBluetoothDevice
private lateinit var helpItem: StateFlow<DeviceSettingPreferenceModel.HelpPreference?>
// TODO(b/343317785): add metrics category // TODO(b/343317785): add metrics category
override fun getMetricsCategory(): Int = 0 override fun getMetricsCategory(): Int = 0
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
lifecycleScope.launch {
helpItem.filterNotNull().collect { item ->
val iconRes = item.icon as? DeviceSettingIcon.ResourceIcon ?: return@collect
val item: MenuItem =
menu.add(0, MENU_HELP_ITEM_ID, 0, R.string.bluetooth_device_tip_support)
item.setIcon(iconRes.resId)
item.icon?.setColorFilter(
resources.getColor(
com.android.settingslib.widget.theme.R.color
.settingslib_materialColorOnSurface),
PorterDuff.Mode.SRC_ATOP)
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
}
}
}
override fun onOptionsItemSelected(menuItem: MenuItem): Boolean {
if (menuItem.itemId == MENU_HELP_ITEM_ID) {
helpItem.value?.let { it.onClick() }
return true
}
return super.onOptionsItemSelected(menuItem)
}
override fun getPreferenceScreenResId(): Int { override fun getPreferenceScreenResId(): Int {
return R.xml.bluetooth_device_more_settings_fragment return R.xml.bluetooth_device_more_settings_fragment
} }
@@ -78,6 +117,10 @@ class DeviceDetailsMoreSettingsFragment : DashboardFragment() {
formatter = formatter =
featureFactory.bluetoothFeatureProvider.getDeviceDetailsFragmentFormatter( featureFactory.bluetoothFeatureProvider.getDeviceDetailsFragmentFormatter(
requireContext(), this, bluetoothManager.adapter, cachedDevice) requireContext(), this, bluetoothManager.adapter, cachedDevice)
helpItem =
formatter
.getMenuItem(FragmentTypeModel.DeviceDetailsMoreSettingsFragment)
.stateIn(lifecycleScope, SharingStarted.WhileSubscribed(), initialValue = null)
return listOf( return listOf(
BluetoothDetailsProfilesController( BluetoothDetailsProfilesController(
context, this, localBluetoothManager, cachedDevice, settingsLifecycle)) context, this, localBluetoothManager, cachedDevice, settingsLifecycle))
@@ -88,5 +131,6 @@ class DeviceDetailsMoreSettingsFragment : DashboardFragment() {
companion object { companion object {
const val TAG: String = "DeviceMoreSettingsFrg" const val TAG: String = "DeviceMoreSettingsFrg"
const val KEY_DEVICE_ADDRESS: String = "device_address" const val KEY_DEVICE_ADDRESS: String = "device_address"
const val MENU_HELP_ITEM_ID = Menu.FIRST
} }
} }

View File

@@ -21,6 +21,7 @@ import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.android.settings.R
import com.android.settings.bluetooth.domain.interactor.SpatialAudioInteractor import com.android.settings.bluetooth.domain.interactor.SpatialAudioInteractor
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayoutRow import com.android.settings.bluetooth.ui.layout.DeviceSettingLayoutRow
@@ -30,8 +31,10 @@ import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
import com.android.settingslib.bluetooth.devicesettings.data.repository.DeviceSettingRepository 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.DeviceSettingConfigItemModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingModel 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.DeviceSettingStateModel
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async import kotlinx.coroutines.async
@@ -47,10 +50,11 @@ class BluetoothDeviceDetailsViewModel(
private val deviceSettingRepository: DeviceSettingRepository, private val deviceSettingRepository: DeviceSettingRepository,
private val spatialAudioInteractor: SpatialAudioInteractor, private val spatialAudioInteractor: SpatialAudioInteractor,
private val cachedDevice: CachedBluetoothDevice, private val cachedDevice: CachedBluetoothDevice,
backgroundCoroutineContext: CoroutineContext,
) : AndroidViewModel(application){ ) : AndroidViewModel(application){
private val items = private val items =
viewModelScope.async(Dispatchers.IO, start = CoroutineStart.LAZY) { viewModelScope.async(backgroundCoroutineContext, start = CoroutineStart.LAZY) {
deviceSettingRepository.getDeviceSettingsConfig(cachedDevice) deviceSettingRepository.getDeviceSettingsConfig(cachedDevice)
} }
@@ -61,6 +65,13 @@ class BluetoothDeviceDetailsViewModel(
items.await()?.moreSettingsItems items.await()?.moreSettingsItems
} }
suspend fun getHelpItem(fragment: FragmentTypeModel): DeviceSettingConfigItemModel? =
when (fragment) {
is FragmentTypeModel.DeviceDetailsMainFragment -> null
is FragmentTypeModel.DeviceDetailsMoreSettingsFragment ->
items.await()?.moreSettingsHelpItem
}
fun getDeviceSetting( fun getDeviceSetting(
cachedDevice: CachedBluetoothDevice, cachedDevice: CachedBluetoothDevice,
@DeviceSettingId settingId: Int @DeviceSettingId settingId: Int
@@ -101,6 +112,13 @@ class BluetoothDeviceDetailsViewModel(
} }
is DeviceSettingModel.FooterPreference -> is DeviceSettingModel.FooterPreference ->
DeviceSettingPreferenceModel.FooterPreference(id = id, footerText = footerText) DeviceSettingPreferenceModel.FooterPreference(id = id, footerText = footerText)
is DeviceSettingModel.HelpPreference ->
DeviceSettingPreferenceModel.HelpPreference(
id = id,
icon = DeviceSettingIcon.ResourceIcon(R.drawable.ic_help),
onClick = {
application.startActivity(intent)
})
is DeviceSettingModel.MultiTogglePreference -> is DeviceSettingModel.MultiTogglePreference ->
DeviceSettingPreferenceModel.MultiTogglePreference( DeviceSettingPreferenceModel.MultiTogglePreference(
id = id, id = id,
@@ -163,11 +181,14 @@ class BluetoothDeviceDetailsViewModel(
private val deviceSettingRepository: DeviceSettingRepository, private val deviceSettingRepository: DeviceSettingRepository,
private val spatialAudioInteractor: SpatialAudioInteractor, private val spatialAudioInteractor: SpatialAudioInteractor,
private val cachedDevice: CachedBluetoothDevice, private val cachedDevice: CachedBluetoothDevice,
private val backgroundCoroutineContext: CoroutineContext,
) : ViewModelProvider.Factory { ) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T { override fun <T : ViewModel> create(modelClass: Class<T>): T {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
return BluetoothDeviceDetailsViewModel( return BluetoothDeviceDetailsViewModel(
application, deviceSettingRepository, spatialAudioInteractor, cachedDevice) application, deviceSettingRepository, spatialAudioInteractor,
cachedDevice,
backgroundCoroutineContext)
as T as T
} }
} }

View File

@@ -18,14 +18,17 @@ package com.android.settings.bluetooth.ui.view
import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothAdapter
import android.content.Context import android.content.Context
import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.media.AudioManager import android.media.AudioManager
import android.net.Uri
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
import com.android.settings.bluetooth.domain.interactor.SpatialAudioInteractor import com.android.settings.bluetooth.domain.interactor.SpatialAudioInteractor
import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
import com.android.settings.bluetooth.ui.model.FragmentTypeModel import com.android.settings.bluetooth.ui.model.FragmentTypeModel
import com.android.settings.dashboard.DashboardFragment import com.android.settings.dashboard.DashboardFragment
import com.android.settings.testutils.FakeFeatureFactory import com.android.settings.testutils.FakeFeatureFactory
@@ -39,8 +42,12 @@ import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSetti
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingStateModel import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingStateModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.ToggleModel import com.android.settingslib.bluetooth.devicesettings.shared.model.ToggleModel
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
@@ -49,13 +56,17 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.eq import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.any import org.mockito.Mockito.any
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` import org.mockito.Mockito.`when`
import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule import org.mockito.junit.MockitoRule
import org.robolectric.Robolectric import org.robolectric.Robolectric
import org.robolectric.RobolectricTestRunner import org.robolectric.RobolectricTestRunner
import org.robolectric.Shadows
import org.robolectric.shadows.ShadowLooper
import org.robolectric.shadows.ShadowLooper.shadowMainLooper import org.robolectric.shadows.ShadowLooper.shadowMainLooper
@RunWith(RobolectricTestRunner::class) @RunWith(RobolectricTestRunner::class)
class DeviceDetailsFragmentFormatterTest { class DeviceDetailsFragmentFormatterTest {
@get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule() @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
@@ -68,6 +79,7 @@ class DeviceDetailsFragmentFormatterTest {
private lateinit var fragment: TestFragment private lateinit var fragment: TestFragment
private lateinit var underTest: DeviceDetailsFragmentFormatter private lateinit var underTest: DeviceDetailsFragmentFormatter
private lateinit var featureFactory: FakeFeatureFactory private lateinit var featureFactory: FakeFeatureFactory
private lateinit var fragmentActivity: FragmentActivity
private val testScope = TestScope() private val testScope = TestScope()
@Before @Before
@@ -79,10 +91,10 @@ class DeviceDetailsFragmentFormatterTest {
eq(context), eq(bluetoothAdapter), any())) eq(context), eq(bluetoothAdapter), any()))
.thenReturn(repository) .thenReturn(repository)
`when`( `when`(
featureFactory.bluetoothFeatureProvider.getSpatialAudioInteractor( featureFactory.bluetoothFeatureProvider.getSpatialAudioInteractor(
eq(context), any(AudioManager::class.java), any())) eq(context), any(AudioManager::class.java), any()))
.thenReturn(spatialAudioInteractor) .thenReturn(spatialAudioInteractor)
val fragmentActivity = Robolectric.setupActivity(FragmentActivity::class.java) fragmentActivity = Robolectric.setupActivity(FragmentActivity::class.java)
assertThat(fragmentActivity.applicationContext).isNotNull() assertThat(fragmentActivity.applicationContext).isNotNull()
fragment = TestFragment(context) fragment = TestFragment(context)
fragmentActivity.supportFragmentManager.beginTransaction().add(fragment, null).commit() fragmentActivity.supportFragmentManager.beginTransaction().add(fragment, null).commit()
@@ -95,7 +107,12 @@ class DeviceDetailsFragmentFormatterTest {
} }
underTest = underTest =
DeviceDetailsFragmentFormatterImpl(context, fragment, bluetoothAdapter, cachedDevice) DeviceDetailsFragmentFormatterImpl(
context,
fragment,
bluetoothAdapter,
cachedDevice,
testScope.testScheduler)
} }
@Test @Test
@@ -111,9 +128,11 @@ class DeviceDetailsFragmentFormatterTest {
DeviceSettingConfigItemModel.BuiltinItem( DeviceSettingConfigItemModel.BuiltinItem(
DeviceSettingId.DEVICE_SETTING_ID_ACTION_BUTTONS, "action_buttons"), DeviceSettingId.DEVICE_SETTING_ID_ACTION_BUTTONS, "action_buttons"),
), ),
listOf())) listOf(),
null))
val keys = underTest.getVisiblePreferenceKeys(FragmentTypeModel.DeviceDetailsMainFragment) val keys =
underTest.getVisiblePreferenceKeys(FragmentTypeModel.DeviceDetailsMainFragment)
assertThat(keys).containsExactly("bluetooth_device_header", "action_buttons") assertThat(keys).containsExactly("bluetooth_device_header", "action_buttons")
} }
@@ -124,12 +143,47 @@ class DeviceDetailsFragmentFormatterTest {
testScope.runTest { testScope.runTest {
`when`(repository.getDeviceSettingsConfig(cachedDevice)).thenReturn(null) `when`(repository.getDeviceSettingsConfig(cachedDevice)).thenReturn(null)
val keys = underTest.getVisiblePreferenceKeys(FragmentTypeModel.DeviceDetailsMainFragment) val keys =
underTest.getVisiblePreferenceKeys(FragmentTypeModel.DeviceDetailsMainFragment)
assertThat(keys).isNull() assertThat(keys).isNull()
} }
} }
@Test
fun getMenuItem_returnItem() {
testScope.runTest {
`when`(repository.getDeviceSettingsConfig(cachedDevice))
.thenReturn(
DeviceSettingConfigModel(
listOf(), listOf(), DeviceSettingConfigItemModel.AppProvidedItem(12345)))
val intent = Intent().apply {
setAction(Intent.ACTION_VIEW)
setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
`when`(repository.getDeviceSetting(cachedDevice, 12345))
.thenReturn(
flowOf(
DeviceSettingModel.HelpPreference(
cachedDevice = cachedDevice,
id = 12345,
intent = intent,
)))
var helpPreference: DeviceSettingPreferenceModel.HelpPreference? = null
underTest.getMenuItem(FragmentTypeModel.DeviceDetailsMoreSettingsFragment).onEach {
helpPreference = it
}.launchIn(testScope.backgroundScope)
delay(100)
runCurrent()
helpPreference!!.onClick()
ShadowLooper.idleMainLooper()
val shadowActivity = Shadows.shadowOf(fragmentActivity)
assertThat(shadowActivity.nextStartedActivity).isSameInstanceAs(intent)
}
}
@Test @Test
fun updateLayout_configIsNull_notChange() { fun updateLayout_configIsNull_notChange() {
testScope.runTest { testScope.runTest {
@@ -156,7 +210,8 @@ class DeviceDetailsFragmentFormatterTest {
DeviceSettingId.DEVICE_SETTING_ID_KEYBOARD_SETTINGS, DeviceSettingId.DEVICE_SETTING_ID_KEYBOARD_SETTINGS,
"keyboard_settings"), "keyboard_settings"),
), ),
listOf())) listOf(),
null))
underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment) underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
@@ -181,7 +236,8 @@ class DeviceDetailsFragmentFormatterTest {
DeviceSettingId.DEVICE_SETTING_ID_KEYBOARD_SETTINGS, DeviceSettingId.DEVICE_SETTING_ID_KEYBOARD_SETTINGS,
"keyboard_settings"), "keyboard_settings"),
), ),
listOf())) listOf(),
null))
`when`(repository.getDeviceSetting(cachedDevice, DeviceSettingId.DEVICE_SETTING_ID_ANC)) `when`(repository.getDeviceSetting(cachedDevice, DeviceSettingId.DEVICE_SETTING_ID_ANC))
.thenReturn( .thenReturn(
flowOf( flowOf(
@@ -192,15 +248,9 @@ class DeviceDetailsFragmentFormatterTest {
toggles = toggles =
listOf( listOf(
ToggleModel( ToggleModel(
"", DeviceSettingIcon.BitmapIcon( "",
Bitmap.createBitmap( DeviceSettingIcon.BitmapIcon(
1, Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)))),
1,
Bitmap.Config.ARGB_8888
)
)
)
),
isActive = true, isActive = true,
state = DeviceSettingStateModel.MultiTogglePreferenceState(0), state = DeviceSettingStateModel.MultiTogglePreferenceState(0),
isAllowedChangingState = true, isAllowedChangingState = true,

View File

@@ -78,7 +78,11 @@ class BluetoothDeviceDetailsViewModelTest {
underTest = underTest =
BluetoothDeviceDetailsViewModel( BluetoothDeviceDetailsViewModel(
application, repository, spatialAudioInteractor, cachedDevice) application,
repository,
spatialAudioInteractor,
cachedDevice,
testScope.testScheduler)
} }
@Test @Test
@@ -87,7 +91,7 @@ class BluetoothDeviceDetailsViewModelTest {
`when`(repository.getDeviceSettingsConfig(cachedDevice)) `when`(repository.getDeviceSettingsConfig(cachedDevice))
.thenReturn( .thenReturn(
DeviceSettingConfigModel( DeviceSettingConfigModel(
listOf(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2), listOf())) listOf(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2), listOf(), null))
val keys = underTest.getItems(FragmentTypeModel.DeviceDetailsMainFragment) val keys = underTest.getItems(FragmentTypeModel.DeviceDetailsMainFragment)
@@ -95,6 +99,38 @@ class BluetoothDeviceDetailsViewModelTest {
} }
} }
@Test
fun getHelpItems_mainPage_returnNull() {
testScope.runTest {
`when`(repository.getDeviceSettingsConfig(cachedDevice))
.thenReturn(
DeviceSettingConfigModel(
listOf(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2),
listOf(),
SETTING_ITEM_HELP))
val item = underTest.getHelpItem(FragmentTypeModel.DeviceDetailsMainFragment)
assertThat(item).isNull()
}
}
@Test
fun getHelpItems_moreSettings_returnConfigHelpItem() {
testScope.runTest {
`when`(repository.getDeviceSettingsConfig(cachedDevice))
.thenReturn(
DeviceSettingConfigModel(
listOf(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2),
listOf(),
SETTING_ITEM_HELP))
val item = underTest.getHelpItem(FragmentTypeModel.DeviceDetailsMoreSettingsFragment)
assertThat(item).isSameInstanceAs(SETTING_ITEM_HELP)
}
}
@Test @Test
fun getDeviceSetting_returnRepositoryResponse() { fun getDeviceSetting_returnRepositoryResponse() {
testScope.runTest { testScope.runTest {
@@ -107,7 +143,8 @@ class BluetoothDeviceDetailsViewModelTest {
BUILTIN_SETTING_ITEM_1, BUILTIN_SETTING_ITEM_1,
buildRemoteSettingItem(remoteSettingId1), buildRemoteSettingItem(remoteSettingId1),
), ),
listOf())) listOf(),
null))
`when`(repository.getDeviceSetting(cachedDevice, remoteSettingId1)) `when`(repository.getDeviceSetting(cachedDevice, remoteSettingId1))
.thenReturn(flowOf(pref)) .thenReturn(flowOf(pref))
@@ -137,7 +174,8 @@ class BluetoothDeviceDetailsViewModelTest {
buildRemoteSettingItem( buildRemoteSettingItem(
DeviceSettingId.DEVICE_SETTING_ID_SPATIAL_AUDIO_MULTI_TOGGLE), DeviceSettingId.DEVICE_SETTING_ID_SPATIAL_AUDIO_MULTI_TOGGLE),
), ),
listOf())) listOf(),
null))
`when`(spatialAudioInteractor.getDeviceSetting(cachedDevice)).thenReturn(flowOf(pref)) `when`(spatialAudioInteractor.getDeviceSetting(cachedDevice)).thenReturn(flowOf(pref))
var deviceSettingPreference: DeviceSettingPreferenceModel? = null var deviceSettingPreference: DeviceSettingPreferenceModel? = null
@@ -159,7 +197,7 @@ class BluetoothDeviceDetailsViewModelTest {
`when`(repository.getDeviceSettingsConfig(cachedDevice)) `when`(repository.getDeviceSettingsConfig(cachedDevice))
.thenReturn( .thenReturn(
DeviceSettingConfigModel( DeviceSettingConfigModel(
listOf(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2), listOf())) listOf(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2), listOf(), null))
val layout = underTest.getLayout(FragmentTypeModel.DeviceDetailsMainFragment)!! val layout = underTest.getLayout(FragmentTypeModel.DeviceDetailsMainFragment)!!
@@ -186,7 +224,8 @@ class BluetoothDeviceDetailsViewModelTest {
buildRemoteSettingItem(remoteSettingId2), buildRemoteSettingItem(remoteSettingId2),
buildRemoteSettingItem(remoteSettingId3), buildRemoteSettingItem(remoteSettingId3),
), ),
listOf())) listOf(),
null))
`when`(repository.getDeviceSetting(cachedDevice, remoteSettingId1)) `when`(repository.getDeviceSetting(cachedDevice, remoteSettingId1))
.thenReturn(flowOf(buildMultiTogglePreference(remoteSettingId1))) .thenReturn(flowOf(buildMultiTogglePreference(remoteSettingId1)))
`when`(repository.getDeviceSetting(cachedDevice, remoteSettingId2)) `when`(repository.getDeviceSetting(cachedDevice, remoteSettingId2))
@@ -248,5 +287,6 @@ class BluetoothDeviceDetailsViewModelTest {
val BUILDIN_SETTING_ITEM_2 = val BUILDIN_SETTING_ITEM_2 =
DeviceSettingConfigItemModel.BuiltinItem( DeviceSettingConfigItemModel.BuiltinItem(
DeviceSettingId.DEVICE_SETTING_ID_ACTION_BUTTONS, "action_buttons") DeviceSettingId.DEVICE_SETTING_ID_ACTION_BUTTONS, "action_buttons")
val SETTING_ITEM_HELP = DeviceSettingConfigItemModel.AppProvidedItem(12345)
} }
} }