Merge "Add help button on the top right corner of more settings page" into main
This commit is contained in:
@@ -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 & 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]-->
|
||||||
|
@@ -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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
|
@@ -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 -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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,
|
||||||
|
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user