Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 165c15a9 authored by Haijie Hong's avatar Haijie Hong
Browse files

Refactor device details UI

1. Show device details UI until all settings providers return value.
2. Clean up some unused code such as BluetoothAdapter
3. Retry when DeadObjectException happens

Test: atest DeviceSettingRepositoryTest
Flag: EXEMPT minor change
Bug: 399532172

Change-Id: Iead0599812c6750ec256b090ff636c4359b6a7c7
parent 7d8b73c1
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.settingslib.bluetooth.devicesettings.data.repository

import android.bluetooth.BluetoothAdapter
import android.content.Context
import android.text.TextUtils
import com.android.settingslib.bluetooth.CachedBluetoothDevice
@@ -68,7 +67,6 @@ interface DeviceSettingRepository {

class DeviceSettingRepositoryImpl(
    private val context: Context,
    private val bluetoothAdaptor: BluetoothAdapter,
    private val coroutineScope: CoroutineScope,
    private val backgroundCoroutineContext: CoroutineContext,
) : DeviceSettingRepository {
@@ -84,7 +82,6 @@ class DeviceSettingRepositoryImpl(
                        DeviceSettingServiceConnection(
                            cachedDevice,
                            context,
                            bluetoothAdaptor,
                            coroutineScope,
                            backgroundCoroutineContext,
                        )
+23 −20
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.settingslib.bluetooth.devicesettings.data.repository

import android.bluetooth.BluetoothAdapter
import android.content.ComponentName
import android.content.Context
import android.content.Intent
@@ -66,6 +65,7 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.retryWhen
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -77,7 +77,6 @@ import kotlinx.coroutines.withContext
class DeviceSettingServiceConnection(
    private val cachedDevice: CachedBluetoothDevice,
    private val context: Context,
    private val bluetoothAdaptor: BluetoothAdapter,
    private val coroutineScope: CoroutineScope,
    private val backgroundCoroutineContext: CoroutineContext,
) {
@@ -121,6 +120,7 @@ class DeviceSettingServiceConnection(
                        null
                    }
                }
                .retryWhen { cause, attempt -> cause is DeadObjectException || attempt < 2 }
                .catch { e ->
                    if (e is DeadObjectException) {
                        Log.e(TAG, "DeadObjectException happens when try to get service status.", e)
@@ -195,20 +195,23 @@ class DeviceSettingServiceConnection(
                    Log.w(TAG, "Service is disabled")
                    return@flow
                }
                getSettingsProviderServices()
                    ?.values
                    ?.map {
                        it.flatMapLatest { status ->
                            when (status) {
                                is ServiceConnectionStatus.Connected ->
                                    getDeviceSettingsFromService(cachedDevice, status.service)
                                else -> flowOf(emptyList())
                val services = getSettingsProviderServices()?.values
                if (services == null || services.isEmpty()) {
                    emit(mapOf())
                    return@flow
                }
                services
                    .map {
                        it.filterIsInstance<
                                ServiceConnectionStatus.Connected<IDeviceSettingsProviderService>
                            >()
                            .flatMapLatest { status ->
                                getDeviceSettingsFromService(cachedDevice, status.service)
                            }
                    }
                    ?.let { items -> combine(items) { it.toList().flatten() } }
                    ?.map { items -> items.associateBy { it.settingId } }
                    ?.let { emitAll(it) }
                    .let { items -> combine(items) { it.toList().flatten() } }
                    .map { items -> items.associateBy { it.settingId } }
                    .let { emitAll(it) }
            }
            .shareIn(scope = coroutineScope, started = SharingStarted.WhileSubscribed(), replay = 1)

@@ -224,13 +227,11 @@ class DeviceSettingServiceConnection(
            Log.w(TAG, "Service is disabled")
            return null
        }
        // Wait until all settings providers are ready.
        settingIdToItemMapping.firstOrNull()
        return readConfig()
    }

    /** Gets all device settings for the device. */
    fun getDeviceSettingList(): Flow<List<DeviceSetting>> =
        settingIdToItemMapping.map { it.values.toList() }

    /** Gets the device settings with the ID for the device. */
    fun getDeviceSetting(@DeviceSettingId deviceSettingId: Int): Flow<DeviceSetting?> =
        settingIdToItemMapping.map { it[deviceSettingId] }
@@ -289,7 +290,9 @@ class DeviceSettingServiceConnection(
                            getService(intent, IDeviceSettingsProviderService.Stub::asInterface)
                                .stateIn(
                                    coroutineScope.plus(backgroundCoroutineContext),
                                    SharingStarted.WhileSubscribed(stopTimeoutMillis = SERVICE_CONNECTION_STOP_MILLIS),
                                    SharingStarted.WhileSubscribed(
                                        stopTimeoutMillis = SERVICE_CONNECTION_STOP_MILLIS
                                    ),
                                    ServiceConnectionStatus.Connecting,
                                )
                        },
@@ -322,7 +325,7 @@ class DeviceSettingServiceConnection(
                    throw e
                }
            }
            .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), emptyList())
            .shareIn(coroutineScope, SharingStarted.WhileSubscribed(), 1)
    }

    private fun <T : IInterface> getService(
+29 −69
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.settingslib.bluetooth.devicesettings.data.repository

import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.content.ComponentName
import android.content.Context
@@ -78,7 +77,6 @@ class DeviceSettingRepositoryTest {
    @Mock private lateinit var cachedDevice: CachedBluetoothDevice
    @Mock private lateinit var bluetoothDevice: BluetoothDevice
    @Mock private lateinit var context: Context
    @Mock private lateinit var bluetoothAdapter: BluetoothAdapter
    @Mock private lateinit var configService: IDeviceSettingsConfigProviderService.Stub
    @Mock private lateinit var settingProviderService1: IDeviceSettingsProviderService.Stub
    @Mock private lateinit var settingProviderService2: IDeviceSettingsProviderService.Stub
@@ -135,7 +133,6 @@ class DeviceSettingRepositoryTest {
        underTest =
            DeviceSettingRepositoryImpl(
                context,
                bluetoothAdapter,
                testScope.backgroundScope,
                testScope.testScheduler,
            )
@@ -145,10 +142,8 @@ class DeviceSettingRepositoryTest {
    fun getDeviceSettingsConfig_withMetadata_success() {
        testScope.runTest {
            setUpConfigService(true, DEVICE_SETTING_CONFIG)
            `when`(settingProviderService1.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            `when`(settingProviderService2.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            setUpProviderService(settingProviderService1, true, listOf())
            setUpProviderService(settingProviderService2, true, listOf())

            val config = underTest.getDeviceSettingsConfig(cachedDevice)

@@ -170,10 +165,8 @@ class DeviceSettingRepositoryTest {
    fun getDeviceSettingsConfig_expandable_success() {
        testScope.runTest {
            setUpConfigService(true, DEVICE_SETTING_CONFIG_EXPANDABLE)
            `when`(settingProviderService1.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            `when`(settingProviderService2.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            setUpProviderService(settingProviderService1, true, listOf())
            setUpProviderService(settingProviderService2, true, listOf())

            val config = underTest.getDeviceSettingsConfig(cachedDevice)!!

@@ -196,10 +189,8 @@ class DeviceSettingRepositoryTest {
                )
                .thenReturn("".toByteArray())
            setUpConfigService(true, DEVICE_SETTING_CONFIG)
            `when`(settingProviderService1.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            `when`(settingProviderService2.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            setUpProviderService(settingProviderService1, true, listOf())
            setUpProviderService(settingProviderService2, true, listOf())

            val config = underTest.getDeviceSettingsConfig(cachedDevice)

@@ -211,10 +202,8 @@ class DeviceSettingRepositoryTest {
    fun getDeviceSettingsConfig_providerServiceNotEnabled_returnNull() {
        testScope.runTest {
            setUpConfigService(true, DEVICE_SETTING_CONFIG)
            `when`(settingProviderService1.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(false))
            `when`(settingProviderService2.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            setUpProviderService(settingProviderService1, true, listOf())
            setUpProviderService(settingProviderService2, false, listOf())

            val config = underTest.getDeviceSettingsConfig(cachedDevice)

@@ -238,16 +227,8 @@ class DeviceSettingRepositoryTest {
    fun getDeviceSetting_actionSwitchPreference_success() {
        testScope.runTest {
            setUpConfigService(true, DEVICE_SETTING_CONFIG)
            `when`(settingProviderService1.registerDeviceSettingsListener(any(), any())).then {
                input ->
                input
                    .getArgument<IDeviceSettingsListener>(1)
                    .onDeviceSettingsChanged(listOf(DEVICE_SETTING_1))
            }
            `when`(settingProviderService1.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            `when`(settingProviderService2.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            setUpProviderService(settingProviderService1, true, listOf(DEVICE_SETTING_1))
            setUpProviderService(settingProviderService2, true, listOf())
            var setting: DeviceSettingModel? = null

            underTest
@@ -264,16 +245,8 @@ class DeviceSettingRepositoryTest {
    fun getDeviceSetting_multiTogglePreference_success() {
        testScope.runTest {
            setUpConfigService(true, DEVICE_SETTING_CONFIG)
            `when`(settingProviderService2.registerDeviceSettingsListener(any(), any())).then {
                input ->
                input
                    .getArgument<IDeviceSettingsListener>(1)
                    .onDeviceSettingsChanged(listOf(DEVICE_SETTING_2))
            }
            `when`(settingProviderService1.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            `when`(settingProviderService2.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            setUpProviderService(settingProviderService1, true, listOf())
            setUpProviderService(settingProviderService2, true, listOf(DEVICE_SETTING_2))
            var setting: DeviceSettingModel? = null

            underTest
@@ -290,16 +263,8 @@ class DeviceSettingRepositoryTest {
    fun getDeviceSetting_helpPreference_success() {
        testScope.runTest {
            setUpConfigService(true, DEVICE_SETTING_CONFIG)
            `when`(settingProviderService2.registerDeviceSettingsListener(any(), any())).then {
                input ->
                input
                    .getArgument<IDeviceSettingsListener>(1)
                    .onDeviceSettingsChanged(listOf(DEVICE_SETTING_HELP))
            }
            `when`(settingProviderService1.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            `when`(settingProviderService2.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            setUpProviderService(settingProviderService1, true, listOf())
            setUpProviderService(settingProviderService2, true, listOf(DEVICE_SETTING_HELP))
            var setting: DeviceSettingModel? = null

            underTest
@@ -338,16 +303,8 @@ class DeviceSettingRepositoryTest {
    fun updateDeviceSettingState_switchState_success() {
        testScope.runTest {
            setUpConfigService(true, DEVICE_SETTING_CONFIG)
            `when`(settingProviderService1.registerDeviceSettingsListener(any(), any())).then {
                input ->
                input
                    .getArgument<IDeviceSettingsListener>(1)
                    .onDeviceSettingsChanged(listOf(DEVICE_SETTING_1))
            }
            `when`(settingProviderService1.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            `when`(settingProviderService2.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            setUpProviderService(settingProviderService1, true, listOf(DEVICE_SETTING_1))
            setUpProviderService(settingProviderService2, true, listOf())
            var setting: DeviceSettingModel? = null

            underTest
@@ -376,16 +333,8 @@ class DeviceSettingRepositoryTest {
    fun updateDeviceSettingState_multiToggleState_success() {
        testScope.runTest {
            setUpConfigService(true, DEVICE_SETTING_CONFIG)
            `when`(settingProviderService2.registerDeviceSettingsListener(any(), any())).then {
                input ->
                input
                    .getArgument<IDeviceSettingsListener>(1)
                    .onDeviceSettingsChanged(listOf(DEVICE_SETTING_2))
            }
            `when`(settingProviderService1.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            `when`(settingProviderService2.serviceStatus)
                .thenReturn(DeviceSettingsProviderServiceStatus(true))
            setUpProviderService(settingProviderService1, true, listOf())
            setUpProviderService(settingProviderService2, true, listOf(DEVICE_SETTING_2))
            var setting: DeviceSettingModel? = null

            underTest
@@ -487,6 +436,17 @@ class DeviceSettingRepositoryTest {
        }
    }

    private fun setUpProviderService(mockService: IDeviceSettingsProviderService.Stub, enabled: Boolean, settings: List<DeviceSetting>) {
        `when`(mockService.registerDeviceSettingsListener(any(), any())).then {
                input ->
            input
                .getArgument<IDeviceSettingsListener>(1)
                .onDeviceSettingsChanged(settings)
        }
        `when`(mockService.serviceStatus)
            .thenReturn(DeviceSettingsProviderServiceStatus(enabled))
    }

    private companion object {
        const val BLUETOOTH_ADDRESS = "12:34:56:78"
        const val CONFIG_SERVICE_PACKAGE_NAME = "com.android.fake.configservice"