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

Commit 7a10fee8 authored by Yiyi Shen's avatar Yiyi Shen
Browse files

[Audiosharing] Update STREAM_MUSIC volume when primary group change

We need to always align the STREAM_MUSIC volume and primary headset volume during audio sharing to make sure the music stream volume can be kept once the audio sharing is stopped

Test: atest
Bug: 336716411
Flag: com.android.settingslib.flags.volume_dialog_audio_sharing_fix
Change-Id: Ic4492307aa61e2c88896673d3d29b9f77f699fec
parent c8e51f85
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -62,6 +62,9 @@ interface AudioSharingRepository {
    /** Whether the device is in audio sharing. */
    val inAudioSharing: Flow<Boolean>

    /** The primary headset groupId in audio sharing. */
    val primaryGroupId: StateFlow<Int>

    /** The secondary headset groupId in audio sharing. */
    val secondaryGroupId: StateFlow<Int>

@@ -109,6 +112,16 @@ class AudioSharingRepositoryImpl(
        awaitClose { contentResolver.unregisterContentObserver(callback) }
    }

    override val primaryGroupId: StateFlow<Int> =
        primaryChange
            .map { BluetoothUtils.getPrimaryGroupIdForBroadcast(contentResolver) }
            .onStart { emit(BluetoothUtils.getPrimaryGroupIdForBroadcast(contentResolver)) }
            .flowOn(backgroundCoroutineContext)
            .stateIn(
                coroutineScope,
                SharingStarted.WhileSubscribed(),
                BluetoothUtils.getPrimaryGroupIdForBroadcast(contentResolver))

    override val secondaryGroupId: StateFlow<Int> =
        merge(
                btManager.profileManager.leAudioBroadcastAssistantProfile
@@ -121,7 +134,7 @@ class AudioSharingRepositoryImpl(
                                BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT
                    }
                    .map { getSecondaryGroupId() },
                primaryChange.map { getSecondaryGroupId() })
                primaryGroupId.map { getSecondaryGroupId() })
            .onStart { emit(getSecondaryGroupId()) }
            .flowOn(backgroundCoroutineContext)
            .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), getSecondaryGroupId())
