Add metrics for new bluetooth device details
BUG: 343317785 Test: atest DeviceDetailsFragmentFormatterTest Flag: com.android.settings.flags.enable_bluetooth_device_details_polish Change-Id: Ic74a885627a1426c338b093dcf949688fe9784d1
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
package com.android.settings.bluetooth.ui.view
|
package com.android.settings.bluetooth.ui.view
|
||||||
|
|
||||||
import android.app.ActivityOptions
|
import android.app.ActivityOptions
|
||||||
|
import android.app.settings.SettingsEnums
|
||||||
import android.bluetooth.BluetoothAdapter
|
import android.bluetooth.BluetoothAdapter
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
@@ -39,6 +40,7 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.SettingsPreferenceFragment
|
import com.android.settings.SettingsPreferenceFragment
|
||||||
@@ -50,30 +52,33 @@ 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.view.DeviceDetailsMoreSettingsFragment.Companion.KEY_DEVICE_ADDRESS
|
||||||
import com.android.settings.bluetooth.ui.viewmodel.BluetoothDeviceDetailsViewModel
|
import com.android.settings.bluetooth.ui.viewmodel.BluetoothDeviceDetailsViewModel
|
||||||
import com.android.settings.core.SubSettingLauncher
|
import com.android.settings.core.SubSettingLauncher
|
||||||
|
import com.android.settings.overlay.FeatureFactory
|
||||||
import com.android.settings.spa.preference.ComposePreference
|
import com.android.settings.spa.preference.ComposePreference
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice
|
||||||
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingActionModel
|
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingActionModel
|
||||||
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
|
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
|
||||||
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
|
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
|
||||||
import com.android.settingslib.spa.framework.theme.SettingsDimension
|
import com.android.settingslib.spa.framework.theme.SettingsDimension
|
||||||
import com.android.settingslib.spa.widget.button.ActionButton
|
|
||||||
import com.android.settingslib.spa.widget.button.ActionButtons
|
|
||||||
import com.android.settingslib.spa.widget.preference.Preference as SpaPreference
|
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.PreferenceModel
|
||||||
import com.android.settingslib.spa.widget.preference.SwitchPreference
|
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.scaffold.RegularScaffold
|
|
||||||
import com.android.settingslib.spa.widget.ui.Footer
|
import com.android.settingslib.spa.widget.ui.Footer
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.FlowPreview
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.emitAll
|
import kotlinx.coroutines.flow.emitAll
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
|
||||||
/** Handles device details fragment layout according to config. */
|
/** Handles device details fragment layout according to config. */
|
||||||
@@ -93,6 +98,7 @@ interface DeviceDetailsFragmentFormatter {
|
|||||||
): Flow<DeviceSettingPreferenceModel.HelpPreference?>
|
): Flow<DeviceSettingPreferenceModel.HelpPreference?>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@FlowPreview
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
class DeviceDetailsFragmentFormatterImpl(
|
class DeviceDetailsFragmentFormatterImpl(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
@@ -101,6 +107,9 @@ class DeviceDetailsFragmentFormatterImpl(
|
|||||||
private val cachedDevice: CachedBluetoothDevice,
|
private val cachedDevice: CachedBluetoothDevice,
|
||||||
private val backgroundCoroutineContext: CoroutineContext,
|
private val backgroundCoroutineContext: CoroutineContext,
|
||||||
) : DeviceDetailsFragmentFormatter {
|
) : DeviceDetailsFragmentFormatter {
|
||||||
|
private val metricsFeatureProvider = FeatureFactory.featureFactory.metricsFeatureProvider
|
||||||
|
private val prefVisibility = mutableMapOf<String, MutableStateFlow<Boolean>>()
|
||||||
|
private val prefVisibilityJobs = mutableListOf<Job>()
|
||||||
|
|
||||||
private val viewModel: BluetoothDeviceDetailsViewModel =
|
private val viewModel: BluetoothDeviceDetailsViewModel =
|
||||||
ViewModelProvider(
|
ViewModelProvider(
|
||||||
@@ -147,21 +156,33 @@ class DeviceDetailsFragmentFormatterImpl(
|
|||||||
prefKeyToSettingId[pref.key]?.let { id -> settingIdToXmlPreferences[id] = pref }
|
prefKeyToSettingId[pref.key]?.let { id -> settingIdToXmlPreferences[id] = pref }
|
||||||
}
|
}
|
||||||
fragment.preferenceScreen.removeAll()
|
fragment.preferenceScreen.removeAll()
|
||||||
|
for (job in prefVisibilityJobs) {
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
prefVisibilityJobs.clear()
|
||||||
|
|
||||||
for (row in items.indices) {
|
for (row in items.indices) {
|
||||||
val settingId = items[row].settingId
|
val settingId = items[row].settingId
|
||||||
if (settingIdToXmlPreferences.containsKey(settingId)) {
|
if (settingIdToXmlPreferences.containsKey(settingId)) {
|
||||||
fragment.preferenceScreen.addPreference(
|
fragment.preferenceScreen.addPreference(
|
||||||
settingIdToXmlPreferences[settingId]!!.apply { order = row }
|
settingIdToXmlPreferences[settingId]!!
|
||||||
|
.apply { order = row }
|
||||||
|
.also { logItemShown(it.key, it.isVisible) }
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
val prefKey = getPreferenceKey(settingId)
|
||||||
|
prefVisibilityJobs.add(
|
||||||
|
getDevicesSettingForRow(layout, row)
|
||||||
|
.onEach { logItemShown(prefKey, it.isNotEmpty()) }
|
||||||
|
.launchIn(fragment.lifecycleScope)
|
||||||
|
)
|
||||||
val pref =
|
val pref =
|
||||||
ComposePreference(context)
|
ComposePreference(context)
|
||||||
.apply {
|
.apply {
|
||||||
key = getPreferenceKey(settingId)
|
key = prefKey
|
||||||
order = row
|
order = row
|
||||||
}
|
}
|
||||||
.also { pref -> pref.setContent { buildPreference(layout, row) } }
|
.also { pref -> pref.setContent { buildPreference(layout, row, prefKey) } }
|
||||||
fragment.preferenceScreen.addPreference(pref)
|
fragment.preferenceScreen.addPreference(pref)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,24 +204,28 @@ class DeviceDetailsFragmentFormatterImpl(
|
|||||||
} ?: emit(null)
|
} ?: emit(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
private fun getDevicesSettingForRow(
|
||||||
private fun buildPreference(layout: DeviceSettingLayout, row: Int) {
|
layout: DeviceSettingLayout,
|
||||||
val contents by
|
row: Int,
|
||||||
remember(row) {
|
): Flow<List<DeviceSettingPreferenceModel>> =
|
||||||
layout.rows[row].columns.flatMapLatest { columns ->
|
layout.rows[row].columns.flatMapLatest { columns ->
|
||||||
if (columns.isEmpty()) {
|
if (columns.isEmpty()) {
|
||||||
flowOf(emptyList<DeviceSettingPreferenceModel>())
|
flowOf(emptyList())
|
||||||
} else {
|
} else {
|
||||||
combine(
|
combine(
|
||||||
columns.map { column ->
|
columns.map { column ->
|
||||||
viewModel.getDeviceSetting(cachedDevice, column.settingId)
|
viewModel.getDeviceSetting(cachedDevice, column.settingId)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
it.toList()
|
it.toList().filterNotNull()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun buildPreference(layout: DeviceSettingLayout, row: Int, prefKey: String) {
|
||||||
|
val contents by
|
||||||
|
remember(row) { getDevicesSettingForRow(layout, row) }
|
||||||
.collectAsStateWithLifecycle(initialValue = listOf())
|
.collectAsStateWithLifecycle(initialValue = listOf())
|
||||||
|
|
||||||
val highlighted by
|
val highlighted by
|
||||||
@@ -226,31 +251,31 @@ class DeviceDetailsFragmentFormatterImpl(
|
|||||||
shape = RoundedCornerShape(28.dp),
|
shape = RoundedCornerShape(28.dp),
|
||||||
)
|
)
|
||||||
) {}
|
) {}
|
||||||
buildPreferences(settings)
|
buildPreferences(settings, prefKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun buildPreferences(settings: List<DeviceSettingPreferenceModel?>) {
|
fun buildPreferences(settings: List<DeviceSettingPreferenceModel?>, prefKey: String) {
|
||||||
when (settings.size) {
|
when (settings.size) {
|
||||||
0 -> {}
|
0 -> {}
|
||||||
1 -> {
|
1 -> {
|
||||||
when (val setting = settings[0]) {
|
when (val setting = settings[0]) {
|
||||||
is DeviceSettingPreferenceModel.PlainPreference -> {
|
is DeviceSettingPreferenceModel.PlainPreference -> {
|
||||||
buildPlainPreference(setting)
|
buildPlainPreference(setting, prefKey)
|
||||||
}
|
}
|
||||||
is DeviceSettingPreferenceModel.SwitchPreference -> {
|
is DeviceSettingPreferenceModel.SwitchPreference -> {
|
||||||
buildSwitchPreference(setting)
|
buildSwitchPreference(setting, prefKey)
|
||||||
}
|
}
|
||||||
is DeviceSettingPreferenceModel.MultiTogglePreference -> {
|
is DeviceSettingPreferenceModel.MultiTogglePreference -> {
|
||||||
buildMultiTogglePreference(setting)
|
buildMultiTogglePreference(setting, prefKey)
|
||||||
}
|
}
|
||||||
is DeviceSettingPreferenceModel.FooterPreference -> {
|
is DeviceSettingPreferenceModel.FooterPreference -> {
|
||||||
buildFooterPreference(setting)
|
buildFooterPreference(setting)
|
||||||
}
|
}
|
||||||
is DeviceSettingPreferenceModel.MoreSettingsPreference -> {
|
is DeviceSettingPreferenceModel.MoreSettingsPreference -> {
|
||||||
buildMoreSettingsPreference()
|
buildMoreSettingsPreference(prefKey)
|
||||||
}
|
}
|
||||||
is DeviceSettingPreferenceModel.HelpPreference -> {}
|
is DeviceSettingPreferenceModel.HelpPreference -> {}
|
||||||
null -> {}
|
null -> {}
|
||||||
@@ -262,20 +287,32 @@ class DeviceDetailsFragmentFormatterImpl(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun buildMultiTogglePreference(
|
private fun buildMultiTogglePreference(
|
||||||
pref: DeviceSettingPreferenceModel.MultiTogglePreference
|
pref: DeviceSettingPreferenceModel.MultiTogglePreference,
|
||||||
|
prefKey: String,
|
||||||
) {
|
) {
|
||||||
MultiTogglePreference(pref)
|
MultiTogglePreference(
|
||||||
|
pref.copy(
|
||||||
|
onSelectedChange = { newState ->
|
||||||
|
logItemClick(prefKey, newState)
|
||||||
|
pref.onSelectedChange(newState)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun buildSwitchPreference(model: DeviceSettingPreferenceModel.SwitchPreference) {
|
private fun buildSwitchPreference(
|
||||||
|
model: DeviceSettingPreferenceModel.SwitchPreference,
|
||||||
|
prefKey: String,
|
||||||
|
) {
|
||||||
val switchPrefModel =
|
val switchPrefModel =
|
||||||
object : SwitchPreferenceModel {
|
object : SwitchPreferenceModel {
|
||||||
override val title = model.title
|
override val title = model.title
|
||||||
override val summary = { model.summary ?: "" }
|
override val summary = { model.summary ?: "" }
|
||||||
override val checked = { model.checked }
|
override val checked = { model.checked }
|
||||||
override val onCheckedChange = { newChecked: Boolean ->
|
override val onCheckedChange = { newState: Boolean ->
|
||||||
model.onCheckedChange(newChecked)
|
logItemClick(prefKey, if (newState) EVENT_SWITCH_ON else EVENT_SWITCH_OFF)
|
||||||
|
model.onCheckedChange(newState)
|
||||||
}
|
}
|
||||||
override val changeable = { !model.disabled }
|
override val changeable = { !model.disabled }
|
||||||
override val icon: (@Composable () -> Unit)?
|
override val icon: (@Composable () -> Unit)?
|
||||||
@@ -289,8 +326,11 @@ class DeviceDetailsFragmentFormatterImpl(
|
|||||||
if (model.action != null) {
|
if (model.action != null) {
|
||||||
TwoTargetSwitchPreference(
|
TwoTargetSwitchPreference(
|
||||||
switchPrefModel,
|
switchPrefModel,
|
||||||
primaryOnClick = { triggerAction(model.action) },
|
primaryOnClick = {
|
||||||
primaryEnabled = { !model.disabled }
|
logItemClick(prefKey, EVENT_CLICK_PRIMARY)
|
||||||
|
triggerAction(model.action)
|
||||||
|
},
|
||||||
|
primaryEnabled = { !model.disabled },
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
SwitchPreference(switchPrefModel)
|
SwitchPreference(switchPrefModel)
|
||||||
@@ -298,12 +338,16 @@ class DeviceDetailsFragmentFormatterImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun buildPlainPreference(model: DeviceSettingPreferenceModel.PlainPreference) {
|
private fun buildPlainPreference(
|
||||||
|
model: DeviceSettingPreferenceModel.PlainPreference,
|
||||||
|
prefKey: String,
|
||||||
|
) {
|
||||||
SpaPreference(
|
SpaPreference(
|
||||||
object : PreferenceModel {
|
object : PreferenceModel {
|
||||||
override val title = model.title
|
override val title = model.title
|
||||||
override val summary = { model.summary ?: "" }
|
override val summary = { model.summary ?: "" }
|
||||||
override val onClick = {
|
override val onClick = {
|
||||||
|
logItemClick(prefKey, EVENT_CLICK_PRIMARY)
|
||||||
model.action?.let { triggerAction(it) }
|
model.action?.let { triggerAction(it) }
|
||||||
Unit
|
Unit
|
||||||
}
|
}
|
||||||
@@ -319,7 +363,7 @@ class DeviceDetailsFragmentFormatterImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun buildMoreSettingsPreference() {
|
fun buildMoreSettingsPreference(prefKey: String) {
|
||||||
SpaPreference(
|
SpaPreference(
|
||||||
object : PreferenceModel {
|
object : PreferenceModel {
|
||||||
override val title =
|
override val title =
|
||||||
@@ -328,6 +372,7 @@ class DeviceDetailsFragmentFormatterImpl(
|
|||||||
context.getString(R.string.bluetooth_device_more_settings_preference_summary)
|
context.getString(R.string.bluetooth_device_more_settings_preference_summary)
|
||||||
}
|
}
|
||||||
override val onClick = {
|
override val onClick = {
|
||||||
|
logItemClick(prefKey, EVENT_CLICK_PRIMARY)
|
||||||
SubSettingLauncher(context)
|
SubSettingLauncher(context)
|
||||||
.setDestination(DeviceDetailsMoreSettingsFragment::class.java.name)
|
.setDestination(DeviceDetailsMoreSettingsFragment::class.java.name)
|
||||||
.setSourceMetricsCategory(fragment.getMetricsCategory())
|
.setSourceMetricsCategory(fragment.getMetricsCategory())
|
||||||
@@ -356,6 +401,35 @@ class DeviceDetailsFragmentFormatterImpl(
|
|||||||
icon?.let { Icon(it, modifier = Modifier.size(SettingsDimension.itemIconSize)) }
|
icon?.let { Icon(it, modifier = Modifier.size(SettingsDimension.itemIconSize)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun logItemClick(preferenceKey: String, value: Int = 0) {
|
||||||
|
logAction(preferenceKey, SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_ITEM_CLICKED, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun logItemShown(preferenceKey: String, visible: Boolean) {
|
||||||
|
if (!visible && !prefVisibility.containsKey(preferenceKey)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
prefVisibility
|
||||||
|
.computeIfAbsent(preferenceKey) {
|
||||||
|
MutableStateFlow(true).also { visibilityFlow ->
|
||||||
|
visibilityFlow
|
||||||
|
.onEach {
|
||||||
|
logAction(
|
||||||
|
preferenceKey,
|
||||||
|
SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_ITEM_SHOWN,
|
||||||
|
if (it) EVENT_VISIBLE else EVENT_INVISIBLE,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.launchIn(fragment.lifecycleScope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.value = visible
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun logAction(preferenceKey: String, action: Int, value: Int) {
|
||||||
|
metricsFeatureProvider.action(SettingsEnums.PAGE_UNKNOWN, action, 0, preferenceKey, value)
|
||||||
|
}
|
||||||
|
|
||||||
private fun triggerAction(action: DeviceSettingActionModel) {
|
private fun triggerAction(action: DeviceSettingActionModel) {
|
||||||
when (action) {
|
when (action) {
|
||||||
is DeviceSettingActionModel.IntentAction -> {
|
is DeviceSettingActionModel.IntentAction -> {
|
||||||
@@ -375,7 +449,12 @@ class DeviceDetailsFragmentFormatterImpl(
|
|||||||
|
|
||||||
private fun getPreferenceKey(settingId: Int) = "DEVICE_SETTING_${settingId}"
|
private fun getPreferenceKey(settingId: Int) = "DEVICE_SETTING_${settingId}"
|
||||||
|
|
||||||
companion object {
|
private companion object {
|
||||||
const val TAG = "DeviceDetailsFormatter"
|
const val TAG = "DeviceDetailsFormatter"
|
||||||
|
const val EVENT_SWITCH_OFF = 0
|
||||||
|
const val EVENT_SWITCH_ON = 1
|
||||||
|
const val EVENT_CLICK_PRIMARY = 2
|
||||||
|
const val EVENT_INVISIBLE = 0
|
||||||
|
const val EVENT_VISIBLE = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.settings.bluetooth.ui.view
|
package com.android.settings.bluetooth.ui.view
|
||||||
|
|
||||||
|
import android.app.settings.SettingsEnums;
|
||||||
import android.bluetooth.BluetoothAdapter
|
import android.bluetooth.BluetoothAdapter
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
@@ -39,6 +40,7 @@ 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.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
@@ -53,6 +55,7 @@ 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
|
||||||
@@ -62,6 +65,7 @@ import org.robolectric.shadows.ShadowLooper
|
|||||||
import org.robolectric.shadows.ShadowLooper.shadowMainLooper
|
import org.robolectric.shadows.ShadowLooper.shadowMainLooper
|
||||||
|
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
@RunWith(RobolectricTestRunner::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
class DeviceDetailsFragmentFormatterTest {
|
class DeviceDetailsFragmentFormatterTest {
|
||||||
@get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
|
@get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
|
||||||
@@ -70,6 +74,7 @@ class DeviceDetailsFragmentFormatterTest {
|
|||||||
@Mock private lateinit var bluetoothAdapter: BluetoothAdapter
|
@Mock private lateinit var bluetoothAdapter: BluetoothAdapter
|
||||||
@Mock private lateinit var repository: DeviceSettingRepository
|
@Mock private lateinit var repository: DeviceSettingRepository
|
||||||
|
|
||||||
|
private lateinit var context: Context
|
||||||
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
|
||||||
@@ -78,7 +83,7 @@ class DeviceDetailsFragmentFormatterTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
context = ApplicationProvider.getApplicationContext()
|
||||||
featureFactory = FakeFeatureFactory.setupForTest()
|
featureFactory = FakeFeatureFactory.setupForTest()
|
||||||
`when`(
|
`when`(
|
||||||
featureFactory.bluetoothFeatureProvider.getDeviceSettingRepository(
|
featureFactory.bluetoothFeatureProvider.getDeviceSettingRepository(
|
||||||
@@ -204,9 +209,22 @@ class DeviceDetailsFragmentFormatterTest {
|
|||||||
null))
|
null))
|
||||||
|
|
||||||
underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
|
underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
assertThat(getDisplayedPreferences().mapNotNull { it.key })
|
assertThat(getDisplayedPreferences().mapNotNull { it.key })
|
||||||
.containsExactly("bluetooth_device_header", "keyboard_settings")
|
.containsExactly("bluetooth_device_header", "keyboard_settings")
|
||||||
|
verify(featureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
SettingsEnums.PAGE_UNKNOWN,
|
||||||
|
SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_ITEM_SHOWN,
|
||||||
|
0,
|
||||||
|
"bluetooth_device_header", 1)
|
||||||
|
verify(featureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
SettingsEnums.PAGE_UNKNOWN,
|
||||||
|
SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_ITEM_SHOWN,
|
||||||
|
0,
|
||||||
|
"keyboard_settings", 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,12 +267,20 @@ class DeviceDetailsFragmentFormatterTest {
|
|||||||
updateState = {})))
|
updateState = {})))
|
||||||
|
|
||||||
underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
|
underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
assertThat(getDisplayedPreferences().mapNotNull { it.key })
|
assertThat(getDisplayedPreferences().mapNotNull { it.key })
|
||||||
.containsExactly(
|
.containsExactly(
|
||||||
"bluetooth_device_header",
|
"bluetooth_device_header",
|
||||||
"DEVICE_SETTING_${DeviceSettingId.DEVICE_SETTING_ID_ANC}",
|
"DEVICE_SETTING_${DeviceSettingId.DEVICE_SETTING_ID_ANC}",
|
||||||
"keyboard_settings")
|
"keyboard_settings")
|
||||||
|
verify(featureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
SettingsEnums.PAGE_UNKNOWN,
|
||||||
|
SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_ITEM_SHOWN,
|
||||||
|
0,
|
||||||
|
"DEVICE_SETTING_${DeviceSettingId.DEVICE_SETTING_ID_ANC}", 1
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user