summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsProviderServiceStatus.aidl19
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsProviderServiceStatus.kt60
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/IDeviceSettingsProviderService.aidl10
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/model/ServiceConnectionStatus.kt31
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingServiceConnection.kt216
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsProviderServiceStatusTest.kt51
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepositoryTest.kt93
7 files changed, 354 insertions, 126 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsProviderServiceStatus.aidl b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsProviderServiceStatus.aidl
new file mode 100644
index 000000000000..1726036f0ded
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsProviderServiceStatus.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth.devicesettings;
+
+parcelable DeviceSettingsProviderServiceStatus; \ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsProviderServiceStatus.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsProviderServiceStatus.kt
new file mode 100644
index 000000000000..977849e75556
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsProviderServiceStatus.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth.devicesettings
+
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+
+/**
+ * A data class representing a device settings item in bluetooth device details config.
+ *
+ * @property enabled Whether the service is enabled.
+ * @property extras Extra bundle
+ */
+data class DeviceSettingsProviderServiceStatus(
+ val enabled: Boolean,
+ val extras: Bundle = Bundle.EMPTY,
+) : Parcelable {
+
+ override fun describeContents(): Int = 0
+
+ override fun writeToParcel(parcel: Parcel, flags: Int) {
+ parcel.run {
+ writeBoolean(enabled)
+ writeBundle(extras)
+ }
+ }
+
+ companion object {
+ @JvmField
+ val CREATOR: Parcelable.Creator<DeviceSettingsProviderServiceStatus> =
+ object : Parcelable.Creator<DeviceSettingsProviderServiceStatus> {
+ override fun createFromParcel(parcel: Parcel) =
+ parcel.run {
+ DeviceSettingsProviderServiceStatus(
+ enabled = readBoolean(),
+ extras = readBundle((Bundle::class.java.classLoader)) ?: Bundle.EMPTY,
+ )
+ }
+
+ override fun newArray(size: Int): Array<DeviceSettingsProviderServiceStatus?> {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/IDeviceSettingsProviderService.aidl b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/IDeviceSettingsProviderService.aidl
index d5efac9d0336..1c0a1fd6b798 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/IDeviceSettingsProviderService.aidl
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/IDeviceSettingsProviderService.aidl
@@ -18,10 +18,12 @@ package com.android.settingslib.bluetooth.devicesettings;
import com.android.settingslib.bluetooth.devicesettings.DeviceInfo;
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingState;
+import com.android.settingslib.bluetooth.devicesettings.DeviceSettingsProviderServiceStatus;
import com.android.settingslib.bluetooth.devicesettings.IDeviceSettingsListener;
-oneway interface IDeviceSettingsProviderService {
- void registerDeviceSettingsListener(in DeviceInfo device, in IDeviceSettingsListener callback);
- void unregisterDeviceSettingsListener(in DeviceInfo device, in IDeviceSettingsListener callback);
- void updateDeviceSettings(in DeviceInfo device, in DeviceSettingState params);
+interface IDeviceSettingsProviderService {
+ DeviceSettingsProviderServiceStatus getServiceStatus();
+ oneway void registerDeviceSettingsListener(in DeviceInfo device, in IDeviceSettingsListener callback);
+ oneway void unregisterDeviceSettingsListener(in DeviceInfo device, in IDeviceSettingsListener callback);
+ oneway void updateDeviceSettings(in DeviceInfo device, in DeviceSettingState params);
} \ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/model/ServiceConnectionStatus.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/model/ServiceConnectionStatus.kt
new file mode 100644
index 000000000000..25080bcef061
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/model/ServiceConnectionStatus.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth.devicesettings.data.model
+
+import android.os.IInterface
+
+/** Present a service connection status. */
+sealed interface ServiceConnectionStatus<out T : IInterface> {
+ /** Service is connecting. */
+ data object Connecting : ServiceConnectionStatus<Nothing>
+
+ /** Service is connected. */
+ data class Connected<T : IInterface>(val service: T) : ServiceConnectionStatus<T>
+
+ /** Service connection failed. */
+ data object Failed : ServiceConnectionStatus<Nothing>
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingServiceConnection.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingServiceConnection.kt
index d6b28629d16b..33beb06e2ed5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingServiceConnection.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingServiceConnection.kt
@@ -22,7 +22,8 @@ import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder
-import com.android.internal.util.ConcurrentUtils
+import android.os.IInterface
+import android.util.Log
import com.android.settingslib.bluetooth.BluetoothUtils
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.devicesettings.DeviceInfo
@@ -34,27 +35,28 @@ import com.android.settingslib.bluetooth.devicesettings.DeviceSettingsConfig
import com.android.settingslib.bluetooth.devicesettings.IDeviceSettingsConfigProviderService
import com.android.settingslib.bluetooth.devicesettings.IDeviceSettingsListener
import com.android.settingslib.bluetooth.devicesettings.IDeviceSettingsProviderService
+import com.android.settingslib.bluetooth.devicesettings.data.model.ServiceConnectionStatus
import java.util.concurrent.ConcurrentHashMap
-import java.util.concurrent.atomic.AtomicReference
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.async
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.emitAll
-import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.flatMapConcat
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -84,64 +86,132 @@ class DeviceSettingServiceConnection(
}
}
- private var config = AtomicReference<DeviceSettingsConfig?>(null)
- private var idToSetting = AtomicReference<Flow<Map<Int, DeviceSetting>>?>(null)
+ private var isServiceEnabled =
+ coroutineScope.async(backgroundCoroutineContext, start = CoroutineStart.LAZY) {
+ val states = getSettingsProviderServices()?.values ?: return@async false
+ combine(states) { it.toList() }
+ .mapNotNull { allStatus ->
+ if (allStatus.any { it is ServiceConnectionStatus.Failed }) {
+ false
+ } else if (allStatus.all { it is ServiceConnectionStatus.Connected }) {
+ allStatus
+ .filterIsInstance<
+ ServiceConnectionStatus.Connected<IDeviceSettingsProviderService>
+ >()
+ .all { it.service.serviceStatus?.enabled == true }
+ } else {
+ null
+ }
+ }
+ .first()
+ }
- /** Gets [DeviceSettingsConfig] for the device, return null when failed. */
- suspend fun getDeviceSettingsConfig(): DeviceSettingsConfig? =
- config.computeIfAbsent {
- getConfigServiceBindingIntent(cachedDevice)
- .flatMapLatest { getService(it) }
- .map { it?.let { IDeviceSettingsConfigProviderService.Stub.asInterface(it) } }
- .map {
- it?.getDeviceSettingsConfig(
- deviceInfo { setBluetoothAddress(cachedDevice.address) }
- )
+ private var config =
+ coroutineScope.async(backgroundCoroutineContext, start = CoroutineStart.LAZY) {
+ val intent =
+ tryGetEndpointFromMetadata(cachedDevice)?.toIntent()
+ ?: run {
+ Log.i(TAG, "Unable to read device setting metadata from $cachedDevice")
+ return@async null
+ }
+ getService(intent, IDeviceSettingsConfigProviderService.Stub::asInterface)
+ .flatMapConcat {
+ when (it) {
+ is ServiceConnectionStatus.Connected ->
+ flowOf(
+ it.service.getDeviceSettingsConfig(
+ deviceInfo { setBluetoothAddress(cachedDevice.address) }
+ )
+ )
+ ServiceConnectionStatus.Connecting -> flowOf()
+ ServiceConnectionStatus.Failed -> flowOf(null)
+ }
}
.first()
}
+ private val settingIdToItemMapping =
+ flow {
+ if (!isServiceEnabled.await()) {
+ 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())
+ }
+ }
+ }
+ ?.let { items -> combine(items) { it.toList().flatten() } }
+ ?.map { items -> items.associateBy { it.settingId } }
+ ?.let { emitAll(it) }
+ }
+ .shareIn(scope = coroutineScope, started = SharingStarted.WhileSubscribed(), replay = 1)
+
+ /** Gets [DeviceSettingsConfig] for the device, return null when failed. */
+ suspend fun getDeviceSettingsConfig(): DeviceSettingsConfig? {
+ if (!isServiceEnabled.await()) {
+ Log.w(TAG, "Service is disabled")
+ return null
+ }
+ return readConfig()
+ }
+
/** Gets all device settings for the device. */
fun getDeviceSettingList(): Flow<List<DeviceSetting>> =
- getSettingIdToItemMapping().map { it.values.toList() }
+ settingIdToItemMapping.map { it.values.toList() }
/** Gets the device settings with the ID for the device. */
fun getDeviceSetting(@DeviceSettingId deviceSettingId: Int): Flow<DeviceSetting?> =
- getSettingIdToItemMapping().map { it[deviceSettingId] }
+ settingIdToItemMapping.map { it[deviceSettingId] }
/** Updates the device setting state for the device. */
suspend fun updateDeviceSettings(
@DeviceSettingId deviceSettingId: Int,
deviceSettingPreferenceState: DeviceSettingPreferenceState,
) {
- getDeviceSettingsConfig()?.let { config ->
+ if (!isServiceEnabled.await()) {
+ Log.w(TAG, "Service is disabled")
+ return
+ }
+ readConfig()?.let { config ->
(config.mainContentItems + config.moreSettingsItems)
.find { it.settingId == deviceSettingId }
?.let {
getSettingsProviderServices()
?.get(EndPoint(it.packageName, it.className, it.intentAction))
- ?.filterNotNull()
+ ?.filterIsInstance<
+ ServiceConnectionStatus.Connected<IDeviceSettingsProviderService>
+ >()
?.first()
}
+ ?.service
?.updateDeviceSettings(
deviceInfo { setBluetoothAddress(cachedDevice.address) },
DeviceSettingState.Builder()
.setSettingId(deviceSettingId)
.setPreferenceState(deviceSettingPreferenceState)
- .build()
+ .build(),
)
}
}
+ private suspend fun readConfig(): DeviceSettingsConfig? = config.await()
+
private suspend fun getSettingsProviderServices():
- Map<EndPoint, StateFlow<IDeviceSettingsProviderService?>>? =
- getDeviceSettingsConfig()
+ Map<EndPoint, StateFlow<ServiceConnectionStatus<IDeviceSettingsProviderService>>>? =
+ readConfig()
?.let { config ->
(config.mainContentItems + config.moreSettingsItems).map {
EndPoint(
packageName = it.packageName,
className = it.className,
- intentAction = it.intentAction
+ intentAction = it.intentAction,
)
}
}
@@ -150,43 +220,22 @@ class DeviceSettingServiceConnection(
{ it },
{ endpoint ->
services.computeIfAbsent(endpoint) {
- getService(endpoint.toIntent())
- .map { service ->
- IDeviceSettingsProviderService.Stub.asInterface(service)
- }
- .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), null)
+ getService(
+ endpoint.toIntent(),
+ IDeviceSettingsProviderService.Stub::asInterface,
+ )
+ .stateIn(
+ coroutineScope,
+ SharingStarted.WhileSubscribed(),
+ ServiceConnectionStatus.Connecting,
+ )
}
- }
+ },
)
- private fun getSettingIdToItemMapping(): Flow<Map<Int, DeviceSetting>> =
- idToSetting.computeIfAbsent {
- flow {
- getSettingsProviderServices()
- ?.values
- ?.map {
- it.flatMapLatest { service ->
- if (service != null) {
- getDeviceSettingsFromService(cachedDevice, service)
- } else {
- flowOf(emptyList())
- }
- }
- }
- ?.let { items -> combine(items) { it.toList().flatten() } }
- ?.map { items -> items.associateBy { it.settingId } }
- ?.let { emitAll(it) }
- }
- .shareIn(
- scope = coroutineScope,
- started = SharingStarted.WhileSubscribed(),
- replay = 1
- )
- }!!
-
private fun getDeviceSettingsFromService(
cachedDevice: CachedBluetoothDevice,
- service: IDeviceSettingsProviderService
+ service: IDeviceSettingsProviderService,
): Flow<List<DeviceSetting>> {
return callbackFlow {
val listener =
@@ -202,51 +251,28 @@ class DeviceSettingServiceConnection(
.stateIn(coroutineScope, SharingStarted.WhileSubscribed(), emptyList())
}
- private fun getService(intent: Intent): Flow<IBinder?> {
+ private fun <T : IInterface> getService(
+ intent: Intent,
+ transform: ((IBinder) -> T),
+ ): Flow<ServiceConnectionStatus<T>> {
return callbackFlow {
val serviceConnection =
object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
- launch { send(service) }
+ launch { send(ServiceConnectionStatus.Connected(transform(service))) }
}
override fun onServiceDisconnected(name: ComponentName?) {
- launch { send(null) }
+ launch { send(ServiceConnectionStatus.Connecting) }
}
}
if (!context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)) {
- launch { send(null) }
+ launch { send(ServiceConnectionStatus.Failed) }
}
awaitClose { context.unbindService(serviceConnection) }
}
}
- private fun getConfigServiceBindingIntent(cachedDevice: CachedBluetoothDevice): Flow<Intent> {
- return callbackFlow {
- val listener =
- BluetoothAdapter.OnMetadataChangedListener { device, key, _ ->
- if (
- key == METADATA_FAST_PAIR_CUSTOMIZED_FIELDS &&
- cachedDevice.device == device
- ) {
- launch { tryGetEndpointFromMetadata(cachedDevice)?.let { send(it) } }
- }
- }
- bluetoothAdaptor.addOnMetadataChangedListener(
- cachedDevice.device,
- ConcurrentUtils.DIRECT_EXECUTOR,
- listener,
- )
- awaitClose {
- bluetoothAdaptor.removeOnMetadataChangedListener(cachedDevice.device, listener)
- }
- }
- .onStart { tryGetEndpointFromMetadata(cachedDevice)?.let { emit(it) } }
- .distinctUntilChanged()
- .map { it.toIntent() }
- .flowOn(backgroundCoroutineContext)
- }
-
private suspend fun tryGetEndpointFromMetadata(cachedDevice: CachedBluetoothDevice): EndPoint? =
withContext(backgroundCoroutineContext) {
val packageName =
@@ -257,29 +283,31 @@ class DeviceSettingServiceConnection(
val className =
BluetoothUtils.getFastPairCustomizedField(
cachedDevice.device,
- CONFIG_SERVICE_CLASS_NAME
+ CONFIG_SERVICE_CLASS_NAME,
) ?: return@withContext null
val intentAction =
BluetoothUtils.getFastPairCustomizedField(
cachedDevice.device,
- CONFIG_SERVICE_INTENT_ACTION
+ CONFIG_SERVICE_INTENT_ACTION,
) ?: return@withContext null
EndPoint(packageName, className, intentAction)
}
- private inline fun <T> AtomicReference<T?>.computeIfAbsent(producer: () -> T): T? =
- get() ?: producer().let { compareAndExchange(null, it) ?: it }
-
private inline fun deviceInfo(block: DeviceInfo.Builder.() -> Unit): DeviceInfo {
return DeviceInfo.Builder().apply { block() }.build()
}
companion object {
+ const val TAG = "DeviceSettingSrvConn"
const val METADATA_FAST_PAIR_CUSTOMIZED_FIELDS: Int = 25
const val CONFIG_SERVICE_PACKAGE_NAME = "DEVICE_SETTINGS_CONFIG_PACKAGE_NAME"
const val CONFIG_SERVICE_CLASS_NAME = "DEVICE_SETTINGS_CONFIG_CLASS"
const val CONFIG_SERVICE_INTENT_ACTION = "DEVICE_SETTINGS_CONFIG_ACTION"
- val services = ConcurrentHashMap<EndPoint, StateFlow<IDeviceSettingsProviderService?>>()
+ val services =
+ ConcurrentHashMap<
+ EndPoint,
+ StateFlow<ServiceConnectionStatus<IDeviceSettingsProviderService>>,
+ >()
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsProviderServiceStatusTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsProviderServiceStatusTest.kt
new file mode 100644
index 000000000000..aa22fac49cd8
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsProviderServiceStatusTest.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth.devicesettings
+
+import android.os.Bundle
+import android.os.Parcel
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+
+@RunWith(RobolectricTestRunner::class)
+class DeviceSettingsProviderServiceStatusTest {
+
+ @Test
+ fun parcelOperation() {
+ val item =
+ DeviceSettingsProviderServiceStatus(
+ enabled = true,
+ extras = Bundle().apply { putString("key1", "value1") },
+ )
+
+ val fromParcel = writeAndRead(item)
+
+ assertThat(fromParcel.enabled).isEqualTo(item.enabled)
+ assertThat(fromParcel.extras.getString("key1")).isEqualTo(item.extras.getString("key1"))
+ }
+
+ private fun writeAndRead(
+ item: DeviceSettingsProviderServiceStatus
+ ): DeviceSettingsProviderServiceStatus {
+ val parcel = Parcel.obtain()
+ item.writeToParcel(parcel, 0)
+ parcel.setDataPosition(0)
+ return DeviceSettingsProviderServiceStatus.CREATOR.createFromParcel(parcel)
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepositoryTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepositoryTest.kt
index 95ee46e4fdb9..ce155b5c0fa4 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepositoryTest.kt
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepositoryTest.kt
@@ -33,6 +33,7 @@ import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingItem
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingState
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingsConfig
+import com.android.settingslib.bluetooth.devicesettings.DeviceSettingsProviderServiceStatus
import com.android.settingslib.bluetooth.devicesettings.IDeviceSettingsConfigProviderService
import com.android.settingslib.bluetooth.devicesettings.IDeviceSettingsListener
import com.android.settingslib.bluetooth.devicesettings.IDeviceSettingsProviderService
@@ -47,10 +48,8 @@ import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSetti
import com.android.settingslib.bluetooth.devicesettings.shared.model.ToggleModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -59,12 +58,9 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.verify
@@ -85,9 +81,6 @@ class DeviceSettingRepositoryTest {
@Mock private lateinit var configService: IDeviceSettingsConfigProviderService.Stub
@Mock private lateinit var settingProviderService1: IDeviceSettingsProviderService.Stub
@Mock private lateinit var settingProviderService2: IDeviceSettingsProviderService.Stub
- @Captor
- private lateinit var metadataChangeCaptor:
- ArgumentCaptor<BluetoothAdapter.OnMetadataChangedListener>
private lateinit var underTest: DeviceSettingRepository
private val testScope = TestScope()
@@ -153,6 +146,12 @@ class DeviceSettingRepositoryTest {
fun getDeviceSettingsConfig_withMetadata_success() {
testScope.runTest {
`when`(configService.getDeviceSettingsConfig(any())).thenReturn(DEVICE_SETTING_CONFIG)
+ `when`(settingProviderService1.serviceStatus).thenReturn(
+ DeviceSettingsProviderServiceStatus(true)
+ )
+ `when`(settingProviderService2.serviceStatus).thenReturn(
+ DeviceSettingsProviderServiceStatus(true)
+ )
val config = underTest.getDeviceSettingsConfig(cachedDevice)
@@ -161,32 +160,40 @@ class DeviceSettingRepositoryTest {
}
@Test
- fun getDeviceSettingsConfig_waitMetadataChange_success() {
+ fun getDeviceSettingsConfig_noMetadata_returnNull() {
testScope.runTest {
- `when`(configService.getDeviceSettingsConfig(any())).thenReturn(DEVICE_SETTING_CONFIG)
`when`(
- bluetoothDevice.getMetadata(
- DeviceSettingServiceConnection.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS))
+ bluetoothDevice.getMetadata(
+ DeviceSettingServiceConnection.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS))
.thenReturn("".toByteArray())
+ `when`(configService.getDeviceSettingsConfig(any())).thenReturn(DEVICE_SETTING_CONFIG)
+ `when`(settingProviderService1.serviceStatus).thenReturn(
+ DeviceSettingsProviderServiceStatus(true)
+ )
+ `when`(settingProviderService2.serviceStatus).thenReturn(
+ DeviceSettingsProviderServiceStatus(true)
+ )
- var config: DeviceSettingConfigModel? = null
- val job = launch { config = underTest.getDeviceSettingsConfig(cachedDevice) }
- delay(1000)
- verify(bluetoothAdapter)
- .addOnMetadataChangedListener(
- eq(bluetoothDevice), any(), metadataChangeCaptor.capture())
- metadataChangeCaptor.value.onMetadataChanged(
- bluetoothDevice,
- DeviceSettingServiceConnection.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS,
- BLUETOOTH_DEVICE_METADATA.toByteArray(),
+ val config = underTest.getDeviceSettingsConfig(cachedDevice)
+
+ assertThat(config).isNull()
+ }
+ }
+
+ @Test
+ fun getDeviceSettingsConfig_providerServiceNotEnabled_returnNull() {
+ testScope.runTest {
+ `when`(configService.getDeviceSettingsConfig(any())).thenReturn(DEVICE_SETTING_CONFIG)
+ `when`(settingProviderService1.serviceStatus).thenReturn(
+ DeviceSettingsProviderServiceStatus(false)
+ )
+ `when`(settingProviderService2.serviceStatus).thenReturn(
+ DeviceSettingsProviderServiceStatus(true)
)
- `when`(
- bluetoothDevice.getMetadata(
- DeviceSettingServiceConnection.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS))
- .thenReturn(BLUETOOTH_DEVICE_METADATA.toByteArray())
- job.join()
- assertConfig(config!!, DEVICE_SETTING_CONFIG)
+ val config = underTest.getDeviceSettingsConfig(cachedDevice)
+
+ assertThat(config).isNull()
}
}
@@ -212,6 +219,12 @@ class DeviceSettingRepositoryTest {
.getArgument<IDeviceSettingsListener>(1)
.onDeviceSettingsChanged(listOf(DEVICE_SETTING_1))
}
+ `when`(settingProviderService1.serviceStatus).thenReturn(
+ DeviceSettingsProviderServiceStatus(true)
+ )
+ `when`(settingProviderService2.serviceStatus).thenReturn(
+ DeviceSettingsProviderServiceStatus(true)
+ )
var setting: DeviceSettingModel? = null
underTest
@@ -234,6 +247,12 @@ class DeviceSettingRepositoryTest {
.getArgument<IDeviceSettingsListener>(1)
.onDeviceSettingsChanged(listOf(DEVICE_SETTING_2))
}
+ `when`(settingProviderService1.serviceStatus).thenReturn(
+ DeviceSettingsProviderServiceStatus(true)
+ )
+ `when`(settingProviderService2.serviceStatus).thenReturn(
+ DeviceSettingsProviderServiceStatus(true)
+ )
var setting: DeviceSettingModel? = null
underTest
@@ -256,6 +275,12 @@ class DeviceSettingRepositoryTest {
.getArgument<IDeviceSettingsListener>(1)
.onDeviceSettingsChanged(listOf(DEVICE_SETTING_HELP))
}
+ `when`(settingProviderService1.serviceStatus).thenReturn(
+ DeviceSettingsProviderServiceStatus(true)
+ )
+ `when`(settingProviderService2.serviceStatus).thenReturn(
+ DeviceSettingsProviderServiceStatus(true)
+ )
var setting: DeviceSettingModel? = null
underTest
@@ -299,6 +324,12 @@ class DeviceSettingRepositoryTest {
.getArgument<IDeviceSettingsListener>(1)
.onDeviceSettingsChanged(listOf(DEVICE_SETTING_1))
}
+ `when`(settingProviderService1.serviceStatus).thenReturn(
+ DeviceSettingsProviderServiceStatus(true)
+ )
+ `when`(settingProviderService2.serviceStatus).thenReturn(
+ DeviceSettingsProviderServiceStatus(true)
+ )
var setting: DeviceSettingModel? = null
underTest
@@ -331,6 +362,12 @@ class DeviceSettingRepositoryTest {
.getArgument<IDeviceSettingsListener>(1)
.onDeviceSettingsChanged(listOf(DEVICE_SETTING_2))
}
+ `when`(settingProviderService1.serviceStatus).thenReturn(
+ DeviceSettingsProviderServiceStatus(true)
+ )
+ `when`(settingProviderService2.serviceStatus).thenReturn(
+ DeviceSettingsProviderServiceStatus(true)
+ )
var setting: DeviceSettingModel? = null
underTest