@@ -193,6 +206,8 @@ class AudioSharingRepositoryImpl(

class AudioSharingRepositoryEmptyImpl : AudioSharingRepository {
    override val inAudioSharing: Flow<Boolean> = flowOf(false)
    override val primaryGroupId: StateFlow<Int> =
        MutableStateFlow(BluetoothCsipSetCoordinator.GROUP_ID_INVALID)
    override val secondaryGroupId: StateFlow<Int> =
        MutableStateFlow(BluetoothCsipSetCoordinator.GROUP_ID_INVALID)
    override val volumeMap: StateFlow<GroupIdToVolumes> = MutableStateFlow(emptyMap())
+25 −5
Original line number Diff line number Diff line
@@ -131,6 +131,10 @@ class AudioSharingRepositoryTest {
        `when`(deviceManager.findDevice(device2)).thenReturn(cachedDevice2)
        `when`(receiveState.bisSyncState).thenReturn(arrayListOf(TEST_RECEIVE_STATE_CONTENT))
        `when`(assistant.getAllSources(any())).thenReturn(listOf(receiveState))
        Settings.Secure.putInt(
            contentResolver,
            BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
            TEST_GROUP_ID_INVALID)
        underTest =
            AudioSharingRepositoryImpl(
                contentResolver,
@@ -155,6 +159,22 @@ class AudioSharingRepositoryTest {
        }
    }

    @Test
    fun primaryGroupIdChange_emitValues() {
        testScope.runTest {
            val groupIds = mutableListOf<Int?>()
            underTest.primaryGroupId.onEach { groupIds.add(it) }.launchIn(backgroundScope)
            runCurrent()
            triggerContentObserverChange()
            runCurrent()

            Truth.assertThat(groupIds)
                .containsExactly(
                    TEST_GROUP_ID_INVALID,
                    TEST_GROUP_ID2)
        }
    }

    @Test
    fun secondaryGroupIdChange_emitValues() {
        testScope.runTest {
@@ -217,7 +237,7 @@ class AudioSharingRepositoryTest {
    fun setSecondaryVolume_setValue() {
        testScope.runTest {
            Settings.Secure.putInt(
                context.contentResolver,
                contentResolver,
                BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
                TEST_GROUP_ID2)
            `when`(assistant.allConnectedDevices).thenReturn(listOf(device1, device2))
@@ -248,7 +268,7 @@ class AudioSharingRepositoryTest {
    private fun triggerSourceAdded() {
        verify(assistant).registerServiceCallBack(any(), assistantCallbackCaptor.capture())
        Settings.Secure.putInt(
            context.contentResolver,
            contentResolver,
            BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
            TEST_GROUP_ID1)
        `when`(assistant.allConnectedDevices).thenReturn(listOf(device1, device2))
@@ -259,7 +279,7 @@ class AudioSharingRepositoryTest {
        verify(assistant).registerServiceCallBack(any(), assistantCallbackCaptor.capture())
        `when`(assistant.allConnectedDevices).thenReturn(listOf(device1))
        Settings.Secure.putInt(
            context.contentResolver,
            contentResolver,
            BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
            TEST_GROUP_ID1)
        assistantCallbackCaptor.value.sourceRemoved(device2)
@@ -269,7 +289,7 @@ class AudioSharingRepositoryTest {
        verify(eventManager).registerCallback(btCallbackCaptor.capture())
        `when`(assistant.allConnectedDevices).thenReturn(listOf(device1))
        Settings.Secure.putInt(
            context.contentResolver,
            contentResolver,
            BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
            TEST_GROUP_ID1)
        btCallbackCaptor.value.onProfileConnectionStateChanged(cachedDevice2, state, profile)
@@ -283,7 +303,7 @@ class AudioSharingRepositoryTest {
                contentObserverCaptor.capture())
        `when`(assistant.allConnectedDevices).thenReturn(listOf(device1, device2))
        Settings.Secure.putInt(
            context.contentResolver,
            contentResolver,
            BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
            TEST_GROUP_ID2)
        contentObserverCaptor.value.primaryChanged()
+53 −13
Original line number Diff line number Diff line
@@ -16,8 +16,10 @@

package com.android.systemui.volume.domain.interactor

import android.media.AudioManager.STREAM_MUSIC
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.volume.shared.model.AudioStream
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
@@ -40,17 +42,57 @@ class AudioSharingInteractorTest : SysuiTestCase() {

    @Before
    fun setUp() {
        with(kosmos) { underTest = audioSharingInteractor }
        with(kosmos) {
            with(audioSharingRepository) { setVolumeMap(mapOf(TEST_GROUP_ID to TEST_VOLUME)) }
            underTest = audioSharingInteractor
        }
    }

    @Test
    fun volumeChanges_returnVolume() {
    fun handlePrimaryGroupChange_nullVolume() {
        with(kosmos) {
            testScope.runTest {
                with(audioSharingRepository) {
                    setSecondaryGroupId(TEST_GROUP_ID)
                    setVolumeMap(mapOf(TEST_GROUP_ID to TEST_VOLUME))
                with(audioSharingRepository) { setPrimaryGroupId(TEST_GROUP_ID_INVALID) }
                val preMusicStream by
                    collectLastValue(
                        audioVolumeInteractor.getAudioStream(AudioStream(STREAM_MUSIC))
                    )
                val preVolume = preMusicStream?.volume
                runCurrent()
                underTest.handlePrimaryGroupChange()
                val musicStream by
                    collectLastValue(
                        audioVolumeInteractor.getAudioStream(AudioStream(STREAM_MUSIC))
                    )
                runCurrent()

                Truth.assertThat(musicStream?.volume).isEqualTo(preVolume)
            }
        }
    }

    @Test
    fun handlePrimaryGroupChange_setStreamVolume() {
        with(kosmos) {
            testScope.runTest {
                with(audioSharingRepository) { setPrimaryGroupId(TEST_GROUP_ID) }
                underTest.handlePrimaryGroupChange()
                val musicStream by
                    collectLastValue(
                        audioVolumeInteractor.getAudioStream(AudioStream(STREAM_MUSIC))
                    )
                runCurrent()

                Truth.assertThat(musicStream?.volume).isEqualTo(TEST_MUSIC_VOLUME)
            }
        }
    }

    @Test
    fun secondaryGroupVolumeChanges_returnVolume() {
        with(kosmos) {
            testScope.runTest {
                with(audioSharingRepository) { setSecondaryGroupId(TEST_GROUP_ID) }
                val volume by collectLastValue(underTest.volume)
                runCurrent()

@@ -60,13 +102,10 @@ class AudioSharingInteractorTest : SysuiTestCase() {
    }

    @Test
    fun volumeChanges_returnNull() {
    fun secondaryGroupVolumeChanges_returnNull() {
        with(kosmos) {
            testScope.runTest {
                with(audioSharingRepository) {
                    setSecondaryGroupId(TEST_GROUP_ID_INVALID)
                    setVolumeMap(mapOf(TEST_GROUP_ID to TEST_VOLUME))
                }
                with(audioSharingRepository) { setSecondaryGroupId(TEST_GROUP_ID_INVALID) }
                val volume by collectLastValue(underTest.volume)
                runCurrent()

@@ -76,7 +115,7 @@ class AudioSharingInteractorTest : SysuiTestCase() {
    }

    @Test
    fun volumeChanges_returnDefaultVolume() {
    fun secondaryGroupVolumeChanges_returnDefaultVolume() {
        with(kosmos) {
            testScope.runTest {
                with(audioSharingRepository) {
@@ -94,7 +133,8 @@ class AudioSharingInteractorTest : SysuiTestCase() {
    private companion object {
        const val TEST_GROUP_ID = 1
        const val TEST_GROUP_ID_INVALID = -1
        const val TEST_VOLUME = 10
        const val TEST_MUSIC_VOLUME = 10
        const val TEST_VOLUME = 255
        const val TEST_VOLUME_DEFAULT = 20
    }
}
+11 −2
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.systemui.volume;

import static com.android.settingslib.flags.Flags.volumeDialogAudioSharingFix;

import android.content.Context;
import android.content.res.Configuration;
import android.os.Handler;
@@ -26,6 +28,7 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.volume.domain.interactor.AudioSharingInteractor;

import java.io.PrintWriter;

@@ -41,11 +44,14 @@ public class VolumeUI implements CoreStartable, ConfigurationController.Configur
    private boolean mEnabled;
    private final Context mContext;
    private VolumeDialogComponent mVolumeComponent;
    private AudioSharingInteractor mAudioSharingInteractor;

    @Inject
    public VolumeUI(Context context, VolumeDialogComponent volumeDialogComponent) {
    public VolumeUI(Context context, VolumeDialogComponent volumeDialogComponent,
            AudioSharingInteractor audioSharingInteractor) {
        mContext = context;
        mVolumeComponent = volumeDialogComponent;
        mAudioSharingInteractor = audioSharingInteractor;
    }

    @Override
@@ -58,6 +64,9 @@ public class VolumeUI implements CoreStartable, ConfigurationController.Configur

        mVolumeComponent.setEnableDialogs(enableVolumeUi, enableSafetyWarning);
        setDefaultVolumeController();
        if (volumeDialogAudioSharingFix()) {
            mAudioSharingInteractor.handlePrimaryGroupChange();
        }
    }

    @Override
+0 −1
Original line number Diff line number Diff line
@@ -75,7 +75,6 @@ interface AudioModule {
        @Provides
        @SysUISingleton
        fun provideAudioSharingRepository(
            @Application context: Context,
            contentResolver: ContentResolver,
            localBluetoothManager: LocalBluetoothManager?,
            @Application coroutineScope: CoroutineScope,
Loading