[Audiosharing] Use new API to get primary group id change

Test: atest
Bug: 397568136
Flag: com.android.settingslib.flags.adopt_primary_group_management_api_v2
Change-Id: I06e8b51ba9714f48c035c92e78e697967815d0bb
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 8771ba0..98cae31 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
@@ -30,9 +30,11 @@
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
 import com.android.settingslib.bluetooth.LocalBluetoothManager
 import com.android.settingslib.bluetooth.onBroadcastStartedOrStopped
+import com.android.settingslib.bluetooth.onBroadcastToUnicastFallbackGroupChanged
 import com.android.settingslib.bluetooth.onProfileConnectionStateChanged
 import com.android.settingslib.bluetooth.onServiceStateChanged
 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 com.android.settingslib.volume.shared.AudioSharingLogger
@@ -140,15 +142,26 @@
     }
 
     override val primaryGroupId: StateFlow<Int> =
-        primaryChange
-            .map { BluetoothUtils.getPrimaryGroupIdForBroadcast(contentResolver) }
-            .onStart { emit(BluetoothUtils.getPrimaryGroupIdForBroadcast(contentResolver)) }
-            .flowOn(backgroundCoroutineContext)
-            .stateIn(
-                coroutineScope,
-                SharingStarted.WhileSubscribed(),
-                BluetoothCsipSetCoordinator.GROUP_ID_INVALID
-            )
+        if (Flags.adoptPrimaryGroupManagementApiV2()) {
+            isAudioSharingProfilesReady.flatMapLatest { ready ->
+                if (ready) {
+                    btManager.profileManager.leAudioProfile.onBroadcastToUnicastFallbackGroupChanged
+                        .onStart { emit(BluetoothCsipSetCoordinator.GROUP_ID_INVALID) }
+                        .flowOn(backgroundCoroutineContext)
+                } else {
+                    flowOf(BluetoothCsipSetCoordinator.GROUP_ID_INVALID)
+                }
+            }
+        } else {
+            primaryChange
+                .map { BluetoothUtils.getPrimaryGroupIdForBroadcast(contentResolver) }
+                .onStart { emit(BluetoothUtils.getPrimaryGroupIdForBroadcast(contentResolver)) }
+                .flowOn(backgroundCoroutineContext)
+        }.stateIn(
+            coroutineScope,
+            SharingStarted.WhileSubscribed(),
+            BluetoothCsipSetCoordinator.GROUP_ID_INVALID
+        )
 
     override val primaryDevice: StateFlow<CachedBluetoothDevice?> =
         primaryGroupId
@@ -273,8 +286,12 @@
     private fun isVolumeControlProfileReady(): Boolean =
         btManager.profileManager.volumeControlProfile?.isProfileReady ?: false
 
+    private fun isLeAudioProfileReady(): Boolean =
+        btManager.profileManager.leAudioProfile?.isProfileReady ?: false
+
     private fun isAudioSharingProfilesReady(): Boolean =
         isBroadcastProfileReady() && isAssistantProfileReady() && isVolumeControlProfileReady()
+                && isLeAudioProfileReady()
 
     private fun isBroadcasting(): Boolean =
         btManager.profileManager.leAudioBroadcastProfile?.isEnabled(null) ?: false
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 0f25ae2..6fd5ab7 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
@@ -18,6 +18,7 @@
 
 import android.bluetooth.BluetoothAdapter
 import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothLeAudio
 import android.bluetooth.BluetoothLeBroadcast
 import android.bluetooth.BluetoothLeBroadcastAssistant
 import android.bluetooth.BluetoothLeBroadcastReceiveState
@@ -26,6 +27,8 @@
 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
@@ -36,11 +39,13 @@
 import com.android.settingslib.bluetooth.BluetoothUtils
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager
+import com.android.settingslib.bluetooth.LeAudioProfile
 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.android.settingslib.flags.Flags
 import com.google.common.truth.Truth
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.launchIn
@@ -83,6 +88,8 @@
 
     @Mock private lateinit var volumeControl: VolumeControlProfile
 
+    @Mock private lateinit var leAudio: LeAudioProfile
+
     @Mock private lateinit var eventManager: BluetoothEventManager
 
     @Mock private lateinit var deviceManager: CachedBluetoothDeviceManager
@@ -104,6 +111,8 @@
     private lateinit var assistantCallbackCaptor:
             ArgumentCaptor<BluetoothLeBroadcastAssistant.Callback>
 
+    @Captor private lateinit var leAudioCallbackCaptor: ArgumentCaptor<BluetoothLeAudio.Callback>
+
     @Captor private lateinit var btCallbackCaptor: ArgumentCaptor<BluetoothCallback>
 
     @Captor private lateinit var contentObserverCaptor: ArgumentCaptor<ContentObserver>
