diff options
| author | 2024-07-22 23:45:32 +0800 | |
|---|---|---|
| committer | 2024-07-24 10:57:08 +0800 | |
| commit | 4c66984562ba77455b2b57448ce18f316384e840 (patch) | |
| tree | 9608c3ad822e3b3848b5c8a238dae3fe33c377f8 | |
| parent | 1b1fcd1708929e6cab0d6af611c3b0e60ab7670a (diff) | |
[Audiosharing] Refine audio sharing volume support
1. Extract flags to modules
2. Extract broadcast callback flow to LocalBluetoothLeBroadcastCallbackExt
Test: atest
Bug: 336716411
Flag: com.android.settingslib.flags.volume_dialog_audio_sharing_fix
Change-Id: I9bd2c9b1060fa68fdd1522d5c185ad84a8c79ec2
6 files changed, 319 insertions, 189 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastCallbackExt.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastCallbackExt.kt new file mode 100644 index 000000000000..0bcf7fed5c80 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastCallbackExt.kt @@ -0,0 +1,70 @@ +/* + * 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 + +import android.bluetooth.BluetoothLeBroadcast +import android.bluetooth.BluetoothLeBroadcastMetadata +import com.android.internal.util.ConcurrentUtils +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.buffer +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.launch + +/** [Flow] for [BluetoothLeBroadcast.Callback] source start/stop events */ +val LocalBluetoothLeBroadcast.onBroadcastStartedOrStopped: Flow<Unit> + get() = + callbackFlow { + val listener = + object : BluetoothLeBroadcast.Callback { + override fun onBroadcastStarted(reason: Int, broadcastId: Int) { + launch { trySend(Unit) } + } + + override fun onBroadcastStartFailed(reason: Int) { + launch { trySend(Unit) } + } + + override fun onBroadcastStopped(reason: Int, broadcastId: Int) { + launch { trySend(Unit) } + } + + override fun onBroadcastStopFailed(reason: Int) { + launch { trySend(Unit) } + } + + override fun onPlaybackStarted(reason: Int, broadcastId: Int) {} + + override fun onPlaybackStopped(reason: Int, broadcastId: Int) {} + + override fun onBroadcastUpdated(reason: Int, broadcastId: Int) {} + + override fun onBroadcastUpdateFailed(reason: Int, broadcastId: Int) {} + + override fun onBroadcastMetadataChanged( + broadcastId: Int, + metadata: BluetoothLeBroadcastMetadata + ) {} + } + registerServiceCallBack( + ConcurrentUtils.DIRECT_EXECUTOR, + listener, + ) + awaitClose { unregisterServiceCallBack(listener) } + } + .buffer(capacity = Channel.CONFLATED) diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt index eb33a7a10524..e78b8a738b1c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt +++ b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt @@ -19,21 +19,18 @@ package com.android.settingslib.volume.data.repository import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothCsipSetCoordinator import android.bluetooth.BluetoothDevice -import android.bluetooth.BluetoothLeBroadcast -import android.bluetooth.BluetoothLeBroadcastMetadata import android.bluetooth.BluetoothProfile import android.bluetooth.BluetoothVolumeControl import android.content.ContentResolver -import android.content.Context import android.database.ContentObserver import android.provider.Settings import androidx.annotation.IntRange import com.android.internal.util.ConcurrentUtils import com.android.settingslib.bluetooth.BluetoothUtils import com.android.settingslib.bluetooth.LocalBluetoothManager +import com.android.settingslib.bluetooth.onBroadcastStartedOrStopped import com.android.settingslib.bluetooth.onProfileConnectionStateChanged import com.android.settingslib.bluetooth.onSourceConnectedOrRemoved -import com.android.settingslib.flags.Flags import com.android.settingslib.volume.data.repository.AudioSharingRepository.Companion.AUDIO_SHARING_VOLUME_MAX import com.android.settingslib.volume.data.repository.AudioSharingRepository.Companion.AUDIO_SHARING_VOLUME_MIN import kotlin.coroutines.CoroutineContext @@ -41,10 +38,10 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flatMapLatest @@ -85,63 +82,18 @@ interface AudioSharingRepository { @OptIn(ExperimentalCoroutinesApi::class) class AudioSharingRepositoryImpl( - private val context: Context, private val contentResolver: ContentResolver, - private val btManager: LocalBluetoothManager?, + private val btManager: LocalBluetoothManager, private val coroutineScope: CoroutineScope, private val backgroundCoroutineContext: CoroutineContext, ) : AudioSharingRepository { override val inAudioSharing: Flow<Boolean> = - if (Flags.enableLeAudioSharing()) { - btManager?.profileManager?.leAudioBroadcastProfile?.let { leBroadcast -> - callbackFlow { - val listener = - object : BluetoothLeBroadcast.Callback { - override fun onBroadcastStarted(reason: Int, broadcastId: Int) { - launch { send(isBroadcasting()) } - } - - override fun onBroadcastStartFailed(reason: Int) { - launch { send(isBroadcasting()) } - } - - override fun onBroadcastStopped(reason: Int, broadcastId: Int) { - launch { send(isBroadcasting()) } - } - - override fun onBroadcastStopFailed(reason: Int) { - launch { send(isBroadcasting()) } - } - - override fun onPlaybackStarted(reason: Int, broadcastId: Int) {} - - override fun onPlaybackStopped(reason: Int, broadcastId: Int) {} - - override fun onBroadcastUpdated(reason: Int, broadcastId: Int) {} - - override fun onBroadcastUpdateFailed( - reason: Int, - broadcastId: Int - ) {} - - override fun onBroadcastMetadataChanged( - broadcastId: Int, - metadata: BluetoothLeBroadcastMetadata - ) {} - } - - leBroadcast.registerServiceCallBack( - ConcurrentUtils.DIRECT_EXECUTOR, - listener, - ) - awaitClose { leBroadcast.unregisterServiceCallBack(listener) } - } - .onStart { emit(isBroadcasting()) } - .flowOn(backgroundCoroutineContext) - } ?: flowOf(false) - } else { - flowOf(false) - } + btManager.profileManager.leAudioBroadcastProfile?.let { broadcast -> + broadcast.onBroadcastStartedOrStopped + .map { isBroadcasting() } + .onStart { emit(isBroadcasting()) } + .flowOn(backgroundCoroutineContext) + } ?: flowOf(false) private val primaryChange: Flow<Unit> = callbackFlow { val callback = @@ -158,34 +110,24 @@ class AudioSharingRepositoryImpl( } override val secondaryGroupId: StateFlow<Int> = - if (Flags.volumeDialogAudioSharingFix()) { - merge( - btManager - ?.profileManager - ?.leAudioBroadcastAssistantProfile - ?.onSourceConnectedOrRemoved - ?.map { getSecondaryGroupId() } ?: emptyFlow(), - btManager - ?.eventManager - ?.onProfileConnectionStateChanged - ?.filter { profileConnection -> - profileConnection.state == BluetoothAdapter.STATE_DISCONNECTED && - profileConnection.bluetoothProfile == - BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT - } - ?.map { getSecondaryGroupId() } ?: emptyFlow(), - primaryChange.map { getSecondaryGroupId() }) - .onStart { emit(getSecondaryGroupId()) } - .distinctUntilChanged() - .flowOn(backgroundCoroutineContext) - } else { - emptyFlow() - } + merge( + btManager.profileManager.leAudioBroadcastAssistantProfile + ?.onSourceConnectedOrRemoved + ?.map { getSecondaryGroupId() } ?: emptyFlow(), + btManager.eventManager.onProfileConnectionStateChanged + .filter { profileConnection -> + profileConnection.state == BluetoothAdapter.STATE_DISCONNECTED && + profileConnection.bluetoothProfile == + BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT + } + .map { getSecondaryGroupId() }, + primaryChange.map { getSecondaryGroupId() }) + .onStart { emit(getSecondaryGroupId()) } + .flowOn(backgroundCoroutineContext) .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), getSecondaryGroupId()) override val volumeMap: StateFlow<GroupIdToVolumes> = - if (Flags.volumeDialogAudioSharingFix()) { - btManager?.profileManager?.volumeControlProfile?.let { volumeControl -> + (btManager.profileManager.volumeControlProfile?.let { volumeControl -> inAudioSharing.flatMapLatest { isSharing -> if (isSharing) { callbackFlow { @@ -210,50 +152,53 @@ class AudioSharingRepositoryImpl( .runningFold(emptyMap<Int, Int>()) { acc, value -> val groupId = BluetoothUtils.getGroupId( - btManager.cachedDeviceManager?.findDevice(value.first)) + btManager.cachedDeviceManager.findDevice(value.first)) if (groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) { acc + Pair(groupId, value.second) } else { acc } } - .distinctUntilChanged() .flowOn(backgroundCoroutineContext) } else { emptyFlow() } } - } ?: emptyFlow() - } else { - emptyFlow() - } - .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), emptyMap()) + } ?: emptyFlow()) + .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), emptyMap()) override suspend fun setSecondaryVolume( @IntRange(from = AUDIO_SHARING_VOLUME_MIN.toLong(), to = AUDIO_SHARING_VOLUME_MAX.toLong()) volume: Int ) { withContext(backgroundCoroutineContext) { - if (Flags.volumeDialogAudioSharingFix()) { - btManager?.profileManager?.volumeControlProfile?.let { - // Find secondary headset and set volume. - val cachedDevice = - BluetoothUtils.getSecondaryDeviceForBroadcast(context, btManager) - if (cachedDevice != null) { - it.setDeviceVolume(cachedDevice.device, volume, /* isGroupOp= */ true) - } + btManager.profileManager.volumeControlProfile?.let { + // Find secondary headset and set volume. + val cachedDevice = + BluetoothUtils.getSecondaryDeviceForBroadcast(contentResolver, btManager) + if (cachedDevice != null) { + it.setDeviceVolume(cachedDevice.device, volume, /* isGroupOp= */ true) } } } } - private fun isBroadcasting(): Boolean { - return Flags.enableLeAudioSharing() && - (btManager?.profileManager?.leAudioBroadcastProfile?.isEnabled(null) ?: false) - } + private fun isBroadcasting(): Boolean = + btManager.profileManager.leAudioBroadcastProfile?.isEnabled(null) ?: false - private fun getSecondaryGroupId(): Int { - return BluetoothUtils.getGroupId( - BluetoothUtils.getSecondaryDeviceForBroadcast(context, btManager)) - } + private fun getSecondaryGroupId(): Int = + BluetoothUtils.getGroupId( + BluetoothUtils.getSecondaryDeviceForBroadcast(contentResolver, btManager)) +} + +class AudioSharingRepositoryEmptyImpl : AudioSharingRepository { + override val inAudioSharing: Flow<Boolean> = flowOf(false) + override val secondaryGroupId: StateFlow<Int> = + MutableStateFlow(BluetoothCsipSetCoordinator.GROUP_ID_INVALID) + override val volumeMap: StateFlow<GroupIdToVolumes> = MutableStateFlow(emptyMap()) + + override suspend fun setSecondaryVolume( + @IntRange(from = AUDIO_SHARING_VOLUME_MIN.toLong(), to = AUDIO_SHARING_VOLUME_MAX.toLong()) + volume: Int + ) {} } diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioSharingRepositoryEmptyImplTest.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioSharingRepositoryEmptyImplTest.kt new file mode 100644 index 000000000000..2601592ce5ee --- /dev/null +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioSharingRepositoryEmptyImplTest.kt @@ -0,0 +1,174 @@ +/* + * 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.volume.data.repository + +import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothLeBroadcastReceiveState +import android.content.Context +import android.platform.test.flag.junit.SetFlagsRule +import android.provider.Settings +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.settingslib.bluetooth.BluetoothEventManager +import com.android.settingslib.bluetooth.BluetoothUtils +import com.android.settingslib.bluetooth.CachedBluetoothDevice +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager +import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast +import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant +import com.android.settingslib.bluetooth.LocalBluetoothManager +import com.android.settingslib.bluetooth.LocalBluetoothProfileManager +import com.android.settingslib.bluetooth.VolumeControlProfile +import com.google.common.truth.Truth +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyBoolean +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.Mock +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` +import org.mockito.junit.MockitoJUnit +import org.mockito.junit.MockitoRule + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidJUnit4::class) +class AudioSharingRepositoryEmptyImplTest { + @get:Rule val mockito: MockitoRule = MockitoJUnit.rule() + + @get:Rule val setFlagsRule: SetFlagsRule = SetFlagsRule() + + @Mock private lateinit var btManager: LocalBluetoothManager + + @Mock private lateinit var profileManager: LocalBluetoothProfileManager + + @Mock private lateinit var broadcast: LocalBluetoothLeBroadcast + + @Mock private lateinit var assistant: LocalBluetoothLeBroadcastAssistant + + @Mock private lateinit var volumeControl: VolumeControlProfile + + @Mock private lateinit var eventManager: BluetoothEventManager + + @Mock private lateinit var deviceManager: CachedBluetoothDeviceManager + + @Mock private lateinit var device1: BluetoothDevice + + @Mock private lateinit var device2: BluetoothDevice + + @Mock private lateinit var cachedDevice1: CachedBluetoothDevice + + @Mock private lateinit var cachedDevice2: CachedBluetoothDevice + + @Mock private lateinit var receiveState: BluetoothLeBroadcastReceiveState + + private val testScope = TestScope() + private val context: Context = ApplicationProvider.getApplicationContext() + private lateinit var underTest: AudioSharingRepository + + @Before + fun setup() { + `when`(btManager.profileManager).thenReturn(profileManager) + `when`(profileManager.leAudioBroadcastProfile).thenReturn(broadcast) + `when`(profileManager.leAudioBroadcastAssistantProfile).thenReturn(assistant) + `when`(profileManager.volumeControlProfile).thenReturn(volumeControl) + `when`(btManager.eventManager).thenReturn(eventManager) + `when`(btManager.cachedDeviceManager).thenReturn(deviceManager) + `when`(broadcast.isEnabled(null)).thenReturn(true) + `when`(cachedDevice1.groupId).thenReturn(TEST_GROUP_ID1) + `when`(cachedDevice1.device).thenReturn(device1) + `when`(deviceManager.findDevice(device1)).thenReturn(cachedDevice1) + `when`(cachedDevice2.groupId).thenReturn(TEST_GROUP_ID2) + `when`(cachedDevice2.device).thenReturn(device2) + `when`(deviceManager.findDevice(device2)).thenReturn(cachedDevice2) + `when`(receiveState.bisSyncState).thenReturn(arrayListOf(TEST_RECEIVE_STATE_CONTENT)) + `when`(assistant.getAllSources(any())).thenReturn(listOf(receiveState)) + underTest = AudioSharingRepositoryEmptyImpl() + } + + @Test + fun inAudioSharing_returnFalse() { + testScope.runTest { + val states = mutableListOf<Boolean?>() + underTest.inAudioSharing.onEach { states.add(it) }.launchIn(backgroundScope) + runCurrent() + + Truth.assertThat(states).containsExactly(false) + verify(broadcast, never()).registerServiceCallBack(any(), any()) + verify(broadcast, never()).isEnabled(any()) + } + } + + @Test + fun secondaryGroupIdChange_returnFalse() { + testScope.runTest { + val groupIds = mutableListOf<Int?>() + underTest.secondaryGroupId.onEach { groupIds.add(it) }.launchIn(backgroundScope) + runCurrent() + + Truth.assertThat(groupIds).containsExactly(TEST_GROUP_ID_INVALID) + verify(assistant, never()).registerServiceCallBack(any(), any()) + verify(eventManager, never()).registerCallback(any()) + } + } + + @Test + fun volumeMapChange_returnFalse() { + testScope.runTest { + val volumeMaps = mutableListOf<GroupIdToVolumes?>() + underTest.volumeMap.onEach { volumeMaps.add(it) }.launchIn(backgroundScope) + runCurrent() + + Truth.assertThat(volumeMaps).containsExactly(emptyMap<Int, Int>()) + verify(broadcast, never()).registerServiceCallBack(any(), any()) + verify(volumeControl, never()).registerCallback(any(), any()) + } + } + + @Test + fun setSecondaryVolume_doNothing() { + testScope.runTest { + Settings.Secure.putInt( + context.contentResolver, + BluetoothUtils.getPrimaryGroupIdUriForBroadcast(), + TEST_GROUP_ID2) + `when`(assistant.allConnectedDevices).thenReturn(listOf(device1, device2)) + underTest.setSecondaryVolume(TEST_VOLUME1) + + runCurrent() + verify(volumeControl, never()).setDeviceVolume(any(), anyInt(), anyBoolean()) + } + } + + private companion object { + const val TEST_GROUP_ID_INVALID = -1 + const val TEST_GROUP_ID1 = 1 + const val TEST_GROUP_ID2 = 2 + const val TEST_RECEIVE_STATE_CONTENT = 1L + const val TEST_VOLUME1 = 10 + } +} diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioSharingRepositoryTest.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioSharingRepositoryTest.kt index 000664dd1552..94595d3be8df 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioSharingRepositoryTest.kt +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioSharingRepositoryTest.kt @@ -26,8 +26,6 @@ import android.bluetooth.BluetoothVolumeControl import android.content.ContentResolver import android.content.Context import android.database.ContentObserver -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.SetFlagsRule import android.provider.Settings import androidx.test.core.app.ApplicationProvider @@ -43,7 +41,6 @@ import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant import com.android.settingslib.bluetooth.LocalBluetoothManager import com.android.settingslib.bluetooth.LocalBluetoothProfileManager import com.android.settingslib.bluetooth.VolumeControlProfile -import com.android.settingslib.flags.Flags import com.google.common.truth.Truth import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.launchIn @@ -57,14 +54,12 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.any -import org.mockito.ArgumentMatchers.anyBoolean -import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.eq import org.mockito.Captor import org.mockito.Mock -import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.`when` +import org.mockito.Spy import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule @@ -100,8 +95,6 @@ class AudioSharingRepositoryTest { @Mock private lateinit var receiveState: BluetoothLeBroadcastReceiveState - @Mock private lateinit var contentResolver: ContentResolver - @Captor private lateinit var broadcastCallbackCaptor: ArgumentCaptor<BluetoothLeBroadcast.Callback> @@ -118,6 +111,7 @@ class AudioSharingRepositoryTest { private val testScope = TestScope() private val context: Context = ApplicationProvider.getApplicationContext() + @Spy private val contentResolver: ContentResolver = context.contentResolver private lateinit var underTest: AudioSharingRepository @Before @@ -139,7 +133,6 @@ class AudioSharingRepositoryTest { `when`(assistant.getAllSources(any())).thenReturn(listOf(receiveState)) underTest = AudioSharingRepositoryImpl( - context, contentResolver, btManager, testScope.backgroundScope, @@ -148,7 +141,6 @@ class AudioSharingRepositoryTest { } @Test - @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING) fun audioSharingStateChange_emitValues() { testScope.runTest { val states = mutableListOf<Boolean?>() @@ -164,21 +156,6 @@ class AudioSharingRepositoryTest { } @Test - @DisableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING) - fun audioSharingFlagOff_returnFalse() { - testScope.runTest { - val states = mutableListOf<Boolean?>() - underTest.inAudioSharing.onEach { states.add(it) }.launchIn(backgroundScope) - runCurrent() - - Truth.assertThat(states).containsExactly(false) - verify(broadcast, never()).registerServiceCallBack(any(), any()) - verify(broadcast, never()).isEnabled(any()) - } - } - - @Test - @EnableFlags(Flags.FLAG_VOLUME_DIALOG_AUDIO_SHARING_FIX) fun secondaryGroupIdChange_emitValues() { testScope.runTest { val groupIds = mutableListOf<Int?>() @@ -214,21 +191,6 @@ class AudioSharingRepositoryTest { } @Test - @DisableFlags(Flags.FLAG_VOLUME_DIALOG_AUDIO_SHARING_FIX) - fun secondaryGroupIdChange_audioSharingFlagOff_returnFalse() { - testScope.runTest { - val groupIds = mutableListOf<Int?>() - underTest.secondaryGroupId.onEach { groupIds.add(it) }.launchIn(backgroundScope) - runCurrent() - - Truth.assertThat(groupIds).containsExactly(TEST_GROUP_ID_INVALID) - verify(assistant, never()).registerServiceCallBack(any(), any()) - verify(eventManager, never()).registerCallback(any()) - } - } - - @Test - @EnableFlags(Flags.FLAG_VOLUME_DIALOG_AUDIO_SHARING_FIX) fun volumeMapChange_emitValues() { testScope.runTest { val volumeMaps = mutableListOf<GroupIdToVolumes?>() @@ -252,21 +214,6 @@ class AudioSharingRepositoryTest { } @Test - @DisableFlags(Flags.FLAG_VOLUME_DIALOG_AUDIO_SHARING_FIX) - fun volumeMapChange_audioSharingFlagOff_returnFalse() { - testScope.runTest { - val volumeMaps = mutableListOf<GroupIdToVolumes?>() - underTest.volumeMap.onEach { volumeMaps.add(it) }.launchIn(backgroundScope) - runCurrent() - - Truth.assertThat(volumeMaps).isEmpty() - verify(broadcast, never()).registerServiceCallBack(any(), any()) - verify(volumeControl, never()).registerCallback(any(), any()) - } - } - - @Test - @EnableFlags(Flags.FLAG_VOLUME_DIALOG_AUDIO_SHARING_FIX) fun setSecondaryVolume_setValue() { testScope.runTest { Settings.Secure.putInt( @@ -281,22 +228,6 @@ class AudioSharingRepositoryTest { } } - @Test - @DisableFlags(Flags.FLAG_VOLUME_DIALOG_AUDIO_SHARING_FIX) - fun setSecondaryVolume_audioSharingFlagOff_doNothing() { - testScope.runTest { - Settings.Secure.putInt( - context.contentResolver, - BluetoothUtils.getPrimaryGroupIdUriForBroadcast(), - TEST_GROUP_ID2) - `when`(assistant.allConnectedDevices).thenReturn(listOf(device1, device2)) - underTest.setSecondaryVolume(TEST_VOLUME1) - - runCurrent() - verify(volumeControl, never()).setDeviceVolume(any(), anyInt(), anyBoolean()) - } - } - private fun triggerAudioSharingStateChange( type: TriggerType, broadcastAction: BluetoothLeBroadcast.Callback.() -> Unit diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt index eb2f71a1cd7d..0c1bc21decfe 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt @@ -19,11 +19,13 @@ package com.android.systemui.volume.dagger import android.content.ContentResolver import android.content.Context import android.media.AudioManager +import com.android.settingslib.bluetooth.BluetoothUtils import com.android.settingslib.bluetooth.LocalBluetoothManager import com.android.settingslib.notification.domain.interactor.NotificationsSoundPolicyInteractor import com.android.settingslib.volume.data.repository.AudioRepository import com.android.settingslib.volume.data.repository.AudioRepositoryImpl import com.android.settingslib.volume.data.repository.AudioSharingRepository +import com.android.settingslib.volume.data.repository.AudioSharingRepositoryEmptyImpl import com.android.settingslib.volume.data.repository.AudioSharingRepositoryImpl import com.android.settingslib.volume.domain.interactor.AudioModeInteractor import com.android.settingslib.volume.domain.interactor.AudioVolumeInteractor @@ -79,13 +81,16 @@ interface AudioModule { @Application coroutineScope: CoroutineScope, @Background coroutineContext: CoroutineContext, ): AudioSharingRepository = - AudioSharingRepositoryImpl( - context, - contentResolver, - localBluetoothManager, - coroutineScope, - coroutineContext - ) + if (BluetoothUtils.isAudioSharingEnabled() && localBluetoothManager != null) { + AudioSharingRepositoryImpl( + contentResolver, + localBluetoothManager, + coroutineScope, + coroutineContext + ) + } else { + AudioSharingRepositoryEmptyImpl() + } @Provides @SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioSharingModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioSharingModule.kt index 9f1e60e855e2..1c80887dd3e8 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioSharingModule.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioSharingModule.kt @@ -16,14 +16,14 @@ package com.android.systemui.volume.dagger -import com.android.settingslib.volume.data.repository.AudioSharingRepository +import com.android.settingslib.flags.Flags import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.volume.domain.interactor.AudioSharingInteractor +import com.android.systemui.volume.domain.interactor.AudioSharingInteractorEmptyImpl import com.android.systemui.volume.domain.interactor.AudioSharingInteractorImpl +import dagger.Lazy import dagger.Module import dagger.Provides -import kotlinx.coroutines.CoroutineScope /** Dagger module for audio sharing code in the volume package */ @Module @@ -33,8 +33,13 @@ interface AudioSharingModule { @Provides @SysUISingleton fun provideAudioSharingInteractor( - @Application coroutineScope: CoroutineScope, - repository: AudioSharingRepository - ): AudioSharingInteractor = AudioSharingInteractorImpl(coroutineScope, repository) + impl: Lazy<AudioSharingInteractorImpl>, + emptyImpl: Lazy<AudioSharingInteractorEmptyImpl>, + ): AudioSharingInteractor = + if (Flags.volumeDialogAudioSharingFix()) { + impl.get() + } else { + emptyImpl.get() + } } } |