Loading android/app/src/com/android/bluetooth/bass_client/BassClientService.java +2 −5 Original line number Diff line number Diff line Loading @@ -59,8 +59,8 @@ import com.android.bluetooth.flags.FeatureFlagsImpl; import com.android.bluetooth.le_audio.LeAudioService; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Deque; Loading Loading @@ -1583,12 +1583,9 @@ public class BassClientService extends ProfileService { continue; } BluetoothLeBroadcastReceiveState recvState = stateMachine.getBroadcastReceiveStateForSourceId(sourceId); BluetoothLeBroadcastMetadata metaData = stateMachine.getCurrentBroadcastMetadata(sourceId); if (metaData != null && recvState != null && recvState.getPaSyncState() == BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED) { if (metaData != null && stateMachine.isSyncedToTheSource(sourceId)) { sEventLogger.logd( DBG, TAG, Loading android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java +14 −7 Original line number Diff line number Diff line Loading @@ -325,6 +325,19 @@ public class BassClientStateMachine extends StateMachine { return null; } boolean isSyncedToTheSource(int sourceId) { BluetoothLeBroadcastReceiveState recvState = getBroadcastReceiveStateForSourceId(sourceId); return recvState != null && (recvState.getPaSyncState() == BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED || recvState.getBisSyncState().stream() .anyMatch( bitmap -> { return bitmap != 0; })); } void parseBaseData(BluetoothDevice device, int syncHandle, byte[] serviceData) { log("parseBaseData" + Arrays.toString(serviceData)); BaseData base = BaseData.parseBaseData(serviceData); Loading Loading @@ -1759,15 +1772,9 @@ public class BassClientStateMachine extends StateMachine { // Save pending source to be added once existing source got removed mPendingSourceToSwitch = metaData; // Remove the source first BluetoothLeBroadcastReceiveState recvStateToUpdate = getBroadcastReceiveStateForSourceId(sourceIdToRemove); BluetoothLeBroadcastMetadata metaDataToUpdate = getCurrentBroadcastMetadata(sourceIdToRemove); if (metaDataToUpdate != null && recvStateToUpdate != null && recvStateToUpdate.getPaSyncState() == BluetoothLeBroadcastReceiveState .PA_SYNC_STATE_SYNCHRONIZED) { if (metaDataToUpdate != null && isSyncedToTheSource(sourceIdToRemove)) { log("SWITCH_BCAST_SOURCE force source to lost PA sync"); Message msg = obtainMessage(UPDATE_BCAST_SOURCE); msg.arg1 = sourceIdToRemove; Loading android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceTest.java +83 −0 Original line number Diff line number Diff line Loading @@ -751,6 +751,89 @@ public class BassClientServiceTest { } } /** * Test whether service.removeSource() does send modify source to all the state machines if * either PA or BIS is synced */ @Test public void testRemoveSourceForGroupAndTriggerModifySource() { prepareConnectedDeviceGroup(); BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); verifyAddSourceForGroup(meta); for (BassClientStateMachine sm : mStateMachines.values()) { injectRemoteSourceStateSourceAdded( sm, meta, TEST_SOURCE_ID, BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED, meta.isEncrypted() ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING : BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, null); doReturn(meta).when(sm).getCurrentBroadcastMetadata(eq(TEST_SOURCE_ID)); doReturn(true).when(sm).isSyncedToTheSource(eq(TEST_SOURCE_ID)); } // Remove broadcast source mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); // Verify all group members getting UPDATE_BCAST_SOURCE message // because PA state is synced assertThat(mStateMachines.size()).isEqualTo(2); for (BassClientStateMachine sm : mStateMachines.values()) { ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); Optional<Message> msg = messageCaptor.getAllValues().stream() .filter(m -> m.what == BassClientStateMachine.UPDATE_BCAST_SOURCE) .findFirst(); assertThat(msg.isPresent()).isEqualTo(true); // Verify using the right sourceId on each device assertThat(msg.get().arg1).isEqualTo(TEST_SOURCE_ID); } for (BassClientStateMachine sm : mStateMachines.values()) { // Update receiver state injectRemoteSourceStateChanged( sm, meta, TEST_SOURCE_ID, BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, meta.isEncrypted() ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING : BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, null, (long) 0x00000001); verify(mLeAudioService).activeBroadcastAssistantNotification(eq(true)); } // Remove broadcast source mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); // Verify all group members getting UPDATE_BCAST_SOURCE message if // bis sync state is non-zero and pa sync state is not synced assertThat(mStateMachines.size()).isEqualTo(2); for (BassClientStateMachine sm : mStateMachines.values()) { ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); Optional<Message> msg = messageCaptor.getAllValues().stream() .filter(m -> m.what == BassClientStateMachine.UPDATE_BCAST_SOURCE) .findFirst(); assertThat(msg.isPresent()).isEqualTo(true); // Verify using the right sourceId on each device assertThat(msg.get().arg1).isEqualTo(TEST_SOURCE_ID); } for (BassClientStateMachine sm : mStateMachines.values()) { injectRemoteSourceStateRemoval(sm, TEST_SOURCE_ID); } } /** * Test whether the group operation flag is set on addSource() and removed on removeSource */ Loading Loading
android/app/src/com/android/bluetooth/bass_client/BassClientService.java +2 −5 Original line number Diff line number Diff line Loading @@ -59,8 +59,8 @@ import com.android.bluetooth.flags.FeatureFlagsImpl; import com.android.bluetooth.le_audio.LeAudioService; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Deque; Loading Loading @@ -1583,12 +1583,9 @@ public class BassClientService extends ProfileService { continue; } BluetoothLeBroadcastReceiveState recvState = stateMachine.getBroadcastReceiveStateForSourceId(sourceId); BluetoothLeBroadcastMetadata metaData = stateMachine.getCurrentBroadcastMetadata(sourceId); if (metaData != null && recvState != null && recvState.getPaSyncState() == BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED) { if (metaData != null && stateMachine.isSyncedToTheSource(sourceId)) { sEventLogger.logd( DBG, TAG, Loading
android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java +14 −7 Original line number Diff line number Diff line Loading @@ -325,6 +325,19 @@ public class BassClientStateMachine extends StateMachine { return null; } boolean isSyncedToTheSource(int sourceId) { BluetoothLeBroadcastReceiveState recvState = getBroadcastReceiveStateForSourceId(sourceId); return recvState != null && (recvState.getPaSyncState() == BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED || recvState.getBisSyncState().stream() .anyMatch( bitmap -> { return bitmap != 0; })); } void parseBaseData(BluetoothDevice device, int syncHandle, byte[] serviceData) { log("parseBaseData" + Arrays.toString(serviceData)); BaseData base = BaseData.parseBaseData(serviceData); Loading Loading @@ -1759,15 +1772,9 @@ public class BassClientStateMachine extends StateMachine { // Save pending source to be added once existing source got removed mPendingSourceToSwitch = metaData; // Remove the source first BluetoothLeBroadcastReceiveState recvStateToUpdate = getBroadcastReceiveStateForSourceId(sourceIdToRemove); BluetoothLeBroadcastMetadata metaDataToUpdate = getCurrentBroadcastMetadata(sourceIdToRemove); if (metaDataToUpdate != null && recvStateToUpdate != null && recvStateToUpdate.getPaSyncState() == BluetoothLeBroadcastReceiveState .PA_SYNC_STATE_SYNCHRONIZED) { if (metaDataToUpdate != null && isSyncedToTheSource(sourceIdToRemove)) { log("SWITCH_BCAST_SOURCE force source to lost PA sync"); Message msg = obtainMessage(UPDATE_BCAST_SOURCE); msg.arg1 = sourceIdToRemove; Loading
android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceTest.java +83 −0 Original line number Diff line number Diff line Loading @@ -751,6 +751,89 @@ public class BassClientServiceTest { } } /** * Test whether service.removeSource() does send modify source to all the state machines if * either PA or BIS is synced */ @Test public void testRemoveSourceForGroupAndTriggerModifySource() { prepareConnectedDeviceGroup(); BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); verifyAddSourceForGroup(meta); for (BassClientStateMachine sm : mStateMachines.values()) { injectRemoteSourceStateSourceAdded( sm, meta, TEST_SOURCE_ID, BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED, meta.isEncrypted() ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING : BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, null); doReturn(meta).when(sm).getCurrentBroadcastMetadata(eq(TEST_SOURCE_ID)); doReturn(true).when(sm).isSyncedToTheSource(eq(TEST_SOURCE_ID)); } // Remove broadcast source mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); // Verify all group members getting UPDATE_BCAST_SOURCE message // because PA state is synced assertThat(mStateMachines.size()).isEqualTo(2); for (BassClientStateMachine sm : mStateMachines.values()) { ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); Optional<Message> msg = messageCaptor.getAllValues().stream() .filter(m -> m.what == BassClientStateMachine.UPDATE_BCAST_SOURCE) .findFirst(); assertThat(msg.isPresent()).isEqualTo(true); // Verify using the right sourceId on each device assertThat(msg.get().arg1).isEqualTo(TEST_SOURCE_ID); } for (BassClientStateMachine sm : mStateMachines.values()) { // Update receiver state injectRemoteSourceStateChanged( sm, meta, TEST_SOURCE_ID, BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, meta.isEncrypted() ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING : BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, null, (long) 0x00000001); verify(mLeAudioService).activeBroadcastAssistantNotification(eq(true)); } // Remove broadcast source mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); // Verify all group members getting UPDATE_BCAST_SOURCE message if // bis sync state is non-zero and pa sync state is not synced assertThat(mStateMachines.size()).isEqualTo(2); for (BassClientStateMachine sm : mStateMachines.values()) { ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); Optional<Message> msg = messageCaptor.getAllValues().stream() .filter(m -> m.what == BassClientStateMachine.UPDATE_BCAST_SOURCE) .findFirst(); assertThat(msg.isPresent()).isEqualTo(true); // Verify using the right sourceId on each device assertThat(msg.get().arg1).isEqualTo(TEST_SOURCE_ID); } for (BassClientStateMachine sm : mStateMachines.values()) { injectRemoteSourceStateRemoval(sm, TEST_SOURCE_ID); } } /** * Test whether the group operation flag is set on addSource() and removed on removeSource */ Loading