@@ -123,6 +132,7 @@
         `when`(profileManager.leAudioBroadcastProfile).thenReturn(broadcast)
         `when`(profileManager.leAudioBroadcastAssistantProfile).thenReturn(assistant)
         `when`(profileManager.volumeControlProfile).thenReturn(volumeControl)
+        `when`(profileManager.leAudioProfile).thenReturn(leAudio)
         `when`(btManager.eventManager).thenReturn(eventManager)
         `when`(btManager.cachedDeviceManager).thenReturn(deviceManager)
         `when`(broadcast.isEnabled(null)).thenReturn(true)
@@ -160,6 +170,7 @@
             `when`(broadcast.isProfileReady).thenReturn(true)
             `when`(assistant.isProfileReady).thenReturn(true)
             `when`(volumeControl.isProfileReady).thenReturn(true)
+            `when`(leAudio.isProfileReady).thenReturn(true)
             val states = mutableListOf<Boolean?>()
             underTest.inAudioSharing.onEach { states.add(it) }.launchIn(backgroundScope)
             runCurrent()
@@ -192,7 +203,8 @@
     }
 
     @Test
-    fun primaryGroupIdChange_emitValues() {
+    @DisableFlags(Flags.FLAG_ADOPT_PRIMARY_GROUP_MANAGEMENT_API_V2)
+    fun primaryGroupIdChange_getValueFromContentResolver_emitValues() {
         testScope.runTest {
             val groupIds = mutableListOf<Int?>()
             underTest.primaryGroupId.onEach { groupIds.add(it) }.launchIn(backgroundScope)
@@ -209,6 +221,29 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ADOPT_PRIMARY_GROUP_MANAGEMENT_API_V2)
+    fun primaryGroupIdChange_getValueFromApi_emitValues() {
+        testScope.runTest {
+            `when`(broadcast.isProfileReady).thenReturn(true)
+            `when`(assistant.isProfileReady).thenReturn(true)
+            `when`(volumeControl.isProfileReady).thenReturn(true)
+            `when`(leAudio.isProfileReady).thenReturn(true)
+            val groupIds = mutableListOf<Int?>()
+            underTest.primaryGroupId.onEach { groupIds.add(it) }.launchIn(backgroundScope)
+            runCurrent()
+            triggerPrimaryGroupIdChanged()
+            runCurrent()
+
+            Truth.assertThat(groupIds)
+                .containsExactly(
+                    TEST_GROUP_ID_INVALID,
+                    TEST_GROUP_ID2
+                )
+        }
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ADOPT_PRIMARY_GROUP_MANAGEMENT_API_V2)
     fun primaryDeviceChange_emitValues() {
         testScope.runTest {
             `when`(assistant.allConnectedDevices).thenReturn(listOf(device1, device2))
@@ -224,6 +259,26 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ADOPT_PRIMARY_GROUP_MANAGEMENT_API_V2)
+    fun primaryDeviceChange_getPrimaryGroupIdFromApi_emitValues() {
+        testScope.runTest {
+            `when`(broadcast.isProfileReady).thenReturn(true)
+            `when`(assistant.isProfileReady).thenReturn(true)
+            `when`(volumeControl.isProfileReady).thenReturn(true)
+            `when`(leAudio.isProfileReady).thenReturn(true)
+            `when`(assistant.allConnectedDevices).thenReturn(listOf(device1, device2))
+
+            val devices = mutableListOf<CachedBluetoothDevice?>()
+            underTest.primaryDevice.onEach { devices.add(it) }.launchIn(backgroundScope)
+            runCurrent()
+            triggerPrimaryGroupIdChanged()
+            runCurrent()
+
+            Truth.assertThat(devices).containsExactly(null, cachedDevice2)
+        }
+    }
+
+    @Test
     fun secondaryGroupIdChange_profileNotReady_assistantCallbackNotRegistered() {
         testScope.runTest {
             val groupIds = mutableListOf<Int?>()
@@ -234,11 +289,13 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_ADOPT_PRIMARY_GROUP_MANAGEMENT_API_V2)
     fun secondaryGroupIdChange_profileReady_emitValues() {
         testScope.runTest {
             `when`(broadcast.isProfileReady).thenReturn(true)
             `when`(assistant.isProfileReady).thenReturn(true)
             `when`(volumeControl.isProfileReady).thenReturn(true)
+            `when`(leAudio.isProfileReady).thenReturn(true)
             val groupIds = mutableListOf<Int?>()
             underTest.secondaryGroupId.onEach { groupIds.add(it) }.launchIn(backgroundScope)
             runCurrent()
@@ -284,11 +341,65 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ADOPT_PRIMARY_GROUP_MANAGEMENT_API_V2)
+    fun secondaryGroupIdChange_getPrimaryGroupIdFromApi_profileReady_emitValues() {
+        testScope.runTest {
+            `when`(broadcast.isProfileReady).thenReturn(true)
+            `when`(assistant.isProfileReady).thenReturn(true)
+            `when`(volumeControl.isProfileReady).thenReturn(true)
+            `when`(leAudio.isProfileReady).thenReturn(true)
+            val groupIds = mutableListOf<Int?>()
+            underTest.secondaryGroupId.onEach { groupIds.add(it) }.launchIn(backgroundScope)
+            runCurrent()
+            triggerSourceAddedWithGetPrimaryGroupApi()
+            runCurrent()
+            triggerPrimaryGroupIdChanged()
+            runCurrent()
+            triggerSourceRemovedWithGetPrimaryGroupApi()
+            runCurrent()
+            triggerSourceAddedWithGetPrimaryGroupApi()
+            runCurrent()
+            triggerProfileConnectionChangeWithGetPrimaryGroupApi(
+                BluetoothAdapter.STATE_CONNECTING, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT
+            )
+            runCurrent()
+            triggerProfileConnectionChangeWithGetPrimaryGroupApi(
+                BluetoothAdapter.STATE_DISCONNECTED, BluetoothProfile.LE_AUDIO
+            )
+            runCurrent()
+            triggerProfileConnectionChangeWithGetPrimaryGroupApi(
+                BluetoothAdapter.STATE_DISCONNECTED, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT
+            )
+            runCurrent()
+
+            Truth.assertThat(groupIds)
+                .containsExactly(
+                    TEST_GROUP_ID_INVALID,
+                    TEST_GROUP_ID2,
+                    TEST_GROUP_ID1,
+                    TEST_GROUP_ID_INVALID,
+                    TEST_GROUP_ID2,
+                    TEST_GROUP_ID_INVALID
+                )
+            Truth.assertThat(logger.logs)
+                .containsAtLeastElementsIn(
+                    listOf(
+                        "onSecondaryGroupIdChanged groupId=$TEST_GROUP_ID_INVALID",
+                        "onSecondaryGroupIdChanged groupId=$TEST_GROUP_ID2",
+                        "onSecondaryGroupIdChanged groupId=$TEST_GROUP_ID1",
+                    )
+                ).inOrder()
+        }
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ADOPT_PRIMARY_GROUP_MANAGEMENT_API_V2)
     fun secondaryDeviceChange_emitValues() {
         testScope.runTest {
             `when`(broadcast.isProfileReady).thenReturn(true)
             `when`(assistant.isProfileReady).thenReturn(true)
             `when`(volumeControl.isProfileReady).thenReturn(true)
+            `when`(leAudio.isProfileReady).thenReturn(true)
             val devices = mutableListOf<CachedBluetoothDevice?>()
             underTest.secondaryDevice.onEach { devices.add(it) }.launchIn(backgroundScope)
             runCurrent()
@@ -307,11 +418,37 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ADOPT_PRIMARY_GROUP_MANAGEMENT_API_V2)
+    fun secondaryDeviceChange_getPrimaryGroupIdFromApi_emitValues() {
+        testScope.runTest {
+            `when`(broadcast.isProfileReady).thenReturn(true)
+            `when`(assistant.isProfileReady).thenReturn(true)
+            `when`(volumeControl.isProfileReady).thenReturn(true)
+            `when`(leAudio.isProfileReady).thenReturn(true)
+            val devices = mutableListOf<CachedBluetoothDevice?>()
+            underTest.secondaryDevice.onEach { devices.add(it) }.launchIn(backgroundScope)
+            runCurrent()
+            triggerSourceAddedWithGetPrimaryGroupApi()
+            runCurrent()
+            triggerPrimaryGroupIdChanged()
+            runCurrent()
+
+            Truth.assertThat(devices)
+                .containsExactly(
+                    null,
+                    cachedDevice2,
+                    cachedDevice1,
+                )
+        }
+    }
+
+    @Test
     fun volumeMapChange_profileReady_emitValues() {
         testScope.runTest {
             `when`(broadcast.isProfileReady).thenReturn(true)
             `when`(assistant.isProfileReady).thenReturn(true)
             `when`(volumeControl.isProfileReady).thenReturn(true)
+            `when`(leAudio.isProfileReady).thenReturn(true)
             val volumeMaps = mutableListOf<GroupIdToVolumes?>()
             underTest.volumeMap.onEach { volumeMaps.add(it) }.launchIn(backgroundScope)
             runCurrent()
@@ -354,6 +491,7 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_ADOPT_PRIMARY_GROUP_MANAGEMENT_API_V2)
     fun setSecondaryVolume_setValue() {
         testScope.runTest {
             Settings.Secure.putInt(
@@ -375,6 +513,29 @@
         }
     }
 
+    @Test
+    @EnableFlags(Flags.FLAG_ADOPT_PRIMARY_GROUP_MANAGEMENT_API_V2)
+    fun setSecondaryVolume_getPrimaryGroupIdFromApi_setValue() {
+        testScope.runTest {
+            `when`(broadcast.isProfileReady).thenReturn(true)
+            `when`(assistant.isProfileReady).thenReturn(true)
+            `when`(volumeControl.isProfileReady).thenReturn(true)
+            `when`(leAudio.isProfileReady).thenReturn(true)
+            `when`(leAudio.broadcastToUnicastFallbackGroup).thenReturn(TEST_GROUP_ID2)
+            `when`(assistant.allConnectedDevices).thenReturn(listOf(device1, device2))
+            underTest.setSecondaryVolume(TEST_VOLUME1)
+
+            runCurrent()
+            verify(volumeControl).setDeviceVolume(device1, TEST_VOLUME1, true)
+            Truth.assertThat(logger.logs)
+                .isEqualTo(
+                    listOf(
+                        "onSetVolumeRequested volume=$TEST_VOLUME1",
+                    )
+                )
+        }
+    }
+
     private fun triggerAudioSharingStateChange(
         type: TriggerType,
         broadcastAction: BluetoothLeBroadcast.Callback.() -> Unit
@@ -404,6 +565,13 @@
         assistantCallbackCaptor.value.sourceAdded(device1)
     }
 
+    private fun triggerSourceAddedWithGetPrimaryGroupApi() {
+        verify(assistant).registerServiceCallBack(any(), assistantCallbackCaptor.capture())
+        `when`(leAudio.broadcastToUnicastFallbackGroup).thenReturn(TEST_GROUP_ID1)
+        `when`(assistant.allConnectedDevices).thenReturn(listOf(device1, device2))
+        assistantCallbackCaptor.value.sourceAdded(device1)
+    }
+
     private fun triggerSourceRemoved() {
         verify(assistant).registerServiceCallBack(any(), assistantCallbackCaptor.capture())
         `when`(assistant.allConnectedDevices).thenReturn(listOf(device1))
@@ -415,6 +583,13 @@
         assistantCallbackCaptor.value.sourceRemoved(device2)
     }
 
+    private fun triggerSourceRemovedWithGetPrimaryGroupApi() {
+        verify(assistant).registerServiceCallBack(any(), assistantCallbackCaptor.capture())
+        `when`(assistant.allConnectedDevices).thenReturn(listOf(device1))
+        `when`(leAudio.broadcastToUnicastFallbackGroup).thenReturn(TEST_GROUP_ID1)
+        assistantCallbackCaptor.value.sourceRemoved(device2)
+    }
+
     private fun triggerProfileConnectionChange(state: Int, profile: Int) {
         verify(eventManager).registerCallback(btCallbackCaptor.capture())
         `when`(assistant.allConnectedDevices).thenReturn(listOf(device1))
@@ -426,6 +601,13 @@
         btCallbackCaptor.value.onProfileConnectionStateChanged(cachedDevice2, state, profile)
     }
 
+    private fun triggerProfileConnectionChangeWithGetPrimaryGroupApi(state: Int, profile: Int) {
+        verify(eventManager).registerCallback(btCallbackCaptor.capture())
+        `when`(assistant.allConnectedDevices).thenReturn(listOf(device1))
+        `when`(leAudio.broadcastToUnicastFallbackGroup).thenReturn(TEST_GROUP_ID1)
+        btCallbackCaptor.value.onProfileConnectionStateChanged(cachedDevice2, state, profile)
+    }
+
     private fun triggerContentObserverChange() {
         verify(contentResolver)
             .registerContentObserver(
@@ -442,6 +624,12 @@
         contentObserverCaptor.value.primaryChanged()
     }
 
+    private fun triggerPrimaryGroupIdChanged() {
+        verify(leAudio).registerCallback(any(), leAudioCallbackCaptor.capture())
+        `when`(leAudio.broadcastToUnicastFallbackGroup).thenReturn(TEST_GROUP_ID2)
+        leAudioCallbackCaptor.value.onBroadcastToUnicastFallbackGroupChanged(TEST_GROUP_ID2)
+    }
+
     private fun triggerVolumeMapChange(change: Pair<BluetoothDevice, Int>) {
         verify(volumeControl).registerCallback(any(), volumeCallbackCaptor.capture())
         volumeCallbackCaptor.value.onDeviceVolumeChanged(change.first, change.second)