Add tests for BCAST msgs of BassClientStateMachine
Bug: 237467631
Test: atest BluetoothInstrumentationTests:BassClientStateMachineTest
Change-Id: Ie65e5570a33bf65a8fb82c03cc237ad69add8f6a
Merged-In: Ie65e5570a33bf65a8fb82c03cc237ad69add8f6a
(cherry picked from commit 10a610951d8333cb91b8200f9bb6d840f24d498f)
diff --git a/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java b/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java
index 589db7b..f8e8388 100755
--- a/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java
+++ b/android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java
@@ -1575,7 +1575,6 @@
case SET_BCAST_CODE:
BluetoothLeBroadcastReceiveState recvState =
(BluetoothLeBroadcastReceiveState) message.obj;
- sourceId = message.arg2;
log("SET_BCAST_CODE metaData: " + recvState);
if (!isItRightTimeToUpdateBroadcastPin((byte) recvState.getSourceId())) {
mSetBroadcastCodePending = true;
diff --git a/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientStateMachineTest.java
index b49a60d..2a7a4f4 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientStateMachineTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientStateMachineTest.java
@@ -69,6 +69,7 @@
import android.bluetooth.BluetoothLeBroadcastSubgroup;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.ScanRecord;
+import android.bluetooth.le.ScanResult;
import android.content.Intent;
import android.os.Bundle;
import android.os.HandlerThread;
@@ -98,6 +99,7 @@
import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.UUID;
@@ -1038,7 +1040,263 @@
verify(mBassClientService, never()).sendBroadcast(any(Intent.class), anyString(), any());
}
- // TODO: add sendMessage tests for BCAST related messages
+ @Test
+ public void sendSelectBcastSourceMessage_inConnectedState() {
+ initToConnectedState();
+
+ byte[] scanRecord = new byte[]{
+ 0x02, 0x01, 0x1a, // advertising flags
+ 0x05, 0x02, 0x52, 0x18, 0x0a, 0x11, // 16 bit service uuids
+ 0x04, 0x09, 0x50, 0x65, 0x64, // name
+ 0x02, 0x0A, (byte) 0xec, // tx power level
+ 0x06, 0x16, 0x52, 0x18, 0x50, 0x64, 0x65, // service data
+ 0x05, (byte) 0xff, (byte) 0xe0, 0x00, 0x02, 0x15, // manufacturer specific data
+ 0x03, 0x50, 0x01, 0x02, // an unknown data type won't cause trouble
+ };
+ ScanRecord record = ScanRecord.parseFromBytes(scanRecord);
+
+ doNothing().when(mMethodProxy).periodicAdvertisingManagerRegisterSync(
+ any(), any(), anyInt(), anyInt(), any(), any());
+ ScanResult scanResult = new ScanResult(mTestDevice, 0, 0, 0, 0, 0, 0, 0, record, 0);
+ mBassClientStateMachine.sendMessage(
+ SELECT_BCAST_SOURCE, BassConstants.AUTO, 0, scanResult);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ verify(mBassClientService).updatePeriodicAdvertisementResultMap(
+ any(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void sendAddBcastSourceMessage_inConnectedState() {
+ initToConnectedState();
+
+ BassClientService.Callbacks callbacks = Mockito.mock(BassClientService.Callbacks.class);
+ when(mBassClientService.getCallbacks()).thenReturn(callbacks);
+
+ BluetoothLeBroadcastMetadata metadata = createBroadcastMetadata();
+ mBassClientStateMachine.sendMessage(ADD_BCAST_SOURCE, metadata);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+
+ verify(mBassClientService).getCallbacks();
+ verify(callbacks).notifySourceAddFailed(any(), any(), anyInt());
+
+ BassClientStateMachine.BluetoothGattTestableWrapper btGatt = Mockito.mock(
+ BassClientStateMachine.BluetoothGattTestableWrapper.class);
+ mBassClientStateMachine.mBluetoothGatt = btGatt;
+ BluetoothGattCharacteristic scanControlPoint = Mockito.mock(
+ BluetoothGattCharacteristic.class);
+ mBassClientStateMachine.mBroadcastScanControlPoint = scanControlPoint;
+
+ sendMessageAndVerifyTransition(
+ mBassClientStateMachine.obtainMessage(ADD_BCAST_SOURCE, metadata),
+ BassClientStateMachine.ConnectedProcessing.class);
+ verify(scanControlPoint).setValue(any(byte[].class));
+ verify(btGatt).writeCharacteristic(any());
+ }
+
+ @Test
+ public void sendUpdateBcastSourceMessage_inConnectedState() {
+ initToConnectedState();
+ mBassClientStateMachine.connectGatt(true);
+ mBassClientStateMachine.mNumOfBroadcastReceiverStates = 2;
+
+ // Prepare mBluetoothLeBroadcastReceiveStates for test
+ BassClientService.Callbacks callbacks = Mockito.mock(BassClientService.Callbacks.class);
+ when(mBassClientService.getCallbacks()).thenReturn(callbacks);
+ int sourceId = 1;
+ int paSync = BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE;
+ byte[] value = new byte[] {
+ (byte) sourceId, // sourceId
+ 0x00, // sourceAddressType
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, // sourceAddress
+ 0x00, // sourceAdvSid
+ 0x00, 0x00, 0x00, // broadcastIdBytes
+ (byte) paSync,
+ (byte) BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_BAD_CODE,
+ // 16 bytes badBroadcastCode
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, // numSubGroups
+ // SubGroup #1
+ 0x00, 0x00, 0x00, 0x00, // audioSyncIndex
+ 0x02, // metaDataLength
+ 0x00, 0x00, // metadata
+ };
+ BluetoothGattCharacteristic characteristic =
+ Mockito.mock(BluetoothGattCharacteristic.class);
+ when(characteristic.getValue()).thenReturn(value);
+ when(characteristic.getInstanceId()).thenReturn(sourceId);
+ when(characteristic.getUuid()).thenReturn(BassConstants.BASS_BCAST_RECEIVER_STATE);
+ mBassClientStateMachine.mGattCallback.onCharacteristicRead(
+ null, characteristic, GATT_SUCCESS);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+
+ BluetoothLeBroadcastMetadata metadata = createBroadcastMetadata();
+ when(mBassClientService.getPeriodicAdvertisementResult(any())).thenReturn(null);
+
+ mBassClientStateMachine.sendMessage(UPDATE_BCAST_SOURCE, sourceId, paSync, metadata);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ verify(callbacks).notifySourceRemoveFailed(any(), anyInt(), anyInt());
+
+ PeriodicAdvertisementResult paResult = Mockito.mock(PeriodicAdvertisementResult.class);
+ when(mBassClientService.getPeriodicAdvertisementResult(any())).thenReturn(paResult);
+ when(mBassClientService.getBase(anyInt())).thenReturn(null);
+ Mockito.clearInvocations(callbacks);
+
+ mBassClientStateMachine.sendMessage(UPDATE_BCAST_SOURCE, sourceId, paSync, metadata);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ verify(callbacks).notifySourceRemoveFailed(any(), anyInt(), anyInt());
+
+ BaseData data = Mockito.mock(BaseData.class);
+ when(mBassClientService.getBase(anyInt())).thenReturn(data);
+ when(data.getNumberOfSubgroupsofBIG()).thenReturn((byte) 1);
+ Mockito.clearInvocations(callbacks);
+
+ mBassClientStateMachine.sendMessage(UPDATE_BCAST_SOURCE, sourceId, paSync, metadata);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ verify(callbacks).notifySourceModifyFailed(any(), anyInt(), anyInt());
+
+ BassClientStateMachine.BluetoothGattTestableWrapper btGatt = Mockito.mock(
+ BassClientStateMachine.BluetoothGattTestableWrapper.class);
+ BluetoothGattCharacteristic scanControlPoint = Mockito.mock(
+ BluetoothGattCharacteristic.class);
+ mBassClientStateMachine.mBluetoothGatt = btGatt;
+ mBassClientStateMachine.mBroadcastScanControlPoint = scanControlPoint;
+ mBassClientStateMachine.mPendingOperation = 0;
+ mBassClientStateMachine.mPendingSourceId = 0;
+ mBassClientStateMachine.mPendingMetadata = null;
+ Mockito.clearInvocations(callbacks);
+
+ sendMessageAndVerifyTransition(
+ mBassClientStateMachine.obtainMessage(
+ UPDATE_BCAST_SOURCE, sourceId, paSync, metadata),
+ BassClientStateMachine.ConnectedProcessing.class);
+ assertThat(mBassClientStateMachine.mPendingOperation).isEqualTo(UPDATE_BCAST_SOURCE);
+ assertThat(mBassClientStateMachine.mPendingSourceId).isEqualTo(sourceId);
+ assertThat(mBassClientStateMachine.mPendingMetadata).isEqualTo(metadata);
+ }
+
+ @Test
+ public void sendSetBcastCodeMessage_inConnectedState() {
+ initToConnectedState();
+ mBassClientStateMachine.connectGatt(true);
+ mBassClientStateMachine.mNumOfBroadcastReceiverStates = 2;
+ BassClientService.Callbacks callbacks = Mockito.mock(BassClientService.Callbacks.class);
+ when(mBassClientService.getCallbacks()).thenReturn(callbacks);
+
+ // Prepare mBluetoothLeBroadcastReceiveStates with metadata for test
+ mBassClientStateMachine.mShouldHandleMessage = false;
+ int sourceId = 1;
+ byte[] value = new byte[] {
+ (byte) sourceId, // sourceId
+ 0x00, // sourceAddressType
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, // sourceAddress
+ 0x00, // sourceAdvSid
+ 0x00, 0x00, 0x00, // broadcastIdBytes
+ (byte) BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE,
+ (byte) BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_CODE_REQUIRED,
+ // 16 bytes badBroadcastCode
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, // numSubGroups
+ // SubGroup #1
+ 0x00, 0x00, 0x00, 0x00, // audioSyncIndex
+ 0x02, // metaDataLength
+ 0x00, 0x00, // metadata
+ };
+ mBassClientStateMachine.mPendingOperation = REMOVE_BCAST_SOURCE;
+ mBassClientStateMachine.mPendingSourceId = (byte) sourceId;
+ BluetoothGattCharacteristic characteristic =
+ Mockito.mock(BluetoothGattCharacteristic.class);
+ when(characteristic.getValue()).thenReturn(value);
+ when(characteristic.getInstanceId()).thenReturn(sourceId);
+ when(characteristic.getUuid()).thenReturn(BassConstants.BASS_BCAST_RECEIVER_STATE);
+
+ mBassClientStateMachine.mGattCallback.onCharacteristicRead(
+ null, characteristic, GATT_SUCCESS);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+
+ mBassClientStateMachine.mPendingMetadata = createBroadcastMetadata();
+ mBassClientStateMachine.mGattCallback.onCharacteristicRead(
+ null, characteristic, GATT_SUCCESS);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ mBassClientStateMachine.mShouldHandleMessage = true;
+
+ BluetoothLeBroadcastReceiveState recvState = new BluetoothLeBroadcastReceiveState(
+ 2,
+ BluetoothDevice.ADDRESS_TYPE_PUBLIC,
+ mAdapter.getRemoteLeDevice("00:00:00:00:00:00",
+ BluetoothDevice.ADDRESS_TYPE_PUBLIC),
+ 0,
+ 0,
+ BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE,
+ BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_CODE_REQUIRED,
+ null,
+ 0,
+ Arrays.asList(new Long[0]),
+ Arrays.asList(new BluetoothLeAudioContentMetadata[0])
+ );
+ mBassClientStateMachine.mSetBroadcastCodePending = false;
+ mBassClientStateMachine.sendMessage(SET_BCAST_CODE, recvState);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ assertThat(mBassClientStateMachine.mSetBroadcastCodePending).isTrue();
+
+ recvState = new BluetoothLeBroadcastReceiveState(
+ sourceId,
+ BluetoothDevice.ADDRESS_TYPE_PUBLIC,
+ mAdapter.getRemoteLeDevice("00:00:00:00:00:00",
+ BluetoothDevice.ADDRESS_TYPE_PUBLIC),
+ 0,
+ 0,
+ BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE,
+ BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_CODE_REQUIRED,
+ null,
+ 0,
+ Arrays.asList(new Long[0]),
+ Arrays.asList(new BluetoothLeAudioContentMetadata[0])
+ );
+ mBassClientStateMachine.sendMessage(SET_BCAST_CODE, recvState);
+ BassClientStateMachine.BluetoothGattTestableWrapper btGatt = Mockito.mock(
+ BassClientStateMachine.BluetoothGattTestableWrapper.class);
+ mBassClientStateMachine.mBluetoothGatt = btGatt;
+ BluetoothGattCharacteristic scanControlPoint = Mockito.mock(
+ BluetoothGattCharacteristic.class);
+ mBassClientStateMachine.mBroadcastScanControlPoint = scanControlPoint;
+
+ sendMessageAndVerifyTransition(
+ mBassClientStateMachine.obtainMessage(SET_BCAST_CODE, recvState),
+ BassClientStateMachine.ConnectedProcessing.class);
+ assertThat(mBassClientStateMachine.mPendingOperation).isEqualTo(SET_BCAST_CODE);
+ assertThat(mBassClientStateMachine.mPendingSourceId).isEqualTo(sourceId);
+ verify(btGatt).writeCharacteristic(any());
+ verify(scanControlPoint).setValue(any(byte[].class));
+ }
+
+ @Test
+ public void sendRemoveBcastSourceMessage_inConnectedState() {
+ initToConnectedState();
+ BassClientService.Callbacks callbacks = Mockito.mock(BassClientService.Callbacks.class);
+ when(mBassClientService.getCallbacks()).thenReturn(callbacks);
+
+ int sid = 10;
+ mBassClientStateMachine.sendMessage(REMOVE_BCAST_SOURCE, sid);
+ TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ verify(callbacks).notifySourceRemoveFailed(any(), anyInt(), anyInt());
+
+ BassClientStateMachine.BluetoothGattTestableWrapper btGatt = Mockito.mock(
+ BassClientStateMachine.BluetoothGattTestableWrapper.class);
+ mBassClientStateMachine.mBluetoothGatt = btGatt;
+ BluetoothGattCharacteristic scanControlPoint = Mockito.mock(
+ BluetoothGattCharacteristic.class);
+ mBassClientStateMachine.mBroadcastScanControlPoint = scanControlPoint;
+
+ sendMessageAndVerifyTransition(
+ mBassClientStateMachine.obtainMessage(REMOVE_BCAST_SOURCE, sid),
+ BassClientStateMachine.ConnectedProcessing.class);
+ verify(scanControlPoint).setValue(any(byte[].class));
+ verify(btGatt).writeCharacteristic(any());
+ assertThat(mBassClientStateMachine.mPendingOperation).isEqualTo(REMOVE_BCAST_SOURCE);
+ assertThat(mBassClientStateMachine.mPendingSourceId).isEqualTo(sid);
+ }
@Test
public void sendConnectMessage_inConnectedProcessingState_doesNotChangeState() {
@@ -1299,7 +1557,7 @@
.setSourceDevice(testDevice, BluetoothDevice.ADDRESS_TYPE_RANDOM)
.setSourceAdvertisingSid(testAdvertiserSid)
.setBroadcastId(testBroadcastId)
- .setBroadcastCode(null)
+ .setBroadcastCode(new byte[] { 0x00 })
.setPaSyncInterval(testPaSyncInterval)
.setPresentationDelayMicros(testPresentationDelayMs);
// builder expect at least one subgroup