1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.bluetooth.bass_client; 18 19 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; 20 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; 21 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; 22 import static android.bluetooth.BluetoothProfile.EXTRA_PREVIOUS_STATE; 23 import static android.bluetooth.BluetoothProfile.EXTRA_STATE; 24 import static android.bluetooth.BluetoothProfile.STATE_CONNECTED; 25 import static android.bluetooth.BluetoothProfile.STATE_CONNECTING; 26 import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; 27 28 import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction; 29 import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra; 30 31 import static com.android.bluetooth.TestUtils.MockitoRule; 32 import static com.android.bluetooth.TestUtils.getTestDevice; 33 34 import static com.google.common.truth.Truth.assertThat; 35 36 import static org.mockito.ArgumentMatchers.anyInt; 37 import static org.mockito.ArgumentMatchers.eq; 38 import static org.mockito.Mockito.any; 39 import static org.mockito.Mockito.anyInt; 40 import static org.mockito.Mockito.atLeast; 41 import static org.mockito.Mockito.clearInvocations; 42 import static org.mockito.Mockito.doAnswer; 43 import static org.mockito.Mockito.doCallRealMethod; 44 import static org.mockito.Mockito.doNothing; 45 import static org.mockito.Mockito.doReturn; 46 import static org.mockito.Mockito.eq; 47 import static org.mockito.Mockito.inOrder; 48 import static org.mockito.Mockito.mock; 49 import static org.mockito.Mockito.never; 50 import static org.mockito.Mockito.notNull; 51 import static org.mockito.Mockito.timeout; 52 import static org.mockito.Mockito.times; 53 import static org.mockito.Mockito.verify; 54 import static org.mockito.Mockito.when; 55 56 import android.app.BroadcastOptions; 57 import android.bluetooth.BluetoothAdapter; 58 import android.bluetooth.BluetoothDevice; 59 import android.bluetooth.BluetoothGatt; 60 import android.bluetooth.BluetoothLeAudio; 61 import android.bluetooth.BluetoothLeAudioCodecConfigMetadata; 62 import android.bluetooth.BluetoothLeAudioContentMetadata; 63 import android.bluetooth.BluetoothLeBroadcastAssistant; 64 import android.bluetooth.BluetoothLeBroadcastChannel; 65 import android.bluetooth.BluetoothLeBroadcastMetadata; 66 import android.bluetooth.BluetoothLeBroadcastReceiveState; 67 import android.bluetooth.BluetoothLeBroadcastSubgroup; 68 import android.bluetooth.BluetoothProfile; 69 import android.bluetooth.BluetoothStatusCodes; 70 import android.bluetooth.BluetoothUuid; 71 import android.bluetooth.IBluetoothLeBroadcastAssistantCallback; 72 import android.bluetooth.le.IScannerCallback; 73 import android.bluetooth.le.PeriodicAdvertisingReport; 74 import android.bluetooth.le.ScanCallback; 75 import android.bluetooth.le.ScanFilter; 76 import android.bluetooth.le.ScanRecord; 77 import android.bluetooth.le.ScanResult; 78 import android.bluetooth.le.ScanSettings; 79 import android.content.Intent; 80 import android.os.Binder; 81 import android.os.Handler; 82 import android.os.Message; 83 import android.os.ParcelUuid; 84 import android.os.RemoteException; 85 import android.platform.test.annotations.DisableFlags; 86 import android.platform.test.annotations.EnableFlags; 87 import android.platform.test.flag.junit.SetFlagsRule; 88 89 import androidx.test.filters.MediumTest; 90 import androidx.test.runner.AndroidJUnit4; 91 92 import com.android.bluetooth.BluetoothMethodProxy; 93 import com.android.bluetooth.TestUtils; 94 import com.android.bluetooth.btservice.AdapterService; 95 import com.android.bluetooth.btservice.ServiceFactory; 96 import com.android.bluetooth.btservice.storage.DatabaseManager; 97 import com.android.bluetooth.csip.CsipSetCoordinatorService; 98 import com.android.bluetooth.flags.Flags; 99 import com.android.bluetooth.le_audio.LeAudioService; 100 import com.android.bluetooth.le_scan.ScanController; 101 102 import com.google.common.truth.Expect; 103 104 import org.hamcrest.Matcher; 105 import org.hamcrest.core.AllOf; 106 import org.junit.After; 107 import org.junit.Before; 108 import org.junit.Rule; 109 import org.junit.Test; 110 import org.junit.runner.RunWith; 111 import org.mockito.ArgumentCaptor; 112 import org.mockito.InOrder; 113 import org.mockito.Mock; 114 import org.mockito.Mockito; 115 import org.mockito.Spy; 116 import org.mockito.hamcrest.MockitoHamcrest; 117 118 import java.util.ArrayList; 119 import java.util.Arrays; 120 import java.util.HashMap; 121 import java.util.List; 122 import java.util.Optional; 123 import java.util.Set; 124 import java.util.stream.Collectors; 125 126 /** Test cases for {@link BassClientService}. */ 127 @MediumTest 128 @RunWith(AndroidJUnit4.class) 129 public class BassClientServiceTest { 130 @Rule public final MockitoRule mMockitoRule = new MockitoRule(); 131 @Rule public Expect expect = Expect.create(); 132 @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); 133 134 @Spy private BassObjectsFactory mObjectsFactory = BassObjectsFactory.getInstance(); 135 @Mock private AdapterService mAdapterService; 136 @Mock private DatabaseManager mDatabaseManager; 137 @Mock private BluetoothLeScannerWrapper mBluetoothLeScannerWrapper; 138 @Mock private ServiceFactory mServiceFactory; 139 @Mock private ScanController mScanController; 140 @Mock private CsipSetCoordinatorService mCsipService; 141 @Mock private LeAudioService mLeAudioService; 142 @Mock private IBluetoothLeBroadcastAssistantCallback mCallback; 143 @Mock private Binder mBinder; 144 @Mock private BluetoothMethodProxy mMethodProxy; 145 146 private static final int TIMEOUT_MS = 1000; 147 148 private static final ParcelUuid[] FAKE_SERVICE_UUIDS = {BluetoothUuid.BASS}; 149 150 private static final int TEST_BROADCAST_ID = 42; 151 private static final int TEST_ADVERTISER_SID = 1234; 152 private static final int TEST_PA_SYNC_INTERVAL = 100; 153 private static final int TEST_PRESENTATION_DELAY_MS = 345; 154 private static final int TEST_RSSI = -40; 155 156 private static final int TEST_SYNC_HANDLE = 0; 157 158 private static final int TEST_CODEC_ID = 42; 159 private static final int TEST_CHANNEL_INDEX = 56; 160 161 // For BluetoothLeAudioCodecConfigMetadata 162 private static final long TEST_AUDIO_LOCATION_FRONT_LEFT = 0x01; 163 private static final long TEST_AUDIO_LOCATION_FRONT_RIGHT = 0x02; 164 165 // For BluetoothLeAudioContentMetadata 166 private static final String TEST_PROGRAM_INFO = "Test"; 167 // German language code in ISO 639-3 168 private static final String TEST_LANGUAGE = "deu"; 169 private static final int TEST_SOURCE_ID = 10; 170 private static final int TEST_NUM_SOURCES = 1; 171 172 private final HashMap<BluetoothDevice, BassClientStateMachine> mStateMachines = new HashMap<>(); 173 174 private final BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 175 private final BluetoothDevice mCurrentDevice = getTestDevice(0); 176 private final BluetoothDevice mCurrentDevice1 = getTestDevice(1); 177 178 private BassClientService mBassClientService; 179 180 private final BluetoothDevice mSourceDevice = 181 mBluetoothAdapter.getRemoteLeDevice( 182 "00:11:22:33:44:55", BluetoothDevice.ADDRESS_TYPE_RANDOM); 183 private final BluetoothDevice mSourceDevice2 = 184 mBluetoothAdapter.getRemoteLeDevice( 185 "00:11:22:33:44:66", BluetoothDevice.ADDRESS_TYPE_RANDOM); 186 private ArgumentCaptor<ScanCallback> mCallbackCaptor; 187 private ArgumentCaptor<IScannerCallback> mBassScanCallbackCaptor; 188 189 private InOrder mInOrderMethodProxy; 190 private InOrder mInOrder; 191 createBroadcastSubgroup()192 BluetoothLeBroadcastSubgroup createBroadcastSubgroup() { 193 BluetoothLeAudioCodecConfigMetadata codecMetadata = 194 new BluetoothLeAudioCodecConfigMetadata.Builder() 195 .setAudioLocation(TEST_AUDIO_LOCATION_FRONT_LEFT) 196 .build(); 197 BluetoothLeAudioContentMetadata contentMetadata = 198 new BluetoothLeAudioContentMetadata.Builder() 199 .setProgramInfo(TEST_PROGRAM_INFO) 200 .setLanguage(TEST_LANGUAGE) 201 .build(); 202 BluetoothLeBroadcastSubgroup.Builder builder = 203 new BluetoothLeBroadcastSubgroup.Builder() 204 .setCodecId(TEST_CODEC_ID) 205 .setCodecSpecificConfig(codecMetadata) 206 .setContentMetadata(contentMetadata); 207 208 BluetoothLeAudioCodecConfigMetadata channelCodecMetadata = 209 new BluetoothLeAudioCodecConfigMetadata.Builder() 210 .setAudioLocation(TEST_AUDIO_LOCATION_FRONT_RIGHT) 211 .build(); 212 213 // builder expect at least one channel 214 BluetoothLeBroadcastChannel channel = 215 new BluetoothLeBroadcastChannel.Builder() 216 .setSelected(true) 217 .setChannelIndex(TEST_CHANNEL_INDEX) 218 .setCodecMetadata(channelCodecMetadata) 219 .build(); 220 builder.addChannel(channel); 221 return builder.build(); 222 } 223 createBroadcastMetadata(int broadcastId)224 BluetoothLeBroadcastMetadata createBroadcastMetadata(int broadcastId) { 225 BluetoothLeBroadcastMetadata.Builder builder = 226 new BluetoothLeBroadcastMetadata.Builder() 227 .setEncrypted(false) 228 .setSourceDevice(mSourceDevice, BluetoothDevice.ADDRESS_TYPE_RANDOM) 229 .setSourceAdvertisingSid(TEST_ADVERTISER_SID) 230 .setBroadcastId(broadcastId) 231 .setBroadcastCode(null) 232 .setPaSyncInterval(TEST_PA_SYNC_INTERVAL) 233 .setPresentationDelayMicros(TEST_PRESENTATION_DELAY_MS); 234 // builder expect at least one subgroup 235 builder.addSubgroup(createBroadcastSubgroup()); 236 return builder.build(); 237 } 238 createEmptyBroadcastMetadata()239 BluetoothLeBroadcastMetadata createEmptyBroadcastMetadata() { 240 BluetoothLeBroadcastMetadata.Builder builder = 241 new BluetoothLeBroadcastMetadata.Builder() 242 .setEncrypted(false) 243 .setSourceDevice( 244 mBluetoothAdapter.getRemoteLeDevice( 245 "00:00:00:00:00:00", BluetoothDevice.ADDRESS_TYPE_RANDOM), 246 BluetoothDevice.ADDRESS_TYPE_RANDOM) 247 .setSourceAdvertisingSid(TEST_ADVERTISER_SID) 248 .setBroadcastId(0) 249 .setBroadcastCode(null) 250 .setPaSyncInterval(TEST_PA_SYNC_INTERVAL) 251 .setPresentationDelayMicros(TEST_PRESENTATION_DELAY_MS); 252 // builder expect at least one subgroup 253 builder.addSubgroup(createBroadcastSubgroup()); 254 return builder.build(); 255 } 256 257 @Before setUp()258 public void setUp() throws Exception { 259 mInOrderMethodProxy = inOrder(mMethodProxy); 260 mInOrder = inOrder(mAdapterService); 261 262 BassObjectsFactory.setInstanceForTesting(mObjectsFactory); 263 BluetoothMethodProxy.setInstanceForTesting(mMethodProxy); 264 265 doReturn(true).when(mMethodProxy).initializePeriodicAdvertisingManagerOnDefaultAdapter(); 266 doNothing() 267 .when(mMethodProxy) 268 .periodicAdvertisingManagerRegisterSync( 269 any(), any(), anyInt(), anyInt(), any(), any()); 270 doNothing().when(mMethodProxy).periodicAdvertisingManagerUnregisterSync(any(), any()); 271 272 doReturn(mAdapterService).when(mAdapterService).getBaseContext(); 273 doReturn(new ParcelUuid[] {BluetoothUuid.BASS}) 274 .when(mAdapterService) 275 .getRemoteUuids(any(BluetoothDevice.class)); 276 277 // Mock methods in AdapterService 278 doReturn(FAKE_SERVICE_UUIDS) 279 .when(mAdapterService) 280 .getRemoteUuids(any(BluetoothDevice.class)); 281 doReturn(BluetoothDevice.BOND_BONDED) 282 .when(mAdapterService) 283 .getBondState(any(BluetoothDevice.class)); 284 doReturn(mDatabaseManager).when(mAdapterService).getDatabase(); 285 doAnswer( 286 invocation -> { 287 Set<BluetoothDevice> keys = mStateMachines.keySet(); 288 return keys.toArray(new BluetoothDevice[keys.size()]); 289 }) 290 .when(mAdapterService) 291 .getBondedDevices(); 292 doReturn(mScanController).when(mAdapterService).getBluetoothScanController(); 293 294 // Mock methods in BassObjectsFactory 295 doAnswer( 296 invocation -> { 297 assertThat(mCurrentDevice).isNotNull(); 298 final BassClientStateMachine stateMachine = 299 mock(BassClientStateMachine.class); 300 doReturn(new ArrayList<>()).when(stateMachine).getAllSources(); 301 doReturn(TEST_NUM_SOURCES) 302 .when(stateMachine) 303 .getMaximumSourceCapacity(); 304 doReturn((BluetoothDevice) invocation.getArgument(0)) 305 .when(stateMachine) 306 .getDevice(); 307 doReturn(true).when(stateMachine).isBassStateReady(); 308 mStateMachines.put( 309 (BluetoothDevice) invocation.getArgument(0), stateMachine); 310 doAnswer( 311 inv -> { 312 return Message.obtain( 313 (Handler) null, (int) inv.getArgument(0)); 314 }) 315 .when(stateMachine) 316 .obtainMessage(anyInt()); 317 return stateMachine; 318 }) 319 .when(mObjectsFactory) 320 .makeStateMachine(any(), any(), any(), any()); 321 doReturn(mBluetoothLeScannerWrapper) 322 .when(mObjectsFactory) 323 .getBluetoothLeScannerWrapper(any()); 324 325 mBassClientService = new BassClientService(mAdapterService); 326 mBassClientService.setAvailable(true); 327 328 mBassClientService.mServiceFactory = mServiceFactory; 329 doReturn(mCsipService).when(mServiceFactory).getCsipSetCoordinatorService(); 330 doReturn(mLeAudioService).when(mServiceFactory).getLeAudioService(); 331 332 when(mCallback.asBinder()).thenReturn(mBinder); 333 mBassClientService.registerCallback(mCallback); 334 } 335 336 @After tearDown()337 public void tearDown() throws Exception { 338 mBassClientService.unregisterCallback(mCallback); 339 340 mBassClientService.cleanup(); 341 assertThat(BassClientService.getBassClientService()).isNull(); 342 mStateMachines.clear(); 343 BassObjectsFactory.setInstanceForTesting(null); 344 } 345 346 /** Test to verify that BassClientService can be successfully started */ 347 @Test testGetBassClientService()348 public void testGetBassClientService() { 349 assertThat(mBassClientService).isEqualTo(BassClientService.getBassClientService()); 350 // Verify default connection and audio states 351 assertThat(mBassClientService.getConnectionState(mCurrentDevice)) 352 .isEqualTo(STATE_DISCONNECTED); 353 } 354 355 /** Test if getProfileConnectionPolicy works after the service is stopped. */ 356 @Test testGetPolicyAfterStopped()357 public void testGetPolicyAfterStopped() { 358 mBassClientService.cleanup(); 359 when(mDatabaseManager.getProfileConnectionPolicy( 360 mCurrentDevice, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT)) 361 .thenReturn(CONNECTION_POLICY_UNKNOWN); 362 assertThat(mBassClientService.getConnectionPolicy(mCurrentDevice)) 363 .isEqualTo(CONNECTION_POLICY_UNKNOWN); 364 } 365 366 /** 367 * Test connecting to a test device. - service.connect() should return false - 368 * bassClientStateMachine.sendMessage(CONNECT) should be called. 369 */ 370 @Test testConnect()371 public void testConnect() { 372 when(mDatabaseManager.getProfileConnectionPolicy( 373 any(BluetoothDevice.class), 374 eq(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT))) 375 .thenReturn(CONNECTION_POLICY_ALLOWED); 376 377 assertThat(mBassClientService.connect(mCurrentDevice)).isTrue(); 378 verify(mObjectsFactory) 379 .makeStateMachine( 380 eq(mCurrentDevice), eq(mBassClientService), eq(mAdapterService), any()); 381 BassClientStateMachine stateMachine = mStateMachines.get(mCurrentDevice); 382 assertThat(stateMachine).isNotNull(); 383 verify(stateMachine).sendMessage(BassClientStateMachine.CONNECT); 384 } 385 386 /** Test connecting to a null device. - service.connect() should return false. */ 387 @Test testConnect_nullDevice()388 public void testConnect_nullDevice() { 389 when(mDatabaseManager.getProfileConnectionPolicy( 390 any(BluetoothDevice.class), 391 eq(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT))) 392 .thenReturn(CONNECTION_POLICY_ALLOWED); 393 BluetoothDevice nullDevice = null; 394 395 assertThat(mBassClientService.connect(nullDevice)).isFalse(); 396 } 397 398 /** 399 * Test connecting to a device when the connection policy is forbidden. - service.connect() 400 * should return false. 401 */ 402 @Test testConnect_whenConnectionPolicyIsForbidden()403 public void testConnect_whenConnectionPolicyIsForbidden() { 404 when(mDatabaseManager.getProfileConnectionPolicy( 405 any(BluetoothDevice.class), 406 eq(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT))) 407 .thenReturn(CONNECTION_POLICY_FORBIDDEN); 408 assertThat(mCurrentDevice).isNotNull(); 409 410 assertThat(mBassClientService.connect(mCurrentDevice)).isFalse(); 411 } 412 413 /** 414 * Test whether service.startSearchingForSources() calls BluetoothLeScannerWrapper.startScan(). 415 */ 416 @Test testStartSearchingForSources()417 public void testStartSearchingForSources() { 418 prepareConnectedDeviceGroup(); 419 List<ScanFilter> scanFilters = new ArrayList<>(); 420 421 assertThat(mStateMachines).hasSize(2); 422 for (BassClientStateMachine sm : mStateMachines.values()) { 423 Mockito.clearInvocations(sm); 424 } 425 426 mBassClientService.startSearchingForSources(scanFilters); 427 428 if (Flags.leaudioBassScanWithInternalScanController()) { 429 verify(mScanController).registerScannerInternal(any(), any(), any()); 430 } else { 431 verify(mBluetoothLeScannerWrapper).startScan(notNull(), notNull(), notNull()); 432 } 433 for (BassClientStateMachine sm : mStateMachines.values()) { 434 verify(sm).sendMessage(BassClientStateMachine.START_SCAN_OFFLOAD); 435 } 436 } 437 438 /** 439 * Test whether service.startSearchingForSources() does not call 440 * BluetoothLeScannerWrapper.startScan() when the scanner instance cannot be achieved. 441 */ 442 @Test 443 @DisableFlags(Flags.FLAG_LEAUDIO_BASS_SCAN_WITH_INTERNAL_SCAN_CONTROLLER) testStartSearchingForSources_whenScannerIsNull()444 public void testStartSearchingForSources_whenScannerIsNull() { 445 doReturn(null).when(mObjectsFactory).getBluetoothLeScannerWrapper(any()); 446 List<ScanFilter> scanFilters = new ArrayList<>(); 447 448 mBassClientService.startSearchingForSources(scanFilters); 449 450 verify(mBluetoothLeScannerWrapper, never()).startScan(any(), any(), any()); 451 } 452 prepareConnectedDeviceGroup()453 private void prepareConnectedDeviceGroup() { 454 when(mDatabaseManager.getProfileConnectionPolicy( 455 any(BluetoothDevice.class), 456 eq(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT))) 457 .thenReturn(CONNECTION_POLICY_ALLOWED); 458 459 // Mock the CSIP group 460 List<BluetoothDevice> groupDevices = new ArrayList<>(); 461 groupDevices.add(mCurrentDevice); 462 groupDevices.add(mCurrentDevice1); 463 doReturn(groupDevices) 464 .when(mCsipService) 465 .getGroupDevicesOrdered(mCurrentDevice, BluetoothUuid.CAP); 466 doReturn(groupDevices) 467 .when(mCsipService) 468 .getGroupDevicesOrdered(mCurrentDevice1, BluetoothUuid.CAP); 469 470 // Prepare connected devices 471 assertThat(mBassClientService.connect(mCurrentDevice)).isTrue(); 472 assertThat(mBassClientService.connect(mCurrentDevice1)).isTrue(); 473 474 assertThat(mStateMachines).hasSize(2); 475 for (BassClientStateMachine sm : mStateMachines.values()) { 476 // Verify the call 477 verify(sm).sendMessage(eq(BassClientStateMachine.CONNECT)); 478 479 // Notify the service about the connection event 480 BluetoothDevice dev = sm.getDevice(); 481 doCallRealMethod() 482 .when(sm) 483 .broadcastConnectionState(eq(dev), any(Integer.class), any(Integer.class)); 484 sm.mService = mBassClientService; 485 sm.mDevice = dev; 486 sm.broadcastConnectionState(dev, STATE_CONNECTING, STATE_CONNECTED); 487 488 doReturn(STATE_CONNECTED).when(sm).getConnectionState(); 489 doReturn(true).when(sm).isConnected(); 490 491 // Inject initial broadcast source state 492 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 493 if (sm.getDevice().equals(mCurrentDevice)) { 494 injectRemoteSourceStateSourceAdded( 495 sm, 496 meta, 497 TEST_SOURCE_ID, 498 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 499 meta.isEncrypted() 500 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 501 : BluetoothLeBroadcastReceiveState 502 .BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 503 null); 504 injectRemoteSourceStateRemoval(sm, TEST_SOURCE_ID); 505 } else if (sm.getDevice().equals(mCurrentDevice1)) { 506 injectRemoteSourceStateSourceAdded( 507 sm, 508 meta, 509 TEST_SOURCE_ID + 1, 510 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 511 meta.isEncrypted() 512 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 513 : BluetoothLeBroadcastReceiveState 514 .BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 515 null); 516 injectRemoteSourceStateRemoval(sm, TEST_SOURCE_ID + 1); 517 } 518 } 519 520 doReturn(true).when(mLeAudioService).isPrimaryDevice(mCurrentDevice); 521 doReturn(true).when(mLeAudioService).isPrimaryDevice(mCurrentDevice1); 522 } 523 startSearchingForSources()524 private void startSearchingForSources() { 525 List<ScanFilter> scanFilters = new ArrayList<>(); 526 int scannerId = 1; 527 528 assertThat(mStateMachines).hasSize(2); 529 for (BassClientStateMachine sm : mStateMachines.values()) { 530 Mockito.clearInvocations(sm); 531 } 532 533 clearInvocations(mBluetoothLeScannerWrapper); 534 clearInvocations(mScanController); 535 536 mBassClientService.startSearchingForSources(scanFilters); 537 538 if (Flags.leaudioBassScanWithInternalScanController()) { 539 mBassScanCallbackCaptor = ArgumentCaptor.forClass(IScannerCallback.class); 540 verify(mScanController) 541 .registerScannerInternal(mBassScanCallbackCaptor.capture(), any(), any()); 542 543 try { 544 mBassScanCallbackCaptor.getValue().onScannerRegistered(0, scannerId); 545 } catch (RemoteException e) { 546 // the mocked onScannerRegistered doesn't throw RemoteException 547 } 548 verify(mScanController).startScanInternal(eq(scannerId), any(), any()); 549 } else { 550 mCallbackCaptor = ArgumentCaptor.forClass(ScanCallback.class); 551 verify(mBluetoothLeScannerWrapper) 552 .startScan(notNull(), notNull(), mCallbackCaptor.capture()); 553 } 554 for (BassClientStateMachine sm : mStateMachines.values()) { 555 verify(sm).sendMessage(BassClientStateMachine.START_SCAN_OFFLOAD); 556 } 557 } 558 559 @Test testStopSearchingForSources()560 public void testStopSearchingForSources() { 561 prepareConnectedDeviceGroup(); 562 startSearchingForSources(); 563 564 // Scan and sync 1 565 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 566 mInOrderMethodProxy 567 .verify(mMethodProxy) 568 .periodicAdvertisingManagerRegisterSync( 569 any(), any(), anyInt(), anyInt(), any(), any()); 570 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 571 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 572 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 573 .isEqualTo(mSourceDevice); 574 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 575 .isEqualTo(TEST_BROADCAST_ID); 576 577 // Stop searching 578 mBassClientService.stopSearchingForSources(); 579 if (Flags.leaudioBassScanWithInternalScanController()) { 580 verify(mScanController).stopScanInternal(anyInt()); 581 582 } else { 583 verify(mBluetoothLeScannerWrapper).stopScan(mCallbackCaptor.getValue()); 584 } 585 for (BassClientStateMachine sm : mStateMachines.values()) { 586 verify(sm).sendMessage(BassClientStateMachine.STOP_SCAN_OFFLOAD); 587 } 588 589 // Check if unsyced 590 mInOrderMethodProxy 591 .verify(mMethodProxy) 592 .periodicAdvertisingManagerUnregisterSync(any(), any()); 593 expect.that(mBassClientService.getActiveSyncedSources()).isEmpty(); 594 expect.that(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)).isNull(); 595 expect.that(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 596 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 597 } 598 599 @Test testStop()600 public void testStop() { 601 prepareConnectedDeviceGroup(); 602 startSearchingForSources(); 603 604 // Scan and sync 1 605 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 606 mInOrderMethodProxy 607 .verify(mMethodProxy) 608 .periodicAdvertisingManagerRegisterSync( 609 any(), any(), anyInt(), anyInt(), any(), any()); 610 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 611 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 612 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 613 .isEqualTo(mSourceDevice); 614 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 615 .isEqualTo(TEST_BROADCAST_ID); 616 617 // Stop 618 mBassClientService.cleanup(); 619 if (Flags.leaudioBassScanWithInternalScanController()) { 620 verify(mScanController).stopScanInternal(anyInt()); 621 } else { 622 verify(mBluetoothLeScannerWrapper).stopScan(mCallbackCaptor.getValue()); 623 } 624 625 // Check if unsyced 626 mInOrderMethodProxy 627 .verify(mMethodProxy) 628 .periodicAdvertisingManagerUnregisterSync(any(), any()); 629 expect.that(mBassClientService.getActiveSyncedSources()).isEmpty(); 630 expect.that(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)).isNull(); 631 expect.that(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 632 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 633 } 634 635 @Test testStopSearchingForSources_startAndSyncAgain()636 public void testStopSearchingForSources_startAndSyncAgain() { 637 prepareConnectedDeviceGroup(); 638 startSearchingForSources(); 639 640 // Scan and sync 1 641 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 642 mInOrderMethodProxy 643 .verify(mMethodProxy) 644 .periodicAdvertisingManagerRegisterSync( 645 any(), any(), anyInt(), anyInt(), any(), any()); 646 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 647 648 // Stop searching 649 mBassClientService.stopSearchingForSources(); 650 651 // Start searching again 652 startSearchingForSources(); 653 654 // Sync the same device again 655 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 656 mInOrderMethodProxy 657 .verify(mMethodProxy) 658 .periodicAdvertisingManagerRegisterSync( 659 any(), any(), anyInt(), anyInt(), any(), any()); 660 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 661 expect.that(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); 662 expect.that(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 663 .isEqualTo(mSourceDevice); 664 expect.that(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 665 .isEqualTo(TEST_BROADCAST_ID); 666 } 667 668 @Test testStop_startAndSyncAgain()669 public void testStop_startAndSyncAgain() { 670 prepareConnectedDeviceGroup(); 671 startSearchingForSources(); 672 673 // Scan and sync 1 674 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 675 mInOrderMethodProxy 676 .verify(mMethodProxy) 677 .periodicAdvertisingManagerRegisterSync( 678 any(), any(), anyInt(), anyInt(), any(), any()); 679 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 680 681 // Stop 682 mBassClientService.cleanup(); 683 684 // Start again 685 mBassClientService = new BassClientService(mAdapterService); 686 687 // Start searching again 688 prepareConnectedDeviceGroup(); 689 startSearchingForSources(); 690 691 // Sync the same device again 692 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 693 mInOrderMethodProxy 694 .verify(mMethodProxy) 695 .periodicAdvertisingManagerRegisterSync( 696 any(), any(), anyInt(), anyInt(), any(), any()); 697 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 698 expect.that(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); 699 expect.that(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 700 .isEqualTo(mSourceDevice); 701 expect.that(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 702 .isEqualTo(TEST_BROADCAST_ID); 703 } 704 705 @Test testStopSearchingForSources_addSourceCauseSyncEvenWithoutScanning()706 public void testStopSearchingForSources_addSourceCauseSyncEvenWithoutScanning() { 707 prepareConnectedDeviceGroup(); 708 startSearchingForSources(); 709 710 // Scan and sync 1 711 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 712 mInOrderMethodProxy 713 .verify(mMethodProxy) 714 .periodicAdvertisingManagerRegisterSync( 715 any(), any(), anyInt(), anyInt(), any(), any()); 716 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 717 718 // Stop searching 719 mBassClientService.stopSearchingForSources(); 720 721 // Add source to unsynced broadcast, causes synchronization first 722 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 723 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 724 handleHandoverSupport(); 725 mInOrderMethodProxy 726 .verify(mMethodProxy) 727 .periodicAdvertisingManagerRegisterSync( 728 any(), any(), anyInt(), anyInt(), any(), any()); 729 730 // Verify not getting ADD_BCAST_SOURCE message before source sync 731 assertThat(mStateMachines).hasSize(2); 732 for (BassClientStateMachine sm : mStateMachines.values()) { 733 verify(sm, never()).sendMessage(any()); 734 } 735 736 // Source synced which cause execute pending add source 737 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 738 expect.that(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); 739 expect.that(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 740 .isEqualTo(mSourceDevice); 741 expect.that(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 742 .isEqualTo(TEST_BROADCAST_ID); 743 744 // Verify all group members getting ADD_BCAST_SOURCE message 745 expect.that(mStateMachines.size()).isEqualTo(2); 746 for (BassClientStateMachine sm : mStateMachines.values()) { 747 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 748 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 749 750 Message msg = 751 messageCaptor.getAllValues().stream() 752 .filter( 753 m -> 754 (m.what == BassClientStateMachine.ADD_BCAST_SOURCE) 755 && (m.obj == meta)) 756 .findFirst() 757 .orElse(null); 758 expect.that(msg).isNotNull(); 759 } 760 } 761 762 @Test 763 @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) testNotRemovingCachedBroadcastOnLostWithoutScanning_noResyncFlag()764 public void testNotRemovingCachedBroadcastOnLostWithoutScanning_noResyncFlag() 765 throws RemoteException { 766 prepareConnectedDeviceGroup(); 767 startSearchingForSources(); 768 769 // Scan and sync 1 770 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 771 mInOrderMethodProxy 772 .verify(mMethodProxy) 773 .periodicAdvertisingManagerRegisterSync( 774 any(), any(), anyInt(), anyInt(), any(), any()); 775 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 776 777 // Sync lost during scanning removes cached broadcast 778 onSyncLost(); 779 780 // Add source to not cached broadcast cause addFailed notification 781 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 782 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 783 handleHandoverSupport(); 784 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 785 verify(mCallback) 786 .onSourceAddFailed( 787 eq(mCurrentDevice), 788 eq(meta), 789 eq(BluetoothStatusCodes.ERROR_BAD_PARAMETERS)); 790 791 // Add broadcast to cache 792 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 793 mInOrderMethodProxy 794 .verify(mMethodProxy) 795 .periodicAdvertisingManagerRegisterSync( 796 any(), any(), anyInt(), anyInt(), any(), any()); 797 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 798 799 // Stop searching 800 mBassClientService.stopSearchingForSources(); 801 802 // Add sync handle by add source 803 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 804 handleHandoverSupport(); 805 mInOrderMethodProxy 806 .verify(mMethodProxy) 807 .periodicAdvertisingManagerRegisterSync( 808 any(), any(), anyInt(), anyInt(), any(), any()); 809 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 810 811 // Sync lost without active scanning should not remove broadcast cache 812 onSyncLost(); 813 814 // Add source to unsynced broadcast, causes synchronization first 815 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 816 handleHandoverSupport(); 817 mInOrderMethodProxy 818 .verify(mMethodProxy) 819 .periodicAdvertisingManagerRegisterSync( 820 any(), any(), anyInt(), anyInt(), any(), any()); 821 } 822 823 @Test 824 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) testNotRemovingCachedBroadcastOnLostWithoutScanning()825 public void testNotRemovingCachedBroadcastOnLostWithoutScanning() throws RemoteException { 826 prepareConnectedDeviceGroup(); 827 startSearchingForSources(); 828 829 // Scan and sync 1 830 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 831 mInOrderMethodProxy 832 .verify(mMethodProxy) 833 .periodicAdvertisingManagerRegisterSync( 834 any(), any(), anyInt(), anyInt(), any(), any()); 835 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 836 837 // Sync lost during scanning removes cached broadcast 838 onSyncLost(); 839 checkAndDispatchTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_SYNC_LOST_TIMEOUT); 840 841 // Add source to not cached broadcast cause addFailed notification 842 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 843 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 844 handleHandoverSupport(); 845 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 846 verify(mCallback) 847 .onSourceAddFailed( 848 eq(mCurrentDevice), 849 eq(meta), 850 eq(BluetoothStatusCodes.ERROR_BAD_PARAMETERS)); 851 852 // Add broadcast to cache 853 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 854 mInOrderMethodProxy 855 .verify(mMethodProxy) 856 .periodicAdvertisingManagerRegisterSync( 857 any(), any(), anyInt(), anyInt(), any(), any()); 858 859 // Stop searching 860 mBassClientService.stopSearchingForSources(); 861 862 // Add sync handle by add source 863 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 864 handleHandoverSupport(); 865 mInOrderMethodProxy 866 .verify(mMethodProxy) 867 .periodicAdvertisingManagerRegisterSync( 868 any(), any(), anyInt(), anyInt(), any(), any()); 869 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 870 871 // Sync lost without active scanning should not remove broadcast cache 872 onSyncLost(); 873 checkAndDispatchTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_SYNC_LOST_TIMEOUT); 874 875 // Add source to unsynced broadcast, causes synchronization first 876 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 877 handleHandoverSupport(); 878 mInOrderMethodProxy 879 .verify(mMethodProxy) 880 .periodicAdvertisingManagerRegisterSync( 881 any(), any(), anyInt(), anyInt(), any(), any()); 882 } 883 884 @Test testNotRemovingCachedBroadcastOnFailEstablishWithoutScanning()885 public void testNotRemovingCachedBroadcastOnFailEstablishWithoutScanning() 886 throws RemoteException { 887 final BluetoothDevice device1 = 888 mBluetoothAdapter.getRemoteLeDevice( 889 "00:11:22:33:44:11", BluetoothDevice.ADDRESS_TYPE_RANDOM); 890 final BluetoothDevice device2 = 891 mBluetoothAdapter.getRemoteLeDevice( 892 "00:11:22:33:44:22", BluetoothDevice.ADDRESS_TYPE_RANDOM); 893 final BluetoothDevice device3 = 894 mBluetoothAdapter.getRemoteLeDevice( 895 "00:11:22:33:44:33", BluetoothDevice.ADDRESS_TYPE_RANDOM); 896 final BluetoothDevice device4 = 897 mBluetoothAdapter.getRemoteLeDevice( 898 "00:11:22:33:44:44", BluetoothDevice.ADDRESS_TYPE_RANDOM); 899 final BluetoothDevice device5 = 900 mBluetoothAdapter.getRemoteLeDevice( 901 "00:11:22:33:44:55", BluetoothDevice.ADDRESS_TYPE_RANDOM); 902 final int handle1 = 0; 903 final int handle2 = 1; 904 final int handle3 = 2; 905 final int handle4 = 3; 906 final int handle5 = 4; 907 final int broadcastId1 = 1111; 908 final int broadcastId2 = 2222; 909 final int broadcastId3 = 3333; 910 final int broadcastId4 = 4444; 911 final int broadcastId5 = 5555; 912 913 prepareConnectedDeviceGroup(); 914 startSearchingForSources(); 915 916 // Scan and sync 5 sources cause removing 1 synced element 917 onScanResult(device1, broadcastId1); 918 onSyncEstablished(device1, handle1); 919 onScanResult(device2, broadcastId2); 920 onSyncEstablished(device2, handle2); 921 onScanResult(device3, broadcastId3); 922 onSyncEstablished(device3, handle3); 923 onScanResult(device4, broadcastId4); 924 onSyncEstablished(device4, handle4); 925 onScanResult(device5, broadcastId5); 926 onSyncEstablished(device5, handle5); 927 mInOrderMethodProxy 928 .verify(mMethodProxy, times(5)) 929 .periodicAdvertisingManagerRegisterSync( 930 any(), any(), anyInt(), anyInt(), any(), any()); 931 932 BluetoothLeBroadcastMetadata.Builder builder = 933 new BluetoothLeBroadcastMetadata.Builder() 934 .setEncrypted(false) 935 .setSourceDevice(device1, BluetoothDevice.ADDRESS_TYPE_RANDOM) 936 .setSourceAdvertisingSid(TEST_ADVERTISER_SID) 937 .setBroadcastId(broadcastId1) 938 .setBroadcastCode(null) 939 .setPaSyncInterval(TEST_PA_SYNC_INTERVAL) 940 .setPresentationDelayMicros(TEST_PRESENTATION_DELAY_MS); 941 // builder expect at least one subgroup 942 builder.addSubgroup(createBroadcastSubgroup()); 943 BluetoothLeBroadcastMetadata meta = builder.build(); 944 945 // Add source to unsynced broadcast, causes synchronization first 946 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 947 handleHandoverSupport(); 948 mInOrderMethodProxy 949 .verify(mMethodProxy) 950 .periodicAdvertisingManagerRegisterSync( 951 any(), any(), anyInt(), anyInt(), any(), any()); 952 953 // Error in syncEstablished causes sourceLost, sourceAddFailed notification 954 // and removing cache because scanning is active 955 onSyncEstablishedFailed(device1, handle1); 956 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 957 InOrder inOrderCallback = inOrder(mCallback); 958 inOrderCallback.verify(mCallback).onSourceLost(eq(broadcastId1)); 959 inOrderCallback 960 .verify(mCallback) 961 .onSourceAddFailed( 962 eq(mCurrentDevice), 963 eq(meta), 964 eq(BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES)); 965 966 // Add source to not cached broadcast causes addFailed notification 967 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 968 handleHandoverSupport(); 969 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 970 inOrderCallback 971 .verify(mCallback) 972 .onSourceAddFailed( 973 eq(mCurrentDevice), 974 eq(meta), 975 eq(BluetoothStatusCodes.ERROR_BAD_PARAMETERS)); 976 977 // Scan and sync again 978 onScanResult(device1, broadcastId1); 979 mInOrderMethodProxy 980 .verify(mMethodProxy) 981 .periodicAdvertisingManagerRegisterSync( 982 any(), any(), anyInt(), anyInt(), any(), any()); 983 onSyncEstablished(device1, handle1); 984 985 // Stop searching 986 mBassClientService.stopSearchingForSources(); 987 988 // Add source to unsynced broadcast, causes synchronization first 989 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 990 handleHandoverSupport(); 991 mInOrderMethodProxy 992 .verify(mMethodProxy) 993 .periodicAdvertisingManagerRegisterSync( 994 any(), any(), anyInt(), anyInt(), any(), any()); 995 996 // Error in syncEstablished causes sourceLost, sourceAddFailed notification 997 // and not removing cache because scanning is inactive 998 onSyncEstablishedFailed(device1, handle1); 999 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 1000 inOrderCallback.verify(mCallback).onSourceLost(eq(broadcastId1)); 1001 inOrderCallback 1002 .verify(mCallback) 1003 .onSourceAddFailed( 1004 eq(mCurrentDevice), 1005 eq(meta), 1006 eq(BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES)); 1007 1008 // Add source to unsynced broadcast, causes synchronization first 1009 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 1010 handleHandoverSupport(); 1011 mInOrderMethodProxy 1012 .verify(mMethodProxy) 1013 .periodicAdvertisingManagerRegisterSync( 1014 any(), any(), anyInt(), anyInt(), any(), any()); 1015 } 1016 1017 @Test testMultipleAddSourceToUnsyncedBroadcaster()1018 public void testMultipleAddSourceToUnsyncedBroadcaster() { 1019 prepareConnectedDeviceGroup(); 1020 startSearchingForSources(); 1021 1022 // Scan and sync 1 1023 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 1024 mInOrderMethodProxy 1025 .verify(mMethodProxy) 1026 .periodicAdvertisingManagerRegisterSync( 1027 any(), any(), anyInt(), anyInt(), any(), any()); 1028 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 1029 1030 // Stop searching to unsync broadcaster 1031 mBassClientService.stopSearchingForSources(); 1032 1033 // Sink1 aAdd source to unsynced broadcast, causes synchronization first 1034 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 1035 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ false); 1036 handleHandoverSupport(); 1037 mInOrderMethodProxy 1038 .verify(mMethodProxy) 1039 .periodicAdvertisingManagerRegisterSync( 1040 any(), any(), anyInt(), anyInt(), any(), any()); 1041 1042 // Sink2 add source to unsynced broadcast 1043 mBassClientService.addSource(mCurrentDevice1, meta, /* isGroupOp */ false); 1044 handleHandoverSupport(); 1045 1046 // Sync established 1047 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 1048 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 1049 1050 // Both add sources should be called to state machines 1051 expect.that(mStateMachines.size()).isEqualTo(2); 1052 for (BassClientStateMachine sm : mStateMachines.values()) { 1053 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 1054 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 1055 1056 Message msg = 1057 messageCaptor.getAllValues().stream() 1058 .filter( 1059 m -> 1060 (m.what == BassClientStateMachine.ADD_BCAST_SOURCE) 1061 && (m.obj == meta)) 1062 .findFirst() 1063 .orElse(null); 1064 expect.that(msg).isNotNull(); 1065 } 1066 1067 // There should be no second selectSource call 1068 mInOrderMethodProxy 1069 .verify(mMethodProxy, never()) 1070 .periodicAdvertisingManagerRegisterSync( 1071 any(), any(), anyInt(), anyInt(), any(), any()); 1072 } 1073 1074 @Test testMultipleAddSourceToUnsyncedInactiveBroadcaster()1075 public void testMultipleAddSourceToUnsyncedInactiveBroadcaster() throws RemoteException { 1076 prepareConnectedDeviceGroup(); 1077 startSearchingForSources(); 1078 1079 // Scan and sync 1 1080 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 1081 mInOrderMethodProxy 1082 .verify(mMethodProxy) 1083 .periodicAdvertisingManagerRegisterSync( 1084 any(), any(), anyInt(), anyInt(), any(), any()); 1085 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 1086 1087 // Stop searching to unsync broadcaster 1088 mBassClientService.stopSearchingForSources(); 1089 1090 // Sink1 aAdd source to unsynced broadcast, causes synchronization first 1091 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 1092 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ false); 1093 handleHandoverSupport(); 1094 mInOrderMethodProxy 1095 .verify(mMethodProxy) 1096 .periodicAdvertisingManagerRegisterSync( 1097 any(), any(), anyInt(), anyInt(), any(), any()); 1098 1099 // Sink2 add source to unsynced broadcast 1100 mBassClientService.addSource(mCurrentDevice1, meta, /* isGroupOp */ false); 1101 handleHandoverSupport(); 1102 1103 // Error in syncEstablished causes sourceLost, sourceAddFailed notification for both sinks 1104 onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); 1105 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 1106 InOrder inOrderCallback = inOrder(mCallback); 1107 inOrderCallback.verify(mCallback).onSourceLost(eq(TEST_BROADCAST_ID)); 1108 inOrderCallback 1109 .verify(mCallback) 1110 .onSourceAddFailed( 1111 eq(mCurrentDevice), 1112 eq(meta), 1113 eq(BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES)); 1114 inOrderCallback 1115 .verify(mCallback) 1116 .onSourceAddFailed( 1117 eq(mCurrentDevice1), 1118 eq(meta), 1119 eq(BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES)); 1120 1121 // There should be no second selectSource call 1122 mInOrderMethodProxy 1123 .verify(mMethodProxy, never()) 1124 .periodicAdvertisingManagerRegisterSync( 1125 any(), any(), anyInt(), anyInt(), any(), any()); 1126 } 1127 checkNoTimeout(int broadcastId, int message)1128 private void checkNoTimeout(int broadcastId, int message) { 1129 assertThat(mBassClientService.mTimeoutHandler.isStarted(broadcastId, message)).isFalse(); 1130 } 1131 checkTimeout(int broadcastId, int message)1132 private void checkTimeout(int broadcastId, int message) { 1133 assertThat(mBassClientService.mTimeoutHandler.isStarted(broadcastId, message)).isTrue(); 1134 } 1135 checkAndDispatchTimeout(int broadcastId, int message)1136 private void checkAndDispatchTimeout(int broadcastId, int message) { 1137 checkTimeout(broadcastId, message); 1138 mBassClientService.mTimeoutHandler.stop(broadcastId, message); 1139 Handler handler = mBassClientService.mTimeoutHandler.getOrCreateHandler(broadcastId); 1140 Message newMsg = handler.obtainMessage(message); 1141 handler.dispatchMessage(newMsg); 1142 } 1143 1144 @Test 1145 @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) testStopSearchingForSources_timeoutForActiveSync()1146 public void testStopSearchingForSources_timeoutForActiveSync() { 1147 prepareConnectedDeviceGroup(); 1148 startSearchingForSources(); 1149 1150 // Scan and sync 1 1151 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 1152 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 1153 1154 // Stop searching 1155 mBassClientService.stopSearchingForSources(); 1156 mInOrderMethodProxy 1157 .verify(mMethodProxy) 1158 .periodicAdvertisingManagerUnregisterSync(any(), any()); 1159 1160 // Add source to unsynced broadcast, causes synchronization first 1161 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 1162 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 1163 handleHandoverSupport(); 1164 1165 // Source synced which cause start timeout event 1166 assertThat(mBassClientService.mHandler.hasMessages(BassClientService.MESSAGE_SYNC_TIMEOUT)) 1167 .isFalse(); 1168 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 1169 1170 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 1171 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 1172 .isEqualTo(mSourceDevice); 1173 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 1174 .isEqualTo(TEST_BROADCAST_ID); 1175 1176 assertThat(mBassClientService.mHandler.hasMessages(BassClientService.MESSAGE_SYNC_TIMEOUT)) 1177 .isTrue(); 1178 mBassClientService.mHandler.removeMessages(BassClientService.MESSAGE_SYNC_TIMEOUT); 1179 Message newMsg = 1180 mBassClientService.mHandler.obtainMessage(BassClientService.MESSAGE_SYNC_TIMEOUT); 1181 newMsg.arg1 = TEST_BROADCAST_ID; 1182 mBassClientService.mHandler.dispatchMessage(newMsg); 1183 1184 // Check if unsyced 1185 mInOrderMethodProxy 1186 .verify(mMethodProxy) 1187 .periodicAdvertisingManagerUnregisterSync(any(), any()); 1188 } 1189 1190 @Test 1191 @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) testStopSearchingForSources_clearTimeoutForActiveSync()1192 public void testStopSearchingForSources_clearTimeoutForActiveSync() { 1193 prepareConnectedDeviceGroup(); 1194 startSearchingForSources(); 1195 1196 // Scan and sync 1 1197 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 1198 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 1199 1200 // Stop searching 1201 mBassClientService.stopSearchingForSources(); 1202 mInOrderMethodProxy 1203 .verify(mMethodProxy) 1204 .periodicAdvertisingManagerUnregisterSync(any(), any()); 1205 1206 // Add source to unsynced broadcast, causes synchronization first 1207 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 1208 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 1209 handleHandoverSupport(); 1210 1211 // Source synced which cause start timeout event 1212 assertThat(mBassClientService.mHandler.hasMessages(BassClientService.MESSAGE_SYNC_TIMEOUT)) 1213 .isFalse(); 1214 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 1215 assertThat(mBassClientService.mHandler.hasMessages(BassClientService.MESSAGE_SYNC_TIMEOUT)) 1216 .isTrue(); 1217 1218 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 1219 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 1220 .isEqualTo(mSourceDevice); 1221 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 1222 .isEqualTo(TEST_BROADCAST_ID); 1223 1224 // Start searching again should clear timeout 1225 startSearchingForSources(); 1226 assertThat(mBassClientService.mHandler.hasMessages(BassClientService.MESSAGE_SYNC_TIMEOUT)) 1227 .isFalse(); 1228 1229 mInOrderMethodProxy 1230 .verify(mMethodProxy, never()) 1231 .periodicAdvertisingManagerUnregisterSync(any(), any()); 1232 expect.that(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); 1233 expect.that(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 1234 .isEqualTo(mSourceDevice); 1235 expect.that(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 1236 .isEqualTo(TEST_BROADCAST_ID); 1237 } 1238 getScanRecord(int broadcastId)1239 private static byte[] getScanRecord(int broadcastId) { 1240 return new byte[] { 1241 0x02, 1242 0x01, 1243 0x1a, // advertising flags 1244 0x05, 1245 0x02, 1246 0x52, 1247 0x18, 1248 0x0a, 1249 0x11, // 16 bit service uuids 1250 0x04, 1251 0x09, 1252 0x50, 1253 0x65, 1254 0x64, // name 1255 0x02, 1256 0x0A, 1257 (byte) 0xec, // tx power level 1258 0x05, 1259 0x30, 1260 0x54, 1261 0x65, 1262 0x73, 1263 0x74, // broadcast name: Test 1264 0x06, 1265 0x16, 1266 0x52, 1267 0x18, 1268 (byte) broadcastId, 1269 (byte) (broadcastId >> 8), 1270 (byte) (broadcastId >> 16), // service data, broadcast id 1271 0x08, 1272 0x16, 1273 0x56, 1274 0x18, 1275 0x07, 1276 0x03, 1277 0x06, 1278 0x07, 1279 0x08, 1280 // service data - public broadcast, 1281 // feature - 0x7, metadata len - 0x3, metadata - 0x6, 0x7, 0x8 1282 0x05, 1283 (byte) 0xff, 1284 (byte) 0xe0, 1285 0x00, 1286 0x02, 1287 0x15, // manufacturer specific data 1288 0x03, 1289 0x50, 1290 0x01, 1291 0x02, // an unknown data type won't cause trouble 1292 }; 1293 } 1294 generateScanResult(ScanResult result)1295 private void generateScanResult(ScanResult result) { 1296 if (Flags.leaudioBassScanWithInternalScanController()) { 1297 try { 1298 mBassScanCallbackCaptor.getValue().onScanResult(result); 1299 } catch (RemoteException e) { 1300 // the mocked onScanResult doesn't throw RemoteException 1301 } 1302 } else { 1303 mCallbackCaptor.getValue().onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, result); 1304 } 1305 } 1306 onScanResult(BluetoothDevice testDevice, int broadcastId)1307 private void onScanResult(BluetoothDevice testDevice, int broadcastId) { 1308 byte[] scanRecord = getScanRecord(broadcastId); 1309 ScanResult scanResult = 1310 new ScanResult( 1311 testDevice, 1312 0, 1313 0, 1314 0, 1315 0, 1316 0, 1317 TEST_RSSI, 1318 0, 1319 ScanRecord.parseFromBytes(scanRecord), 1320 0); 1321 generateScanResult(scanResult); 1322 } 1323 getPAScanRecord()1324 private static byte[] getPAScanRecord() { 1325 return new byte[] { 1326 (byte) 0x02, 1327 (byte) 0x01, 1328 (byte) 0x1a, // advertising flags 1329 (byte) 0x05, 1330 (byte) 0x02, 1331 (byte) 0x51, 1332 (byte) 0x18, 1333 (byte) 0x0a, 1334 (byte) 0x11, // 16 bit service uuids 1335 (byte) 0x04, 1336 (byte) 0x09, 1337 (byte) 0x50, 1338 (byte) 0x65, 1339 (byte) 0x64, // name 1340 (byte) 0x02, 1341 (byte) 0x0A, 1342 (byte) 0xec, // tx power level 1343 (byte) 0x19, 1344 (byte) 0x16, 1345 (byte) 0x51, 1346 (byte) 0x18, // service data (base data with 18 bytes) 1347 // LEVEL 1 1348 (byte) 0x01, 1349 (byte) 0x02, 1350 (byte) 0x03, // mPresentationDelay 1351 (byte) 0x01, // mNumSubGroups 1352 // LEVEL 2 1353 (byte) 0x01, // mNumSubGroups 1354 (byte) 0x00, 1355 (byte) 0x00, 1356 (byte) 0x00, 1357 (byte) 0x00, 1358 (byte) 0x00, // UNKNOWN_CODEC 1359 (byte) 0x02, // mCodecConfigLength 1360 (byte) 0x01, 1361 (byte) 'A', // mCodecConfigInfo 1362 (byte) 0x03, // mMetaDataLength 1363 (byte) 0x06, 1364 (byte) 0x07, 1365 (byte) 0x08, // mMetaData 1366 // LEVEL 3 1367 (byte) 0x04, // mIndex 1368 (byte) 0x03, // mCodecConfigLength 1369 (byte) 0x02, 1370 (byte) 'B', 1371 (byte) 'C', // mCodecConfigInfo 1372 (byte) 0x05, 1373 (byte) 0xff, 1374 (byte) 0xe0, 1375 (byte) 0x00, 1376 (byte) 0x02, 1377 (byte) 0x15, // manufacturer specific data 1378 (byte) 0x03, 1379 (byte) 0x50, 1380 (byte) 0x01, 1381 (byte) 0x02, // an unknown data type won't cause trouble 1382 }; 1383 } 1384 onPeriodicAdvertisingReport()1385 private void onPeriodicAdvertisingReport() { 1386 byte[] scanRecord = getPAScanRecord(); 1387 ScanRecord record = ScanRecord.parseFromBytes(scanRecord); 1388 PeriodicAdvertisingReport report = 1389 new PeriodicAdvertisingReport(TEST_SYNC_HANDLE, 0, 0, 0, record); 1390 BassClientService.PACallback callback = mBassClientService.new PACallback(); 1391 callback.onPeriodicAdvertisingReport(report); 1392 } 1393 onBigInfoAdvertisingReport()1394 private void onBigInfoAdvertisingReport() { 1395 BassClientService.PACallback callback = mBassClientService.new PACallback(); 1396 callback.onBigInfoAdvertisingReport(TEST_SYNC_HANDLE, true); 1397 } 1398 onSyncLost()1399 private void onSyncLost() { 1400 BassClientService.PACallback callback = mBassClientService.new PACallback(); 1401 callback.onSyncLost(TEST_SYNC_HANDLE); 1402 } 1403 onSyncEstablished(BluetoothDevice testDevice, int syncHandle)1404 private void onSyncEstablished(BluetoothDevice testDevice, int syncHandle) { 1405 BassClientService.PACallback callback = mBassClientService.new PACallback(); 1406 callback.onSyncEstablished( 1407 syncHandle, testDevice, TEST_ADVERTISER_SID, 0, 200, BluetoothGatt.GATT_SUCCESS); 1408 } 1409 onSyncEstablishedFailed(BluetoothDevice testDevice, int syncHandle)1410 private void onSyncEstablishedFailed(BluetoothDevice testDevice, int syncHandle) { 1411 BassClientService.PACallback callback = mBassClientService.new PACallback(); 1412 callback.onSyncEstablished( 1413 syncHandle, testDevice, TEST_ADVERTISER_SID, 0, 200, BluetoothGatt.GATT_FAILURE); 1414 } 1415 handleHandoverSupport()1416 private void handleHandoverSupport() { 1417 /* Unicast finished streaming */ 1418 mBassClientService.handleUnicastSourceStreamStatusChange( 1419 2 /* STATUS_LOCAL_STREAM_SUSPENDED */); 1420 } 1421 verifyAddSourceForGroup(BluetoothLeBroadcastMetadata meta)1422 private void verifyAddSourceForGroup(BluetoothLeBroadcastMetadata meta) { 1423 // Add broadcast source 1424 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 1425 1426 /* In case if device supports handover, Source stream status needs to be updated */ 1427 handleHandoverSupport(); 1428 1429 // Verify all group members getting ADD_BCAST_SOURCE message 1430 assertThat(mStateMachines).hasSize(2); 1431 for (BassClientStateMachine sm : mStateMachines.values()) { 1432 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 1433 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 1434 1435 Message msg = 1436 messageCaptor.getAllValues().stream() 1437 .filter( 1438 m -> 1439 (m.what == BassClientStateMachine.ADD_BCAST_SOURCE) 1440 && (m.obj == meta)) 1441 .findFirst() 1442 .orElse(null); 1443 assertThat(msg).isNotNull(); 1444 clearInvocations(sm); 1445 } 1446 } 1447 injectRemoteSourceState( BassClientStateMachine sm, BluetoothLeBroadcastMetadata meta, int sourceId, int paSynState, int encryptionState, byte[] badCode, long bisSyncState)1448 private static BluetoothLeBroadcastReceiveState injectRemoteSourceState( 1449 BassClientStateMachine sm, 1450 BluetoothLeBroadcastMetadata meta, 1451 int sourceId, 1452 int paSynState, 1453 int encryptionState, 1454 byte[] badCode, 1455 long bisSyncState) { 1456 BluetoothLeBroadcastReceiveState recvState = 1457 new BluetoothLeBroadcastReceiveState( 1458 sourceId, 1459 meta.getSourceAddressType(), 1460 meta.getSourceDevice(), 1461 meta.getSourceAdvertisingSid(), 1462 meta.getBroadcastId(), 1463 paSynState, 1464 encryptionState, 1465 badCode, 1466 meta.getSubgroups().size(), 1467 // Bis sync states 1468 meta.getSubgroups().stream() 1469 .map(e -> bisSyncState) 1470 .collect(Collectors.toList()), 1471 meta.getSubgroups().stream() 1472 .map(e -> e.getContentMetadata()) 1473 .collect(Collectors.toList())); 1474 doReturn(meta).when(sm).getCurrentBroadcastMetadata(eq(sourceId)); 1475 1476 List<BluetoothLeBroadcastReceiveState> stateList = sm.getAllSources(); 1477 if (stateList == null) { 1478 stateList = new ArrayList<BluetoothLeBroadcastReceiveState>(); 1479 } else { 1480 stateList.removeIf(e -> e.getSourceId() == sourceId); 1481 } 1482 stateList.add(recvState); 1483 doReturn(stateList).when(sm).getAllSources(); 1484 1485 return recvState; 1486 } 1487 injectRemoteSourceStateSourceAdded( BassClientStateMachine sm, BluetoothLeBroadcastMetadata meta, int sourceId, int paSynState, int encryptionState, byte[] badCode)1488 private BluetoothLeBroadcastReceiveState injectRemoteSourceStateSourceAdded( 1489 BassClientStateMachine sm, 1490 BluetoothLeBroadcastMetadata meta, 1491 int sourceId, 1492 int paSynState, 1493 int encryptionState, 1494 byte[] badCode) { 1495 BluetoothLeBroadcastReceiveState recvState = 1496 injectRemoteSourceState( 1497 sm, 1498 meta, 1499 sourceId, 1500 paSynState, 1501 encryptionState, 1502 badCode, 1503 (long) 0x00000000); 1504 1505 mBassClientService 1506 .getCallbacks() 1507 .notifySourceAdded( 1508 sm.getDevice(), recvState, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST); 1509 mBassClientService 1510 .getCallbacks() 1511 .notifyReceiveStateChanged(sm.getDevice(), recvState.getSourceId(), recvState); 1512 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 1513 1514 return recvState; 1515 } 1516 injectRemoteSourceStateChanged( BassClientStateMachine sm, BluetoothLeBroadcastMetadata meta, int sourceId, int paSynState, int encryptionState, byte[] badCode, long bisSyncState)1517 private BluetoothLeBroadcastReceiveState injectRemoteSourceStateChanged( 1518 BassClientStateMachine sm, 1519 BluetoothLeBroadcastMetadata meta, 1520 int sourceId, 1521 int paSynState, 1522 int encryptionState, 1523 byte[] badCode, 1524 long bisSyncState) { 1525 BluetoothLeBroadcastReceiveState recvState = 1526 injectRemoteSourceState( 1527 sm, meta, sourceId, paSynState, encryptionState, badCode, bisSyncState); 1528 1529 mBassClientService 1530 .getCallbacks() 1531 .notifyReceiveStateChanged(sm.getDevice(), recvState.getSourceId(), recvState); 1532 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 1533 1534 return recvState; 1535 } 1536 injectRemoteSourceStateChanged( BassClientStateMachine sm, BluetoothLeBroadcastMetadata meta, boolean isPaSynced, boolean isBisSynced)1537 private void injectRemoteSourceStateChanged( 1538 BassClientStateMachine sm, 1539 BluetoothLeBroadcastMetadata meta, 1540 boolean isPaSynced, 1541 boolean isBisSynced) { 1542 // Update receiver state 1543 if (sm.getDevice().equals(mCurrentDevice)) { 1544 injectRemoteSourceStateChanged( 1545 sm, 1546 meta, 1547 TEST_SOURCE_ID, 1548 isPaSynced 1549 ? BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED 1550 : BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 1551 meta.isEncrypted() 1552 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 1553 : BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 1554 null, 1555 isBisSynced ? (long) 0x00000001 : (long) 0x00000000); 1556 } else if (sm.getDevice().equals(mCurrentDevice1)) { 1557 injectRemoteSourceStateChanged( 1558 sm, 1559 meta, 1560 TEST_SOURCE_ID + 1, 1561 isPaSynced 1562 ? BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED 1563 : BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 1564 meta.isEncrypted() 1565 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 1566 : BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 1567 null, 1568 isBisSynced ? (long) 0x00000002 : (long) 0x00000000); 1569 } 1570 } 1571 injectRemoteSourceStateChanged( BluetoothLeBroadcastMetadata meta, boolean isPaSynced, boolean isBisSynced)1572 private void injectRemoteSourceStateChanged( 1573 BluetoothLeBroadcastMetadata meta, boolean isPaSynced, boolean isBisSynced) { 1574 for (BassClientStateMachine sm : mStateMachines.values()) { 1575 injectRemoteSourceStateChanged(sm, meta, isPaSynced, isBisSynced); 1576 } 1577 } 1578 injectRemoteSourceStateChanged( BluetoothLeBroadcastMetadata meta, int paSynState, boolean isBisSynced)1579 private void injectRemoteSourceStateChanged( 1580 BluetoothLeBroadcastMetadata meta, int paSynState, boolean isBisSynced) { 1581 for (BassClientStateMachine sm : mStateMachines.values()) { 1582 // Update receiver state 1583 if (sm.getDevice().equals(mCurrentDevice)) { 1584 injectRemoteSourceStateChanged( 1585 sm, 1586 meta, 1587 TEST_SOURCE_ID, 1588 paSynState, 1589 meta.isEncrypted() 1590 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 1591 : BluetoothLeBroadcastReceiveState 1592 .BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 1593 null, 1594 isBisSynced ? (long) 0x00000001 : (long) 0x00000000); 1595 } else if (sm.getDevice().equals(mCurrentDevice1)) { 1596 injectRemoteSourceStateChanged( 1597 sm, 1598 meta, 1599 TEST_SOURCE_ID + 1, 1600 paSynState, 1601 meta.isEncrypted() 1602 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 1603 : BluetoothLeBroadcastReceiveState 1604 .BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 1605 null, 1606 isBisSynced ? (long) 0x00000002 : (long) 0x00000000); 1607 } 1608 } 1609 } 1610 injectRemoteSourceStateRemoval(BassClientStateMachine sm, int sourceId)1611 private void injectRemoteSourceStateRemoval(BassClientStateMachine sm, int sourceId) { 1612 List<BluetoothLeBroadcastReceiveState> stateList = sm.getAllSources(); 1613 if (stateList == null) { 1614 stateList = new ArrayList<BluetoothLeBroadcastReceiveState>(); 1615 } 1616 stateList.replaceAll( 1617 e -> { 1618 if (e.getSourceId() != sourceId) return e; 1619 return new BluetoothLeBroadcastReceiveState( 1620 sourceId, 1621 BluetoothDevice.ADDRESS_TYPE_PUBLIC, 1622 mBluetoothAdapter.getRemoteLeDevice( 1623 "00:00:00:00:00:00", BluetoothDevice.ADDRESS_TYPE_PUBLIC), 1624 0, 1625 0, 1626 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 1627 BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 1628 null, 1629 0, 1630 Arrays.asList(new Long[0]), 1631 Arrays.asList(new BluetoothLeAudioContentMetadata[0])); 1632 }); 1633 doReturn(stateList).when(sm).getAllSources(); 1634 1635 Optional<BluetoothLeBroadcastReceiveState> receiveState = 1636 stateList.stream().filter(e -> e.getSourceId() == sourceId).findFirst(); 1637 1638 mBassClientService 1639 .getCallbacks() 1640 .notifySourceRemoved( 1641 sm.getDevice(), sourceId, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST); 1642 mBassClientService 1643 .getCallbacks() 1644 .notifyReceiveStateChanged(sm.getDevice(), sourceId, receiveState.get()); 1645 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 1646 } 1647 prepareRemoteSourceState( BluetoothLeBroadcastMetadata meta, boolean isPaSynced, boolean isBisSynced)1648 private void prepareRemoteSourceState( 1649 BluetoothLeBroadcastMetadata meta, boolean isPaSynced, boolean isBisSynced) { 1650 for (BassClientStateMachine sm : mStateMachines.values()) { 1651 if (sm.getDevice().equals(mCurrentDevice)) { 1652 injectRemoteSourceStateSourceAdded( 1653 sm, 1654 meta, 1655 TEST_SOURCE_ID, 1656 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 1657 meta.isEncrypted() 1658 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 1659 : BluetoothLeBroadcastReceiveState 1660 .BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 1661 null); 1662 } else if (sm.getDevice().equals(mCurrentDevice1)) { 1663 injectRemoteSourceStateSourceAdded( 1664 sm, 1665 meta, 1666 TEST_SOURCE_ID + 1, 1667 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 1668 meta.isEncrypted() 1669 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 1670 : BluetoothLeBroadcastReceiveState 1671 .BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 1672 null); 1673 } 1674 } 1675 injectRemoteSourceStateChanged(meta, isPaSynced, isBisSynced); 1676 } 1677 1678 /** 1679 * Test whether service.addSource() does send proper messages to all the state machines within 1680 * the Csip coordinated group 1681 */ 1682 @Test testAddSourceForGroup()1683 public void testAddSourceForGroup() { 1684 prepareConnectedDeviceGroup(); 1685 startSearchingForSources(); 1686 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 1687 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 1688 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 1689 verifyAddSourceForGroup(meta); 1690 } 1691 1692 /** Test whether service.addSource() source id can be propagated through callback correctly */ 1693 @Test testAddSourceCallbackForGroup()1694 public void testAddSourceCallbackForGroup() throws RemoteException { 1695 prepareConnectedDeviceGroup(); 1696 startSearchingForSources(); 1697 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 1698 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 1699 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 1700 verifyAddSourceForGroup(meta); 1701 for (BassClientStateMachine sm : mStateMachines.values()) { 1702 if (sm.getDevice().equals(mCurrentDevice)) { 1703 injectRemoteSourceStateSourceAdded( 1704 sm, 1705 meta, 1706 TEST_SOURCE_ID, 1707 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 1708 meta.isEncrypted() 1709 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 1710 : BluetoothLeBroadcastReceiveState 1711 .BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 1712 null); 1713 // verify source id 1714 verify(mCallback, timeout(TIMEOUT_MS).atLeastOnce()) 1715 .onSourceAdded( 1716 eq(mCurrentDevice), 1717 eq(TEST_SOURCE_ID), 1718 eq(BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST)); 1719 } else if (sm.getDevice().equals(mCurrentDevice1)) { 1720 injectRemoteSourceStateSourceAdded( 1721 sm, 1722 meta, 1723 TEST_SOURCE_ID + 1, 1724 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 1725 meta.isEncrypted() 1726 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 1727 : BluetoothLeBroadcastReceiveState 1728 .BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 1729 null); 1730 // verify source id 1731 verify(mCallback, timeout(TIMEOUT_MS).atLeastOnce()) 1732 .onSourceAdded( 1733 eq(mCurrentDevice1), 1734 eq(TEST_SOURCE_ID + 1), 1735 eq(BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST)); 1736 } 1737 } 1738 } 1739 1740 /** 1741 * Test whether service.modifySource() does send proper messages to all the state machines 1742 * within the Csip coordinated group 1743 */ 1744 @Test testModifySourceForGroup()1745 public void testModifySourceForGroup() { 1746 prepareConnectedDeviceGroup(); 1747 startSearchingForSources(); 1748 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 1749 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 1750 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 1751 verifyAddSourceForGroup(meta); 1752 prepareRemoteSourceState(meta, /* isPaSynced */ true, /* isBisSynced */ false); 1753 1754 // Update broadcast source using other member of the same group 1755 BluetoothLeBroadcastMetadata metaUpdate = 1756 new BluetoothLeBroadcastMetadata.Builder(meta) 1757 .setBroadcastId(TEST_BROADCAST_ID + 1) 1758 .build(); 1759 mBassClientService.modifySource(mCurrentDevice1, TEST_SOURCE_ID + 1, metaUpdate); 1760 1761 // Verify all group members getting UPDATE_BCAST_SOURCE message on proper sources 1762 expect.that(mStateMachines.size()).isEqualTo(2); 1763 for (BassClientStateMachine sm : mStateMachines.values()) { 1764 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 1765 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 1766 1767 Optional<Message> msg = 1768 messageCaptor.getAllValues().stream() 1769 .filter(m -> m.what == BassClientStateMachine.UPDATE_BCAST_SOURCE) 1770 .findFirst(); 1771 expect.that(msg.isPresent()).isEqualTo(true); 1772 expect.that(msg.get().obj).isEqualTo(metaUpdate); 1773 1774 // Verify using the right sourceId on each device 1775 if (sm.getDevice().equals(mCurrentDevice)) { 1776 expect.that(msg.get().arg1).isEqualTo(TEST_SOURCE_ID); 1777 } else if (sm.getDevice().equals(mCurrentDevice1)) { 1778 expect.that(msg.get().arg1).isEqualTo(TEST_SOURCE_ID + 1); 1779 } 1780 } 1781 } 1782 1783 /** 1784 * Test whether service.removeSource() does send proper messages to all the state machines 1785 * within the Csip coordinated group 1786 */ 1787 @Test testRemoveSourceForGroup()1788 public void testRemoveSourceForGroup() { 1789 prepareConnectedDeviceGroup(); 1790 startSearchingForSources(); 1791 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 1792 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 1793 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 1794 verifyAddSourceForGroup(meta); 1795 prepareRemoteSourceState(meta, /* isPaSynced */ true, /* isBisSynced */ false); 1796 1797 // Remove broadcast source using other member of the same group 1798 mBassClientService.removeSource(mCurrentDevice1, TEST_SOURCE_ID + 1); 1799 1800 // Verify all group members getting REMOVE_BCAST_SOURCE message 1801 expect.that(mStateMachines.size()).isEqualTo(2); 1802 for (BassClientStateMachine sm : mStateMachines.values()) { 1803 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 1804 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 1805 1806 Optional<Message> msg = 1807 messageCaptor.getAllValues().stream() 1808 .filter(m -> m.what == BassClientStateMachine.REMOVE_BCAST_SOURCE) 1809 .findFirst(); 1810 expect.that(msg.isPresent()).isEqualTo(true); 1811 1812 // Verify using the right sourceId on each device 1813 if (sm.getDevice().equals(mCurrentDevice)) { 1814 expect.that(msg.get().arg1).isEqualTo(TEST_SOURCE_ID); 1815 } else if (sm.getDevice().equals(mCurrentDevice1)) { 1816 expect.that(msg.get().arg1).isEqualTo(TEST_SOURCE_ID + 1); 1817 } 1818 } 1819 } 1820 1821 /** 1822 * Test whether service.removeSource() does send modify source to all the state machines if 1823 * either PA or BIS is synced 1824 */ 1825 @Test testRemoveSourceForGroupAndTriggerModifySource()1826 public void testRemoveSourceForGroupAndTriggerModifySource() { 1827 prepareConnectedDeviceGroup(); 1828 startSearchingForSources(); 1829 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 1830 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 1831 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 1832 verifyAddSourceForGroup(meta); 1833 for (BassClientStateMachine sm : mStateMachines.values()) { 1834 injectRemoteSourceStateSourceAdded( 1835 sm, 1836 meta, 1837 TEST_SOURCE_ID, 1838 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED, 1839 meta.isEncrypted() 1840 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 1841 : BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 1842 null); 1843 doReturn(meta).when(sm).getCurrentBroadcastMetadata(eq(TEST_SOURCE_ID)); 1844 doReturn(true).when(sm).isSyncedToTheSource(eq(TEST_SOURCE_ID)); 1845 } 1846 1847 // Remove broadcast source 1848 mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); 1849 1850 // Verify all group members getting UPDATE_BCAST_SOURCE message 1851 // because PA state is synced 1852 assertThat(mStateMachines).hasSize(2); 1853 for (BassClientStateMachine sm : mStateMachines.values()) { 1854 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 1855 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 1856 1857 Optional<Message> msg = 1858 messageCaptor.getAllValues().stream() 1859 .filter(m -> m.what == BassClientStateMachine.UPDATE_BCAST_SOURCE) 1860 .findFirst(); 1861 assertThat(msg.isPresent()).isEqualTo(true); 1862 1863 // Verify using the right sourceId on each device 1864 assertThat(msg.get().arg1).isEqualTo(TEST_SOURCE_ID); 1865 } 1866 1867 for (BassClientStateMachine sm : mStateMachines.values()) { 1868 // Update receiver state 1869 injectRemoteSourceStateChanged( 1870 sm, 1871 meta, 1872 TEST_SOURCE_ID, 1873 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 1874 meta.isEncrypted() 1875 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 1876 : BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 1877 null, 1878 (long) 0x00000001); 1879 } 1880 1881 // Remove broadcast source 1882 mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); 1883 1884 // Verify all group members getting UPDATE_BCAST_SOURCE message if 1885 // bis sync state is non-zero and pa sync state is not synced 1886 assertThat(mStateMachines).hasSize(2); 1887 for (BassClientStateMachine sm : mStateMachines.values()) { 1888 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 1889 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 1890 1891 Optional<Message> msg = 1892 messageCaptor.getAllValues().stream() 1893 .filter(m -> m.what == BassClientStateMachine.UPDATE_BCAST_SOURCE) 1894 .findFirst(); 1895 assertThat(msg.isPresent()).isEqualTo(true); 1896 1897 // Verify using the right sourceId on each device 1898 assertThat(msg.get().arg1).isEqualTo(TEST_SOURCE_ID); 1899 } 1900 1901 for (BassClientStateMachine sm : mStateMachines.values()) { 1902 injectRemoteSourceStateRemoval(sm, TEST_SOURCE_ID); 1903 } 1904 1905 verify(mLeAudioService).activeBroadcastAssistantNotification(eq(false)); 1906 } 1907 verifyRemoveMessageAndInjectSourceRemoval()1908 private void verifyRemoveMessageAndInjectSourceRemoval() { 1909 for (BassClientStateMachine sm : mStateMachines.values()) { 1910 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 1911 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 1912 1913 Optional<Message> msg = 1914 messageCaptor.getAllValues().stream() 1915 .filter(m -> m.what == BassClientStateMachine.REMOVE_BCAST_SOURCE) 1916 .findFirst(); 1917 assertThat(msg.isPresent()).isEqualTo(true); 1918 1919 if (sm.getDevice().equals(mCurrentDevice)) { 1920 assertThat(msg.get().arg1).isEqualTo(TEST_SOURCE_ID); 1921 injectRemoteSourceStateRemoval(sm, TEST_SOURCE_ID); 1922 } else if (sm.getDevice().equals(mCurrentDevice1)) { 1923 assertThat(msg.get().arg1).isEqualTo(TEST_SOURCE_ID + 1); 1924 injectRemoteSourceStateRemoval(sm, TEST_SOURCE_ID + 1); 1925 } 1926 } 1927 } 1928 verifyModifyMessageAndInjectSourceModfified()1929 private void verifyModifyMessageAndInjectSourceModfified() { 1930 for (BassClientStateMachine sm : mStateMachines.values()) { 1931 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 1932 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 1933 1934 Optional<Message> msg = 1935 messageCaptor.getAllValues().stream() 1936 .filter(m -> m.what == BassClientStateMachine.UPDATE_BCAST_SOURCE) 1937 .findFirst(); 1938 assertThat(msg.isPresent()).isEqualTo(true); 1939 1940 if (sm.getDevice().equals(mCurrentDevice)) { 1941 assertThat(msg.get().arg1).isEqualTo(TEST_SOURCE_ID); 1942 injectRemoteSourceStateChanged( 1943 sm, createBroadcastMetadata(TEST_BROADCAST_ID), false, false); 1944 } else if (sm.getDevice().equals(mCurrentDevice1)) { 1945 assertThat(msg.get().arg1).isEqualTo(TEST_SOURCE_ID + 1); 1946 injectRemoteSourceStateChanged( 1947 sm, createBroadcastMetadata(TEST_BROADCAST_ID), false, false); 1948 } 1949 } 1950 } 1951 1952 /** 1953 * Test whether service.removeSource() does send modify source if source is from remote receive 1954 * state. In this case, assistant should be able to remove source which was not managed by BASS 1955 * service (external manager/no source metadata) 1956 */ 1957 @Test testRemoveSourceForGroupAndTriggerModifySourceWithoutMetadata()1958 public void testRemoveSourceForGroupAndTriggerModifySourceWithoutMetadata() { 1959 prepareConnectedDeviceGroup(); 1960 startSearchingForSources(); 1961 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 1962 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 1963 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 1964 1965 for (BassClientStateMachine sm : mStateMachines.values()) { 1966 injectRemoteSourceStateSourceAdded( 1967 sm, 1968 meta, 1969 TEST_SOURCE_ID, 1970 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED, 1971 meta.isEncrypted() 1972 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 1973 : BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 1974 null); 1975 // no current broadcast metadata for external broadcast source 1976 doReturn(null).when(sm).getCurrentBroadcastMetadata(eq(TEST_SOURCE_ID)); 1977 doReturn(true).when(sm).isSyncedToTheSource(eq(TEST_SOURCE_ID)); 1978 } 1979 1980 for (BassClientStateMachine sm : mStateMachines.values()) { 1981 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 1982 mBassClientService.removeSource(sm.getDevice(), TEST_SOURCE_ID); 1983 // Verify device get update source 1984 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 1985 1986 Optional<Message> msg = 1987 messageCaptor.getAllValues().stream() 1988 .filter(m -> m.what == BassClientStateMachine.UPDATE_BCAST_SOURCE) 1989 .findFirst(); 1990 assertThat(msg.isPresent()).isEqualTo(true); 1991 1992 assertThat(msg.get().arg1).isEqualTo(TEST_SOURCE_ID); 1993 assertThat(msg.get().arg2).isEqualTo(BassConstants.PA_SYNC_DO_NOT_SYNC); 1994 // Verify metadata is null 1995 assertThat(msg.get().obj).isNull(); 1996 } 1997 1998 for (BassClientStateMachine sm : mStateMachines.values()) { 1999 injectRemoteSourceStateRemoval(sm, TEST_SOURCE_ID); 2000 } 2001 } 2002 2003 @Test 2004 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_API_GET_LOCAL_METADATA) testGetSourceMetadata()2005 public void testGetSourceMetadata() { 2006 prepareConnectedDeviceGroup(); 2007 startSearchingForSources(); 2008 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 2009 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 2010 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 2011 2012 for (BassClientStateMachine sm : mStateMachines.values()) { 2013 injectRemoteSourceStateSourceAdded( 2014 sm, 2015 meta, 2016 TEST_SOURCE_ID, 2017 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED, 2018 meta.isEncrypted() 2019 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 2020 : BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 2021 null); 2022 doReturn(null).when(sm).getCurrentBroadcastMetadata(eq(TEST_SOURCE_ID)); 2023 assertThat(mBassClientService.getSourceMetadata(sm.getDevice(), TEST_SOURCE_ID)) 2024 .isNull(); 2025 2026 doReturn(meta).when(sm).getCurrentBroadcastMetadata(eq(TEST_SOURCE_ID)); 2027 doReturn(true).when(sm).isSyncedToTheSource(eq(TEST_SOURCE_ID)); 2028 assertThat(mBassClientService.getSourceMetadata(sm.getDevice(), TEST_SOURCE_ID)) 2029 .isEqualTo(meta); 2030 } 2031 2032 for (BassClientStateMachine sm : mStateMachines.values()) { 2033 injectRemoteSourceStateRemoval(sm, TEST_SOURCE_ID); 2034 } 2035 } 2036 2037 /** Test whether the group operation flag is set on addSource() and removed on removeSource */ 2038 @Test testGroupStickyFlagSetUnset()2039 public void testGroupStickyFlagSetUnset() { 2040 prepareConnectedDeviceGroup(); 2041 startSearchingForSources(); 2042 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 2043 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 2044 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 2045 verifyAddSourceForGroup(meta); 2046 prepareRemoteSourceState(meta, /* isPaSynced */ true, /* isBisSynced */ false); 2047 2048 // Remove broadcast source 2049 mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); 2050 verifyRemoveMessageAndInjectSourceRemoval(); 2051 2052 // Update broadcast source 2053 BluetoothLeBroadcastMetadata metaUpdate = createBroadcastMetadata(TEST_BROADCAST_ID + 1); 2054 mBassClientService.modifySource(mCurrentDevice, TEST_SOURCE_ID, metaUpdate); 2055 2056 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 2057 Optional<Message> msg; 2058 2059 // Verify that one device got the message... 2060 verify(mStateMachines.get(mCurrentDevice), atLeast(1)).sendMessage(messageCaptor.capture()); 2061 msg = 2062 messageCaptor.getAllValues().stream() 2063 .filter(m -> m.what == BassClientStateMachine.UPDATE_BCAST_SOURCE) 2064 .findFirst(); 2065 expect.that(msg.isPresent()).isTrue(); 2066 expect.that(msg.orElse(null)).isNotNull(); 2067 2068 // ... but not the other one, since the sticky group flag should have been removed 2069 messageCaptor = ArgumentCaptor.forClass(Message.class); 2070 verify(mStateMachines.get(mCurrentDevice1), atLeast(1)) 2071 .sendMessage(messageCaptor.capture()); 2072 msg = 2073 messageCaptor.getAllValues().stream() 2074 .filter(m -> m.what == BassClientStateMachine.UPDATE_BCAST_SOURCE) 2075 .findFirst(); 2076 expect.that(msg.isPresent()).isFalse(); 2077 } 2078 2079 /** Test switch source will be triggered if adding new source when sink has source */ 2080 @Test testSwitchSourceAfterSourceAdded()2081 public void testSwitchSourceAfterSourceAdded() { 2082 prepareConnectedDeviceGroup(); 2083 startSearchingForSources(); 2084 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 2085 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 2086 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 2087 BluetoothLeBroadcastMetadata newMeta = createBroadcastMetadata(TEST_BROADCAST_ID + 1); 2088 verifyAddSourceForGroup(meta); 2089 prepareRemoteSourceState(meta, /* isPaSynced */ true, /* isBisSynced */ true); 2090 2091 // Add another new broadcast source 2092 onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1); 2093 onSyncEstablished(mSourceDevice2, TEST_SYNC_HANDLE + 1); 2094 mBassClientService.addSource(mCurrentDevice, newMeta, /* isGroupOp */ true); 2095 2096 // Verify all group members getting SWITCH_BCAST_SOURCE message and first source got 2097 // selected to remove 2098 expect.that(mStateMachines.size()).isEqualTo(2); 2099 for (BassClientStateMachine sm : mStateMachines.values()) { 2100 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 2101 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 2102 if (sm.getDevice().equals(mCurrentDevice)) { 2103 Optional<Message> msg = 2104 messageCaptor.getAllValues().stream() 2105 .filter( 2106 m -> 2107 (m.what 2108 == BassClientStateMachine 2109 .SWITCH_BCAST_SOURCE) 2110 && (m.obj == newMeta) 2111 && (m.arg1 == TEST_SOURCE_ID)) 2112 .findFirst(); 2113 expect.that(msg.isPresent()).isTrue(); 2114 expect.that(msg.orElse(null)).isNotNull(); 2115 } else if (sm.getDevice().equals(mCurrentDevice1)) { 2116 Optional<Message> msg = 2117 messageCaptor.getAllValues().stream() 2118 .filter( 2119 m -> 2120 (m.what 2121 == BassClientStateMachine 2122 .SWITCH_BCAST_SOURCE) 2123 && (m.obj == newMeta) 2124 && (m.arg1 == TEST_SOURCE_ID + 1)) 2125 .findFirst(); 2126 expect.that(msg.isPresent()).isTrue(); 2127 expect.that(msg.orElse(null)).isNotNull(); 2128 } else { 2129 throw new AssertionError("Unexpected device"); 2130 } 2131 } 2132 } 2133 2134 @Test testSecondAddSourceWithCapacityGreaterThanOne()2135 public void testSecondAddSourceWithCapacityGreaterThanOne() { 2136 prepareConnectedDeviceGroup(); 2137 2138 // Set maximum source capacity to 2 2139 for (BassClientStateMachine sm : mStateMachines.values()) { 2140 doReturn(2).when(sm).getMaximumSourceCapacity(); 2141 } 2142 2143 startSearchingForSources(); 2144 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 2145 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 2146 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 2147 verifyAddSourceForGroup(meta); 2148 prepareRemoteSourceState(meta, /* isPaSynced */ true, /* isBisSynced */ true); 2149 2150 // Add another new broadcast source 2151 onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1); 2152 onSyncEstablished(mSourceDevice2, TEST_SYNC_HANDLE + 1); 2153 BluetoothLeBroadcastMetadata newMeta = createBroadcastMetadata(TEST_BROADCAST_ID + 1); 2154 verifyAddSourceForGroup(newMeta); 2155 } 2156 2157 /** 2158 * Test that after multiple calls to service.addSource() with a group operation flag set, there 2159 * are two call to service.removeSource() needed to clear the flag 2160 */ 2161 @Test testAddRemoveMultipleSourcesForGroup()2162 public void testAddRemoveMultipleSourcesForGroup() { 2163 prepareConnectedDeviceGroup(); 2164 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 2165 2166 // Add more room for the source broadcasts 2167 for (BassClientStateMachine sm : mStateMachines.values()) { 2168 if (sm.getDevice().equals(mCurrentDevice)) { 2169 injectRemoteSourceStateSourceAdded( 2170 sm, 2171 meta, 2172 TEST_SOURCE_ID + 1, 2173 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 2174 meta.isEncrypted() 2175 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 2176 : BluetoothLeBroadcastReceiveState 2177 .BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 2178 null); 2179 injectRemoteSourceStateRemoval(sm, TEST_SOURCE_ID + 1); 2180 } else if (sm.getDevice().equals(mCurrentDevice1)) { 2181 injectRemoteSourceStateSourceAdded( 2182 sm, 2183 meta, 2184 TEST_SOURCE_ID, 2185 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 2186 meta.isEncrypted() 2187 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 2188 : BluetoothLeBroadcastReceiveState 2189 .BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 2190 null); 2191 injectRemoteSourceStateRemoval(sm, TEST_SOURCE_ID); 2192 } 2193 } 2194 2195 startSearchingForSources(); 2196 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 2197 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 2198 verifyAddSourceForGroup(meta); 2199 assertThat(mStateMachines).hasSize(2); 2200 prepareRemoteSourceState(meta, /* isPaSynced */ true, /* isBisSynced */ true); 2201 2202 // Add another broadcast source 2203 BluetoothLeBroadcastMetadata meta1 = 2204 new BluetoothLeBroadcastMetadata.Builder(meta) 2205 .setBroadcastId(TEST_BROADCAST_ID + 1) 2206 .build(); 2207 onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1); 2208 onSyncEstablished(mSourceDevice2, TEST_SYNC_HANDLE + 1); 2209 verifyAddSourceForGroup(meta1); 2210 assertThat(mStateMachines).hasSize(2); 2211 for (BassClientStateMachine sm : mStateMachines.values()) { 2212 if (sm.getDevice().equals(mCurrentDevice)) { 2213 injectRemoteSourceStateSourceAdded( 2214 sm, 2215 meta1, 2216 TEST_SOURCE_ID + 2, 2217 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 2218 meta1.isEncrypted() 2219 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 2220 : BluetoothLeBroadcastReceiveState 2221 .BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 2222 null); 2223 } else if (sm.getDevice().equals(mCurrentDevice1)) { 2224 injectRemoteSourceStateSourceAdded( 2225 sm, 2226 meta1, 2227 TEST_SOURCE_ID + 3, 2228 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 2229 meta1.isEncrypted() 2230 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 2231 : BluetoothLeBroadcastReceiveState 2232 .BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 2233 null); 2234 } else { 2235 throw new AssertionError("Unexpected device"); 2236 } 2237 } 2238 2239 // Remove the first broadcast source 2240 mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); 2241 assertThat(mStateMachines).hasSize(2); 2242 verifyRemoveMessageAndInjectSourceRemoval(); 2243 2244 // Modify the second one and verify all group members getting UPDATE_BCAST_SOURCE 2245 BluetoothLeBroadcastMetadata metaUpdate = createBroadcastMetadata(TEST_BROADCAST_ID + 3); 2246 mBassClientService.modifySource(mCurrentDevice1, TEST_SOURCE_ID + 3, metaUpdate); 2247 assertThat(mStateMachines).hasSize(2); 2248 for (BassClientStateMachine sm : mStateMachines.values()) { 2249 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 2250 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 2251 2252 Optional<Message> msg = 2253 messageCaptor.getAllValues().stream() 2254 .filter(m -> m.what == BassClientStateMachine.UPDATE_BCAST_SOURCE) 2255 .findFirst(); 2256 assertThat(msg.isPresent()).isEqualTo(true); 2257 assertThat(msg.get().obj).isEqualTo(metaUpdate); 2258 2259 // Verify using the right sourceId on each device 2260 if (sm.getDevice().equals(mCurrentDevice)) { 2261 assertThat(msg.get().arg1).isEqualTo(TEST_SOURCE_ID + 2); 2262 } else if (sm.getDevice().equals(mCurrentDevice1)) { 2263 assertThat(msg.get().arg1).isEqualTo(TEST_SOURCE_ID + 3); 2264 } else { 2265 throw new AssertionError("Unexpected device"); 2266 } 2267 } 2268 2269 // Remove the second broadcast source and verify all group members getting 2270 // REMOVE_BCAST_SOURCE message for the second source 2271 mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID + 2); 2272 assertThat(mStateMachines).hasSize(2); 2273 for (BassClientStateMachine sm : mStateMachines.values()) { 2274 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 2275 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 2276 2277 if (sm.getDevice().equals(mCurrentDevice)) { 2278 Optional<Message> msg = 2279 messageCaptor.getAllValues().stream() 2280 .filter( 2281 m -> 2282 (m.what 2283 == BassClientStateMachine 2284 .REMOVE_BCAST_SOURCE) 2285 && (m.arg1 == TEST_SOURCE_ID + 2)) 2286 .findFirst(); 2287 assertThat(msg.isPresent()).isEqualTo(true); 2288 injectRemoteSourceStateRemoval(sm, TEST_SOURCE_ID + 2); 2289 } else if (sm.getDevice().equals(mCurrentDevice1)) { 2290 Optional<Message> msg = 2291 messageCaptor.getAllValues().stream() 2292 .filter( 2293 m -> 2294 (m.what 2295 == BassClientStateMachine 2296 .REMOVE_BCAST_SOURCE) 2297 && (m.arg1 == TEST_SOURCE_ID + 3)) 2298 .findFirst(); 2299 assertThat(msg.isPresent()).isEqualTo(true); 2300 injectRemoteSourceStateRemoval(sm, TEST_SOURCE_ID + 3); 2301 } else { 2302 throw new AssertionError("Unexpected device"); 2303 } 2304 } 2305 2306 // Fake the autonomous source change - or other client setting the source 2307 for (BassClientStateMachine sm : mStateMachines.values()) { 2308 clearInvocations(sm); 2309 2310 BluetoothLeBroadcastMetadata metaOther = 2311 createBroadcastMetadata(TEST_BROADCAST_ID + 20); 2312 injectRemoteSourceStateSourceAdded( 2313 sm, 2314 metaOther, 2315 TEST_SOURCE_ID + 20, 2316 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 2317 meta.isEncrypted() 2318 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 2319 : BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 2320 null); 2321 } 2322 2323 // Modify this source and verify it is not group managed 2324 BluetoothLeBroadcastMetadata metaUpdate2 = createBroadcastMetadata(TEST_BROADCAST_ID + 30); 2325 mBassClientService.modifySource(mCurrentDevice1, TEST_SOURCE_ID + 20, metaUpdate2); 2326 for (BassClientStateMachine sm : mStateMachines.values()) { 2327 if (sm.getDevice().equals(mCurrentDevice)) { 2328 verify(sm, never()).sendMessage(any()); 2329 } else if (sm.getDevice().equals(mCurrentDevice1)) { 2330 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 2331 verify(sm).sendMessage(messageCaptor.capture()); 2332 List<Message> msgs = 2333 messageCaptor.getAllValues().stream() 2334 .filter( 2335 m -> 2336 (m.what 2337 == BassClientStateMachine 2338 .UPDATE_BCAST_SOURCE) 2339 && (m.arg1 == TEST_SOURCE_ID + 20)) 2340 .collect(Collectors.toList()); 2341 assertThat(msgs).hasSize(1); 2342 } else { 2343 throw new AssertionError("Unexpected device"); 2344 } 2345 } 2346 } 2347 2348 @Test testInvalidRequestForGroup()2349 public void testInvalidRequestForGroup() throws RemoteException { 2350 // Prepare the initial state 2351 prepareConnectedDeviceGroup(); 2352 2353 // Verify errors are reported for the entire group 2354 mBassClientService.addSource(mCurrentDevice1, null, /* isGroupOp */ true); 2355 assertThat(mStateMachines).hasSize(2); 2356 for (BassClientStateMachine sm : mStateMachines.values()) { 2357 verify(sm, never()).sendMessage(any()); 2358 } 2359 startSearchingForSources(); 2360 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 2361 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 2362 // Prepare valid source for group 2363 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 2364 verifyAddSourceForGroup(meta); 2365 prepareRemoteSourceState(meta, /* isPaSynced */ true, /* isBisSynced */ false); 2366 2367 // Verify errors are reported for the entire group 2368 mBassClientService.modifySource(mCurrentDevice, TEST_SOURCE_ID, null); 2369 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 2370 assertThat(mStateMachines).hasSize(2); 2371 for (BassClientStateMachine sm : mStateMachines.values()) { 2372 if (sm.getDevice().equals(mCurrentDevice)) { 2373 verify(mCallback) 2374 .onSourceModifyFailed( 2375 eq(sm.getDevice()), 2376 eq(TEST_SOURCE_ID), 2377 eq(BluetoothStatusCodes.ERROR_BAD_PARAMETERS)); 2378 } else if (sm.getDevice().equals(mCurrentDevice1)) { 2379 verify(mCallback) 2380 .onSourceModifyFailed( 2381 eq(sm.getDevice()), 2382 eq(TEST_SOURCE_ID + 1), 2383 eq(BluetoothStatusCodes.ERROR_BAD_PARAMETERS)); 2384 } 2385 } 2386 2387 assertThat(mStateMachines).hasSize(2); 2388 for (BassClientStateMachine sm : mStateMachines.values()) { 2389 doReturn(STATE_DISCONNECTED).when(sm).getConnectionState(); 2390 } 2391 2392 // Verify errors are reported for the entire group 2393 mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); 2394 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 2395 assertThat(mStateMachines).hasSize(2); 2396 for (BassClientStateMachine sm : mStateMachines.values()) { 2397 if (sm.getDevice().equals(mCurrentDevice)) { 2398 verify(mCallback) 2399 .onSourceRemoveFailed( 2400 eq(sm.getDevice()), 2401 eq(TEST_SOURCE_ID), 2402 eq(BluetoothStatusCodes.ERROR_REMOTE_LINK_ERROR)); 2403 } else if (sm.getDevice().equals(mCurrentDevice1)) { 2404 verify(mCallback) 2405 .onSourceRemoveFailed( 2406 eq(sm.getDevice()), 2407 eq(TEST_SOURCE_ID + 1), 2408 eq(BluetoothStatusCodes.ERROR_REMOTE_LINK_ERROR)); 2409 } 2410 } 2411 } 2412 2413 /** 2414 * Test that an outgoing connection to two device that have BASS UUID is successful and a 2415 * connection state change intent is sent 2416 */ 2417 @Test testConnectedIntent()2418 public void testConnectedIntent() { 2419 prepareConnectedDeviceGroup(); 2420 2421 expect.that(mStateMachines.size()).isEqualTo(2); 2422 for (BassClientStateMachine sm : mStateMachines.values()) { 2423 BluetoothDevice dev = sm.getDevice(); 2424 verifyConnectionStateIntent(dev, STATE_CONNECTED, STATE_CONNECTING); 2425 } 2426 2427 List<BluetoothDevice> devices = mBassClientService.getConnectedDevices(); 2428 expect.that(devices.contains(mCurrentDevice)).isTrue(); 2429 expect.that(devices.contains(mCurrentDevice1)).isTrue(); 2430 } 2431 2432 @Test testActiveSyncedSource_AddRemoveGet()2433 public void testActiveSyncedSource_AddRemoveGet() { 2434 final int handle1 = 1; 2435 final int handle2 = 2; 2436 final int handle3 = 3; 2437 2438 // Check if empty 2439 assertThat(mBassClientService.getActiveSyncedSources()).isEmpty(); 2440 2441 // Check adding first handle 2442 mBassClientService.addActiveSyncedSource(handle1); 2443 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 2444 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(handle1); 2445 2446 // Check if cannot add duplicate element 2447 mBassClientService.addActiveSyncedSource(handle1); 2448 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 2449 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(handle1); 2450 2451 // Check adding second element 2452 mBassClientService.addActiveSyncedSource(handle2); 2453 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(2); 2454 assertThat(mBassClientService.getActiveSyncedSources()) 2455 .containsExactly(handle1, handle2) 2456 .inOrder(); 2457 2458 // Check removing non existing element 2459 mBassClientService.removeActiveSyncedSource(handle3); 2460 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(2); 2461 assertThat(mBassClientService.getActiveSyncedSources()) 2462 .containsExactly(handle1, handle2) 2463 .inOrder(); 2464 // Check removing second element 2465 mBassClientService.removeActiveSyncedSource(handle1); 2466 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 2467 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(handle2); 2468 2469 // Check removing first element 2470 mBassClientService.removeActiveSyncedSource(handle2); 2471 assertThat(mBassClientService.getActiveSyncedSources()).isEmpty(); 2472 2473 // Add 2 elements 2474 mBassClientService.addActiveSyncedSource(handle1); 2475 mBassClientService.addActiveSyncedSource(handle2); 2476 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(2); 2477 2478 // Check removing all at once 2479 mBassClientService.removeActiveSyncedSource(null); 2480 assertThat(mBassClientService.getActiveSyncedSources()).isEmpty(); 2481 } 2482 2483 @Test testScanResult_withSameBroadcastId()2484 public void testScanResult_withSameBroadcastId() { 2485 prepareConnectedDeviceGroup(); 2486 startSearchingForSources(); 2487 2488 // First scanResult 2489 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 2490 mInOrderMethodProxy 2491 .verify(mMethodProxy) 2492 .periodicAdvertisingManagerRegisterSync( 2493 any(), any(), anyInt(), anyInt(), any(), any()); 2494 // Finish select 2495 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 2496 2497 // Second scanResult with the same broadcast id 2498 onScanResult(mSourceDevice2, TEST_BROADCAST_ID); 2499 mInOrderMethodProxy 2500 .verify(mMethodProxy, never()) 2501 .periodicAdvertisingManagerRegisterSync( 2502 any(), any(), anyInt(), anyInt(), any(), any()); 2503 2504 // Third scanResult with new broadcast id 2505 onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1); 2506 mInOrderMethodProxy 2507 .verify(mMethodProxy) 2508 .periodicAdvertisingManagerRegisterSync( 2509 any(), any(), anyInt(), anyInt(), any(), any()); 2510 } 2511 2512 @Test testSelectSource_withSameBroadcastId()2513 public void testSelectSource_withSameBroadcastId() { 2514 prepareConnectedDeviceGroup(); 2515 startSearchingForSources(); 2516 2517 // First selectSource 2518 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 2519 mInOrderMethodProxy 2520 .verify(mMethodProxy) 2521 .periodicAdvertisingManagerRegisterSync( 2522 any(), any(), anyInt(), anyInt(), any(), any()); 2523 // Finish select 2524 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 2525 2526 // Second selectSource with the same broadcast id 2527 onScanResult(mSourceDevice2, TEST_BROADCAST_ID); 2528 mInOrderMethodProxy 2529 .verify(mMethodProxy, never()) 2530 .periodicAdvertisingManagerRegisterSync( 2531 any(), any(), anyInt(), anyInt(), any(), any()); 2532 } 2533 2534 @Test testSelectSource_wrongBassUUID()2535 public void testSelectSource_wrongBassUUID() { 2536 byte[] scanRecord = 2537 new byte[] { 2538 0x02, 2539 0x01, 2540 0x1a, // advertising flags 2541 0x05, 2542 0x02, 2543 0x52, 2544 0x18, 2545 0x0a, 2546 0x11, // 16 bit service uuids 2547 0x04, 2548 0x09, 2549 0x50, 2550 0x65, 2551 0x64, // name 2552 0x02, 2553 0x0A, 2554 (byte) 0xec, // tx power level 2555 0x05, 2556 0x30, 2557 0x54, 2558 0x65, 2559 0x73, 2560 0x74, // broadcast name: Test 2561 0x06, 2562 0x16, 2563 0x00, // WRONG BAAS_UUID UUID 2564 0x18, 2565 (byte) TEST_BROADCAST_ID, 2566 (byte) (TEST_BROADCAST_ID >> 8), 2567 (byte) (TEST_BROADCAST_ID >> 16), // service data, broadcast id 2568 0x08, 2569 0x16, 2570 0x56, 2571 0x18, 2572 0x07, 2573 0x03, 2574 0x06, 2575 0x07, 2576 0x08, 2577 // service data - public broadcast, 2578 // feature - 0x7, metadata len - 0x3, metadata - 0x6, 0x7, 0x8 2579 0x05, 2580 (byte) 0xff, 2581 (byte) 0xe0, 2582 0x00, 2583 0x02, 2584 0x15, // manufacturer specific data 2585 0x03, 2586 0x50, 2587 0x01, 2588 0x02, // an unknown data type won't cause trouble 2589 }; 2590 ScanResult scanResult = 2591 new ScanResult( 2592 mSourceDevice, 2593 0, 2594 0, 2595 0, 2596 0, 2597 0, 2598 TEST_RSSI, 2599 0, 2600 ScanRecord.parseFromBytes(scanRecord), 2601 0); 2602 2603 prepareConnectedDeviceGroup(); 2604 startSearchingForSources(); 2605 generateScanResult(scanResult); 2606 verify(mMethodProxy, never()) 2607 .periodicAdvertisingManagerRegisterSync( 2608 any(), any(), anyInt(), anyInt(), any(), any()); 2609 } 2610 2611 @Test testSyncEstablished_statusFailed()2612 public void testSyncEstablished_statusFailed() { 2613 prepareConnectedDeviceGroup(); 2614 startSearchingForSources(); 2615 2616 // First scanResult 2617 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 2618 mInOrderMethodProxy 2619 .verify(mMethodProxy) 2620 .periodicAdvertisingManagerRegisterSync( 2621 any(), any(), anyInt(), anyInt(), any(), any()); 2622 2623 // Finish select with failed status 2624 onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); 2625 2626 // Could try to sync again 2627 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 2628 mInOrderMethodProxy 2629 .verify(mMethodProxy) 2630 .periodicAdvertisingManagerRegisterSync( 2631 any(), any(), anyInt(), anyInt(), any(), any()); 2632 } 2633 2634 @Test testSelectSource_wrongPublicBroadcastUUID()2635 public void testSelectSource_wrongPublicBroadcastUUID() { 2636 byte[] scanRecord = 2637 new byte[] { 2638 0x02, 2639 0x01, 2640 0x1a, // advertising flags 2641 0x05, 2642 0x02, 2643 0x52, 2644 0x18, 2645 0x0a, 2646 0x11, // 16 bit service uuids 2647 0x04, 2648 0x09, 2649 0x50, 2650 0x65, 2651 0x64, // name 2652 0x02, 2653 0x0A, 2654 (byte) 0xec, // tx power level 2655 0x05, 2656 0x30, 2657 0x54, 2658 0x65, 2659 0x73, 2660 0x74, // broadcast name: Test 2661 0x06, 2662 0x16, 2663 0x52, 2664 0x18, 2665 (byte) TEST_BROADCAST_ID, 2666 (byte) (TEST_BROADCAST_ID >> 8), 2667 (byte) (TEST_BROADCAST_ID >> 16), // service data, broadcast id 2668 0x08, 2669 0x16, 2670 0x00, // WRONG PUBLIC_BROADCAST_UUID 2671 0x18, 2672 0x07, 2673 0x03, 2674 0x06, 2675 0x07, 2676 0x08, 2677 // service data - public broadcast, 2678 // feature - 0x7, metadata len - 0x3, metadata - 0x6, 0x7, 0x8 2679 0x05, 2680 (byte) 0xff, 2681 (byte) 0xe0, 2682 0x00, 2683 0x02, 2684 0x15, // manufacturer specific data 2685 0x03, 2686 0x50, 2687 0x01, 2688 0x02, // an unknown data type won't cause trouble 2689 }; 2690 ScanResult scanResult = 2691 new ScanResult( 2692 mSourceDevice, 2693 0, 2694 0, 2695 0, 2696 0, 2697 0, 2698 TEST_RSSI, 2699 0, 2700 ScanRecord.parseFromBytes(scanRecord), 2701 0); 2702 2703 prepareConnectedDeviceGroup(); 2704 startSearchingForSources(); 2705 generateScanResult(scanResult); 2706 verify(mMethodProxy) 2707 .periodicAdvertisingManagerRegisterSync( 2708 any(), any(), anyInt(), anyInt(), any(), any()); 2709 } 2710 2711 @Test testSelectSource_wrongPublicBroadcastData()2712 public void testSelectSource_wrongPublicBroadcastData() { 2713 byte[] scanRecord = 2714 new byte[] { 2715 0x02, 2716 0x01, 2717 0x1a, // advertising flags 2718 0x05, 2719 0x02, 2720 0x52, 2721 0x18, 2722 0x0a, 2723 0x11, // 16 bit service uuids 2724 0x04, 2725 0x09, 2726 0x50, 2727 0x65, 2728 0x64, // name 2729 0x02, 2730 0x0A, 2731 (byte) 0xec, // tx power level 2732 0x05, 2733 0x30, 2734 0x54, 2735 0x65, 2736 0x73, 2737 0x74, // broadcast name: Test 2738 0x06, 2739 0x16, 2740 0x52, 2741 0x18, 2742 (byte) TEST_BROADCAST_ID, 2743 (byte) (TEST_BROADCAST_ID >> 8), 2744 (byte) (TEST_BROADCAST_ID >> 16), // service data, broadcast id 2745 0x08, 2746 0x16, 2747 0x56, 2748 0x18, 2749 0x07, 2750 0x04, // WRONG PUBLIC_BROADCAST data (metadata size) 2751 0x06, 2752 0x07, 2753 0x08, 2754 // service data - public broadcast, 2755 // feature - 0x7, metadata len - 0x3, metadata - 0x6, 0x7, 0x8 2756 0x05, 2757 (byte) 0xff, 2758 (byte) 0xe0, 2759 0x00, 2760 0x02, 2761 0x15, // manufacturer specific data 2762 0x03, 2763 0x50, 2764 0x01, 2765 0x02, // an unknown data type won't cause trouble 2766 }; 2767 ScanResult scanResult = 2768 new ScanResult( 2769 mSourceDevice, 2770 0, 2771 0, 2772 0, 2773 0, 2774 0, 2775 TEST_RSSI, 2776 0, 2777 ScanRecord.parseFromBytes(scanRecord), 2778 0); 2779 2780 prepareConnectedDeviceGroup(); 2781 startSearchingForSources(); 2782 generateScanResult(scanResult); 2783 verify(mMethodProxy) 2784 .periodicAdvertisingManagerRegisterSync( 2785 any(), any(), anyInt(), anyInt(), any(), any()); 2786 } 2787 2788 @Test testSelectSource_queueAndRemoveAfterMaxLimit()2789 public void testSelectSource_queueAndRemoveAfterMaxLimit() { 2790 final BluetoothDevice device1 = 2791 mBluetoothAdapter.getRemoteLeDevice( 2792 "00:11:22:33:44:11", BluetoothDevice.ADDRESS_TYPE_RANDOM); 2793 final BluetoothDevice device2 = 2794 mBluetoothAdapter.getRemoteLeDevice( 2795 "00:11:22:33:44:22", BluetoothDevice.ADDRESS_TYPE_RANDOM); 2796 final BluetoothDevice device3 = 2797 mBluetoothAdapter.getRemoteLeDevice( 2798 "00:11:22:33:44:33", BluetoothDevice.ADDRESS_TYPE_RANDOM); 2799 final BluetoothDevice device4 = 2800 mBluetoothAdapter.getRemoteLeDevice( 2801 "00:11:22:33:44:44", BluetoothDevice.ADDRESS_TYPE_RANDOM); 2802 final BluetoothDevice device5 = 2803 mBluetoothAdapter.getRemoteLeDevice( 2804 "00:11:22:33:44:55", BluetoothDevice.ADDRESS_TYPE_RANDOM); 2805 final int handle1 = 0; 2806 final int handle2 = 1; 2807 final int handle3 = 2; 2808 final int handle4 = 3; 2809 final int handle5 = 4; 2810 final int broadcastId1 = 1111; 2811 final int broadcastId2 = 2222; 2812 final int broadcastId3 = 3333; 2813 final int broadcastId4 = 4444; 2814 final int broadcastId5 = 5555; 2815 2816 prepareConnectedDeviceGroup(); 2817 startSearchingForSources(); 2818 2819 // Queue two scan requests 2820 onScanResult(device1, broadcastId1); 2821 onScanResult(device2, broadcastId2); 2822 mInOrderMethodProxy 2823 .verify(mMethodProxy) 2824 .periodicAdvertisingManagerRegisterSync( 2825 any(), any(), anyInt(), anyInt(), any(), any()); 2826 2827 // Two SyncRequest queued but not synced yet 2828 assertThat(mBassClientService.getActiveSyncedSources()).isEmpty(); 2829 assertThat(mBassClientService.getDeviceForSyncHandle(handle1)).isNull(); 2830 assertThat(mBassClientService.getDeviceForSyncHandle(handle2)).isNull(); 2831 assertThat(mBassClientService.getDeviceForSyncHandle(handle3)).isNull(); 2832 assertThat(mBassClientService.getDeviceForSyncHandle(handle4)).isNull(); 2833 assertThat(mBassClientService.getDeviceForSyncHandle(handle5)).isNull(); 2834 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle1)) 2835 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 2836 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle2)) 2837 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 2838 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle3)) 2839 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 2840 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle4)) 2841 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 2842 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle5)) 2843 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 2844 2845 // Sync 1 2846 onSyncEstablished(device1, handle1); 2847 mInOrderMethodProxy 2848 .verify(mMethodProxy) 2849 .periodicAdvertisingManagerRegisterSync( 2850 any(), any(), anyInt(), anyInt(), any(), any()); 2851 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 2852 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(handle1); 2853 assertThat(mBassClientService.getDeviceForSyncHandle(handle1)).isEqualTo(device1); 2854 assertThat(mBassClientService.getDeviceForSyncHandle(handle2)).isNull(); 2855 assertThat(mBassClientService.getDeviceForSyncHandle(handle3)).isNull(); 2856 assertThat(mBassClientService.getDeviceForSyncHandle(handle4)).isNull(); 2857 assertThat(mBassClientService.getDeviceForSyncHandle(handle5)).isNull(); 2858 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle1)).isEqualTo(broadcastId1); 2859 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle2)) 2860 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 2861 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle3)) 2862 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 2863 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle4)) 2864 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 2865 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle5)) 2866 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 2867 2868 // Sync 2 2869 onSyncEstablished(device2, handle2); 2870 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(2); 2871 assertThat(mBassClientService.getActiveSyncedSources()) 2872 .containsExactly(handle1, handle2) 2873 .inOrder(); 2874 assertThat(mBassClientService.getDeviceForSyncHandle(handle1)).isEqualTo(device1); 2875 assertThat(mBassClientService.getDeviceForSyncHandle(handle2)).isEqualTo(device2); 2876 assertThat(mBassClientService.getDeviceForSyncHandle(handle3)).isNull(); 2877 assertThat(mBassClientService.getDeviceForSyncHandle(handle4)).isNull(); 2878 assertThat(mBassClientService.getDeviceForSyncHandle(handle5)).isNull(); 2879 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle1)).isEqualTo(broadcastId1); 2880 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle2)).isEqualTo(broadcastId2); 2881 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle3)) 2882 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 2883 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle4)) 2884 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 2885 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle5)) 2886 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 2887 2888 // Scan and sync 3 2889 onScanResult(device3, broadcastId3); 2890 mInOrderMethodProxy 2891 .verify(mMethodProxy) 2892 .periodicAdvertisingManagerRegisterSync( 2893 any(), any(), anyInt(), anyInt(), any(), any()); 2894 onSyncEstablished(device3, handle3); 2895 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(3); 2896 assertThat(mBassClientService.getActiveSyncedSources()) 2897 .containsExactly(handle1, handle2, handle3) 2898 .inOrder(); 2899 assertThat(mBassClientService.getDeviceForSyncHandle(handle2)).isEqualTo(device2); 2900 assertThat(mBassClientService.getDeviceForSyncHandle(handle3)).isEqualTo(device3); 2901 assertThat(mBassClientService.getDeviceForSyncHandle(handle4)).isNull(); 2902 assertThat(mBassClientService.getDeviceForSyncHandle(handle5)).isNull(); 2903 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle1)).isEqualTo(broadcastId1); 2904 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle2)).isEqualTo(broadcastId2); 2905 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle3)).isEqualTo(broadcastId3); 2906 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle4)) 2907 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 2908 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle5)) 2909 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 2910 2911 // Scan and sync 4 2912 onScanResult(device4, broadcastId4); 2913 mInOrderMethodProxy 2914 .verify(mMethodProxy) 2915 .periodicAdvertisingManagerRegisterSync( 2916 any(), any(), anyInt(), anyInt(), any(), any()); 2917 onSyncEstablished(device4, handle4); 2918 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(4); 2919 assertThat(mBassClientService.getActiveSyncedSources()) 2920 .containsExactly(handle1, handle2, handle3, handle4) 2921 .inOrder(); 2922 assertThat(mBassClientService.getDeviceForSyncHandle(handle1)).isEqualTo(device1); 2923 assertThat(mBassClientService.getDeviceForSyncHandle(handle2)).isEqualTo(device2); 2924 assertThat(mBassClientService.getDeviceForSyncHandle(handle3)).isEqualTo(device3); 2925 assertThat(mBassClientService.getDeviceForSyncHandle(handle4)).isEqualTo(device4); 2926 assertThat(mBassClientService.getDeviceForSyncHandle(handle5)).isNull(); 2927 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle1)).isEqualTo(broadcastId1); 2928 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle2)).isEqualTo(broadcastId2); 2929 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle3)).isEqualTo(broadcastId3); 2930 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle4)).isEqualTo(broadcastId4); 2931 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle5)) 2932 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 2933 2934 // Scan 5 cause removing first element 2935 onScanResult(device5, broadcastId5); 2936 mInOrderMethodProxy 2937 .verify(mMethodProxy) 2938 .periodicAdvertisingManagerUnregisterSync(any(), any()); 2939 mInOrderMethodProxy 2940 .verify(mMethodProxy) 2941 .periodicAdvertisingManagerRegisterSync( 2942 any(), any(), anyInt(), anyInt(), any(), any()); 2943 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(3); 2944 assertThat(mBassClientService.getActiveSyncedSources()) 2945 .containsExactly(handle2, handle3, handle4) 2946 .inOrder(); 2947 assertThat(mBassClientService.getDeviceForSyncHandle(handle1)).isNull(); 2948 assertThat(mBassClientService.getDeviceForSyncHandle(handle2)).isEqualTo(device2); 2949 assertThat(mBassClientService.getDeviceForSyncHandle(handle3)).isEqualTo(device3); 2950 assertThat(mBassClientService.getDeviceForSyncHandle(handle4)).isEqualTo(device4); 2951 assertThat(mBassClientService.getDeviceForSyncHandle(handle5)).isNull(); 2952 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle1)) 2953 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 2954 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle2)).isEqualTo(broadcastId2); 2955 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle3)).isEqualTo(broadcastId3); 2956 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle4)).isEqualTo(broadcastId4); 2957 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle5)) 2958 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 2959 2960 // Sync 5 2961 onSyncEstablished(device5, handle5); 2962 expect.that(mBassClientService.getActiveSyncedSources().size()).isEqualTo(4); 2963 expect.that(mBassClientService.getActiveSyncedSources()) 2964 .containsExactly(handle2, handle3, handle4, handle5) 2965 .inOrder(); 2966 expect.that(mBassClientService.getDeviceForSyncHandle(handle1)).isNull(); 2967 expect.that(mBassClientService.getDeviceForSyncHandle(handle2)).isEqualTo(device2); 2968 expect.that(mBassClientService.getDeviceForSyncHandle(handle3)).isEqualTo(device3); 2969 expect.that(mBassClientService.getDeviceForSyncHandle(handle4)).isEqualTo(device4); 2970 expect.that(mBassClientService.getDeviceForSyncHandle(handle5)).isEqualTo(device5); 2971 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle1)) 2972 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 2973 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle2)) 2974 .isEqualTo(broadcastId2); 2975 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle3)) 2976 .isEqualTo(broadcastId3); 2977 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle4)) 2978 .isEqualTo(broadcastId4); 2979 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle5)) 2980 .isEqualTo(broadcastId5); 2981 } 2982 2983 @Test 2984 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) testSelectSource_removeAfterMaxLimit_notSyncedToAnySink()2985 public void testSelectSource_removeAfterMaxLimit_notSyncedToAnySink() { 2986 final BluetoothDevice device1 = 2987 mBluetoothAdapter.getRemoteLeDevice( 2988 "00:11:22:33:44:11", BluetoothDevice.ADDRESS_TYPE_RANDOM); 2989 final BluetoothDevice device2 = 2990 mBluetoothAdapter.getRemoteLeDevice( 2991 "00:11:22:33:44:22", BluetoothDevice.ADDRESS_TYPE_RANDOM); 2992 final BluetoothDevice device3 = 2993 mBluetoothAdapter.getRemoteLeDevice( 2994 "00:11:22:33:44:33", BluetoothDevice.ADDRESS_TYPE_RANDOM); 2995 final BluetoothDevice device4 = 2996 mBluetoothAdapter.getRemoteLeDevice( 2997 "00:11:22:33:44:44", BluetoothDevice.ADDRESS_TYPE_RANDOM); 2998 final BluetoothDevice device5 = 2999 mBluetoothAdapter.getRemoteLeDevice( 3000 "00:11:22:33:44:55", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3001 final int handle1 = 0; 3002 final int handle2 = 1; 3003 final int handle3 = 2; 3004 final int handle4 = 3; 3005 final int handle5 = 4; 3006 final int broadcastId1 = 1111; 3007 final int broadcastId2 = 2222; 3008 final int broadcastId3 = 3333; 3009 final int broadcastId4 = 4444; 3010 final int broadcastId5 = 5555; 3011 3012 prepareConnectedDeviceGroup(); 3013 startSearchingForSources(); 3014 3015 // Scan and sync 4 sources 3016 onScanResult(device1, broadcastId1); 3017 onSyncEstablished(device1, handle1); 3018 onScanResult(device2, broadcastId2); 3019 onSyncEstablished(device2, handle2); 3020 onScanResult(device3, broadcastId3); 3021 onSyncEstablished(device3, handle3); 3022 onScanResult(device4, broadcastId4); 3023 onSyncEstablished(device4, handle4); 3024 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(4); 3025 assertThat(mBassClientService.getActiveSyncedSources()) 3026 .containsExactly(handle1, handle2, handle3, handle4) 3027 .inOrder(); 3028 assertThat(mBassClientService.getDeviceForSyncHandle(handle1)).isEqualTo(device1); 3029 assertThat(mBassClientService.getDeviceForSyncHandle(handle2)).isEqualTo(device2); 3030 assertThat(mBassClientService.getDeviceForSyncHandle(handle3)).isEqualTo(device3); 3031 assertThat(mBassClientService.getDeviceForSyncHandle(handle4)).isEqualTo(device4); 3032 assertThat(mBassClientService.getDeviceForSyncHandle(handle5)).isNull(); 3033 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle1)).isEqualTo(broadcastId1); 3034 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle2)).isEqualTo(broadcastId2); 3035 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle3)).isEqualTo(broadcastId3); 3036 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle4)).isEqualTo(broadcastId4); 3037 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle5)) 3038 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 3039 3040 // Add source 1 3041 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(broadcastId1); 3042 verifyAddSourceForGroup(meta); 3043 prepareRemoteSourceState(meta, /* isPaSynced */ true, /* isBisSynced */ true); 3044 3045 // Scan 5 cause removing first element which is not synced to any sink 3046 onScanResult(device5, broadcastId5); 3047 mInOrderMethodProxy 3048 .verify(mMethodProxy) 3049 .periodicAdvertisingManagerUnregisterSync(any(), any()); 3050 mInOrderMethodProxy 3051 .verify(mMethodProxy) 3052 .periodicAdvertisingManagerRegisterSync( 3053 any(), any(), anyInt(), anyInt(), any(), any()); 3054 expect.that(mBassClientService.getActiveSyncedSources().size()).isEqualTo(3); 3055 expect.that(mBassClientService.getActiveSyncedSources()) 3056 .containsExactly(handle1, handle3, handle4) 3057 .inOrder(); 3058 expect.that(mBassClientService.getDeviceForSyncHandle(handle1)).isEqualTo(device1); 3059 expect.that(mBassClientService.getDeviceForSyncHandle(handle2)).isNull(); 3060 expect.that(mBassClientService.getDeviceForSyncHandle(handle3)).isEqualTo(device3); 3061 expect.that(mBassClientService.getDeviceForSyncHandle(handle4)).isEqualTo(device4); 3062 expect.that(mBassClientService.getDeviceForSyncHandle(handle5)).isNull(); 3063 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle1)) 3064 .isEqualTo(broadcastId1); 3065 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle2)) 3066 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 3067 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle3)) 3068 .isEqualTo(broadcastId3); 3069 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle4)) 3070 .isEqualTo(broadcastId4); 3071 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle5)) 3072 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 3073 } 3074 3075 @Test 3076 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) testSelectSource_removeAfterMaxLimit_firstIfAllSyncedToSinks()3077 public void testSelectSource_removeAfterMaxLimit_firstIfAllSyncedToSinks() { 3078 final BluetoothDevice device1 = 3079 mBluetoothAdapter.getRemoteLeDevice( 3080 "00:11:22:33:44:11", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3081 final BluetoothDevice device2 = 3082 mBluetoothAdapter.getRemoteLeDevice( 3083 "00:11:22:33:44:22", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3084 final BluetoothDevice device3 = 3085 mBluetoothAdapter.getRemoteLeDevice( 3086 "00:11:22:33:44:33", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3087 final BluetoothDevice device4 = 3088 mBluetoothAdapter.getRemoteLeDevice( 3089 "00:11:22:33:44:44", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3090 final BluetoothDevice device5 = 3091 mBluetoothAdapter.getRemoteLeDevice( 3092 "00:11:22:33:44:55", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3093 final int handle1 = 0; 3094 final int handle2 = 1; 3095 final int handle3 = 2; 3096 final int handle4 = 3; 3097 final int handle5 = 4; 3098 final int broadcastId1 = 1111; 3099 final int broadcastId2 = 2222; 3100 final int broadcastId3 = 3333; 3101 final int broadcastId4 = 4444; 3102 final int broadcastId5 = 5555; 3103 3104 prepareConnectedDeviceGroup(); 3105 startSearchingForSources(); 3106 3107 // Scan and sync 4 sources 3108 onScanResult(device1, broadcastId1); 3109 onSyncEstablished(device1, handle1); 3110 onScanResult(device2, broadcastId2); 3111 onSyncEstablished(device2, handle2); 3112 onScanResult(device3, broadcastId3); 3113 onSyncEstablished(device3, handle3); 3114 onScanResult(device4, broadcastId4); 3115 onSyncEstablished(device4, handle4); 3116 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(4); 3117 assertThat(mBassClientService.getActiveSyncedSources()) 3118 .containsExactly(handle1, handle2, handle3, handle4) 3119 .inOrder(); 3120 assertThat(mBassClientService.getDeviceForSyncHandle(handle1)).isEqualTo(device1); 3121 assertThat(mBassClientService.getDeviceForSyncHandle(handle2)).isEqualTo(device2); 3122 assertThat(mBassClientService.getDeviceForSyncHandle(handle3)).isEqualTo(device3); 3123 assertThat(mBassClientService.getDeviceForSyncHandle(handle4)).isEqualTo(device4); 3124 assertThat(mBassClientService.getDeviceForSyncHandle(handle5)).isNull(); 3125 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle1)).isEqualTo(broadcastId1); 3126 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle2)).isEqualTo(broadcastId2); 3127 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle3)).isEqualTo(broadcastId3); 3128 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle4)).isEqualTo(broadcastId4); 3129 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle5)) 3130 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 3131 3132 // Fake add 4 sources 3133 BluetoothLeBroadcastMetadata meta1 = createBroadcastMetadata(broadcastId1); 3134 BluetoothLeBroadcastMetadata meta2 = createBroadcastMetadata(broadcastId2); 3135 BluetoothLeBroadcastMetadata meta3 = createBroadcastMetadata(broadcastId3); 3136 BluetoothLeBroadcastMetadata meta4 = createBroadcastMetadata(broadcastId4); 3137 for (BassClientStateMachine sm : mStateMachines.values()) { 3138 injectRemoteSourceStateSourceAdded( 3139 sm, 3140 meta1, 3141 TEST_SOURCE_ID + 1, 3142 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 3143 meta1.isEncrypted() 3144 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 3145 : BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 3146 null); 3147 injectRemoteSourceStateSourceAdded( 3148 sm, 3149 meta2, 3150 TEST_SOURCE_ID + 2, 3151 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 3152 meta2.isEncrypted() 3153 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 3154 : BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 3155 null); 3156 injectRemoteSourceStateSourceAdded( 3157 sm, 3158 meta3, 3159 TEST_SOURCE_ID + 3, 3160 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 3161 meta3.isEncrypted() 3162 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 3163 : BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 3164 null); 3165 injectRemoteSourceStateSourceAdded( 3166 sm, 3167 meta4, 3168 TEST_SOURCE_ID + 4, 3169 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 3170 meta4.isEncrypted() 3171 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 3172 : BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 3173 null); 3174 } 3175 3176 // Scan 5 cause removing first element which is not synced to any sink or first at all 3177 onScanResult(device5, broadcastId5); 3178 mInOrderMethodProxy 3179 .verify(mMethodProxy) 3180 .periodicAdvertisingManagerUnregisterSync(any(), any()); 3181 mInOrderMethodProxy 3182 .verify(mMethodProxy) 3183 .periodicAdvertisingManagerRegisterSync( 3184 any(), any(), anyInt(), anyInt(), any(), any()); 3185 expect.that(mBassClientService.getActiveSyncedSources().size()).isEqualTo(3); 3186 expect.that(mBassClientService.getActiveSyncedSources()) 3187 .containsExactly(handle2, handle3, handle4) 3188 .inOrder(); 3189 expect.that(mBassClientService.getDeviceForSyncHandle(handle1)).isNull(); 3190 expect.that(mBassClientService.getDeviceForSyncHandle(handle2)).isEqualTo(device2); 3191 expect.that(mBassClientService.getDeviceForSyncHandle(handle3)).isEqualTo(device3); 3192 expect.that(mBassClientService.getDeviceForSyncHandle(handle4)).isEqualTo(device4); 3193 expect.that(mBassClientService.getDeviceForSyncHandle(handle5)).isNull(); 3194 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle1)) 3195 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 3196 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle2)) 3197 .isEqualTo(broadcastId2); 3198 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle3)) 3199 .isEqualTo(broadcastId3); 3200 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle4)) 3201 .isEqualTo(broadcastId4); 3202 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle5)) 3203 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 3204 } 3205 3206 @Test testAddSourceToUnsyncedSource_causesSyncBeforeAddingSource()3207 public void testAddSourceToUnsyncedSource_causesSyncBeforeAddingSource() { 3208 final BluetoothDevice device1 = 3209 mBluetoothAdapter.getRemoteLeDevice( 3210 "00:11:22:33:44:11", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3211 final BluetoothDevice device2 = 3212 mBluetoothAdapter.getRemoteLeDevice( 3213 "00:11:22:33:44:22", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3214 final BluetoothDevice device3 = 3215 mBluetoothAdapter.getRemoteLeDevice( 3216 "00:11:22:33:44:33", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3217 final BluetoothDevice device4 = 3218 mBluetoothAdapter.getRemoteLeDevice( 3219 "00:11:22:33:44:44", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3220 final BluetoothDevice device5 = 3221 mBluetoothAdapter.getRemoteLeDevice( 3222 "00:11:22:33:44:55", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3223 final int handle1 = 0; 3224 final int handle2 = 1; 3225 final int handle3 = 2; 3226 final int handle4 = 3; 3227 final int handle5 = 4; 3228 final int broadcastId1 = 1111; 3229 final int broadcastId2 = 2222; 3230 final int broadcastId3 = 3333; 3231 final int broadcastId4 = 4444; 3232 final int broadcastId5 = 5555; 3233 3234 prepareConnectedDeviceGroup(); 3235 startSearchingForSources(); 3236 3237 // Scan and sync 5 sources cause removing 1 synced element 3238 onScanResult(device1, broadcastId1); 3239 onSyncEstablished(device1, handle1); 3240 onScanResult(device2, broadcastId2); 3241 onSyncEstablished(device2, handle2); 3242 onScanResult(device3, broadcastId3); 3243 onSyncEstablished(device3, handle3); 3244 onScanResult(device4, broadcastId4); 3245 onSyncEstablished(device4, handle4); 3246 onScanResult(device5, broadcastId5); 3247 mInOrderMethodProxy 3248 .verify(mMethodProxy, times(4)) 3249 .periodicAdvertisingManagerRegisterSync( 3250 any(), any(), anyInt(), anyInt(), any(), any()); 3251 mInOrderMethodProxy 3252 .verify(mMethodProxy) 3253 .periodicAdvertisingManagerUnregisterSync(any(), any()); 3254 mInOrderMethodProxy 3255 .verify(mMethodProxy) 3256 .periodicAdvertisingManagerRegisterSync( 3257 any(), any(), anyInt(), anyInt(), any(), any()); 3258 onSyncEstablished(device5, handle5); 3259 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(4); 3260 assertThat(mBassClientService.getActiveSyncedSources()) 3261 .containsExactly(handle2, handle3, handle4, handle5) 3262 .inOrder(); 3263 assertThat(mBassClientService.getDeviceForSyncHandle(handle1)).isNull(); 3264 assertThat(mBassClientService.getDeviceForSyncHandle(handle2)).isEqualTo(device2); 3265 assertThat(mBassClientService.getDeviceForSyncHandle(handle3)).isEqualTo(device3); 3266 assertThat(mBassClientService.getDeviceForSyncHandle(handle4)).isEqualTo(device4); 3267 assertThat(mBassClientService.getDeviceForSyncHandle(handle5)).isEqualTo(device5); 3268 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle1)) 3269 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 3270 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle2)).isEqualTo(broadcastId2); 3271 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle3)).isEqualTo(broadcastId3); 3272 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle4)).isEqualTo(broadcastId4); 3273 assertThat(mBassClientService.getBroadcastIdForSyncHandle(handle5)).isEqualTo(broadcastId5); 3274 3275 BluetoothLeBroadcastMetadata.Builder builder = 3276 new BluetoothLeBroadcastMetadata.Builder() 3277 .setEncrypted(false) 3278 .setSourceDevice(device1, BluetoothDevice.ADDRESS_TYPE_RANDOM) 3279 .setSourceAdvertisingSid(TEST_ADVERTISER_SID) 3280 .setBroadcastId(broadcastId1) 3281 .setBroadcastCode(null) 3282 .setPaSyncInterval(TEST_PA_SYNC_INTERVAL) 3283 .setPresentationDelayMicros(TEST_PRESENTATION_DELAY_MS); 3284 // builder expect at least one subgroup 3285 builder.addSubgroup(createBroadcastSubgroup()); 3286 BluetoothLeBroadcastMetadata meta = builder.build(); 3287 ArgumentCaptor<ScanResult> resultCaptor = ArgumentCaptor.forClass(ScanResult.class); 3288 3289 // Add source to unsynced broadcast, causes synchronization first 3290 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 3291 handleHandoverSupport(); 3292 mInOrderMethodProxy 3293 .verify(mMethodProxy) 3294 .periodicAdvertisingManagerRegisterSync( 3295 any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any()); 3296 assertThat( 3297 BassUtils.parseBroadcastId( 3298 resultCaptor 3299 .getValue() 3300 .getScanRecord() 3301 .getServiceData() 3302 .get(BassConstants.BAAS_UUID))) 3303 .isEqualTo(broadcastId1); 3304 3305 // Verify not getting ADD_BCAST_SOURCE message before source sync 3306 assertThat(mStateMachines).hasSize(2); 3307 for (BassClientStateMachine sm : mStateMachines.values()) { 3308 verify(sm, never()).sendMessage(any()); 3309 } 3310 3311 // Source synced which cause execute pending add source 3312 onSyncEstablished(device1, handle1); 3313 3314 expect.that(mBassClientService.getActiveSyncedSources().size()).isEqualTo(4); 3315 expect.that(mBassClientService.getActiveSyncedSources()) 3316 .containsExactly(handle3, handle4, handle5, handle1) 3317 .inOrder(); 3318 expect.that(mBassClientService.getDeviceForSyncHandle(handle1)).isEqualTo(device1); 3319 expect.that(mBassClientService.getDeviceForSyncHandle(handle2)).isNull(); 3320 expect.that(mBassClientService.getDeviceForSyncHandle(handle3)).isEqualTo(device3); 3321 expect.that(mBassClientService.getDeviceForSyncHandle(handle4)).isEqualTo(device4); 3322 expect.that(mBassClientService.getDeviceForSyncHandle(handle5)).isEqualTo(device5); 3323 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle1)) 3324 .isEqualTo(broadcastId1); 3325 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle2)) 3326 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 3327 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle3)) 3328 .isEqualTo(broadcastId3); 3329 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle4)) 3330 .isEqualTo(broadcastId4); 3331 expect.that(mBassClientService.getBroadcastIdForSyncHandle(handle5)) 3332 .isEqualTo(broadcastId5); 3333 3334 // Verify all group members getting ADD_BCAST_SOURCE message 3335 expect.that(mStateMachines.size()).isEqualTo(2); 3336 for (BassClientStateMachine sm : mStateMachines.values()) { 3337 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 3338 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 3339 3340 Message msg = 3341 messageCaptor.getAllValues().stream() 3342 .filter( 3343 m -> 3344 (m.what == BassClientStateMachine.ADD_BCAST_SOURCE) 3345 && (m.obj == meta)) 3346 .findFirst() 3347 .orElse(null); 3348 expect.that(msg).isNotNull(); 3349 } 3350 } 3351 3352 @Test testAddSourceForExternalBroadcast_triggerSetContextMask()3353 public void testAddSourceForExternalBroadcast_triggerSetContextMask() { 3354 final int testGroupId = 1; 3355 prepareConnectedDeviceGroup(); 3356 startSearchingForSources(); 3357 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 3358 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 3359 3360 /* Fake external broadcast - no Broadcast Metadata from LE Audio service */ 3361 doReturn(new ArrayList<BluetoothLeBroadcastMetadata>()) 3362 .when(mLeAudioService) 3363 .getAllBroadcastMetadata(); 3364 doReturn(testGroupId).when(mLeAudioService).getActiveGroupId(); 3365 doReturn(new ArrayList<BluetoothDevice>(Arrays.asList(mCurrentDevice))) 3366 .when(mLeAudioService) 3367 .getActiveDevices(); 3368 3369 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 3370 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 3371 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 3372 .isEqualTo(mSourceDevice); 3373 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 3374 .isEqualTo(TEST_BROADCAST_ID); 3375 3376 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 3377 3378 // Add source to unsynced broadcast, causes synchronization first 3379 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 3380 3381 // Verify setting allowed context mask is triggered 3382 verify(mLeAudioService) 3383 .setActiveGroupAllowedContextMask( 3384 eq( 3385 BluetoothLeAudio.CONTEXTS_ALL 3386 & ~BluetoothLeAudio.CONTEXT_TYPE_SOUND_EFFECTS), 3387 eq(BluetoothLeAudio.CONTEXTS_ALL)); 3388 handleHandoverSupport(); 3389 3390 // Verify all group members getting ADD_BCAST_SOURCE message 3391 assertThat(mStateMachines).hasSize(2); 3392 for (BassClientStateMachine sm : mStateMachines.values()) { 3393 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 3394 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 3395 3396 Message msg = 3397 messageCaptor.getAllValues().stream() 3398 .filter( 3399 m -> 3400 (m.what == BassClientStateMachine.ADD_BCAST_SOURCE) 3401 && (m.obj == meta)) 3402 .findFirst() 3403 .orElse(null); 3404 assertThat(msg).isNotNull(); 3405 } 3406 3407 mBassClientService 3408 .getCallbacks() 3409 .notifySourceAddFailed(mCurrentDevice, meta, BluetoothStatusCodes.ERROR_UNKNOWN); 3410 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 3411 3412 // Verify resetting allowed context mask is triggered when switching source failed 3413 verify(mLeAudioService) 3414 .setActiveGroupAllowedContextMask( 3415 eq(BluetoothLeAudio.CONTEXTS_ALL), eq(BluetoothLeAudio.CONTEXTS_ALL)); 3416 } 3417 3418 @Test testSelectSource_orderOfSyncRegisteringByPriorityAndRssi()3419 public void testSelectSource_orderOfSyncRegisteringByPriorityAndRssi() { 3420 final BluetoothDevice device1 = 3421 mBluetoothAdapter.getRemoteLeDevice( 3422 "00:11:22:33:44:11", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3423 final BluetoothDevice device2 = 3424 mBluetoothAdapter.getRemoteLeDevice( 3425 "00:11:22:33:44:22", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3426 final BluetoothDevice device3 = 3427 mBluetoothAdapter.getRemoteLeDevice( 3428 "00:11:22:33:44:33", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3429 final BluetoothDevice device4 = 3430 mBluetoothAdapter.getRemoteLeDevice( 3431 "00:11:22:33:44:44", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3432 final BluetoothDevice device5 = 3433 mBluetoothAdapter.getRemoteLeDevice( 3434 "00:11:22:33:44:55", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3435 final BluetoothDevice device6 = 3436 mBluetoothAdapter.getRemoteLeDevice( 3437 "00:11:22:33:44:66", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3438 final BluetoothDevice device7 = 3439 mBluetoothAdapter.getRemoteLeDevice( 3440 "00:11:22:33:44:77", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3441 final int broadcastId1 = 1111; 3442 final int broadcastId2 = 2222; 3443 final int broadcastId3 = 3333; 3444 final int broadcastId4 = 4444; 3445 final int broadcastId5 = 5555; 3446 final int broadcastId6 = 6666; 3447 final int broadcastId7 = 7777; 3448 3449 byte[] scanRecord1 = getScanRecord(broadcastId1); 3450 byte[] scanRecord2 = getScanRecord(broadcastId2); 3451 byte[] scanRecord3 = getScanRecord(broadcastId3); 3452 byte[] scanRecord4 = getScanRecord(broadcastId4); 3453 byte[] scanRecord5 = getScanRecord(broadcastId5); 3454 byte[] scanRecord6 = getScanRecord(broadcastId6); 3455 byte[] scanRecord7 = getScanRecord(broadcastId7); 3456 3457 ScanResult scanResult1 = 3458 new ScanResult( 3459 device1, 3460 0, 3461 0, 3462 0, 3463 0, 3464 0, 3465 TEST_RSSI, 3466 0, 3467 ScanRecord.parseFromBytes(scanRecord1), 3468 0); 3469 ScanResult scanResult2 = 3470 new ScanResult( 3471 device2, 3472 0, 3473 0, 3474 0, 3475 0, 3476 0, 3477 TEST_RSSI + 3, 3478 0, 3479 ScanRecord.parseFromBytes(scanRecord2), 3480 0); 3481 ScanResult scanResult3 = 3482 new ScanResult( 3483 device3, 3484 0, 3485 0, 3486 0, 3487 0, 3488 0, 3489 TEST_RSSI + 7, 3490 0, 3491 ScanRecord.parseFromBytes(scanRecord3), 3492 0); 3493 ScanResult scanResult4 = 3494 new ScanResult( 3495 device4, 3496 0, 3497 0, 3498 0, 3499 0, 3500 0, 3501 TEST_RSSI + 5, 3502 0, 3503 ScanRecord.parseFromBytes(scanRecord4), 3504 0); 3505 ScanResult scanResult5 = 3506 new ScanResult( 3507 device5, 3508 0, 3509 0, 3510 0, 3511 0, 3512 0, 3513 TEST_RSSI + 2, 3514 0, 3515 ScanRecord.parseFromBytes(scanRecord5), 3516 0); 3517 ScanResult scanResult6 = 3518 new ScanResult( 3519 device6, 3520 0, 3521 0, 3522 0, 3523 0, 3524 0, 3525 TEST_RSSI + 6, 3526 0, 3527 ScanRecord.parseFromBytes(scanRecord6), 3528 0); 3529 ScanResult scanResult7 = 3530 new ScanResult( 3531 device7, 3532 0, 3533 0, 3534 0, 3535 0, 3536 0, 3537 TEST_RSSI + 4, 3538 0, 3539 ScanRecord.parseFromBytes(scanRecord7), 3540 0); 3541 3542 prepareConnectedDeviceGroup(); 3543 startSearchingForSources(); 3544 3545 // Added and executed immediately as no other in queue 3546 generateScanResult(scanResult1); 3547 // Added to queue with worst rssi 3548 generateScanResult(scanResult2); 3549 // Added to queue with best rssi 3550 generateScanResult(scanResult3); 3551 // Added to queue with medium rssi 3552 generateScanResult(scanResult4); 3553 // Added to queue with worst rssi (increase priority after all) 3554 generateScanResult(scanResult5); 3555 // Added to queue with best rssi (increase priority after all) 3556 generateScanResult(scanResult6); 3557 // Added to queue with medium rssi (increase priority after all) 3558 generateScanResult(scanResult7); 3559 3560 // Increase priority of last 3 of them 3561 mBassClientService.addSelectSourceRequest(broadcastId5, /* hasPriority */ true); 3562 mBassClientService.addSelectSourceRequest(broadcastId6, /* hasPriority */ true); 3563 mBassClientService.addSelectSourceRequest(broadcastId7, /* hasPriority */ true); 3564 3565 ArgumentCaptor<ScanResult> resultCaptor = ArgumentCaptor.forClass(ScanResult.class); 3566 mInOrderMethodProxy 3567 .verify(mMethodProxy) 3568 .periodicAdvertisingManagerRegisterSync( 3569 any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any()); 3570 assertThat( 3571 BassUtils.parseBroadcastId( 3572 resultCaptor 3573 .getValue() 3574 .getScanRecord() 3575 .getServiceData() 3576 .get(BassConstants.BAAS_UUID))) 3577 .isEqualTo(broadcastId1); 3578 3579 onSyncEstablished(device1, TEST_SYNC_HANDLE); 3580 mInOrderMethodProxy 3581 .verify(mMethodProxy) 3582 .periodicAdvertisingManagerRegisterSync( 3583 any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any()); 3584 assertThat( 3585 BassUtils.parseBroadcastId( 3586 resultCaptor 3587 .getValue() 3588 .getScanRecord() 3589 .getServiceData() 3590 .get(BassConstants.BAAS_UUID))) 3591 .isEqualTo(broadcastId6); 3592 3593 onSyncEstablished(device6, TEST_SYNC_HANDLE + 1); 3594 mInOrderMethodProxy 3595 .verify(mMethodProxy) 3596 .periodicAdvertisingManagerRegisterSync( 3597 any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any()); 3598 assertThat( 3599 BassUtils.parseBroadcastId( 3600 resultCaptor 3601 .getValue() 3602 .getScanRecord() 3603 .getServiceData() 3604 .get(BassConstants.BAAS_UUID))) 3605 .isEqualTo(broadcastId7); 3606 3607 onSyncEstablished(device7, TEST_SYNC_HANDLE + 2); 3608 mInOrderMethodProxy 3609 .verify(mMethodProxy) 3610 .periodicAdvertisingManagerRegisterSync( 3611 any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any()); 3612 assertThat( 3613 BassUtils.parseBroadcastId( 3614 resultCaptor 3615 .getValue() 3616 .getScanRecord() 3617 .getServiceData() 3618 .get(BassConstants.BAAS_UUID))) 3619 .isEqualTo(broadcastId5); 3620 3621 onSyncEstablished(device5, TEST_SYNC_HANDLE + 3); 3622 mInOrderMethodProxy 3623 .verify(mMethodProxy) 3624 .periodicAdvertisingManagerRegisterSync( 3625 any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any()); 3626 assertThat( 3627 BassUtils.parseBroadcastId( 3628 resultCaptor 3629 .getValue() 3630 .getScanRecord() 3631 .getServiceData() 3632 .get(BassConstants.BAAS_UUID))) 3633 .isEqualTo(broadcastId3); 3634 3635 onSyncEstablished(device3, TEST_SYNC_HANDLE + 4); 3636 mInOrderMethodProxy 3637 .verify(mMethodProxy) 3638 .periodicAdvertisingManagerRegisterSync( 3639 any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any()); 3640 assertThat( 3641 BassUtils.parseBroadcastId( 3642 resultCaptor 3643 .getValue() 3644 .getScanRecord() 3645 .getServiceData() 3646 .get(BassConstants.BAAS_UUID))) 3647 .isEqualTo(broadcastId4); 3648 3649 onSyncEstablished(device4, TEST_SYNC_HANDLE + 5); 3650 mInOrderMethodProxy 3651 .verify(mMethodProxy) 3652 .periodicAdvertisingManagerRegisterSync( 3653 any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any()); 3654 assertThat( 3655 BassUtils.parseBroadcastId( 3656 resultCaptor 3657 .getValue() 3658 .getScanRecord() 3659 .getServiceData() 3660 .get(BassConstants.BAAS_UUID))) 3661 .isEqualTo(broadcastId2); 3662 } 3663 3664 @Test 3665 @EnableFlags(Flags.FLAG_LEAUDIO_SORT_SCANS_TO_SYNC_BY_FAILS) testSelectSource_orderOfSyncRegisteringByRssiAndFailsCounter()3666 public void testSelectSource_orderOfSyncRegisteringByRssiAndFailsCounter() { 3667 final BluetoothDevice device1 = 3668 mBluetoothAdapter.getRemoteLeDevice( 3669 "00:11:22:33:44:11", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3670 final BluetoothDevice device2 = 3671 mBluetoothAdapter.getRemoteLeDevice( 3672 "00:11:22:33:44:22", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3673 final BluetoothDevice device3 = 3674 mBluetoothAdapter.getRemoteLeDevice( 3675 "00:11:22:33:44:33", BluetoothDevice.ADDRESS_TYPE_RANDOM); 3676 final int broadcastId1 = 1111; 3677 final int broadcastId2 = 2222; 3678 final int broadcastId3 = 3333; 3679 3680 byte[] scanRecord1 = getScanRecord(broadcastId1); 3681 byte[] scanRecord2 = getScanRecord(broadcastId2); 3682 byte[] scanRecord3 = getScanRecord(broadcastId3); 3683 3684 ScanResult scanResult1 = 3685 new ScanResult( 3686 device1, 3687 0, 3688 0, 3689 0, 3690 0, 3691 0, 3692 TEST_RSSI + 10, 3693 0, 3694 ScanRecord.parseFromBytes(scanRecord1), 3695 0); 3696 ScanResult scanResult2 = 3697 new ScanResult( 3698 device2, 3699 0, 3700 0, 3701 0, 3702 0, 3703 0, 3704 TEST_RSSI + 9, 3705 0, 3706 ScanRecord.parseFromBytes(scanRecord2), 3707 0); 3708 ScanResult scanResult3 = 3709 new ScanResult( 3710 device3, 3711 0, 3712 0, 3713 0, 3714 0, 3715 0, 3716 TEST_RSSI, 3717 0, 3718 ScanRecord.parseFromBytes(scanRecord3), 3719 0); 3720 3721 prepareConnectedDeviceGroup(); 3722 startSearchingForSources(); 3723 3724 // Test using onSyncEstablishedFailed 3725 // Added and executed immediately as no other in queue, high rssi 3726 generateScanResult(scanResult1); 3727 // Added to queue, medium rssi 3728 generateScanResult(scanResult2); 3729 // Added to queue, low rssi 3730 generateScanResult(scanResult3); 3731 3732 ArgumentCaptor<ScanResult> resultCaptor = ArgumentCaptor.forClass(ScanResult.class); 3733 mInOrderMethodProxy 3734 .verify(mMethodProxy) 3735 .periodicAdvertisingManagerRegisterSync( 3736 any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any()); 3737 assertThat( 3738 BassUtils.parseBroadcastId( 3739 resultCaptor 3740 .getValue() 3741 .getScanRecord() 3742 .getServiceData() 3743 .get(BassConstants.BAAS_UUID))) 3744 .isEqualTo(broadcastId1); 3745 3746 onSyncEstablishedFailed(device1, TEST_SYNC_HANDLE); 3747 mInOrderMethodProxy 3748 .verify(mMethodProxy) 3749 .periodicAdvertisingManagerRegisterSync( 3750 any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any()); 3751 assertThat( 3752 BassUtils.parseBroadcastId( 3753 resultCaptor 3754 .getValue() 3755 .getScanRecord() 3756 .getServiceData() 3757 .get(BassConstants.BAAS_UUID))) 3758 .isEqualTo(broadcastId2); 3759 3760 // Added to queue again, high rssi 3761 generateScanResult(scanResult1); 3762 3763 onSyncEstablishedFailed(device2, TEST_SYNC_HANDLE + 1); 3764 mInOrderMethodProxy 3765 .verify(mMethodProxy) 3766 .periodicAdvertisingManagerRegisterSync( 3767 any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any()); 3768 assertThat( 3769 BassUtils.parseBroadcastId( 3770 resultCaptor 3771 .getValue() 3772 .getScanRecord() 3773 .getServiceData() 3774 .get(BassConstants.BAAS_UUID))) 3775 .isEqualTo(broadcastId3); 3776 3777 onSyncEstablished(device3, TEST_SYNC_HANDLE + 2); 3778 mInOrderMethodProxy 3779 .verify(mMethodProxy) 3780 .periodicAdvertisingManagerRegisterSync( 3781 any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any()); 3782 assertThat( 3783 BassUtils.parseBroadcastId( 3784 resultCaptor 3785 .getValue() 3786 .getScanRecord() 3787 .getServiceData() 3788 .get(BassConstants.BAAS_UUID))) 3789 .isEqualTo(broadcastId1); 3790 3791 // Restart searching clears the mSyncFailureCounter 3792 mBassClientService.stopSearchingForSources(); 3793 mInOrderMethodProxy 3794 .verify(mMethodProxy, times(2)) 3795 .periodicAdvertisingManagerUnregisterSync(any(), any()); 3796 startSearchingForSources(); 3797 3798 // Test using onSyncLost 3799 // Added and executed immediately as no other in queue, high rssi 3800 generateScanResult(scanResult1); 3801 // Added to queue, medium rssi 3802 generateScanResult(scanResult2); 3803 // Added to queue, low rssi 3804 generateScanResult(scanResult3); 3805 3806 mInOrderMethodProxy 3807 .verify(mMethodProxy) 3808 .periodicAdvertisingManagerRegisterSync( 3809 any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any()); 3810 assertThat( 3811 BassUtils.parseBroadcastId( 3812 resultCaptor 3813 .getValue() 3814 .getScanRecord() 3815 .getServiceData() 3816 .get(BassConstants.BAAS_UUID))) 3817 .isEqualTo(broadcastId1); 3818 3819 onSyncEstablished(device1, TEST_SYNC_HANDLE); 3820 mInOrderMethodProxy 3821 .verify(mMethodProxy) 3822 .periodicAdvertisingManagerRegisterSync( 3823 any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any()); 3824 assertThat( 3825 BassUtils.parseBroadcastId( 3826 resultCaptor 3827 .getValue() 3828 .getScanRecord() 3829 .getServiceData() 3830 .get(BassConstants.BAAS_UUID))) 3831 .isEqualTo(broadcastId2); 3832 onSyncLost(); 3833 if (Flags.leaudioBroadcastResyncHelper()) { 3834 checkAndDispatchTimeout(broadcastId1, BassClientService.MESSAGE_SYNC_LOST_TIMEOUT); 3835 } 3836 3837 // Added to queue again, high rssi 3838 generateScanResult(scanResult1); 3839 3840 onSyncEstablished(device2, TEST_SYNC_HANDLE + 1); 3841 mInOrderMethodProxy 3842 .verify(mMethodProxy) 3843 .periodicAdvertisingManagerRegisterSync( 3844 any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any()); 3845 assertThat( 3846 BassUtils.parseBroadcastId( 3847 resultCaptor 3848 .getValue() 3849 .getScanRecord() 3850 .getServiceData() 3851 .get(BassConstants.BAAS_UUID))) 3852 .isEqualTo(broadcastId3); 3853 } 3854 3855 @Test testPeriodicAdvertisementResultMap_updateGetAndModifyNotifiedFlag()3856 public void testPeriodicAdvertisementResultMap_updateGetAndModifyNotifiedFlag() { 3857 final String testBroadcastName = "Test"; 3858 final int testSyncHandle = 1; 3859 final int testBroadcastId = 42; 3860 final int testBroadcastIdInvalid = 43; 3861 final int testAdvertiserSid = 1234; 3862 final int testAdvInterval = 100; 3863 3864 // mock the update in selectSource 3865 mBassClientService.updateSyncHandleForBroadcastId( 3866 BassConstants.PENDING_SYNC_HANDLE, testBroadcastId); 3867 mBassClientService.updatePeriodicAdvertisementResultMap( 3868 mSourceDevice, 3869 mSourceDevice.getAddressType(), 3870 BassConstants.PENDING_SYNC_HANDLE, 3871 BassConstants.INVALID_ADV_SID, 3872 testAdvInterval, 3873 testBroadcastId, 3874 null, 3875 testBroadcastName); 3876 3877 // mock the update in onSyncEstablished 3878 mBassClientService.updatePeriodicAdvertisementResultMap( 3879 mSourceDevice, 3880 BassConstants.INVALID_ADV_ADDRESS_TYPE, 3881 testSyncHandle, 3882 testAdvertiserSid, 3883 BassConstants.INVALID_ADV_INTERVAL, 3884 BassConstants.INVALID_BROADCAST_ID, 3885 null, 3886 null); 3887 3888 assertThat( 3889 mBassClientService.getPeriodicAdvertisementResult( 3890 mSourceDevice, testBroadcastIdInvalid)) 3891 .isNull(); 3892 PeriodicAdvertisementResult paResult = 3893 mBassClientService.getPeriodicAdvertisementResult(mSourceDevice, testBroadcastId); 3894 assertThat(paResult.getAddressType()).isEqualTo(BluetoothDevice.ADDRESS_TYPE_RANDOM); 3895 assertThat(paResult.getSyncHandle()).isEqualTo(testSyncHandle); 3896 assertThat(paResult.getAdvSid()).isEqualTo(testAdvertiserSid); 3897 assertThat(paResult.getAdvInterval()).isEqualTo(testAdvInterval); 3898 assertThat(paResult.getBroadcastName()).isEqualTo(testBroadcastName); 3899 3900 // validate modify notified flag 3901 paResult.setNotified(true); 3902 assertThat(paResult.isNotified()).isEqualTo(true); 3903 mBassClientService.clearNotifiedFlags(); 3904 assertThat(paResult.isNotified()).isEqualTo(false); 3905 } 3906 3907 @Test testPeriodicAdvertisementResultMap_syncEstablishedOnTheSameSyncHandle()3908 public void testPeriodicAdvertisementResultMap_syncEstablishedOnTheSameSyncHandle() { 3909 final String testBroadcastName1 = "Test1"; 3910 final String testBroadcastName2 = "Test2"; 3911 final int testSyncHandle = 1; 3912 final int testBroadcastId1 = 42; 3913 final int testBroadcastId2 = 43; 3914 final int testAdvertiserSid1 = 1234; 3915 final int testAdvertiserSid2 = 2345; 3916 final int testAdvInterval1 = 100; 3917 final int testAdvInterval2 = 200; 3918 3919 // mock the update in selectSource 3920 mBassClientService.updateSyncHandleForBroadcastId( 3921 BassConstants.PENDING_SYNC_HANDLE, testBroadcastId1); 3922 mBassClientService.updatePeriodicAdvertisementResultMap( 3923 mSourceDevice, 3924 mSourceDevice.getAddressType(), 3925 BassConstants.PENDING_SYNC_HANDLE, 3926 BassConstants.INVALID_ADV_SID, 3927 testAdvInterval1, 3928 testBroadcastId1, 3929 null, 3930 testBroadcastName1); 3931 3932 // mock the update in onSyncEstablished 3933 mBassClientService.updatePeriodicAdvertisementResultMap( 3934 mSourceDevice, 3935 BassConstants.INVALID_ADV_ADDRESS_TYPE, 3936 testSyncHandle, 3937 testAdvertiserSid1, 3938 BassConstants.INVALID_ADV_INTERVAL, 3939 BassConstants.INVALID_BROADCAST_ID, 3940 null, 3941 null); 3942 3943 assertThat( 3944 mBassClientService.getPeriodicAdvertisementResult( 3945 mSourceDevice, testBroadcastId2)) 3946 .isNull(); 3947 PeriodicAdvertisementResult paResult = 3948 mBassClientService.getPeriodicAdvertisementResult(mSourceDevice, testBroadcastId1); 3949 assertThat(paResult.getAddressType()).isEqualTo(BluetoothDevice.ADDRESS_TYPE_RANDOM); 3950 assertThat(paResult.getSyncHandle()).isEqualTo(testSyncHandle); 3951 assertThat(paResult.getAdvSid()).isEqualTo(testAdvertiserSid1); 3952 assertThat(paResult.getAdvInterval()).isEqualTo(testAdvInterval1); 3953 assertThat(paResult.getBroadcastName()).isEqualTo(testBroadcastName1); 3954 3955 // mock the update in selectSource 3956 mBassClientService.updateSyncHandleForBroadcastId( 3957 BassConstants.PENDING_SYNC_HANDLE, testBroadcastId2); 3958 mBassClientService.updatePeriodicAdvertisementResultMap( 3959 mSourceDevice, 3960 mSourceDevice.getAddressType(), 3961 BassConstants.PENDING_SYNC_HANDLE, 3962 BassConstants.INVALID_ADV_SID, 3963 testAdvInterval2, 3964 testBroadcastId2, 3965 null, 3966 testBroadcastName2); 3967 3968 // mock the update in onSyncEstablished 3969 mBassClientService.updatePeriodicAdvertisementResultMap( 3970 mSourceDevice, 3971 BassConstants.INVALID_ADV_ADDRESS_TYPE, 3972 testSyncHandle, 3973 testAdvertiserSid2, 3974 BassConstants.INVALID_ADV_INTERVAL, 3975 BassConstants.INVALID_BROADCAST_ID, 3976 null, 3977 null); 3978 3979 expect.that( 3980 mBassClientService.getPeriodicAdvertisementResult( 3981 mSourceDevice, testBroadcastId1)) 3982 .isNull(); 3983 paResult = 3984 mBassClientService.getPeriodicAdvertisementResult(mSourceDevice, testBroadcastId2); 3985 expect.that(paResult.getAddressType()).isEqualTo(BluetoothDevice.ADDRESS_TYPE_RANDOM); 3986 expect.that(paResult.getSyncHandle()).isEqualTo(testSyncHandle); 3987 expect.that(paResult.getAdvSid()).isEqualTo(testAdvertiserSid2); 3988 expect.that(paResult.getAdvInterval()).isEqualTo(testAdvInterval2); 3989 expect.that(paResult.getBroadcastName()).isEqualTo(testBroadcastName2); 3990 } 3991 3992 @Test testSyncHandleToBroadcastIdMap_getSyncHandleAndGetBroadcastId()3993 public void testSyncHandleToBroadcastIdMap_getSyncHandleAndGetBroadcastId() { 3994 final int testSyncHandle = 1; 3995 final int testSyncHandleInvalid = 2; 3996 final int testBroadcastId = 42; 3997 final int testBroadcastIdInvalid = 43; 3998 3999 prepareConnectedDeviceGroup(); 4000 startSearchingForSources(); 4001 onScanResult(mSourceDevice, testBroadcastId); 4002 onSyncEstablished(mSourceDevice, testSyncHandle); 4003 4004 assertThat(mBassClientService.getSyncHandleForBroadcastId(testBroadcastIdInvalid)) 4005 .isEqualTo(BassConstants.INVALID_SYNC_HANDLE); 4006 assertThat(mBassClientService.getBroadcastIdForSyncHandle(testSyncHandleInvalid)) 4007 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 4008 assertThat(mBassClientService.getSyncHandleForBroadcastId(testBroadcastId)) 4009 .isEqualTo(testSyncHandle); 4010 assertThat(mBassClientService.getBroadcastIdForSyncHandle(testSyncHandle)) 4011 .isEqualTo(testBroadcastId); 4012 } 4013 verifyAllGroupMembersGettingUpdateOrAddSource(BluetoothLeBroadcastMetadata meta)4014 private void verifyAllGroupMembersGettingUpdateOrAddSource(BluetoothLeBroadcastMetadata meta) { 4015 assertThat(mStateMachines).hasSize(2); 4016 for (BassClientStateMachine sm : mStateMachines.values()) { 4017 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 4018 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 4019 long count; 4020 4021 if (sm.getDevice().equals(mCurrentDevice)) { 4022 count = 4023 messageCaptor.getAllValues().stream() 4024 .filter( 4025 m -> 4026 ((m.what 4027 == BassClientStateMachine 4028 .UPDATE_BCAST_SOURCE) 4029 && (m.obj.equals(meta)) 4030 && (m.arg1 == TEST_SOURCE_ID) 4031 && (m.arg2 4032 == BassConstants 4033 .PA_SYNC_PAST_AVAILABLE)) 4034 || ((m.what 4035 == BassClientStateMachine 4036 .ADD_BCAST_SOURCE) 4037 && (m.obj.equals(meta))) 4038 || ((m.what 4039 == BassClientStateMachine 4040 .SWITCH_BCAST_SOURCE) 4041 && (m.obj.equals(meta)) 4042 && (m.arg1 == TEST_SOURCE_ID))) 4043 .count(); 4044 assertThat(count).isEqualTo(1); 4045 } else if (sm.getDevice().equals(mCurrentDevice1)) { 4046 count = 4047 messageCaptor.getAllValues().stream() 4048 .filter( 4049 m -> 4050 ((m.what 4051 == BassClientStateMachine 4052 .UPDATE_BCAST_SOURCE) 4053 && (m.obj.equals(meta)) 4054 && (m.arg1 == TEST_SOURCE_ID + 1) 4055 && (m.arg2 4056 == BassConstants 4057 .PA_SYNC_PAST_AVAILABLE)) 4058 || ((m.what 4059 == BassClientStateMachine 4060 .ADD_BCAST_SOURCE) 4061 && (m.obj.equals(meta))) 4062 || ((m.what 4063 == BassClientStateMachine 4064 .SWITCH_BCAST_SOURCE) 4065 && (m.obj.equals(meta)) 4066 && (m.arg1 == TEST_SOURCE_ID + 1))) 4067 .count(); 4068 assertThat(count).isEqualTo(1); 4069 } 4070 } 4071 } 4072 4073 @Test testSuspendResumeSourceSynchronization()4074 public void testSuspendResumeSourceSynchronization() { 4075 prepareConnectedDeviceGroup(); 4076 startSearchingForSources(); 4077 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 4078 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 4079 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 4080 verifyAddSourceForGroup(meta); 4081 prepareRemoteSourceState(meta, /* isPaSynced */ true, /* isBisSynced */ false); 4082 4083 injectRemoteSourceStateChanged(meta, /* isPaSynced */ true, /* isBisSynced */ true); 4084 verify(mLeAudioService).activeBroadcastAssistantNotification(eq(true)); 4085 Mockito.clearInvocations(mLeAudioService); 4086 4087 /* Imitate broadcast source stop, sink notify about loosing PA and BIS sync */ 4088 injectRemoteSourceStateChanged(meta, /* isPaSynced */ false, /* isBisSynced */ false); 4089 4090 /* Unicast would like to stream */ 4091 mBassClientService.cacheSuspendingSources(TEST_BROADCAST_ID); 4092 4093 mBassClientService.resumeReceiversSourceSynchronization(); 4094 handleHandoverSupport(); 4095 verifyAllGroupMembersGettingUpdateOrAddSource(meta); 4096 } 4097 4098 @Test testHandleUnicastSourceStreamStatusChange()4099 public void testHandleUnicastSourceStreamStatusChange() { 4100 prepareConnectedDeviceGroup(); 4101 startSearchingForSources(); 4102 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 4103 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 4104 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 4105 4106 /* Fake external broadcast - no Broadcast Metadata from LE Audio service */ 4107 doReturn(new ArrayList<BluetoothLeBroadcastMetadata>()) 4108 .when(mLeAudioService) 4109 .getAllBroadcastMetadata(); 4110 4111 verifyAddSourceForGroup(meta); 4112 prepareRemoteSourceState(meta, /* isPaSynced */ true, /* isBisSynced */ true); 4113 4114 verify(mLeAudioService).activeBroadcastAssistantNotification(eq(true)); 4115 4116 /* Unicast would like to stream */ 4117 mBassClientService.handleUnicastSourceStreamStatusChange( 4118 0 /* STATUS_LOCAL_STREAM_REQUESTED */); 4119 4120 /* Imitate broadcast source stop, sink notify about loosing PA and BIS sync */ 4121 injectRemoteSourceStateChanged(meta, /* isPaSynced */ false, /* isBisSynced */ false); 4122 4123 /* Unicast finished streaming */ 4124 mBassClientService.handleUnicastSourceStreamStatusChange( 4125 2 /* STATUS_LOCAL_STREAM_SUSPENDED */); 4126 4127 verifyAllGroupMembersGettingUpdateOrAddSource(meta); 4128 4129 // Update receiver state with lost BIS sync 4130 injectRemoteSourceStateChanged(meta, /* isPaSynced */ true, /* isBisSynced */ false); 4131 if (!Flags.leaudioBroadcastResyncHelper() 4132 && !Flags.leaudioMonitorUnicastSourceWhenManagedByBroadcastDelegator()) { 4133 verify(mLeAudioService).activeBroadcastAssistantNotification(eq(false)); 4134 } 4135 } 4136 4137 @Test testHandleUnicastSourceStreamStatusChange_MultipleRequests()4138 public void testHandleUnicastSourceStreamStatusChange_MultipleRequests() { 4139 prepareConnectedDeviceGroup(); 4140 startSearchingForSources(); 4141 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 4142 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 4143 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 4144 4145 /* Fake external broadcast - no Broadcast Metadata from LE Audio service */ 4146 doReturn(new ArrayList<BluetoothLeBroadcastMetadata>()) 4147 .when(mLeAudioService) 4148 .getAllBroadcastMetadata(); 4149 4150 verifyAddSourceForGroup(meta); 4151 prepareRemoteSourceState(meta, /* isPaSynced */ true, /* isBisSynced */ true); 4152 4153 verify(mLeAudioService).activeBroadcastAssistantNotification(eq(true)); 4154 4155 /* Unicast would like to stream */ 4156 mBassClientService.handleUnicastSourceStreamStatusChange( 4157 3 /* STATUS_LOCAL_STREAM_REQUESTED_NO_CONTEXT_VALIDATE */); 4158 4159 /* Imitate broadcast source stop, sink notify about loosing BIS sync */ 4160 verifyModifyMessageAndInjectSourceModfified(); 4161 4162 assertThat(mStateMachines).hasSize(2); 4163 for (BassClientStateMachine sm : mStateMachines.values()) { 4164 Mockito.clearInvocations(sm); 4165 } 4166 // Make another stream request with no context validate 4167 mBassClientService.handleUnicastSourceStreamStatusChange( 4168 3 /* STATUS_LOCAL_STREAM_REQUESTED_NO_CONTEXT_VALIDATE */); 4169 4170 // Make another stream request 4171 mBassClientService.handleUnicastSourceStreamStatusChange( 4172 0 /* STATUS_LOCAL_STREAM_REQUESTED */); 4173 4174 /* Unicast finished streaming */ 4175 mBassClientService.handleUnicastSourceStreamStatusChange( 4176 2 /* STATUS_LOCAL_STREAM_SUSPENDED */); 4177 4178 // Verify all group members resume with the previous cached source 4179 for (BassClientStateMachine sm : mStateMachines.values()) { 4180 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 4181 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 4182 4183 Message msg = 4184 messageCaptor.getAllValues().stream() 4185 .filter( 4186 m -> 4187 (m.what == BassClientStateMachine.UPDATE_BCAST_SOURCE) 4188 && (m.obj == meta)) 4189 .findFirst() 4190 .orElse(null); 4191 expect.that(msg).isNotNull(); 4192 } 4193 } 4194 4195 @Test testIsAnyReceiverActive()4196 public void testIsAnyReceiverActive() { 4197 prepareConnectedDeviceGroup(); 4198 startSearchingForSources(); 4199 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 4200 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 4201 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 4202 verifyAddSourceForGroup(meta); 4203 prepareRemoteSourceState(meta, /* isPaSynced */ false, /* isBisSynced */ false); 4204 4205 List<BluetoothDevice> devices = mBassClientService.getConnectedDevices(); 4206 // Verify isAnyReceiverActive returns false if no PA and no BIS synced 4207 assertThat(mBassClientService.isAnyReceiverActive(devices)).isFalse(); 4208 4209 // Update receiver state with PA sync 4210 injectRemoteSourceStateChanged(meta, /* isPaSynced */ true, /* isBisSynced */ false); 4211 BluetoothDevice invalidDevice = getTestDevice(2); 4212 // Verify isAnyReceiverActive returns false if invalid device 4213 expect.that(mBassClientService.isAnyReceiverActive(List.of(invalidDevice))).isFalse(); 4214 // Verify isAnyReceiverActive returns true if PA synced 4215 expect.that(mBassClientService.isAnyReceiverActive(devices)).isTrue(); 4216 4217 // Update receiver state with PA and BIS sync 4218 injectRemoteSourceStateChanged(meta, /* isPaSynced */ true, /* isBisSynced */ true); 4219 // Verify isAnyReceiverActive returns true if PA and BIS synced 4220 expect.that(mBassClientService.isAnyReceiverActive(devices)).isTrue(); 4221 4222 // Update receiver state with BIS only sync 4223 injectRemoteSourceStateChanged(meta, /* isPaSynced */ false, /* isBisSynced */ true); 4224 // Verify isAnyReceiverActive returns true if BIS only synced 4225 expect.that(mBassClientService.isAnyReceiverActive(devices)).isTrue(); 4226 } 4227 4228 @Test testGetSyncedBroadcastSinks()4229 public void testGetSyncedBroadcastSinks() { 4230 prepareConnectedDeviceGroup(); 4231 startSearchingForSources(); 4232 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 4233 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 4234 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 4235 BluetoothLeBroadcastMetadata metaNoBroadcast = createEmptyBroadcastMetadata(); 4236 4237 verifyAddSourceForGroup(meta); 4238 prepareRemoteSourceState(metaNoBroadcast, /* isPaSynced */ true, /* isBisSynced */ false); 4239 4240 // Verify getSyncedBroadcastSinks returns empty device list if no broadcast ID 4241 assertThat(mBassClientService.getSyncedBroadcastSinks().isEmpty()).isTrue(); 4242 assertThat(mBassClientService.getSyncedBroadcastSinks(TEST_BROADCAST_ID).isEmpty()) 4243 .isTrue(); 4244 4245 // Update receiver state with broadcast ID 4246 injectRemoteSourceStateChanged(meta, /* isPaSynced */ true, /* isBisSynced */ false); 4247 4248 List<BluetoothDevice> activeSinks = mBassClientService.getSyncedBroadcastSinks(); 4249 if (Flags.leaudioBigDependsOnAudioState()) { 4250 // Verify getSyncedBroadcastSinks returns correct device list if no BIS synced 4251 assertThat(activeSinks).hasSize(2); 4252 assertThat(activeSinks.contains(mCurrentDevice)).isTrue(); 4253 assertThat(activeSinks.contains(mCurrentDevice1)).isTrue(); 4254 } else { 4255 // Verify getSyncedBroadcastSinks returns empty device list if no BIS synced 4256 assertThat(mBassClientService.getSyncedBroadcastSinks().isEmpty()).isTrue(); 4257 } 4258 4259 activeSinks.clear(); 4260 // Verify getSyncedBroadcastSinks by broadcast id 4261 activeSinks = mBassClientService.getSyncedBroadcastSinks(TEST_BROADCAST_ID); 4262 if (Flags.leaudioBigDependsOnAudioState()) { 4263 // Verify getSyncedBroadcastSinks returns correct device list if no BIS synced 4264 assertThat(activeSinks.size()).isEqualTo(2); 4265 assertThat(activeSinks.contains(mCurrentDevice)).isTrue(); 4266 assertThat(activeSinks.contains(mCurrentDevice1)).isTrue(); 4267 } 4268 4269 // Update receiver state with BIS sync 4270 injectRemoteSourceStateChanged(meta, /* isPaSynced */ true, /* isBisSynced */ true); 4271 4272 // Verify getSyncedBroadcastSinks returns correct device list if BIS synced 4273 activeSinks = mBassClientService.getSyncedBroadcastSinks(); 4274 expect.that(activeSinks.size()).isEqualTo(2); 4275 expect.that(activeSinks.contains(mCurrentDevice)).isTrue(); 4276 expect.that(activeSinks.contains(mCurrentDevice1)).isTrue(); 4277 } 4278 prepareTwoSynchronizedDevicesForLocalBroadcast()4279 private void prepareTwoSynchronizedDevicesForLocalBroadcast() throws RemoteException { 4280 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 4281 4282 doReturn(new ArrayList<BluetoothLeBroadcastMetadata>(Arrays.asList(meta))) 4283 .when(mLeAudioService) 4284 .getAllBroadcastMetadata(); 4285 prepareConnectedDeviceGroup(); 4286 verifyAddSourceForGroup(meta); 4287 for (BassClientStateMachine sm : mStateMachines.values()) { 4288 if (sm.getDevice().equals(mCurrentDevice)) { 4289 injectRemoteSourceStateSourceAdded( 4290 sm, 4291 meta, 4292 TEST_SOURCE_ID, 4293 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 4294 meta.isEncrypted() 4295 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 4296 : BluetoothLeBroadcastReceiveState 4297 .BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 4298 null); 4299 // verify source id 4300 verify(mCallback, timeout(TIMEOUT_MS).atLeastOnce()) 4301 .onSourceAdded( 4302 eq(mCurrentDevice), 4303 eq(TEST_SOURCE_ID), 4304 eq(BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST)); 4305 } else if (sm.getDevice().equals(mCurrentDevice1)) { 4306 injectRemoteSourceStateSourceAdded( 4307 sm, 4308 meta, 4309 TEST_SOURCE_ID + 1, 4310 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 4311 meta.isEncrypted() 4312 ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING 4313 : BluetoothLeBroadcastReceiveState 4314 .BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 4315 null); 4316 // verify source id 4317 verify(mCallback, timeout(TIMEOUT_MS).atLeastOnce()) 4318 .onSourceAdded( 4319 eq(mCurrentDevice1), 4320 eq(TEST_SOURCE_ID + 1), 4321 eq(BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST)); 4322 } 4323 } 4324 } 4325 4326 @Test testLocalAddSourceWhenBroadcastIsPlaying()4327 public void testLocalAddSourceWhenBroadcastIsPlaying() throws RemoteException { 4328 doReturn(true).when(mLeAudioService).isPlaying(TEST_BROADCAST_ID); 4329 if (Flags.leaudioBigDependsOnAudioState()) { 4330 doReturn(false).when(mLeAudioService).isPaused(TEST_BROADCAST_ID); 4331 } 4332 4333 prepareTwoSynchronizedDevicesForLocalBroadcast(); 4334 } 4335 4336 @Test 4337 @EnableFlags({Flags.FLAG_LEAUDIO_BIG_DEPENDS_ON_AUDIO_STATE}) testLocalAddSourceWhenBroadcastIsPaused()4338 public void testLocalAddSourceWhenBroadcastIsPaused() throws RemoteException { 4339 doReturn(false).when(mLeAudioService).isPlaying(TEST_BROADCAST_ID); 4340 doReturn(true).when(mLeAudioService).isPaused(TEST_BROADCAST_ID); 4341 4342 prepareTwoSynchronizedDevicesForLocalBroadcast(); 4343 } 4344 4345 @Test testLocalAddSourceWhenBroadcastIsStopped()4346 public void testLocalAddSourceWhenBroadcastIsStopped() throws RemoteException { 4347 doReturn(false).when(mLeAudioService).isPlaying(TEST_BROADCAST_ID); 4348 if (Flags.leaudioBigDependsOnAudioState()) { 4349 doReturn(false).when(mLeAudioService).isPaused(TEST_BROADCAST_ID); 4350 } 4351 4352 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 4353 4354 doReturn(new ArrayList<BluetoothLeBroadcastMetadata>(Arrays.asList(meta))) 4355 .when(mLeAudioService) 4356 .getAllBroadcastMetadata(); 4357 prepareConnectedDeviceGroup(); 4358 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 4359 verify(mCallback, timeout(TIMEOUT_MS).atLeastOnce()) 4360 .onSourceAddFailed( 4361 eq(mCurrentDevice), 4362 eq(meta), 4363 eq(BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES)); 4364 } 4365 4366 @Test testSinksDisconnectionWhenBroadcastIsPlaying()4367 public void testSinksDisconnectionWhenBroadcastIsPlaying() throws RemoteException { 4368 /* Imitate broadcast being active */ 4369 doReturn(true).when(mLeAudioService).isPlaying(TEST_BROADCAST_ID); 4370 if (Flags.leaudioBigDependsOnAudioState()) { 4371 doReturn(false).when(mLeAudioService).isPaused(TEST_BROADCAST_ID); 4372 } 4373 4374 prepareTwoSynchronizedDevicesForLocalBroadcast(); 4375 4376 /* Imitate scenario when if there would be broadcast - stop would be called */ 4377 mBassClientService.handleDeviceDisconnection(mCurrentDevice, true); 4378 mBassClientService.handleDeviceDisconnection(mCurrentDevice1, true); 4379 4380 verify(mLeAudioService).stopBroadcast(eq(TEST_BROADCAST_ID)); 4381 } 4382 4383 @Test 4384 @EnableFlags(Flags.FLAG_LEAUDIO_BIG_DEPENDS_ON_AUDIO_STATE) testSinksDisconnectionWhenBroadcastIsPaused()4385 public void testSinksDisconnectionWhenBroadcastIsPaused() throws RemoteException { 4386 /* Imitate broadcast being active */ 4387 doReturn(false).when(mLeAudioService).isPlaying(TEST_BROADCAST_ID); 4388 doReturn(true).when(mLeAudioService).isPaused(TEST_BROADCAST_ID); 4389 4390 prepareTwoSynchronizedDevicesForLocalBroadcast(); 4391 4392 /* Imitate scenario when if there would be broadcast - stop would be called */ 4393 mBassClientService.handleDeviceDisconnection(mCurrentDevice, true); 4394 mBassClientService.handleDeviceDisconnection(mCurrentDevice1, true); 4395 4396 verify(mLeAudioService).stopBroadcast(eq(TEST_BROADCAST_ID)); 4397 } 4398 4399 @Test testSinksDisconnectionWhenBroadcastIsStopped()4400 public void testSinksDisconnectionWhenBroadcastIsStopped() throws RemoteException { 4401 /* Imitate broadcast being active */ 4402 doReturn(true).when(mLeAudioService).isPlaying(TEST_BROADCAST_ID); 4403 if (Flags.leaudioBigDependsOnAudioState()) { 4404 doReturn(false).when(mLeAudioService).isPaused(TEST_BROADCAST_ID); 4405 } 4406 4407 prepareTwoSynchronizedDevicesForLocalBroadcast(); 4408 4409 doReturn(false).when(mLeAudioService).isPlaying(TEST_BROADCAST_ID); 4410 4411 /* Imitate scenario when if there would be broadcast - stop would be called */ 4412 mBassClientService.handleDeviceDisconnection(mCurrentDevice, true); 4413 mBassClientService.handleDeviceDisconnection(mCurrentDevice1, true); 4414 4415 verify(mLeAudioService, never()).stopBroadcast(eq(TEST_BROADCAST_ID)); 4416 } 4417 4418 @Test testPrivateBroadcastIntentionalDisconnection()4419 public void testPrivateBroadcastIntentionalDisconnection() throws RemoteException { 4420 /* Imitate broadcast being active */ 4421 doReturn(true).when(mLeAudioService).isPlaying(TEST_BROADCAST_ID); 4422 4423 prepareTwoSynchronizedDevicesForLocalBroadcast(); 4424 4425 /* Imitate devices being primary */ 4426 doReturn(true).when(mLeAudioService).isPrimaryDevice(mCurrentDevice); 4427 doReturn(true).when(mLeAudioService).isPrimaryDevice(mCurrentDevice1); 4428 4429 /* Imitate device 1/2 disconnection from StateMachine context */ 4430 mBassClientService.handleDeviceDisconnection(mCurrentDevice, true); 4431 4432 /* After first device disconnection and de-synchronization expect not stopping broadcast */ 4433 verify(mLeAudioService, never()).stopBroadcast(eq(TEST_BROADCAST_ID)); 4434 4435 /* Imitate first device being in disconnected state */ 4436 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 4437 4438 /* Imitate device 2/2 disconnection from StateMachine context */ 4439 mBassClientService.handleDeviceDisconnection(mCurrentDevice1, true); 4440 4441 /* After second device disconnection and de-synchronization expect stopping broadcast */ 4442 verify(mLeAudioService).stopBroadcast(eq(TEST_BROADCAST_ID)); 4443 } 4444 4445 @Test testPrivateBroadcastUnintentionalDisconnection()4446 public void testPrivateBroadcastUnintentionalDisconnection() throws RemoteException { 4447 /* Imitate broadcast being active */ 4448 doReturn(true).when(mLeAudioService).isPlaying(TEST_BROADCAST_ID); 4449 4450 prepareTwoSynchronizedDevicesForLocalBroadcast(); 4451 4452 /* Imitate devices being primary */ 4453 doReturn(true).when(mLeAudioService).isPrimaryDevice(mCurrentDevice); 4454 doReturn(true).when(mLeAudioService).isPrimaryDevice(mCurrentDevice1); 4455 4456 /* Imitate device 1/2 disconnection from StateMachine context */ 4457 mBassClientService.handleDeviceDisconnection(mCurrentDevice, false); 4458 4459 /* After first device disconnection and de-synchronization expect not stopping broadcast */ 4460 verify(mLeAudioService, never()).stopBroadcast(eq(TEST_BROADCAST_ID)); 4461 4462 /* Imitate first device being in disconnected state */ 4463 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 4464 4465 /* Imitate device 2/2 disconnection from StateMachine context */ 4466 mBassClientService.handleDeviceDisconnection(mCurrentDevice1, false); 4467 4468 /* After second device disconnection and de-synchronization expect stopping broadcast */ 4469 verify(mLeAudioService).stopBroadcast(eq(TEST_BROADCAST_ID)); 4470 } 4471 4472 @Test testAudioSharingIntentionalDisconnection()4473 public void testAudioSharingIntentionalDisconnection() throws RemoteException { 4474 /* Imitate broadcast being active */ 4475 doReturn(true).when(mLeAudioService).isPlaying(TEST_BROADCAST_ID); 4476 4477 prepareTwoSynchronizedDevicesForLocalBroadcast(); 4478 4479 /* Imitate devices being primary */ 4480 doReturn(true).when(mLeAudioService).isPrimaryDevice(mCurrentDevice); 4481 doReturn(false).when(mLeAudioService).isPrimaryDevice(mCurrentDevice1); 4482 4483 /* Imitate device 1/2 disconnection from StateMachine context */ 4484 mBassClientService.handleDeviceDisconnection(mCurrentDevice, true); 4485 4486 /* After first device disconnection and de-synchronization expect stopping broadcast */ 4487 verify(mLeAudioService).stopBroadcast(eq(TEST_BROADCAST_ID)); 4488 4489 /* Imitate first device being in disconnected state */ 4490 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 4491 4492 /* Imitate device 2/2 disconnection from StateMachine context */ 4493 mBassClientService.handleDeviceDisconnection(mCurrentDevice1, true); 4494 4495 /* After second device disconnection and de-synchronization expect not stopping broadcast */ 4496 verify(mLeAudioService).stopBroadcast(eq(TEST_BROADCAST_ID)); 4497 } 4498 4499 @Test testAudioSharingUnintentionalDisconnection()4500 public void testAudioSharingUnintentionalDisconnection() throws RemoteException { 4501 /* Imitate broadcast being active */ 4502 doReturn(true).when(mLeAudioService).isPlaying(TEST_BROADCAST_ID); 4503 4504 prepareTwoSynchronizedDevicesForLocalBroadcast(); 4505 4506 /* Imitate devices being primary */ 4507 doReturn(true).when(mLeAudioService).isPrimaryDevice(mCurrentDevice); 4508 doReturn(false).when(mLeAudioService).isPrimaryDevice(mCurrentDevice1); 4509 4510 /* Imitate device 1/2 disconnection from StateMachine context */ 4511 mBassClientService.handleDeviceDisconnection(mCurrentDevice, false); 4512 4513 /* After first device disconnection and de-synchronization expect not stopping broadcast */ 4514 verify(mLeAudioService, never()).stopBroadcast(eq(TEST_BROADCAST_ID)); 4515 4516 /* Imitate first device being in disconnected state */ 4517 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 4518 4519 /* Imitate device 2/2 disconnection from StateMachine context */ 4520 mBassClientService.handleDeviceDisconnection(mCurrentDevice1, false); 4521 4522 /* After second device disconnection and de-synchronization timeout to be fired */ 4523 verify(mLeAudioService, never()).stopBroadcast(eq(TEST_BROADCAST_ID)); 4524 } 4525 4526 @Test testNotifyBroadcastStateChangedStopped()4527 public void testNotifyBroadcastStateChangedStopped() throws RemoteException { 4528 /* Imitate broadcast being active */ 4529 doReturn(true).when(mLeAudioService).isPlaying(TEST_BROADCAST_ID); 4530 4531 prepareTwoSynchronizedDevicesForLocalBroadcast(); 4532 4533 mBassClientService.notifyBroadcastStateChanged( 4534 0 /* BROADCAST_STATE_STOPPED */, TEST_BROADCAST_ID); 4535 4536 /* Imitate scenario when if there would be broadcast - stop would be called */ 4537 mBassClientService.handleDeviceDisconnection(mCurrentDevice, true); 4538 mBassClientService.handleDeviceDisconnection(mCurrentDevice1, true); 4539 4540 /* After second device disconnection and de-synchronization expect not calling broadcast to 4541 * stop due to previous broadcast stream stopped */ 4542 verify(mLeAudioService, never()).stopBroadcast(eq(TEST_BROADCAST_ID)); 4543 } 4544 4545 @Test onPeriodicAdvertisingReport_withoutBaseData_cancelActiveSync()4546 public void onPeriodicAdvertisingReport_withoutBaseData_cancelActiveSync() { 4547 prepareConnectedDeviceGroup(); 4548 startSearchingForSources(); 4549 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 4550 mInOrderMethodProxy 4551 .verify(mMethodProxy) 4552 .periodicAdvertisingManagerRegisterSync( 4553 any(), any(), anyInt(), anyInt(), any(), any()); 4554 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 4555 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 4556 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 4557 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 4558 .isEqualTo(mSourceDevice); 4559 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 4560 .isEqualTo(TEST_BROADCAST_ID); 4561 assertThat(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNull(); 4562 4563 byte[] scanRecord = 4564 new byte[] { 4565 0x02, 4566 0x01, 4567 0x1a, // advertising flags 4568 0x05, 4569 0x02, 4570 0x0b, 4571 0x11, 4572 0x0a, 4573 0x11, // 16 bit service uuids 4574 0x04, 4575 0x09, 4576 0x50, 4577 0x65, 4578 0x64, // name 4579 0x02, 4580 0x0A, 4581 (byte) 0xec, // tx power level 4582 0x05, 4583 0x16, 4584 0x0b, 4585 0x11, 4586 0x50, 4587 0x64, // service data 4588 0x05, 4589 (byte) 0xff, 4590 (byte) 0xe0, 4591 0x00, 4592 0x02, 4593 0x15, // manufacturer specific data 4594 0x03, 4595 0x50, 4596 0x01, 4597 0x02, // an unknown data type won't cause trouble 4598 }; 4599 PeriodicAdvertisingReport report = 4600 new PeriodicAdvertisingReport( 4601 TEST_SYNC_HANDLE, 0, 0, 0, ScanRecord.parseFromBytes(scanRecord)); 4602 4603 BassClientService.PACallback callback = mBassClientService.new PACallback(); 4604 4605 callback.onPeriodicAdvertisingReport(report); 4606 callback.onPeriodicAdvertisingReport(report); 4607 callback.onPeriodicAdvertisingReport(report); 4608 callback.onPeriodicAdvertisingReport(report); 4609 4610 // Not canceled, not updated base 4611 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 4612 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 4613 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 4614 .isEqualTo(mSourceDevice); 4615 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 4616 .isEqualTo(TEST_BROADCAST_ID); 4617 assertThat(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNull(); 4618 mInOrderMethodProxy 4619 .verify(mMethodProxy, never()) 4620 .periodicAdvertisingManagerUnregisterSync(any(), any()); 4621 4622 callback.onPeriodicAdvertisingReport(report); 4623 4624 // Canceled, not updated base 4625 expect.that(mBassClientService.getActiveSyncedSources()).isEmpty(); 4626 expect.that(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)).isNull(); 4627 expect.that(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 4628 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 4629 expect.that(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNull(); 4630 mInOrderMethodProxy 4631 .verify(mMethodProxy) 4632 .periodicAdvertisingManagerUnregisterSync(any(), any()); 4633 } 4634 4635 @Test onPeriodicAdvertisingReport_wrongBaseData_cancelActiveSync()4636 public void onPeriodicAdvertisingReport_wrongBaseData_cancelActiveSync() { 4637 prepareConnectedDeviceGroup(); 4638 startSearchingForSources(); 4639 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 4640 mInOrderMethodProxy 4641 .verify(mMethodProxy) 4642 .periodicAdvertisingManagerRegisterSync( 4643 any(), any(), anyInt(), anyInt(), any(), any()); 4644 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 4645 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 4646 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 4647 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 4648 .isEqualTo(mSourceDevice); 4649 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 4650 .isEqualTo(TEST_BROADCAST_ID); 4651 assertThat(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNull(); 4652 4653 byte[] scanRecord = 4654 new byte[] { 4655 (byte) 0x02, 4656 (byte) 0x01, 4657 (byte) 0x1a, // advertising flags 4658 (byte) 0x05, 4659 (byte) 0x02, 4660 (byte) 0x51, 4661 (byte) 0x18, 4662 (byte) 0x0a, 4663 (byte) 0x11, // 16 bit service uuids 4664 (byte) 0x04, 4665 (byte) 0x09, 4666 (byte) 0x50, 4667 (byte) 0x65, 4668 (byte) 0x64, // name 4669 (byte) 0x02, 4670 (byte) 0x0A, 4671 (byte) 0xec, // tx power level 4672 (byte) 0x19, 4673 (byte) 0x16, 4674 (byte) 0x51, 4675 (byte) 0x18, // service data (base data with 18 bytes) 4676 // LEVEL 1 4677 (byte) 0x01, 4678 (byte) 0x02, 4679 (byte) 0x03, // mPresentationDelay 4680 (byte) 0x01, // mNumSubGroups 4681 // LEVEL 3 4682 (byte) 0x04, // mIndex 4683 (byte) 0x03, // mCodecConfigLength 4684 (byte) 0x02, 4685 (byte) 'B', 4686 (byte) 'C', // mCodecConfigInfo 4687 (byte) 0x05, 4688 (byte) 0xff, 4689 (byte) 0xe0, 4690 (byte) 0x00, 4691 (byte) 0x02, 4692 (byte) 0x15, // manufacturer specific data 4693 (byte) 0x03, 4694 (byte) 0x50, 4695 (byte) 0x01, 4696 (byte) 0x02, // an unknown data type won't cause trouble 4697 }; 4698 PeriodicAdvertisingReport report = 4699 new PeriodicAdvertisingReport( 4700 TEST_SYNC_HANDLE, 0, 0, 0, ScanRecord.parseFromBytes(scanRecord)); 4701 4702 BassClientService.PACallback callback = mBassClientService.new PACallback(); 4703 4704 callback.onPeriodicAdvertisingReport(report); 4705 callback.onPeriodicAdvertisingReport(report); 4706 callback.onPeriodicAdvertisingReport(report); 4707 callback.onPeriodicAdvertisingReport(report); 4708 4709 // Not canceled, not updated base 4710 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 4711 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 4712 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 4713 .isEqualTo(mSourceDevice); 4714 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 4715 .isEqualTo(TEST_BROADCAST_ID); 4716 assertThat(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNull(); 4717 mInOrderMethodProxy 4718 .verify(mMethodProxy, never()) 4719 .periodicAdvertisingManagerUnregisterSync(any(), any()); 4720 4721 callback.onPeriodicAdvertisingReport(report); 4722 4723 // Canceled, not updated base 4724 expect.that(mBassClientService.getActiveSyncedSources()).isEmpty(); 4725 expect.that(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)).isNull(); 4726 expect.that(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 4727 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 4728 expect.that(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNull(); 4729 mInOrderMethodProxy 4730 .verify(mMethodProxy) 4731 .periodicAdvertisingManagerUnregisterSync(any(), any()); 4732 } 4733 4734 @Test onPeriodicAdvertisingReport_updateBase()4735 public void onPeriodicAdvertisingReport_updateBase() { 4736 prepareConnectedDeviceGroup(); 4737 startSearchingForSources(); 4738 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 4739 mInOrderMethodProxy 4740 .verify(mMethodProxy) 4741 .periodicAdvertisingManagerRegisterSync( 4742 any(), any(), anyInt(), anyInt(), any(), any()); 4743 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 4744 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 4745 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 4746 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 4747 .isEqualTo(mSourceDevice); 4748 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 4749 .isEqualTo(TEST_BROADCAST_ID); 4750 assertThat(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNull(); 4751 4752 onPeriodicAdvertisingReport(); 4753 4754 // Not canceled, updated base 4755 expect.that(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); 4756 expect.that(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 4757 expect.that(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 4758 .isEqualTo(mSourceDevice); 4759 expect.that(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 4760 .isEqualTo(TEST_BROADCAST_ID); 4761 expect.that(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNotNull(); 4762 mInOrderMethodProxy 4763 .verify(mMethodProxy, never()) 4764 .periodicAdvertisingManagerUnregisterSync(any(), any()); 4765 } 4766 4767 @Test onPeriodicAdvertisingReport_updateBaseAfterWrongBaseData()4768 public void onPeriodicAdvertisingReport_updateBaseAfterWrongBaseData() { 4769 prepareConnectedDeviceGroup(); 4770 startSearchingForSources(); 4771 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 4772 mInOrderMethodProxy 4773 .verify(mMethodProxy) 4774 .periodicAdvertisingManagerRegisterSync( 4775 any(), any(), anyInt(), anyInt(), any(), any()); 4776 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 4777 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 4778 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 4779 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 4780 .isEqualTo(mSourceDevice); 4781 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 4782 .isEqualTo(TEST_BROADCAST_ID); 4783 assertThat(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNull(); 4784 4785 byte[] scanRecordNoBaseData = 4786 new byte[] { 4787 0x02, 4788 0x01, 4789 0x1a, // advertising flags 4790 0x05, 4791 0x02, 4792 0x0b, 4793 0x11, 4794 0x0a, 4795 0x11, // 16 bit service uuids 4796 0x04, 4797 0x09, 4798 0x50, 4799 0x65, 4800 0x64, // name 4801 0x02, 4802 0x0A, 4803 (byte) 0xec, // tx power level 4804 0x05, 4805 0x16, 4806 0x0b, 4807 0x11, 4808 0x50, 4809 0x64, // service data 4810 0x05, 4811 (byte) 0xff, 4812 (byte) 0xe0, 4813 0x00, 4814 0x02, 4815 0x15, // manufacturer specific data 4816 0x03, 4817 0x50, 4818 0x01, 4819 0x02, // an unknown data type won't cause trouble 4820 }; 4821 4822 byte[] scanRecordWrongBaseData = 4823 new byte[] { 4824 (byte) 0x02, 4825 (byte) 0x01, 4826 (byte) 0x1a, // advertising flags 4827 (byte) 0x05, 4828 (byte) 0x02, 4829 (byte) 0x51, 4830 (byte) 0x18, 4831 (byte) 0x0a, 4832 (byte) 0x11, // 16 bit service uuids 4833 (byte) 0x04, 4834 (byte) 0x09, 4835 (byte) 0x50, 4836 (byte) 0x65, 4837 (byte) 0x64, // name 4838 (byte) 0x02, 4839 (byte) 0x0A, 4840 (byte) 0xec, // tx power level 4841 (byte) 0x19, 4842 (byte) 0x16, 4843 (byte) 0x51, 4844 (byte) 0x18, // service data (base data with 18 bytes) 4845 // LEVEL 1 4846 (byte) 0x01, 4847 (byte) 0x02, 4848 (byte) 0x03, // mPresentationDelay 4849 (byte) 0x01, // mNumSubGroups 4850 // LEVEL 3 4851 (byte) 0x04, // mIndex 4852 (byte) 0x03, // mCodecConfigLength 4853 (byte) 0x02, 4854 (byte) 'B', 4855 (byte) 'C', // mCodecConfigInfo 4856 (byte) 0x05, 4857 (byte) 0xff, 4858 (byte) 0xe0, 4859 (byte) 0x00, 4860 (byte) 0x02, 4861 (byte) 0x15, // manufacturer specific data 4862 (byte) 0x03, 4863 (byte) 0x50, 4864 (byte) 0x01, 4865 (byte) 0x02, // an unknown data type won't cause trouble 4866 }; 4867 4868 BassClientService.PACallback callback = mBassClientService.new PACallback(); 4869 4870 PeriodicAdvertisingReport report = 4871 new PeriodicAdvertisingReport( 4872 TEST_SYNC_HANDLE, 0, 0, 0, ScanRecord.parseFromBytes(scanRecordNoBaseData)); 4873 callback.onPeriodicAdvertisingReport(report); 4874 report = 4875 new PeriodicAdvertisingReport( 4876 TEST_SYNC_HANDLE, 4877 0, 4878 0, 4879 0, 4880 ScanRecord.parseFromBytes(scanRecordWrongBaseData)); 4881 callback.onPeriodicAdvertisingReport(report); 4882 4883 // Not canceled, not updated base 4884 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 4885 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 4886 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 4887 .isEqualTo(mSourceDevice); 4888 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 4889 .isEqualTo(TEST_BROADCAST_ID); 4890 assertThat(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNull(); 4891 mInOrderMethodProxy 4892 .verify(mMethodProxy, never()) 4893 .periodicAdvertisingManagerUnregisterSync(any(), any()); 4894 4895 onPeriodicAdvertisingReport(); 4896 4897 // Not canceled, updated base 4898 expect.that(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); 4899 expect.that(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 4900 expect.that(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 4901 .isEqualTo(mSourceDevice); 4902 expect.that(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 4903 .isEqualTo(TEST_BROADCAST_ID); 4904 expect.that(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNotNull(); 4905 mInOrderMethodProxy 4906 .verify(mMethodProxy, never()) 4907 .periodicAdvertisingManagerUnregisterSync(any(), any()); 4908 } 4909 4910 @Test notifySourceFound_once_updateRssi()4911 public void notifySourceFound_once_updateRssi() throws RemoteException { 4912 prepareConnectedDeviceGroup(); 4913 startSearchingForSources(); 4914 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 4915 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 4916 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 4917 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 4918 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 4919 .isEqualTo(mSourceDevice); 4920 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 4921 .isEqualTo(TEST_BROADCAST_ID); 4922 assertThat(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNull(); 4923 4924 onPeriodicAdvertisingReport(); 4925 4926 // Not canceled, updated base 4927 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 4928 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 4929 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 4930 .isEqualTo(mSourceDevice); 4931 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 4932 .isEqualTo(TEST_BROADCAST_ID); 4933 assertThat(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNotNull(); 4934 4935 if (!Flags.leaudioBigDependsOnAudioState()) { 4936 onBigInfoAdvertisingReport(); 4937 } 4938 4939 // Notified 4940 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 4941 ArgumentCaptor<BluetoothLeBroadcastMetadata> metaData = 4942 ArgumentCaptor.forClass(BluetoothLeBroadcastMetadata.class); 4943 InOrder inOrder = inOrder(mCallback); 4944 inOrder.verify(mCallback).onSourceFound(metaData.capture()); 4945 assertThat(metaData.getValue().getRssi()).isEqualTo(TEST_RSSI); 4946 4947 // Any of them should not notified second time 4948 onPeriodicAdvertisingReport(); 4949 onBigInfoAdvertisingReport(); 4950 4951 // Not notified second time 4952 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 4953 inOrder.verify(mCallback, never()).onSourceFound(any()); 4954 } 4955 4956 @Test 4957 @EnableFlags(Flags.FLAG_LEAUDIO_BIG_DEPENDS_ON_AUDIO_STATE) notifySourceFound_without_public_announcement()4958 public void notifySourceFound_without_public_announcement() throws RemoteException { 4959 prepareConnectedDeviceGroup(); 4960 startSearchingForSources(); 4961 4962 byte[] broadcastScanRecord = 4963 new byte[] { 4964 0x02, 4965 0x01, 4966 0x1a, // advertising flags 4967 0x05, 4968 0x02, 4969 0x52, 4970 0x18, 4971 0x0a, 4972 0x11, // 16 bit service uuids 4973 0x04, 4974 0x09, 4975 0x50, 4976 0x65, 4977 0x64, // name 4978 0x02, 4979 0x0A, 4980 (byte) 0xec, // tx power level 4981 0x05, 4982 0x30, 4983 0x54, 4984 0x65, 4985 0x73, 4986 0x74, // broadcast name: Test 4987 0x06, 4988 0x16, 4989 0x52, 4990 0x18, 4991 (byte) TEST_BROADCAST_ID, 4992 (byte) (TEST_BROADCAST_ID >> 8), 4993 (byte) (TEST_BROADCAST_ID >> 16), // service data, broadcast id 4994 0x05, 4995 (byte) 0xff, 4996 (byte) 0xe0, 4997 0x00, 4998 0x02, 4999 0x15, // manufacturer specific data 5000 0x03, 5001 0x50, 5002 0x01, 5003 0x02, // an unknown data type won't cause trouble 5004 }; 5005 ScanResult scanResult = 5006 new ScanResult( 5007 mSourceDevice, 5008 0, 5009 0, 5010 0, 5011 0, 5012 0, 5013 TEST_RSSI, 5014 0, 5015 ScanRecord.parseFromBytes(broadcastScanRecord), 5016 0); 5017 generateScanResult(scanResult); 5018 5019 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 5020 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 5021 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 5022 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 5023 .isEqualTo(mSourceDevice); 5024 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 5025 .isEqualTo(TEST_BROADCAST_ID); 5026 assertThat(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNull(); 5027 5028 // No public announcement so it will not notify 5029 onPeriodicAdvertisingReport(); 5030 5031 // Not canceled, updated base 5032 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 5033 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 5034 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 5035 .isEqualTo(mSourceDevice); 5036 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 5037 .isEqualTo(TEST_BROADCAST_ID); 5038 assertThat(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNotNull(); 5039 5040 // Not notified 5041 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 5042 InOrder inOrder = inOrder(mCallback); 5043 inOrder.verify(mCallback, never()).onSourceFound(any()); 5044 5045 // onBigInfoAdvertisingReport causes notification 5046 onBigInfoAdvertisingReport(); 5047 5048 // Notified 5049 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 5050 inOrder.verify(mCallback).onSourceFound(any()); 5051 } 5052 5053 @Test notifySourceFound_periodic_after_big()5054 public void notifySourceFound_periodic_after_big() throws RemoteException { 5055 prepareConnectedDeviceGroup(); 5056 startSearchingForSources(); 5057 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 5058 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 5059 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 5060 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 5061 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 5062 .isEqualTo(mSourceDevice); 5063 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 5064 .isEqualTo(TEST_BROADCAST_ID); 5065 assertThat(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNull(); 5066 5067 // Big report before periodic so before base update 5068 onBigInfoAdvertisingReport(); 5069 5070 // Not notified 5071 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 5072 InOrder inOrder = inOrder(mCallback); 5073 inOrder.verify(mCallback, never()).onSourceFound(any()); 5074 5075 onPeriodicAdvertisingReport(); 5076 5077 // Not canceled, updated base 5078 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 5079 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 5080 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 5081 .isEqualTo(mSourceDevice); 5082 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 5083 .isEqualTo(TEST_BROADCAST_ID); 5084 assertThat(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNotNull(); 5085 5086 if (!Flags.leaudioBigDependsOnAudioState()) { 5087 // onBigInfoAdvertisingReport causes notification 5088 onBigInfoAdvertisingReport(); 5089 } 5090 5091 // Notified 5092 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 5093 inOrder.verify(mCallback).onSourceFound(any()); 5094 } 5095 5096 @Test 5097 @EnableFlags(Flags.FLAG_LEAUDIO_BIG_DEPENDS_ON_AUDIO_STATE) notifySourceFound_periodic_after_wrong_periodic()5098 public void notifySourceFound_periodic_after_wrong_periodic() throws RemoteException { 5099 prepareConnectedDeviceGroup(); 5100 startSearchingForSources(); 5101 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 5102 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 5103 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 5104 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 5105 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 5106 .isEqualTo(mSourceDevice); 5107 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 5108 .isEqualTo(TEST_BROADCAST_ID); 5109 assertThat(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNull(); 5110 5111 byte[] scanRecordNoBaseData = 5112 new byte[] { 5113 0x02, 5114 0x01, 5115 0x1a, // advertising flags 5116 0x05, 5117 0x02, 5118 0x0b, 5119 0x11, 5120 0x0a, 5121 0x11, // 16 bit service uuids 5122 0x04, 5123 0x09, 5124 0x50, 5125 0x65, 5126 0x64, // name 5127 0x02, 5128 0x0A, 5129 (byte) 0xec, // tx power level 5130 0x05, 5131 0x16, 5132 0x0b, 5133 0x11, 5134 0x50, 5135 0x64, // service data 5136 0x05, 5137 (byte) 0xff, 5138 (byte) 0xe0, 5139 0x00, 5140 0x02, 5141 0x15, // manufacturer specific data 5142 0x03, 5143 0x50, 5144 0x01, 5145 0x02, // an unknown data type won't cause trouble 5146 }; 5147 5148 BassClientService.PACallback callback = mBassClientService.new PACallback(); 5149 5150 PeriodicAdvertisingReport report = 5151 new PeriodicAdvertisingReport( 5152 TEST_SYNC_HANDLE, 0, 0, 0, ScanRecord.parseFromBytes(scanRecordNoBaseData)); 5153 5154 // Wrong base data not cause notification 5155 callback.onPeriodicAdvertisingReport(report); 5156 5157 // Not notified 5158 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 5159 InOrder inOrder = inOrder(mCallback); 5160 inOrder.verify(mCallback, never()).onSourceFound(any()); 5161 5162 onPeriodicAdvertisingReport(); 5163 5164 // Not canceled, updated base 5165 expect.that(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); 5166 expect.that(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 5167 expect.that(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 5168 .isEqualTo(mSourceDevice); 5169 expect.that(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 5170 .isEqualTo(TEST_BROADCAST_ID); 5171 expect.that(mBassClientService.getBase(TEST_SYNC_HANDLE)).isNotNull(); 5172 5173 // Notified 5174 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 5175 inOrder.verify(mCallback).onSourceFound(any()); 5176 } 5177 5178 @Test notifySourceFound_alreadySynced_clearFlag()5179 public void notifySourceFound_alreadySynced_clearFlag() throws RemoteException { 5180 // Scan 5181 prepareConnectedDeviceGroup(); 5182 startSearchingForSources(); 5183 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 5184 5185 // Source synced 5186 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 5187 5188 onPeriodicAdvertisingReport(); 5189 if (!Flags.leaudioBigDependsOnAudioState()) { 5190 // onBigInfoAdvertisingReport causes notification 5191 onBigInfoAdvertisingReport(); 5192 } 5193 5194 // Notified 5195 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 5196 InOrder inOrder = inOrder(mCallback); 5197 inOrder.verify(mCallback).onSourceFound(any()); 5198 5199 // Stop searching, unsyc all broadcasters and clear all data except mCachedBroadcasts 5200 mBassClientService.stopSearchingForSources(); 5201 5202 // Add source to unsynced broadcast, causes synchronization first 5203 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 5204 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 5205 handleHandoverSupport(); 5206 5207 // Source synced 5208 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 5209 5210 onPeriodicAdvertisingReport(); 5211 if (!Flags.leaudioBigDependsOnAudioState()) { 5212 // onBigInfoAdvertisingReport causes notification 5213 onBigInfoAdvertisingReport(); 5214 } 5215 5216 // Notified 5217 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 5218 inOrder.verify(mCallback).onSourceFound(any()); 5219 5220 // Start searching again clears timeout, mCachedBroadcasts and notifiedFlags but keep syncs 5221 startSearchingForSources(); 5222 5223 onPeriodicAdvertisingReport(); 5224 if (!Flags.leaudioBigDependsOnAudioState()) { 5225 // onBigInfoAdvertisingReport should notified again 5226 onBigInfoAdvertisingReport(); 5227 } 5228 // Notified 5229 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 5230 inOrder.verify(mCallback).onSourceFound(any()); 5231 } 5232 5233 @Test 5234 @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) onSyncLost_notifySourceLostAndCancelSync_noResyncFlag()5235 public void onSyncLost_notifySourceLostAndCancelSync_noResyncFlag() throws RemoteException { 5236 prepareConnectedDeviceGroup(); 5237 startSearchingForSources(); 5238 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 5239 mInOrderMethodProxy 5240 .verify(mMethodProxy) 5241 .periodicAdvertisingManagerRegisterSync( 5242 any(), any(), anyInt(), anyInt(), any(), any()); 5243 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 5244 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 5245 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 5246 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 5247 .isEqualTo(mSourceDevice); 5248 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 5249 .isEqualTo(TEST_BROADCAST_ID); 5250 5251 onSyncLost(); 5252 5253 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 5254 verify(mCallback).onSourceLost(eq(TEST_BROADCAST_ID)); 5255 5256 // Cleaned all 5257 assertThat(mBassClientService.getActiveSyncedSources()).isEmpty(); 5258 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)).isNull(); 5259 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 5260 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 5261 5262 // Could try to sync again 5263 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 5264 mInOrderMethodProxy 5265 .verify(mMethodProxy) 5266 .periodicAdvertisingManagerRegisterSync( 5267 any(), any(), anyInt(), anyInt(), any(), any()); 5268 } 5269 5270 @Test 5271 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) onSyncLost_notifySourceLostAndCancelSync()5272 public void onSyncLost_notifySourceLostAndCancelSync() throws RemoteException { 5273 prepareConnectedDeviceGroup(); 5274 startSearchingForSources(); 5275 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 5276 mInOrderMethodProxy 5277 .verify(mMethodProxy) 5278 .periodicAdvertisingManagerRegisterSync( 5279 any(), any(), anyInt(), anyInt(), any(), any()); 5280 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 5281 assertThat(mBassClientService.getActiveSyncedSources()).hasSize(1); 5282 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 5283 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 5284 .isEqualTo(mSourceDevice); 5285 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 5286 .isEqualTo(TEST_BROADCAST_ID); 5287 5288 onSyncLost(); 5289 checkAndDispatchTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_SYNC_LOST_TIMEOUT); 5290 5291 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 5292 verify(mCallback).onSourceLost(eq(TEST_BROADCAST_ID)); 5293 5294 // Cleaned all 5295 assertThat(mBassClientService.getActiveSyncedSources()).isEmpty(); 5296 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)).isNull(); 5297 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 5298 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 5299 5300 // Could try to sync again 5301 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 5302 mInOrderMethodProxy 5303 .verify(mMethodProxy) 5304 .periodicAdvertisingManagerRegisterSync( 5305 any(), any(), anyInt(), anyInt(), any(), any()); 5306 } 5307 5308 @Test 5309 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) monitorBroadcastAfterSyncMaxLimit()5310 public void monitorBroadcastAfterSyncMaxLimit() throws RemoteException { 5311 final BluetoothDevice device1 = 5312 mBluetoothAdapter.getRemoteLeDevice( 5313 "00:11:22:33:44:11", BluetoothDevice.ADDRESS_TYPE_RANDOM); 5314 final BluetoothDevice device2 = 5315 mBluetoothAdapter.getRemoteLeDevice( 5316 "00:11:22:33:44:22", BluetoothDevice.ADDRESS_TYPE_RANDOM); 5317 final BluetoothDevice device3 = 5318 mBluetoothAdapter.getRemoteLeDevice( 5319 "00:11:22:33:44:33", BluetoothDevice.ADDRESS_TYPE_RANDOM); 5320 final BluetoothDevice device4 = 5321 mBluetoothAdapter.getRemoteLeDevice( 5322 "00:11:22:33:44:44", BluetoothDevice.ADDRESS_TYPE_RANDOM); 5323 final BluetoothDevice device5 = 5324 mBluetoothAdapter.getRemoteLeDevice( 5325 "00:11:22:33:44:55", BluetoothDevice.ADDRESS_TYPE_RANDOM); 5326 final int handle1 = 0; 5327 final int handle2 = 1; 5328 final int handle3 = 2; 5329 final int handle4 = 3; 5330 final int handle5 = 4; 5331 final int broadcastId1 = 1111; 5332 final int broadcastId2 = 2222; 5333 final int broadcastId3 = 3333; 5334 final int broadcastId4 = 4444; 5335 final int broadcastId5 = 5555; 5336 5337 prepareConnectedDeviceGroup(); 5338 startSearchingForSources(); 5339 5340 // Scan and sync 5 sources cause removing 1 synced element 5341 onScanResult(device1, broadcastId1); 5342 onSyncEstablished(device1, handle1); 5343 onScanResult(device2, broadcastId2); 5344 onSyncEstablished(device2, handle2); 5345 onScanResult(device3, broadcastId3); 5346 onSyncEstablished(device3, handle3); 5347 onScanResult(device4, broadcastId4); 5348 onSyncEstablished(device4, handle4); 5349 onScanResult(device5, broadcastId5); 5350 mInOrderMethodProxy 5351 .verify(mMethodProxy, times(4)) 5352 .periodicAdvertisingManagerRegisterSync( 5353 any(), any(), anyInt(), anyInt(), any(), any()); 5354 mInOrderMethodProxy 5355 .verify(mMethodProxy) 5356 .periodicAdvertisingManagerUnregisterSync(any(), any()); 5357 5358 checkTimeout(broadcastId1, BassClientService.MESSAGE_SYNC_LOST_TIMEOUT); 5359 5360 mInOrderMethodProxy 5361 .verify(mMethodProxy) 5362 .periodicAdvertisingManagerRegisterSync( 5363 any(), any(), anyInt(), anyInt(), any(), any()); 5364 onSyncEstablished(device5, handle5); 5365 5366 // Couldn't sync again as broadcast is in the cache 5367 onScanResult(device1, broadcastId1); 5368 mInOrderMethodProxy 5369 .verify(mMethodProxy, never()) 5370 .periodicAdvertisingManagerRegisterSync( 5371 any(), any(), anyInt(), anyInt(), any(), any()); 5372 5373 // Lost should notify about lost and clear cache 5374 checkAndDispatchTimeout(broadcastId1, BassClientService.MESSAGE_SYNC_LOST_TIMEOUT); 5375 5376 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 5377 verify(mCallback).onSourceLost(eq(broadcastId1)); 5378 5379 // Could try to sync again 5380 onScanResult(device1, broadcastId1); 5381 mInOrderMethodProxy 5382 .verify(mMethodProxy) 5383 .periodicAdvertisingManagerRegisterSync( 5384 any(), any(), anyInt(), anyInt(), any(), any()); 5385 } 5386 prepareSynchronizedPair()5387 private void prepareSynchronizedPair() { 5388 prepareConnectedDeviceGroup(); 5389 startSearchingForSources(); 5390 5391 // Scan and sync 5392 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 5393 mInOrderMethodProxy 5394 .verify(mMethodProxy) 5395 .periodicAdvertisingManagerRegisterSync( 5396 any(), any(), anyInt(), anyInt(), any(), any()); 5397 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 5398 5399 // Add source 5400 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 5401 verifyAddSourceForGroup(meta); 5402 5403 // Bis synced 5404 prepareRemoteSourceState(meta, /* isPaSynced */ true, /* isBisSynced */ true); 5405 verify(mLeAudioService).activeBroadcastAssistantNotification(eq(true)); 5406 } 5407 prepareSynchronizedPairAndStopSearching()5408 private void prepareSynchronizedPairAndStopSearching() { 5409 prepareSynchronizedPair(); 5410 5411 // Stop searching 5412 mBassClientService.stopSearchingForSources(); 5413 mInOrderMethodProxy 5414 .verify(mMethodProxy) 5415 .periodicAdvertisingManagerUnregisterSync(any(), any()); 5416 } 5417 sinkUnintentionalWithoutScanning()5418 private void sinkUnintentionalWithoutScanning() { 5419 prepareSynchronizedPairAndStopSearching(); 5420 5421 // Bis and PA unsynced, SINK_UNINTENTIONAL 5422 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 5423 injectRemoteSourceStateChanged(meta, /* isPaSynced */ false, /* isBisSynced */ false); 5424 mInOrderMethodProxy 5425 .verify(mMethodProxy) 5426 .periodicAdvertisingManagerRegisterSync( 5427 any(), any(), anyInt(), anyInt(), any(), any()); 5428 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 5429 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 5430 } 5431 sinkUnintentionalDuringScanning()5432 private void sinkUnintentionalDuringScanning() { 5433 prepareSynchronizedPair(); 5434 5435 // Bis and PA unsynced, SINK_UNINTENTIONAL 5436 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 5437 injectRemoteSourceStateChanged(meta, /* isPaSynced */ false, /* isBisSynced */ false); 5438 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 5439 } 5440 checkResumeSynchronizationByBig()5441 private void checkResumeSynchronizationByBig() { 5442 // BIG causes resume synchronization 5443 for (BassClientStateMachine sm : mStateMachines.values()) { 5444 clearInvocations(sm); 5445 } 5446 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); // In case of add source to inactive 5447 onPeriodicAdvertisingReport(); 5448 onBigInfoAdvertisingReport(); 5449 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 5450 verifyAllGroupMembersGettingUpdateOrAddSource(meta); 5451 } 5452 checkNoResumeSynchronizationByBig()5453 private void checkNoResumeSynchronizationByBig() { 5454 // BIG not cause resume synchronization 5455 for (BassClientStateMachine sm : mStateMachines.values()) { 5456 clearInvocations(sm); 5457 } 5458 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); // In case of add source to inactive 5459 onPeriodicAdvertisingReport(); 5460 onBigInfoAdvertisingReport(); 5461 for (BassClientStateMachine sm : mStateMachines.values()) { 5462 verify(sm, never()).sendMessage(any()); 5463 } 5464 } 5465 checkResumeSynchronizationByHost()5466 private void checkResumeSynchronizationByHost() { 5467 for (BassClientStateMachine sm : mStateMachines.values()) { 5468 clearInvocations(sm); 5469 } 5470 mBassClientService.resumeReceiversSourceSynchronization(); 5471 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); // In case of add source to inactive 5472 verifyAllGroupMembersGettingUpdateOrAddSource(createBroadcastMetadata(TEST_BROADCAST_ID)); 5473 } 5474 checkNoResumeSynchronizationByHost()5475 private void checkNoResumeSynchronizationByHost() { 5476 // Verify empty resume list 5477 for (BassClientStateMachine sm : mStateMachines.values()) { 5478 clearInvocations(sm); 5479 } 5480 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); // In case of add source to inactive 5481 mBassClientService.resumeReceiversSourceSynchronization(); 5482 for (BassClientStateMachine sm : mStateMachines.values()) { 5483 verify(sm, never()).sendMessage(any()); 5484 } 5485 } 5486 verifyStopBigMonitoringWithUnsync()5487 private void verifyStopBigMonitoringWithUnsync() { 5488 checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 5489 checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 5490 mInOrderMethodProxy 5491 .verify(mMethodProxy) 5492 .periodicAdvertisingManagerUnregisterSync(any(), any()); 5493 } 5494 verifyStopBigMonitoringWithoutUnsync()5495 private void verifyStopBigMonitoringWithoutUnsync() { 5496 checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 5497 checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 5498 mInOrderMethodProxy 5499 .verify(mMethodProxy, never()) 5500 .periodicAdvertisingManagerUnregisterSync(any(), any()); 5501 } 5502 resyncAndVerifyWithUnsync()5503 private void resyncAndVerifyWithUnsync() { 5504 // Resync, verify stopBigMonitoring with broadcast unsync 5505 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 5506 injectRemoteSourceStateChanged(meta, /* isPaSynced */ true, /* isBisSynced */ true); 5507 verifyStopBigMonitoringWithUnsync(); 5508 } 5509 resyncAndVerifyWithoutUnsync()5510 private void resyncAndVerifyWithoutUnsync() { 5511 // Resync, verify stopBigMonitoring without broadcast unsync 5512 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 5513 injectRemoteSourceStateChanged(meta, /* isPaSynced */ true, /* isBisSynced */ true); 5514 verifyStopBigMonitoringWithoutUnsync(); 5515 } 5516 checkNoSinkPause()5517 private void checkNoSinkPause() { 5518 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 5519 injectRemoteSourceStateChanged(meta, /* isPaSynced */ false, /* isBisSynced */ false); 5520 mInOrderMethodProxy 5521 .verify(mMethodProxy, never()) 5522 .periodicAdvertisingManagerRegisterSync( 5523 any(), any(), anyInt(), anyInt(), any(), any()); 5524 checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 5525 checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 5526 } 5527 checkSinkPause()5528 private void checkSinkPause() { 5529 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 5530 injectRemoteSourceStateChanged(meta, /* isPaSynced */ false, /* isBisSynced */ false); 5531 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 5532 } 5533 5534 @Test 5535 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_resync_withoutScanning()5536 public void sinkUnintentional_resync_withoutScanning() { 5537 sinkUnintentionalWithoutScanning(); 5538 5539 checkResumeSynchronizationByBig(); 5540 resyncAndVerifyWithUnsync(); 5541 } 5542 5543 @Test 5544 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_resync_duringScanning()5545 public void sinkUnintentional_resync_duringScanning() { 5546 sinkUnintentionalDuringScanning(); 5547 5548 checkResumeSynchronizationByBig(); 5549 resyncAndVerifyWithoutUnsync(); 5550 } 5551 5552 @Test 5553 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_resyncByRemote_withoutScanning()5554 public void sinkUnintentional_resyncByRemote_withoutScanning() { 5555 sinkUnintentionalWithoutScanning(); 5556 5557 resyncAndVerifyWithUnsync(); 5558 } 5559 5560 @Test 5561 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_resyncByRemote_duringScanning()5562 public void sinkUnintentional_resyncByRemote_duringScanning() { 5563 sinkUnintentionalDuringScanning(); 5564 5565 resyncAndVerifyWithoutUnsync(); 5566 } 5567 5568 @Test 5569 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_addNewSource()5570 public void sinkUnintentional_addNewSource() { 5571 sinkUnintentionalDuringScanning(); 5572 5573 // Scan and sync second broadcast 5574 onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1); 5575 mInOrderMethodProxy 5576 .verify(mMethodProxy) 5577 .periodicAdvertisingManagerRegisterSync( 5578 any(), any(), anyInt(), anyInt(), any(), any()); 5579 onSyncEstablished(mSourceDevice2, TEST_SYNC_HANDLE + 1); 5580 5581 // Add second source, HOST_INTENTIONAL 5582 BluetoothLeBroadcastMetadata.Builder builder = 5583 new BluetoothLeBroadcastMetadata.Builder() 5584 .setEncrypted(false) 5585 .setSourceDevice(mSourceDevice2, BluetoothDevice.ADDRESS_TYPE_RANDOM) 5586 .setSourceAdvertisingSid(TEST_ADVERTISER_SID) 5587 .setBroadcastId(TEST_BROADCAST_ID + 1) 5588 .setBroadcastCode(null) 5589 .setPaSyncInterval(TEST_PA_SYNC_INTERVAL) 5590 .setPresentationDelayMicros(TEST_PRESENTATION_DELAY_MS); 5591 // builder expect at least one subgroup 5592 builder.addSubgroup(createBroadcastSubgroup()); 5593 BluetoothLeBroadcastMetadata meta2 = builder.build(); 5594 mBassClientService.addSource(mCurrentDevice, meta2, /* isGroupOp */ true); 5595 verifyStopBigMonitoringWithoutUnsync(); 5596 5597 // BIG for first broadcast not cause resume synchronization 5598 checkNoResumeSynchronizationByBig(); 5599 } 5600 5601 @Test 5602 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_addSameSource()5603 public void sinkUnintentional_addSameSource() { 5604 sinkUnintentionalDuringScanning(); 5605 5606 // Verify add source clear the SINK_UNINTENTIONAL 5607 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 5608 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 5609 checkSinkPause(); 5610 } 5611 5612 @Test 5613 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_removeSource_withoutScanning()5614 public void sinkUnintentional_removeSource_withoutScanning() { 5615 sinkUnintentionalWithoutScanning(); 5616 5617 // Remove source, HOST_INTENTIONAL 5618 mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); 5619 verifyStopBigMonitoringWithUnsync(); 5620 verifyRemoveMessageAndInjectSourceRemoval(); 5621 checkNoResumeSynchronizationByBig(); 5622 } 5623 5624 @Test 5625 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_removeSource_duringScanning()5626 public void sinkUnintentional_removeSource_duringScanning() { 5627 sinkUnintentionalDuringScanning(); 5628 5629 // Remove source, HOST_INTENTIONAL 5630 mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); 5631 verifyStopBigMonitoringWithoutUnsync(); 5632 verifyRemoveMessageAndInjectSourceRemoval(); 5633 checkNoResumeSynchronizationByBig(); 5634 } 5635 5636 @Test 5637 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_stopReceivers_withoutScanning()5638 public void sinkUnintentional_stopReceivers_withoutScanning() { 5639 sinkUnintentionalWithoutScanning(); 5640 5641 // Stop receivers, HOST_INTENTIONAL 5642 mBassClientService.stopReceiversSourceSynchronization(TEST_BROADCAST_ID); 5643 verifyStopBigMonitoringWithUnsync(); 5644 verifyRemoveMessageAndInjectSourceRemoval(); 5645 checkNoResumeSynchronizationByBig(); 5646 checkNoResumeSynchronizationByHost(); 5647 } 5648 5649 @Test 5650 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_stopReceivers_duringScanning()5651 public void sinkUnintentional_stopReceivers_duringScanning() { 5652 sinkUnintentionalDuringScanning(); 5653 5654 // Stop receivers, HOST_INTENTIONAL 5655 mBassClientService.stopReceiversSourceSynchronization(TEST_BROADCAST_ID); 5656 verifyStopBigMonitoringWithoutUnsync(); 5657 verifyRemoveMessageAndInjectSourceRemoval(); 5658 checkNoResumeSynchronizationByBig(); 5659 checkNoResumeSynchronizationByHost(); 5660 } 5661 5662 @Test 5663 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_suspendReceivers_withoutScanning()5664 public void sinkUnintentional_suspendReceivers_withoutScanning() { 5665 sinkUnintentionalWithoutScanning(); 5666 5667 // Suspend receivers, HOST_INTENTIONAL 5668 mBassClientService.suspendReceiversSourceSynchronization(TEST_BROADCAST_ID); 5669 verifyStopBigMonitoringWithUnsync(); 5670 verifyModifyMessageAndInjectSourceModfified(); 5671 checkNoResumeSynchronizationByBig(); 5672 checkResumeSynchronizationByHost(); 5673 } 5674 5675 @Test 5676 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_suspendReceivers_duringScanning()5677 public void sinkUnintentional_suspendReceivers_duringScanning() { 5678 sinkUnintentionalDuringScanning(); 5679 5680 // Suspend receivers, HOST_INTENTIONAL 5681 mBassClientService.suspendReceiversSourceSynchronization(TEST_BROADCAST_ID); 5682 verifyStopBigMonitoringWithoutUnsync(); 5683 verifyModifyMessageAndInjectSourceModfified(); 5684 checkNoResumeSynchronizationByBig(); 5685 checkResumeSynchronizationByHost(); 5686 } 5687 5688 @Test 5689 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_suspendAllReceivers_withoutScanning()5690 public void sinkUnintentional_suspendAllReceivers_withoutScanning() { 5691 sinkUnintentionalWithoutScanning(); 5692 5693 // Suspend all receivers, HOST_INTENTIONAL 5694 mBassClientService.suspendAllReceiversSourceSynchronization(); 5695 verifyStopBigMonitoringWithUnsync(); 5696 verifyModifyMessageAndInjectSourceModfified(); 5697 checkNoResumeSynchronizationByBig(); 5698 checkResumeSynchronizationByHost(); 5699 } 5700 5701 @Test 5702 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_suspendAllReceivers_duringScanning()5703 public void sinkUnintentional_suspendAllReceivers_duringScanning() { 5704 sinkUnintentionalDuringScanning(); 5705 5706 // Suspend all receivers, HOST_INTENTIONAL 5707 mBassClientService.suspendAllReceiversSourceSynchronization(); 5708 verifyStopBigMonitoringWithoutUnsync(); 5709 verifyModifyMessageAndInjectSourceModfified(); 5710 checkNoResumeSynchronizationByBig(); 5711 checkResumeSynchronizationByHost(); 5712 } 5713 5714 @Test 5715 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_publicStopBigMonitoring_withoutScanning()5716 public void sinkUnintentional_publicStopBigMonitoring_withoutScanning() { 5717 sinkUnintentionalWithoutScanning(); 5718 5719 mBassClientService.stopBigMonitoring(); 5720 verifyStopBigMonitoringWithUnsync(); 5721 checkNoResumeSynchronizationByBig(); 5722 } 5723 5724 @Test 5725 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_publicStopBigMonitoring_duringScanning()5726 public void sinkUnintentional_publicStopBigMonitoring_duringScanning() { 5727 sinkUnintentionalDuringScanning(); 5728 5729 mBassClientService.stopBigMonitoring(); 5730 verifyStopBigMonitoringWithoutUnsync(); 5731 checkNoResumeSynchronizationByBig(); 5732 } 5733 5734 @Test 5735 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_unsync_withoutScanning()5736 public void sinkUnintentional_unsync_withoutScanning() { 5737 sinkUnintentionalWithoutScanning(); 5738 5739 // Unsync not all sinks not cause stop monitoring 5740 for (BassClientStateMachine sm : mStateMachines.values()) { 5741 // Update receiver state 5742 if (sm.getDevice().equals(mCurrentDevice)) { 5743 injectRemoteSourceStateChanged( 5744 sm, 5745 createEmptyBroadcastMetadata(), 5746 TEST_SOURCE_ID, 5747 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 5748 BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 5749 null, 5750 (long) 0x00000000); 5751 } 5752 } 5753 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 5754 5755 // Unsync all sinks cause stop monitoring 5756 for (BassClientStateMachine sm : mStateMachines.values()) { 5757 // Update receiver state 5758 if (sm.getDevice().equals(mCurrentDevice1)) { 5759 injectRemoteSourceStateChanged( 5760 sm, 5761 createEmptyBroadcastMetadata(), 5762 TEST_SOURCE_ID + 1, 5763 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 5764 BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 5765 null, 5766 (long) 0x00000000); 5767 } 5768 } 5769 verifyStopBigMonitoringWithUnsync(); 5770 checkNoResumeSynchronizationByBig(); 5771 } 5772 5773 @Test 5774 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_unsync_duringScanning()5775 public void sinkUnintentional_unsync_duringScanning() { 5776 sinkUnintentionalDuringScanning(); 5777 5778 // Unsync not all sinks not cause stop monitoring 5779 for (BassClientStateMachine sm : mStateMachines.values()) { 5780 // Update receiver state 5781 if (sm.getDevice().equals(mCurrentDevice)) { 5782 injectRemoteSourceStateChanged( 5783 sm, 5784 createEmptyBroadcastMetadata(), 5785 TEST_SOURCE_ID, 5786 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 5787 BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 5788 null, 5789 (long) 0x00000000); 5790 } 5791 } 5792 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 5793 5794 // Unsync all sinks cause stop monitoring 5795 for (BassClientStateMachine sm : mStateMachines.values()) { 5796 // Update receiver state 5797 if (sm.getDevice().equals(mCurrentDevice1)) { 5798 injectRemoteSourceStateChanged( 5799 sm, 5800 createEmptyBroadcastMetadata(), 5801 TEST_SOURCE_ID + 1, 5802 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, 5803 BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 5804 null, 5805 (long) 0x00000000); 5806 } 5807 } 5808 verifyStopBigMonitoringWithoutUnsync(); 5809 checkNoResumeSynchronizationByBig(); 5810 } 5811 5812 @Test 5813 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_disconnect_withoutScanning()5814 public void sinkUnintentional_disconnect_withoutScanning() { 5815 sinkUnintentionalWithoutScanning(); 5816 5817 // Disconnect not all sinks not cause stop monitoring 5818 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 5819 doReturn(false).when(mStateMachines.get(mCurrentDevice)).isConnected(); 5820 mBassClientService.connectionStateChanged( 5821 mCurrentDevice, STATE_CONNECTED, STATE_DISCONNECTED); 5822 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 5823 5824 // Disconnect all sinks cause stop monitoring 5825 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice1)).getConnectionState(); 5826 doReturn(false).when(mStateMachines.get(mCurrentDevice1)).isConnected(); 5827 mBassClientService.connectionStateChanged( 5828 mCurrentDevice1, STATE_CONNECTED, STATE_DISCONNECTED); 5829 verifyStopBigMonitoringWithUnsync(); 5830 checkNoResumeSynchronizationByBig(); 5831 } 5832 5833 @Test 5834 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_disconnect_duringScanning()5835 public void sinkUnintentional_disconnect_duringScanning() { 5836 sinkUnintentionalDuringScanning(); 5837 5838 // Disconnect not all sinks not cause stop monitoring 5839 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 5840 doReturn(false).when(mStateMachines.get(mCurrentDevice)).isConnected(); 5841 mBassClientService.connectionStateChanged( 5842 mCurrentDevice, STATE_CONNECTED, STATE_DISCONNECTED); 5843 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 5844 5845 // Disconnect all sinks cause stop monitoring 5846 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice1)).getConnectionState(); 5847 doReturn(false).when(mStateMachines.get(mCurrentDevice1)).isConnected(); 5848 mBassClientService.connectionStateChanged( 5849 mCurrentDevice1, STATE_CONNECTED, STATE_DISCONNECTED); 5850 verifyStopBigMonitoringWithoutUnsync(); 5851 checkNoResumeSynchronizationByBig(); 5852 } 5853 5854 @Test 5855 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_syncLost_withoutScanning_outOfRange()5856 public void sinkUnintentional_syncLost_withoutScanning_outOfRange() { 5857 sinkUnintentionalWithoutScanning(); 5858 5859 checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 5860 5861 onSyncLost(); 5862 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 5863 mInOrderMethodProxy 5864 .verify(mMethodProxy) 5865 .periodicAdvertisingManagerRegisterSync( 5866 any(), any(), anyInt(), anyInt(), any(), any()); 5867 5868 onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); 5869 mInOrderMethodProxy 5870 .verify(mMethodProxy) 5871 .periodicAdvertisingManagerRegisterSync( 5872 any(), any(), anyInt(), anyInt(), any(), any()); 5873 5874 checkAndDispatchTimeout( 5875 TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 5876 mInOrderMethodProxy 5877 .verify(mMethodProxy) 5878 .periodicAdvertisingManagerUnregisterSync(any(), any()); 5879 verifyRemoveMessageAndInjectSourceRemoval(); 5880 checkNoResumeSynchronizationByBig(); 5881 } 5882 5883 @Test 5884 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_syncLost_duringScanning_outOfRange()5885 public void sinkUnintentional_syncLost_duringScanning_outOfRange() { 5886 sinkUnintentionalDuringScanning(); 5887 5888 checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 5889 5890 onSyncLost(); 5891 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 5892 mInOrderMethodProxy 5893 .verify(mMethodProxy) 5894 .periodicAdvertisingManagerRegisterSync( 5895 any(), any(), anyInt(), anyInt(), any(), any()); 5896 5897 onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); 5898 5899 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 5900 mInOrderMethodProxy 5901 .verify(mMethodProxy) 5902 .periodicAdvertisingManagerRegisterSync( 5903 any(), any(), anyInt(), anyInt(), any(), any()); 5904 5905 checkAndDispatchTimeout( 5906 TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 5907 mInOrderMethodProxy 5908 .verify(mMethodProxy, never()) 5909 .periodicAdvertisingManagerUnregisterSync(any(), any()); 5910 verifyRemoveMessageAndInjectSourceRemoval(); 5911 checkNoResumeSynchronizationByBig(); 5912 } 5913 5914 @Test 5915 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_bigMonitorTimeout_withoutScanning()5916 public void sinkUnintentional_bigMonitorTimeout_withoutScanning() { 5917 sinkUnintentionalWithoutScanning(); 5918 5919 checkAndDispatchTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 5920 mInOrderMethodProxy 5921 .verify(mMethodProxy) 5922 .periodicAdvertisingManagerUnregisterSync(any(), any()); 5923 verifyRemoveMessageAndInjectSourceRemoval(); 5924 checkNoResumeSynchronizationByBig(); 5925 } 5926 5927 @Test 5928 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_bigMonitorTimeout_duringScanning()5929 public void sinkUnintentional_bigMonitorTimeout_duringScanning() { 5930 sinkUnintentionalDuringScanning(); 5931 5932 checkAndDispatchTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 5933 mInOrderMethodProxy 5934 .verify(mMethodProxy, never()) 5935 .periodicAdvertisingManagerUnregisterSync(any(), any()); 5936 verifyRemoveMessageAndInjectSourceRemoval(); 5937 checkNoResumeSynchronizationByBig(); 5938 } 5939 5940 @Test 5941 @EnableFlags({ 5942 Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER, 5943 Flags.FLAG_LEAUDIO_MONITOR_UNICAST_SOURCE_WHEN_MANAGED_BY_BROADCAST_DELEGATOR 5944 }) sinkUnintentional_handleUnicastSourceStreamStatusChange_withoutScanning()5945 public void sinkUnintentional_handleUnicastSourceStreamStatusChange_withoutScanning() { 5946 sinkUnintentionalWithoutScanning(); 5947 5948 /* Unicast would like to stream */ 5949 mBassClientService.handleUnicastSourceStreamStatusChange( 5950 0 /* STATUS_LOCAL_STREAM_REQUESTED */); 5951 verifyStopBigMonitoringWithUnsync(); 5952 checkNoResumeSynchronizationByBig(); 5953 5954 /* Unicast finished streaming */ 5955 mBassClientService.handleUnicastSourceStreamStatusChange( 5956 2 /* STATUS_LOCAL_STREAM_SUSPENDED */); 5957 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 5958 verifyAllGroupMembersGettingUpdateOrAddSource(createBroadcastMetadata(TEST_BROADCAST_ID)); 5959 } 5960 5961 @Test 5962 @EnableFlags({ 5963 Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER, 5964 Flags.FLAG_LEAUDIO_MONITOR_UNICAST_SOURCE_WHEN_MANAGED_BY_BROADCAST_DELEGATOR 5965 }) sinkUnintentional_handleUnicastSourceStreamStatusChange_duringScanning()5966 public void sinkUnintentional_handleUnicastSourceStreamStatusChange_duringScanning() { 5967 sinkUnintentionalDuringScanning(); 5968 5969 /* Unicast would like to stream */ 5970 mBassClientService.handleUnicastSourceStreamStatusChange( 5971 0 /* STATUS_LOCAL_STREAM_REQUESTED */); 5972 verifyStopBigMonitoringWithoutUnsync(); 5973 checkNoResumeSynchronizationByBig(); 5974 5975 /* Unicast finished streaming */ 5976 mBassClientService.handleUnicastSourceStreamStatusChange( 5977 2 /* STATUS_LOCAL_STREAM_SUSPENDED */); 5978 verifyAllGroupMembersGettingUpdateOrAddSource(createBroadcastMetadata(TEST_BROADCAST_ID)); 5979 } 5980 5981 @Test 5982 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_handleUnicastSourceStreamStatusChangeNoContext_withoutScanning()5983 public void sinkUnintentional_handleUnicastSourceStreamStatusChangeNoContext_withoutScanning() { 5984 sinkUnintentionalWithoutScanning(); 5985 5986 /* Unicast would like to stream */ 5987 mBassClientService.handleUnicastSourceStreamStatusChange( 5988 3 /* STATUS_LOCAL_STREAM_REQUESTED_NO_CONTEXT_VALIDATE */); 5989 verifyStopBigMonitoringWithUnsync(); 5990 verifyModifyMessageAndInjectSourceModfified(); 5991 checkNoResumeSynchronizationByBig(); 5992 5993 /* Unicast finished streaming */ 5994 mBassClientService.handleUnicastSourceStreamStatusChange( 5995 2 /* STATUS_LOCAL_STREAM_SUSPENDED */); 5996 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 5997 verifyAllGroupMembersGettingUpdateOrAddSource(createBroadcastMetadata(TEST_BROADCAST_ID)); 5998 } 5999 6000 @Test 6001 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkUnintentional_handleUnicastSourceStreamStatusChangeNoContext_duringScanning()6002 public void sinkUnintentional_handleUnicastSourceStreamStatusChangeNoContext_duringScanning() { 6003 sinkUnintentionalDuringScanning(); 6004 6005 /* Unicast would like to stream */ 6006 mBassClientService.handleUnicastSourceStreamStatusChange( 6007 3 /* STATUS_LOCAL_STREAM_REQUESTED_NO_CONTEXT_VALIDATE */); 6008 verifyStopBigMonitoringWithoutUnsync(); 6009 verifyModifyMessageAndInjectSourceModfified(); 6010 checkNoResumeSynchronizationByBig(); 6011 6012 /* Unicast finished streaming */ 6013 mBassClientService.handleUnicastSourceStreamStatusChange( 6014 2 /* STATUS_LOCAL_STREAM_SUSPENDED */); 6015 verifyAllGroupMembersGettingUpdateOrAddSource(createBroadcastMetadata(TEST_BROADCAST_ID)); 6016 } 6017 6018 @Test 6019 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) 6020 @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_PREVENT_RESUME_INTERRUPTION) sinkUnintentional_autoSyncToBroadcast_onStopSearching()6021 public void sinkUnintentional_autoSyncToBroadcast_onStopSearching() { 6022 sinkUnintentionalDuringScanning(); 6023 6024 // Verify that start searching cause sync when broadcaster synced to sinks 6025 mBassClientService.stopSearchingForSources(); 6026 mInOrderMethodProxy 6027 .verify(mMethodProxy) 6028 .periodicAdvertisingManagerUnregisterSync(any(), any()); 6029 mInOrderMethodProxy 6030 .verify(mMethodProxy) 6031 .periodicAdvertisingManagerRegisterSync( 6032 any(), any(), anyInt(), anyInt(), any(), any()); 6033 } 6034 6035 @Test 6036 @EnableFlags({ 6037 Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER, 6038 Flags.FLAG_LEAUDIO_BROADCAST_PREVENT_RESUME_INTERRUPTION 6039 }) sinkUnintentional_remainEstablishedSync_onStopSearching()6040 public void sinkUnintentional_remainEstablishedSync_onStopSearching() { 6041 sinkUnintentionalDuringScanning(); 6042 6043 // Scan and sync to another broadcaster 6044 onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1); 6045 mInOrderMethodProxy 6046 .verify(mMethodProxy) 6047 .periodicAdvertisingManagerRegisterSync( 6048 any(), any(), anyInt(), anyInt(), any(), any()); 6049 onSyncEstablished(mSourceDevice2, TEST_SYNC_HANDLE + 1); 6050 6051 // Scan and add add sync to pending 6052 final BluetoothDevice sourceDevice3 = 6053 mBluetoothAdapter.getRemoteLeDevice( 6054 "00:11:22:33:44:11", BluetoothDevice.ADDRESS_TYPE_RANDOM); 6055 onScanResult(sourceDevice3, TEST_BROADCAST_ID + 2); 6056 mInOrderMethodProxy 6057 .verify(mMethodProxy) 6058 .periodicAdvertisingManagerRegisterSync( 6059 any(), any(), anyInt(), anyInt(), any(), any()); 6060 6061 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(2); 6062 assertThat(mBassClientService.getActiveSyncedSources()) 6063 .containsExactly(TEST_SYNC_HANDLE, TEST_SYNC_HANDLE + 1); 6064 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 6065 .isEqualTo(mSourceDevice); 6066 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)) 6067 .isEqualTo(mSourceDevice2); 6068 assertThat(mBassClientService.getDeviceForSyncHandle(BassConstants.PENDING_SYNC_HANDLE)) 6069 .isEqualTo(sourceDevice3); 6070 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 6071 .isEqualTo(TEST_BROADCAST_ID); 6072 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6073 .isEqualTo(TEST_BROADCAST_ID + 1); 6074 assertThat( 6075 mBassClientService.getBroadcastIdForSyncHandle( 6076 BassConstants.PENDING_SYNC_HANDLE)) 6077 .isEqualTo(TEST_BROADCAST_ID + 2); 6078 6079 // Verify that stop searching remain the unintentional sync 6080 mBassClientService.stopSearchingForSources(); 6081 // Unintentional sync remain, another sync was removed, pending was canceled 6082 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); 6083 assertThat(mBassClientService.getActiveSyncedSources()).containsExactly(TEST_SYNC_HANDLE); 6084 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 6085 .isEqualTo(mSourceDevice); 6086 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)).isNull(); 6087 assertThat(mBassClientService.getDeviceForSyncHandle(BassConstants.PENDING_SYNC_HANDLE)) 6088 .isNull(); 6089 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 6090 .isEqualTo(TEST_BROADCAST_ID); 6091 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6092 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6093 assertThat( 6094 mBassClientService.getBroadcastIdForSyncHandle( 6095 BassConstants.PENDING_SYNC_HANDLE)) 6096 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6097 6098 // Resume without another register sync is possible 6099 mBassClientService.resumeReceiversSourceSynchronization(); 6100 mInOrderMethodProxy 6101 .verify(mMethodProxy, never()) 6102 .periodicAdvertisingManagerRegisterSync( 6103 any(), any(), anyInt(), anyInt(), any(), any()); 6104 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 6105 verifyAllGroupMembersGettingUpdateOrAddSource(meta); 6106 } 6107 6108 @Test 6109 @EnableFlags({ 6110 Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER, 6111 Flags.FLAG_LEAUDIO_BROADCAST_PREVENT_RESUME_INTERRUPTION 6112 }) waitingForPast_remainPendingSync_onStopSearching()6113 public void waitingForPast_remainPendingSync_onStopSearching() { 6114 prepareSynchronizedPair(); 6115 6116 // Scan and sync to another broadcaster 6117 onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1); 6118 mInOrderMethodProxy 6119 .verify(mMethodProxy) 6120 .periodicAdvertisingManagerRegisterSync( 6121 any(), any(), anyInt(), anyInt(), any(), any()); 6122 onSyncEstablished(mSourceDevice2, TEST_SYNC_HANDLE + 1); 6123 6124 // Sync lost without triggering timeout to keep cache 6125 onSyncLost(); 6126 6127 // Sync info request force syncing to broadcaster and add sinks pending for PAST 6128 mBassClientService.syncRequestForPast(mCurrentDevice, TEST_BROADCAST_ID, TEST_SOURCE_ID); 6129 mBassClientService.syncRequestForPast( 6130 mCurrentDevice1, TEST_BROADCAST_ID, TEST_SOURCE_ID + 1); 6131 mInOrderMethodProxy 6132 .verify(mMethodProxy) 6133 .periodicAdvertisingManagerRegisterSync( 6134 any(), any(), anyInt(), anyInt(), any(), any()); 6135 6136 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); 6137 assertThat(mBassClientService.getActiveSyncedSources()) 6138 .containsExactly(TEST_SYNC_HANDLE + 1); 6139 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)).isNull(); 6140 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)) 6141 .isEqualTo(mSourceDevice2); 6142 assertThat(mBassClientService.getDeviceForSyncHandle(BassConstants.PENDING_SYNC_HANDLE)) 6143 .isEqualTo(mSourceDevice); 6144 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 6145 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6146 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6147 .isEqualTo(TEST_BROADCAST_ID + 1); 6148 assertThat( 6149 mBassClientService.getBroadcastIdForSyncHandle( 6150 BassConstants.PENDING_SYNC_HANDLE)) 6151 .isEqualTo(TEST_BROADCAST_ID); 6152 6153 // Verify that stop searching remain the pending sync 6154 mBassClientService.stopSearchingForSources(); 6155 // Pending remain, another unsynced 6156 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(0); 6157 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)).isNull(); 6158 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)).isNull(); 6159 assertThat(mBassClientService.getDeviceForSyncHandle(BassConstants.PENDING_SYNC_HANDLE)) 6160 .isEqualTo(mSourceDevice); 6161 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 6162 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6163 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6164 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6165 assertThat( 6166 mBassClientService.getBroadcastIdForSyncHandle( 6167 BassConstants.PENDING_SYNC_HANDLE)) 6168 .isEqualTo(TEST_BROADCAST_ID); 6169 6170 // Establishment possible without register sync 6171 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 6172 verifyInitiatePaSyncTransferAndNoOthers(); 6173 } 6174 6175 @Test 6176 @EnableFlags({ 6177 Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER, 6178 Flags.FLAG_LEAUDIO_BROADCAST_PREVENT_RESUME_INTERRUPTION 6179 }) pendingSourceToAdd_remainPendingSync_onStopSearching()6180 public void pendingSourceToAdd_remainPendingSync_onStopSearching() { 6181 prepareConnectedDeviceGroup(); 6182 startSearchingForSources(); 6183 6184 // Scan and sync 6185 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 6186 mInOrderMethodProxy 6187 .verify(mMethodProxy) 6188 .periodicAdvertisingManagerRegisterSync( 6189 any(), any(), anyInt(), anyInt(), any(), any()); 6190 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 6191 6192 // Scan and sync to another broadcaster 6193 onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1); 6194 mInOrderMethodProxy 6195 .verify(mMethodProxy) 6196 .periodicAdvertisingManagerRegisterSync( 6197 any(), any(), anyInt(), anyInt(), any(), any()); 6198 onSyncEstablished(mSourceDevice2, TEST_SYNC_HANDLE + 1); 6199 6200 // Sync lost without triggering timeout to keep cache 6201 onSyncLost(); 6202 6203 // Add source force syncing to broadcaster and add sinks to pendingSourcesToAdd 6204 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 6205 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 6206 mInOrderMethodProxy 6207 .verify(mMethodProxy) 6208 .periodicAdvertisingManagerRegisterSync( 6209 any(), any(), anyInt(), anyInt(), any(), any()); 6210 6211 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); 6212 assertThat(mBassClientService.getActiveSyncedSources()) 6213 .containsExactly(TEST_SYNC_HANDLE + 1); 6214 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)).isNull(); 6215 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)) 6216 .isEqualTo(mSourceDevice2); 6217 assertThat(mBassClientService.getDeviceForSyncHandle(BassConstants.PENDING_SYNC_HANDLE)) 6218 .isEqualTo(mSourceDevice); 6219 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 6220 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6221 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6222 .isEqualTo(TEST_BROADCAST_ID + 1); 6223 assertThat( 6224 mBassClientService.getBroadcastIdForSyncHandle( 6225 BassConstants.PENDING_SYNC_HANDLE)) 6226 .isEqualTo(TEST_BROADCAST_ID); 6227 6228 // Verify that stop searching remain the pending sync 6229 mBassClientService.stopSearchingForSources(); 6230 // Pending remain, another unsynced 6231 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(0); 6232 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)).isNull(); 6233 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)).isNull(); 6234 assertThat(mBassClientService.getDeviceForSyncHandle(BassConstants.PENDING_SYNC_HANDLE)) 6235 .isEqualTo(mSourceDevice); 6236 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 6237 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6238 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6239 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6240 assertThat( 6241 mBassClientService.getBroadcastIdForSyncHandle( 6242 BassConstants.PENDING_SYNC_HANDLE)) 6243 .isEqualTo(TEST_BROADCAST_ID); 6244 6245 // Establishment possible without register sync 6246 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 6247 verifyAllGroupMembersGettingUpdateOrAddSource(meta); 6248 } 6249 6250 @Test 6251 @EnableFlags({ 6252 Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER, 6253 Flags.FLAG_LEAUDIO_BROADCAST_PREVENT_RESUME_INTERRUPTION 6254 }) alreadySynced_remainSyncAndCache_onStartSearching()6255 public void alreadySynced_remainSyncAndCache_onStartSearching() { 6256 prepareConnectedDeviceGroup(); 6257 startSearchingForSources(); 6258 6259 // Scan and sync 6260 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 6261 mInOrderMethodProxy 6262 .verify(mMethodProxy) 6263 .periodicAdvertisingManagerRegisterSync( 6264 any(), any(), anyInt(), anyInt(), any(), any()); 6265 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 6266 6267 // Scan and sync to another broadcaster 6268 onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1); 6269 mInOrderMethodProxy 6270 .verify(mMethodProxy) 6271 .periodicAdvertisingManagerRegisterSync( 6272 any(), any(), anyInt(), anyInt(), any(), any()); 6273 onSyncEstablished(mSourceDevice2, TEST_SYNC_HANDLE + 1); 6274 6275 // Cancel all syncs by stop searching 6276 mBassClientService.stopSearchingForSources(); 6277 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(0); 6278 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)).isNull(); 6279 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)).isNull(); 6280 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 6281 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6282 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6283 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6284 6285 // Add source force syncing to broadcaster 6286 // Not finished to not add UNINTENTIONAL_PAUSE or to not unsync 6287 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 6288 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 6289 mInOrderMethodProxy 6290 .verify(mMethodProxy) 6291 .periodicAdvertisingManagerRegisterSync( 6292 any(), any(), anyInt(), anyInt(), any(), any()); 6293 6294 // Synced 6295 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 6296 verifyAllGroupMembersGettingUpdateOrAddSource(meta); 6297 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); 6298 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 6299 .isEqualTo(mSourceDevice); 6300 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)).isNull(); 6301 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 6302 .isEqualTo(TEST_BROADCAST_ID); 6303 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6304 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6305 6306 // Start searching sources remain synced broadcasters and their cache but remove others 6307 startSearchingForSources(); 6308 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); 6309 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 6310 .isEqualTo(mSourceDevice); 6311 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)).isNull(); 6312 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 6313 .isEqualTo(TEST_BROADCAST_ID); 6314 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6315 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6316 6317 // Sync lost without triggering timeout to keep cache 6318 onSyncLost(); 6319 6320 // Finish adding source without PA and BIS to detect UNINTENTIONAL_PAUSE which will sync 6321 // again. This will confirm that cache is available 6322 prepareRemoteSourceState(meta, /* isPaSynced */ false, /* isBisSynced */ false); 6323 mInOrderMethodProxy 6324 .verify(mMethodProxy) 6325 .periodicAdvertisingManagerRegisterSync( 6326 any(), any(), anyInt(), anyInt(), any(), any()); 6327 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 6328 6329 // Remove source to allow add again 6330 mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); 6331 verifyRemoveMessageAndInjectSourceRemoval(); 6332 6333 // Check if cache is NOT remaining for second broadcaster by adding source 6334 BluetoothLeBroadcastMetadata meta2 = createBroadcastMetadata(TEST_BROADCAST_ID + 1); 6335 mBassClientService.addSource(mCurrentDevice, meta2, /* isGroupOp */ true); 6336 mInOrderMethodProxy 6337 .verify(mMethodProxy, never()) 6338 .periodicAdvertisingManagerRegisterSync( 6339 any(), any(), anyInt(), anyInt(), any(), any()); 6340 } 6341 6342 @Test 6343 @EnableFlags({ 6344 Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER, 6345 Flags.FLAG_LEAUDIO_BROADCAST_PREVENT_RESUME_INTERRUPTION 6346 }) alreadySyncedWithSinks_syncAndRemainCache_onStartSearching()6347 public void alreadySyncedWithSinks_syncAndRemainCache_onStartSearching() { 6348 prepareSynchronizedPair(); 6349 6350 // Scan and sync to another broadcaster 6351 onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1); 6352 mInOrderMethodProxy 6353 .verify(mMethodProxy) 6354 .periodicAdvertisingManagerRegisterSync( 6355 any(), any(), anyInt(), anyInt(), any(), any()); 6356 onSyncEstablished(mSourceDevice2, TEST_SYNC_HANDLE + 1); 6357 6358 // Cancel all syncs by stop searching 6359 mBassClientService.stopSearchingForSources(); 6360 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(0); 6361 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)).isNull(); 6362 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)).isNull(); 6363 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 6364 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6365 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6366 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6367 6368 // Start searching sources syncs to the broadcasters already synced with sinks 6369 startSearchingForSources(); 6370 mInOrderMethodProxy 6371 .verify(mMethodProxy) 6372 .periodicAdvertisingManagerRegisterSync( 6373 any(), any(), anyInt(), anyInt(), any(), any()); 6374 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(0); 6375 assertThat(mBassClientService.getDeviceForSyncHandle(BassConstants.PENDING_SYNC_HANDLE)) 6376 .isEqualTo(mSourceDevice); 6377 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)).isNull(); 6378 assertThat( 6379 mBassClientService.getBroadcastIdForSyncHandle( 6380 BassConstants.PENDING_SYNC_HANDLE)) 6381 .isEqualTo(TEST_BROADCAST_ID); 6382 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6383 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6384 6385 // Synced 6386 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 6387 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); 6388 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 6389 .isEqualTo(mSourceDevice); 6390 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)).isNull(); 6391 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 6392 .isEqualTo(TEST_BROADCAST_ID); 6393 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6394 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6395 6396 // Sync lost without triggering timeout to keep cache 6397 onSyncLost(); 6398 6399 // Remove source to allow add again 6400 mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); 6401 verifyRemoveMessageAndInjectSourceRemoval(); 6402 6403 // Check if cache is NOT remaining for second broadcaster by adding source 6404 BluetoothLeBroadcastMetadata meta2 = createBroadcastMetadata(TEST_BROADCAST_ID + 1); 6405 mBassClientService.addSource(mCurrentDevice, meta2, /* isGroupOp */ true); 6406 mInOrderMethodProxy 6407 .verify(mMethodProxy, never()) 6408 .periodicAdvertisingManagerRegisterSync( 6409 any(), any(), anyInt(), anyInt(), any(), any()); 6410 6411 // Check if cache is remaining for already synced broadcaster by adding source 6412 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 6413 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 6414 mInOrderMethodProxy 6415 .verify(mMethodProxy) 6416 .periodicAdvertisingManagerRegisterSync( 6417 any(), any(), anyInt(), anyInt(), any(), any()); 6418 } 6419 6420 @Test 6421 @EnableFlags({ 6422 Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER, 6423 Flags.FLAG_LEAUDIO_BROADCAST_PREVENT_RESUME_INTERRUPTION 6424 }) waitingForPast_remainPendingSyncAndCache_onStartSearching()6425 public void waitingForPast_remainPendingSyncAndCache_onStartSearching() { 6426 prepareSynchronizedPair(); 6427 6428 // Scan and sync to another broadcaster 6429 onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1); 6430 mInOrderMethodProxy 6431 .verify(mMethodProxy) 6432 .periodicAdvertisingManagerRegisterSync( 6433 any(), any(), anyInt(), anyInt(), any(), any()); 6434 onSyncEstablished(mSourceDevice2, TEST_SYNC_HANDLE + 1); 6435 6436 // Cancel all syncs by stop searching 6437 mBassClientService.stopSearchingForSources(); 6438 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(0); 6439 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)).isNull(); 6440 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)).isNull(); 6441 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 6442 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6443 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6444 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6445 6446 // Sync info request force syncing to broadcaster and add sinks pending for PAST 6447 mBassClientService.syncRequestForPast(mCurrentDevice, TEST_BROADCAST_ID, TEST_SOURCE_ID); 6448 mBassClientService.syncRequestForPast( 6449 mCurrentDevice1, TEST_BROADCAST_ID, TEST_SOURCE_ID + 1); 6450 mInOrderMethodProxy 6451 .verify(mMethodProxy) 6452 .periodicAdvertisingManagerRegisterSync( 6453 any(), any(), anyInt(), anyInt(), any(), any()); 6454 6455 // Start searching sources remain pending sync and cache for broadcaster waiting for past 6456 startSearchingForSources(); 6457 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(0); 6458 assertThat(mBassClientService.getDeviceForSyncHandle(BassConstants.PENDING_SYNC_HANDLE)) 6459 .isEqualTo(mSourceDevice); 6460 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)).isNull(); 6461 assertThat( 6462 mBassClientService.getBroadcastIdForSyncHandle( 6463 BassConstants.PENDING_SYNC_HANDLE)) 6464 .isEqualTo(TEST_BROADCAST_ID); 6465 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6466 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6467 6468 // Synced 6469 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 6470 verifyInitiatePaSyncTransferAndNoOthers(); 6471 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); 6472 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 6473 .isEqualTo(mSourceDevice); 6474 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)).isNull(); 6475 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 6476 .isEqualTo(TEST_BROADCAST_ID); 6477 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6478 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6479 6480 // Sync lost without triggering timeout to keep cache 6481 onSyncLost(); 6482 6483 // Remove source to allow add again 6484 mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); 6485 verifyRemoveMessageAndInjectSourceRemoval(); 6486 6487 // Check if cache is NOT remaining for second broadcaster by adding source 6488 BluetoothLeBroadcastMetadata meta2 = createBroadcastMetadata(TEST_BROADCAST_ID + 1); 6489 mBassClientService.addSource(mCurrentDevice, meta2, /* isGroupOp */ true); 6490 mInOrderMethodProxy 6491 .verify(mMethodProxy, never()) 6492 .periodicAdvertisingManagerRegisterSync( 6493 any(), any(), anyInt(), anyInt(), any(), any()); 6494 6495 // Check if cache is remaining for already synced broadcaster by adding source 6496 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 6497 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 6498 mInOrderMethodProxy 6499 .verify(mMethodProxy) 6500 .periodicAdvertisingManagerRegisterSync( 6501 any(), any(), anyInt(), anyInt(), any(), any()); 6502 } 6503 6504 @Test 6505 @EnableFlags({ 6506 Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER, 6507 Flags.FLAG_LEAUDIO_BROADCAST_PREVENT_RESUME_INTERRUPTION 6508 }) pendingSourcesToAdd_remainPendingSyncAndCache_onStartSearching()6509 public void pendingSourcesToAdd_remainPendingSyncAndCache_onStartSearching() { 6510 prepareConnectedDeviceGroup(); 6511 startSearchingForSources(); 6512 6513 // Scan and sync 6514 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 6515 mInOrderMethodProxy 6516 .verify(mMethodProxy) 6517 .periodicAdvertisingManagerRegisterSync( 6518 any(), any(), anyInt(), anyInt(), any(), any()); 6519 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 6520 6521 // Scan and sync to another broadcaster 6522 onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1); 6523 mInOrderMethodProxy 6524 .verify(mMethodProxy) 6525 .periodicAdvertisingManagerRegisterSync( 6526 any(), any(), anyInt(), anyInt(), any(), any()); 6527 onSyncEstablished(mSourceDevice2, TEST_SYNC_HANDLE + 1); 6528 6529 // Cancel all syncs by stop searching 6530 mBassClientService.stopSearchingForSources(); 6531 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(0); 6532 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)).isNull(); 6533 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)).isNull(); 6534 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 6535 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6536 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6537 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6538 6539 // Add source force syncing to broadcaster 6540 // Not finished to not add UNINTENTIONAL_PAUSE or to not unsync 6541 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 6542 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 6543 mInOrderMethodProxy 6544 .verify(mMethodProxy) 6545 .periodicAdvertisingManagerRegisterSync( 6546 any(), any(), anyInt(), anyInt(), any(), any()); 6547 6548 // Start searching sources remain pending sync and cache for broadcaster 6549 startSearchingForSources(); 6550 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(0); 6551 assertThat(mBassClientService.getDeviceForSyncHandle(BassConstants.PENDING_SYNC_HANDLE)) 6552 .isEqualTo(mSourceDevice); 6553 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)).isNull(); 6554 assertThat( 6555 mBassClientService.getBroadcastIdForSyncHandle( 6556 BassConstants.PENDING_SYNC_HANDLE)) 6557 .isEqualTo(TEST_BROADCAST_ID); 6558 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6559 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6560 6561 // Synced 6562 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 6563 verifyAllGroupMembersGettingUpdateOrAddSource(meta); 6564 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); 6565 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 6566 .isEqualTo(mSourceDevice); 6567 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)).isNull(); 6568 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 6569 .isEqualTo(TEST_BROADCAST_ID); 6570 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6571 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6572 6573 // Sync lost without triggering timeout to keep cache 6574 onSyncLost(); 6575 6576 // Finish adding source without PA and BIS to detect UNINTENTIONAL_PAUSE which will sync 6577 // again. This will confirm that cache is available 6578 prepareRemoteSourceState(meta, /* isPaSynced */ false, /* isBisSynced */ false); 6579 mInOrderMethodProxy 6580 .verify(mMethodProxy) 6581 .periodicAdvertisingManagerRegisterSync( 6582 any(), any(), anyInt(), anyInt(), any(), any()); 6583 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 6584 6585 // Remove source to allow add again 6586 mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); 6587 verifyRemoveMessageAndInjectSourceRemoval(); 6588 6589 // Check if cache is NOT remaining for second broadcaster by adding source 6590 BluetoothLeBroadcastMetadata meta2 = createBroadcastMetadata(TEST_BROADCAST_ID + 1); 6591 mBassClientService.addSource(mCurrentDevice, meta2, /* isGroupOp */ true); 6592 mInOrderMethodProxy 6593 .verify(mMethodProxy, never()) 6594 .periodicAdvertisingManagerRegisterSync( 6595 any(), any(), anyInt(), anyInt(), any(), any()); 6596 } 6597 6598 @Test 6599 @EnableFlags({ 6600 Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER, 6601 Flags.FLAG_LEAUDIO_BROADCAST_PREVENT_RESUME_INTERRUPTION 6602 }) hostIntentional_SyncAndRemainCache_onStartSearching()6603 public void hostIntentional_SyncAndRemainCache_onStartSearching() { 6604 prepareSynchronizedPair(); 6605 6606 // Scan and sync to another broadcaster 6607 onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1); 6608 mInOrderMethodProxy 6609 .verify(mMethodProxy) 6610 .periodicAdvertisingManagerRegisterSync( 6611 any(), any(), anyInt(), anyInt(), any(), any()); 6612 onSyncEstablished(mSourceDevice2, TEST_SYNC_HANDLE + 1); 6613 6614 // Cancel all syncs by stop searching 6615 mBassClientService.stopSearchingForSources(); 6616 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(0); 6617 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)).isNull(); 6618 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)).isNull(); 6619 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 6620 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6621 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6622 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6623 6624 // Suspend all receivers, HOST_INTENTIONAL 6625 mBassClientService.suspendAllReceiversSourceSynchronization(); 6626 verifyModifyMessageAndInjectSourceModfified(); 6627 6628 // Start searching sources sync to paused broadcaster and remain cache 6629 startSearchingForSources(); 6630 mInOrderMethodProxy 6631 .verify(mMethodProxy) 6632 .periodicAdvertisingManagerRegisterSync( 6633 any(), any(), anyInt(), anyInt(), any(), any()); 6634 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(0); 6635 assertThat(mBassClientService.getDeviceForSyncHandle(BassConstants.PENDING_SYNC_HANDLE)) 6636 .isEqualTo(mSourceDevice); 6637 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)).isNull(); 6638 assertThat( 6639 mBassClientService.getBroadcastIdForSyncHandle( 6640 BassConstants.PENDING_SYNC_HANDLE)) 6641 .isEqualTo(TEST_BROADCAST_ID); 6642 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6643 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6644 6645 // Synced 6646 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 6647 assertThat(mBassClientService.getActiveSyncedSources().size()).isEqualTo(1); 6648 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE)) 6649 .isEqualTo(mSourceDevice); 6650 assertThat(mBassClientService.getDeviceForSyncHandle(TEST_SYNC_HANDLE + 1)).isNull(); 6651 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE)) 6652 .isEqualTo(TEST_BROADCAST_ID); 6653 assertThat(mBassClientService.getBroadcastIdForSyncHandle(TEST_SYNC_HANDLE + 1)) 6654 .isEqualTo(BassConstants.INVALID_BROADCAST_ID); 6655 6656 // Resume broadcast 6657 mBassClientService.resumeReceiversSourceSynchronization(); 6658 mInOrderMethodProxy 6659 .verify(mMethodProxy, never()) 6660 .periodicAdvertisingManagerRegisterSync( 6661 any(), any(), anyInt(), anyInt(), any(), any()); 6662 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 6663 verifyAllGroupMembersGettingUpdateOrAddSource(meta); 6664 prepareRemoteSourceState(meta, /* isPaSynced */ true, /* isBisSynced */ true); 6665 6666 // Sync lost without triggering timeout to keep cache 6667 onSyncLost(); 6668 6669 // Remove source to allow add again 6670 mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); 6671 mBassClientService.removeSource(mCurrentDevice1, TEST_SOURCE_ID + 1); 6672 verifyRemoveMessageAndInjectSourceRemoval(); 6673 6674 // Check if cache is NOT remaining for second broadcaster by adding source 6675 BluetoothLeBroadcastMetadata meta2 = createBroadcastMetadata(TEST_BROADCAST_ID + 1); 6676 mBassClientService.addSource(mCurrentDevice, meta2, /* isGroupOp */ true); 6677 mInOrderMethodProxy 6678 .verify(mMethodProxy, never()) 6679 .periodicAdvertisingManagerRegisterSync( 6680 any(), any(), anyInt(), anyInt(), any(), any()); 6681 6682 // Check if cache is remaining for already synced broadcaster by adding source 6683 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 6684 mInOrderMethodProxy 6685 .verify(mMethodProxy) 6686 .periodicAdvertisingManagerRegisterSync( 6687 any(), any(), anyInt(), anyInt(), any(), any()); 6688 } 6689 6690 @Test 6691 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) hostIntentional_addSameSource()6692 public void hostIntentional_addSameSource() { 6693 prepareSynchronizedPair(); 6694 6695 // Remove source, HOST_INTENTIONAL 6696 mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); 6697 checkNoSinkPause(); 6698 verifyRemoveMessageAndInjectSourceRemoval(); 6699 6700 // Verify add source clear the HOST_INTENTIONAL 6701 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 6702 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 6703 verifyAddSourceForGroup(meta); 6704 checkSinkPause(); 6705 } 6706 6707 @Test 6708 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) hostIntentional_removeSource_withoutScanning()6709 public void hostIntentional_removeSource_withoutScanning() { 6710 prepareSynchronizedPairAndStopSearching(); 6711 6712 // Remove source, HOST_INTENTIONAL 6713 mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); 6714 checkNoSinkPause(); 6715 verifyRemoveMessageAndInjectSourceRemoval(); 6716 } 6717 6718 @Test 6719 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) hostIntentional_removeSource_duringScanning()6720 public void hostIntentional_removeSource_duringScanning() { 6721 prepareSynchronizedPair(); 6722 6723 // Remove source, HOST_INTENTIONAL 6724 mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); 6725 checkNoSinkPause(); 6726 verifyRemoveMessageAndInjectSourceRemoval(); 6727 } 6728 6729 @Test 6730 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) hostIntentional_stopReceivers_withoutScanning()6731 public void hostIntentional_stopReceivers_withoutScanning() { 6732 prepareSynchronizedPairAndStopSearching(); 6733 6734 // Stop receivers, HOST_INTENTIONAL 6735 mBassClientService.stopReceiversSourceSynchronization(TEST_BROADCAST_ID); 6736 checkNoSinkPause(); 6737 verifyRemoveMessageAndInjectSourceRemoval(); 6738 } 6739 6740 @Test 6741 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) hostIntentional_stopReceivers_duringScanning()6742 public void hostIntentional_stopReceivers_duringScanning() { 6743 prepareSynchronizedPair(); 6744 6745 // Stop receivers, HOST_INTENTIONAL 6746 mBassClientService.stopReceiversSourceSynchronization(TEST_BROADCAST_ID); 6747 checkNoSinkPause(); 6748 verifyRemoveMessageAndInjectSourceRemoval(); 6749 } 6750 6751 @Test 6752 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) hostIntentional_suspendReceivers_withoutScanning()6753 public void hostIntentional_suspendReceivers_withoutScanning() { 6754 prepareSynchronizedPairAndStopSearching(); 6755 6756 // Suspend receivers, HOST_INTENTIONAL 6757 mBassClientService.suspendReceiversSourceSynchronization(TEST_BROADCAST_ID); 6758 checkNoSinkPause(); 6759 checkResumeSynchronizationByHost(); 6760 } 6761 6762 @Test 6763 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) hostIntentional_suspendReceivers_duringScanning()6764 public void hostIntentional_suspendReceivers_duringScanning() { 6765 prepareSynchronizedPair(); 6766 6767 // Suspend receivers, HOST_INTENTIONAL 6768 mBassClientService.suspendReceiversSourceSynchronization(TEST_BROADCAST_ID); 6769 checkNoSinkPause(); 6770 checkResumeSynchronizationByHost(); 6771 } 6772 6773 @Test 6774 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) hostIntentional_suspendAllReceivers_withoutScanning()6775 public void hostIntentional_suspendAllReceivers_withoutScanning() { 6776 prepareSynchronizedPairAndStopSearching(); 6777 6778 // Suspend all receivers, HOST_INTENTIONAL 6779 mBassClientService.suspendAllReceiversSourceSynchronization(); 6780 checkNoSinkPause(); 6781 checkResumeSynchronizationByHost(); 6782 } 6783 6784 @Test 6785 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) hostIntentional_suspendAllReceivers_duringScanning()6786 public void hostIntentional_suspendAllReceivers_duringScanning() { 6787 prepareSynchronizedPair(); 6788 6789 // Suspend all receivers, HOST_INTENTIONAL 6790 mBassClientService.suspendAllReceiversSourceSynchronization(); 6791 checkNoSinkPause(); 6792 checkResumeSynchronizationByHost(); 6793 } 6794 6795 @Test 6796 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) hostIntentional_handleUnicastSourceStreamStatusChange_withoutScanning()6797 public void hostIntentional_handleUnicastSourceStreamStatusChange_withoutScanning() { 6798 prepareSynchronizedPairAndStopSearching(); 6799 6800 /* Unicast would like to stream */ 6801 mBassClientService.handleUnicastSourceStreamStatusChange( 6802 0 /* STATUS_LOCAL_STREAM_REQUESTED */); 6803 checkNoSinkPause(); 6804 6805 /* Unicast finished streaming */ 6806 mBassClientService.handleUnicastSourceStreamStatusChange( 6807 2 /* STATUS_LOCAL_STREAM_SUSPENDED */); 6808 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); // In case of add source to inactive 6809 verifyAllGroupMembersGettingUpdateOrAddSource(createBroadcastMetadata(TEST_BROADCAST_ID)); 6810 } 6811 6812 @Test 6813 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) hostIntentional_handleUnicastSourceStreamStatusChange_duringScanning()6814 public void hostIntentional_handleUnicastSourceStreamStatusChange_duringScanning() { 6815 prepareSynchronizedPair(); 6816 6817 /* Unicast would like to stream */ 6818 mBassClientService.handleUnicastSourceStreamStatusChange( 6819 0 /* STATUS_LOCAL_STREAM_REQUESTED */); 6820 checkNoSinkPause(); 6821 6822 /* Unicast finished streaming */ 6823 mBassClientService.handleUnicastSourceStreamStatusChange( 6824 2 /* STATUS_LOCAL_STREAM_SUSPENDED */); 6825 verifyAllGroupMembersGettingUpdateOrAddSource(createBroadcastMetadata(TEST_BROADCAST_ID)); 6826 } 6827 6828 @Test 6829 @EnableFlags({ 6830 Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER, 6831 Flags.FLAG_LEAUDIO_MONITOR_UNICAST_SOURCE_WHEN_MANAGED_BY_BROADCAST_DELEGATOR 6832 }) hostIntentional_handleUnicastSourceStreamStatusChange_beforeResumeCompleted()6833 public void hostIntentional_handleUnicastSourceStreamStatusChange_beforeResumeCompleted() { 6834 prepareSynchronizedPairAndStopSearching(); 6835 6836 /* Unicast would like to stream */ 6837 mBassClientService.handleUnicastSourceStreamStatusChange( 6838 0 /* STATUS_LOCAL_STREAM_REQUESTED */); 6839 checkNoSinkPause(); 6840 6841 /* Unicast finished streaming */ 6842 mBassClientService.handleUnicastSourceStreamStatusChange( 6843 2 /* STATUS_LOCAL_STREAM_SUSPENDED */); 6844 mInOrderMethodProxy 6845 .verify(mMethodProxy) 6846 .periodicAdvertisingManagerRegisterSync( 6847 any(), any(), anyInt(), anyInt(), any(), any()); 6848 6849 /* Unicast would like to stream again before previous resume was complete*/ 6850 mBassClientService.handleUnicastSourceStreamStatusChange( 6851 0 /* STATUS_LOCAL_STREAM_REQUESTED */); 6852 6853 /* Unicast finished streaming */ 6854 mBassClientService.handleUnicastSourceStreamStatusChange( 6855 2 /* STATUS_LOCAL_STREAM_SUSPENDED */); 6856 mInOrderMethodProxy 6857 .verify(mMethodProxy) 6858 .periodicAdvertisingManagerRegisterSync( 6859 any(), any(), anyInt(), anyInt(), any(), any()); 6860 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); // In case of add source to inactive 6861 verifyAllGroupMembersGettingUpdateOrAddSource(createBroadcastMetadata(TEST_BROADCAST_ID)); 6862 } 6863 6864 @Test 6865 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) hostIntentional_handleUnicastSourceStreamStatusChangeNoContext_withoutScanning()6866 public void hostIntentional_handleUnicastSourceStreamStatusChangeNoContext_withoutScanning() { 6867 prepareSynchronizedPairAndStopSearching(); 6868 6869 /* Unicast would like to stream */ 6870 mBassClientService.handleUnicastSourceStreamStatusChange( 6871 3 /* STATUS_LOCAL_STREAM_REQUESTED_NO_CONTEXT_VALIDATE */); 6872 checkNoSinkPause(); 6873 verifyModifyMessageAndInjectSourceModfified(); 6874 6875 /* Unicast finished streaming */ 6876 mBassClientService.handleUnicastSourceStreamStatusChange( 6877 2 /* STATUS_LOCAL_STREAM_SUSPENDED */); 6878 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 6879 verifyAllGroupMembersGettingUpdateOrAddSource(createBroadcastMetadata(TEST_BROADCAST_ID)); 6880 } 6881 6882 @Test 6883 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) hostIntentional_handleUnicastSourceStreamStatusChangeNoContext_duringScanning()6884 public void hostIntentional_handleUnicastSourceStreamStatusChangeNoContext_duringScanning() { 6885 prepareSynchronizedPair(); 6886 6887 /* Unicast would like to stream */ 6888 mBassClientService.handleUnicastSourceStreamStatusChange( 6889 3 /* STATUS_LOCAL_STREAM_REQUESTED_NO_CONTEXT_VALIDATE */); 6890 checkNoSinkPause(); 6891 verifyModifyMessageAndInjectSourceModfified(); 6892 6893 /* Unicast finished streaming */ 6894 mBassClientService.handleUnicastSourceStreamStatusChange( 6895 2 /* STATUS_LOCAL_STREAM_SUSPENDED */); 6896 verifyAllGroupMembersGettingUpdateOrAddSource(createBroadcastMetadata(TEST_BROADCAST_ID)); 6897 } 6898 6899 @Test 6900 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) outOfRange_syncEstablishedFailed_stopMonitoringAfterTimeout()6901 public void outOfRange_syncEstablishedFailed_stopMonitoringAfterTimeout() { 6902 prepareSynchronizedPairAndStopSearching(); 6903 6904 // Bis and PA unsynced, SINK_UNINTENTIONAL 6905 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 6906 injectRemoteSourceStateChanged(meta, /* isPaSynced */ false, /* isBisSynced */ false); 6907 mInOrderMethodProxy 6908 .verify(mMethodProxy) 6909 .periodicAdvertisingManagerRegisterSync( 6910 any(), any(), anyInt(), anyInt(), any(), any()); 6911 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 6912 checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 6913 6914 onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); 6915 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 6916 mInOrderMethodProxy 6917 .verify(mMethodProxy) 6918 .periodicAdvertisingManagerRegisterSync( 6919 any(), any(), anyInt(), anyInt(), any(), any()); 6920 6921 onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); 6922 mInOrderMethodProxy 6923 .verify(mMethodProxy) 6924 .periodicAdvertisingManagerRegisterSync( 6925 any(), any(), anyInt(), anyInt(), any(), any()); 6926 6927 checkAndDispatchTimeout( 6928 TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 6929 mInOrderMethodProxy 6930 .verify(mMethodProxy) 6931 .periodicAdvertisingManagerUnregisterSync(any(), any()); 6932 } 6933 6934 @Test 6935 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) outOfRange_syncEstablishedFailed_clearTimeout()6936 public void outOfRange_syncEstablishedFailed_clearTimeout() { 6937 prepareSynchronizedPairAndStopSearching(); 6938 6939 // Bis and PA unsynced, SINK_UNINTENTIONAL 6940 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 6941 injectRemoteSourceStateChanged(meta, /* isPaSynced */ false, /* isBisSynced */ false); 6942 mInOrderMethodProxy 6943 .verify(mMethodProxy) 6944 .periodicAdvertisingManagerRegisterSync( 6945 any(), any(), anyInt(), anyInt(), any(), any()); 6946 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 6947 checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 6948 6949 onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); 6950 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 6951 mInOrderMethodProxy 6952 .verify(mMethodProxy) 6953 .periodicAdvertisingManagerRegisterSync( 6954 any(), any(), anyInt(), anyInt(), any(), any()); 6955 6956 onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); 6957 mInOrderMethodProxy 6958 .verify(mMethodProxy) 6959 .periodicAdvertisingManagerRegisterSync( 6960 any(), any(), anyInt(), anyInt(), any(), any()); 6961 6962 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 6963 checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 6964 } 6965 6966 @Test 6967 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) outOfRange_syncEstablishedFailed_restartSearching()6968 public void outOfRange_syncEstablishedFailed_restartSearching() { 6969 prepareSynchronizedPairAndStopSearching(); 6970 6971 // Bis and PA unsynced, SINK_UNINTENTIONAL 6972 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 6973 injectRemoteSourceStateChanged(meta, /* isPaSynced */ false, /* isBisSynced */ false); 6974 mInOrderMethodProxy 6975 .verify(mMethodProxy) 6976 .periodicAdvertisingManagerRegisterSync( 6977 any(), any(), anyInt(), anyInt(), any(), any()); 6978 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 6979 checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 6980 6981 // Start OOR monitoring 6982 onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); 6983 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 6984 mInOrderMethodProxy 6985 .verify(mMethodProxy) 6986 .periodicAdvertisingManagerRegisterSync( 6987 any(), any(), anyInt(), anyInt(), any(), any()); 6988 6989 // Starting a search should not clear the cache for SINK_UNINTENTIONAL, which allows 6990 // register sync again if available or synchronization attempts after stopping the search 6991 startSearchingForSources(); 6992 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 6993 onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); 6994 6995 // During a search, unintentionally paused broadcasts are monitored via onScanResult 6996 // Test below does not guarantee that the cache is preserved; this will be checked later 6997 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 6998 mInOrderMethodProxy 6999 .verify(mMethodProxy) 7000 .periodicAdvertisingManagerRegisterSync( 7001 any(), any(), anyInt(), anyInt(), any(), any()); 7002 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 7003 onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); 7004 7005 // After a search is stopped, start syncing in a loop for unintentionally paused broadcasts 7006 mBassClientService.stopSearchingForSources(); 7007 mInOrderMethodProxy 7008 .verify(mMethodProxy) 7009 .periodicAdvertisingManagerRegisterSync( 7010 any(), any(), anyInt(), anyInt(), any(), any()); 7011 7012 // Still OOR 7013 onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); 7014 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 7015 mInOrderMethodProxy 7016 .verify(mMethodProxy) 7017 .periodicAdvertisingManagerRegisterSync( 7018 any(), any(), anyInt(), anyInt(), any(), any()); 7019 7020 // Check if cache is not cleared after start searching by using addSource 7021 startSearchingForSources(); 7022 onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); 7023 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 7024 7025 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 7026 mInOrderMethodProxy 7027 .verify(mMethodProxy) 7028 .periodicAdvertisingManagerRegisterSync( 7029 any(), any(), anyInt(), anyInt(), any(), any()); 7030 } 7031 7032 @Test 7033 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) outOfRange_syncEstablishedFailed_allowSyncAnotherBroadcaster()7034 public void outOfRange_syncEstablishedFailed_allowSyncAnotherBroadcaster() { 7035 prepareSynchronizedPairAndStopSearching(); 7036 7037 // Bis and PA unsynced, SINK_UNINTENTIONAL 7038 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 7039 injectRemoteSourceStateChanged(meta, /* isPaSynced */ false, /* isBisSynced */ false); 7040 mInOrderMethodProxy 7041 .verify(mMethodProxy) 7042 .periodicAdvertisingManagerRegisterSync( 7043 any(), any(), anyInt(), anyInt(), any(), any()); 7044 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 7045 checkNoTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 7046 7047 // Start OOR monitoring 7048 onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); 7049 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BROADCAST_MONITOR_TIMEOUT); 7050 mInOrderMethodProxy 7051 .verify(mMethodProxy) 7052 .periodicAdvertisingManagerRegisterSync( 7053 any(), any(), anyInt(), anyInt(), any(), any()); 7054 7055 // Starting a search should not clear the cache for SINK_UNINTENTIONAL, which allows 7056 // register sync again if available or synchronization attempts after stopping the search 7057 startSearchingForSources(); 7058 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 7059 7060 // Check sync to another broadcaster during OOR monitoring 7061 ArgumentCaptor<ScanResult> resultCaptor = ArgumentCaptor.forClass(ScanResult.class); 7062 checkTimeout(TEST_BROADCAST_ID, BassClientService.MESSAGE_BIG_MONITOR_TIMEOUT); 7063 onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1); 7064 onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); 7065 mInOrderMethodProxy 7066 .verify(mMethodProxy) 7067 .periodicAdvertisingManagerRegisterSync( 7068 any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any()); 7069 assertThat( 7070 BassUtils.parseBroadcastId( 7071 resultCaptor 7072 .getValue() 7073 .getScanRecord() 7074 .getServiceData() 7075 .get(BassConstants.BAAS_UUID))) 7076 .isEqualTo(TEST_BROADCAST_ID + 1); 7077 } 7078 7079 @Test 7080 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) autoSyncToBroadcast_AlreadySyncedToSink_onStartSearching()7081 public void autoSyncToBroadcast_AlreadySyncedToSink_onStartSearching() { 7082 prepareSynchronizedPairAndStopSearching(); 7083 7084 // Verify that start searching cause sync when broadcaster synced to sinks 7085 startSearchingForSources(); 7086 mInOrderMethodProxy 7087 .verify(mMethodProxy) 7088 .periodicAdvertisingManagerRegisterSync( 7089 any(), any(), anyInt(), anyInt(), any(), any()); 7090 } 7091 7092 /** 7093 * Test add source will be triggered if new device connected and its peer is synced to broadcast 7094 * source 7095 */ 7096 @Test 7097 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkBassStateReady_addSourceIfPeerDeviceSynced()7098 public void sinkBassStateReady_addSourceIfPeerDeviceSynced() throws RemoteException { 7099 // Imitate broadcast being active 7100 doReturn(true).when(mLeAudioService).isPlaying(TEST_BROADCAST_ID); 7101 prepareTwoSynchronizedDevicesForLocalBroadcast(); 7102 7103 mBassClientService.getCallbacks().notifyBassStateReady(mCurrentDevice); 7104 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 7105 7106 assertThat(mStateMachines).hasSize(2); 7107 for (BassClientStateMachine sm : mStateMachines.values()) { 7108 // No adding source if device remain synced 7109 verify(sm, never()).sendMessage(any()); 7110 } 7111 7112 // Remove source on the mCurrentDevice 7113 injectRemoteSourceStateRemoval(mStateMachines.get(mCurrentDevice), TEST_SOURCE_ID); 7114 7115 mBassClientService.getCallbacks().notifyBassStateReady(mCurrentDevice); 7116 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 7117 7118 for (BassClientStateMachine sm : mStateMachines.values()) { 7119 // Verify mCurrentDevice is resuming the broadcast 7120 if (sm.getDevice().equals(mCurrentDevice1)) { 7121 verify(sm, never()).sendMessage(any()); 7122 } else if (sm.getDevice().equals(mCurrentDevice)) { 7123 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 7124 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 7125 7126 Message msg = 7127 messageCaptor.getAllValues().stream() 7128 .filter(m -> (m.what == BassClientStateMachine.ADD_BCAST_SOURCE)) 7129 .findFirst() 7130 .orElse(null); 7131 assertThat(msg).isNotNull(); 7132 clearInvocations(sm); 7133 } else { 7134 throw new AssertionError("Unexpected device"); 7135 } 7136 } 7137 } 7138 7139 /** Test add pending source when BASS state get ready */ 7140 @Test 7141 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkBassStateReady_addPendingSource()7142 public void sinkBassStateReady_addPendingSource() throws RemoteException { 7143 prepareConnectedDeviceGroup(); 7144 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 7145 // Verify adding source when Bass state not ready 7146 for (BassClientStateMachine sm : mStateMachines.values()) { 7147 doReturn(false).when(sm).isBassStateReady(); 7148 } 7149 doReturn(true).when(mLeAudioService).isPlaying(TEST_BROADCAST_ID); 7150 doReturn(new ArrayList<BluetoothLeBroadcastMetadata>(Arrays.asList(meta))) 7151 .when(mLeAudioService) 7152 .getAllBroadcastMetadata(); 7153 // Add broadcast source and got queued due to BASS not ready 7154 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ false); 7155 7156 mBassClientService.getCallbacks().notifyBassStateSetupFailed(mCurrentDevice); 7157 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 7158 7159 // Verify adding source callback is triggered if BASS state initiate failed 7160 verify(mCallback, timeout(TIMEOUT_MS).atLeastOnce()) 7161 .onSourceAddFailed( 7162 eq(mCurrentDevice), 7163 eq(meta), 7164 eq(BluetoothStatusCodes.ERROR_REMOTE_NOT_ENOUGH_RESOURCES)); 7165 7166 // Verify not getting ADD_BCAST_SOURCE message if no pending source to add 7167 for (BassClientStateMachine sm : mStateMachines.values()) { 7168 doReturn(true).when(sm).isBassStateReady(); 7169 } 7170 mBassClientService.getCallbacks().notifyBassStateReady(mCurrentDevice); 7171 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 7172 7173 for (BassClientStateMachine sm : mStateMachines.values()) { 7174 if (sm.getDevice().equals(mCurrentDevice)) { 7175 verify(sm, never()).sendMessage(any()); 7176 clearInvocations(sm); 7177 } 7178 } 7179 7180 for (BassClientStateMachine sm : mStateMachines.values()) { 7181 doReturn(false).when(sm).isBassStateReady(); 7182 } 7183 // Add broadcast source and got queued due to BASS not ready 7184 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ false); 7185 7186 for (BassClientStateMachine sm : mStateMachines.values()) { 7187 doReturn(true).when(sm).isBassStateReady(); 7188 } 7189 mBassClientService.getCallbacks().notifyBassStateReady(mCurrentDevice); 7190 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 7191 7192 // Verify adding source is resumed once BASS state ready 7193 for (BassClientStateMachine sm : mStateMachines.values()) { 7194 if (sm.getDevice().equals(mCurrentDevice)) { 7195 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 7196 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 7197 7198 Message msg = 7199 messageCaptor.getAllValues().stream() 7200 .filter(m -> (m.what == BassClientStateMachine.ADD_BCAST_SOURCE)) 7201 .findFirst() 7202 .orElse(null); 7203 assertThat(msg).isNotNull(); 7204 clearInvocations(sm); 7205 } 7206 } 7207 } 7208 7209 /** Test add pending source when BASS state get ready */ 7210 @Test 7211 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkBassStateReady_addPendingSourceGroup_oneByOneReady()7212 public void sinkBassStateReady_addPendingSourceGroup_oneByOneReady() throws RemoteException { 7213 prepareConnectedDeviceGroup(); 7214 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 7215 // Verify adding source when Bass state not ready 7216 for (BassClientStateMachine sm : mStateMachines.values()) { 7217 doReturn(false).when(sm).isBassStateReady(); 7218 } 7219 doReturn(true).when(mLeAudioService).isPlaying(TEST_BROADCAST_ID); 7220 doReturn(new ArrayList<BluetoothLeBroadcastMetadata>(Arrays.asList(meta))) 7221 .when(mLeAudioService) 7222 .getAllBroadcastMetadata(); 7223 // Add broadcast source and got queued due to BASS not ready 7224 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 7225 7226 // First BASS ready 7227 doReturn(true).when(mStateMachines.get(mCurrentDevice)).isBassStateReady(); 7228 mBassClientService.getCallbacks().notifyBassStateReady(mCurrentDevice); 7229 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 7230 7231 // Verify adding source is resumed once BASS state ready 7232 for (BassClientStateMachine sm : mStateMachines.values()) { 7233 if (sm.getDevice().equals(mCurrentDevice)) { 7234 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 7235 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 7236 7237 Message msg = 7238 messageCaptor.getAllValues().stream() 7239 .filter(m -> (m.what == BassClientStateMachine.ADD_BCAST_SOURCE)) 7240 .findFirst() 7241 .orElse(null); 7242 assertThat(msg).isNotNull(); 7243 clearInvocations(sm); 7244 } else if (sm.getDevice().equals(mCurrentDevice1)) { 7245 verify(sm, never()).sendMessage(any()); 7246 } 7247 } 7248 7249 // Second BASS ready 7250 doReturn(true).when(mStateMachines.get(mCurrentDevice1)).isBassStateReady(); 7251 mBassClientService.getCallbacks().notifyBassStateReady(mCurrentDevice1); 7252 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 7253 7254 // Verify adding source is resumed once BASS state ready 7255 for (BassClientStateMachine sm : mStateMachines.values()) { 7256 if (sm.getDevice().equals(mCurrentDevice)) { 7257 verify(sm, never()).sendMessage(any()); 7258 } else if (sm.getDevice().equals(mCurrentDevice1)) { 7259 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 7260 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 7261 7262 Message msg = 7263 messageCaptor.getAllValues().stream() 7264 .filter(m -> (m.what == BassClientStateMachine.ADD_BCAST_SOURCE)) 7265 .findFirst() 7266 .orElse(null); 7267 assertThat(msg).isNotNull(); 7268 clearInvocations(sm); 7269 } 7270 } 7271 } 7272 7273 @Test testIsLocalBroadcast()7274 public void testIsLocalBroadcast() { 7275 int broadcastId = 12345; 7276 7277 BluetoothLeBroadcastMetadata metadata = createBroadcastMetadata(broadcastId); 7278 BluetoothLeBroadcastReceiveState receiveState = 7279 new BluetoothLeBroadcastReceiveState( 7280 TEST_SOURCE_ID, 7281 metadata.getSourceAddressType(), 7282 metadata.getSourceDevice(), 7283 metadata.getSourceAdvertisingSid(), 7284 metadata.getBroadcastId(), 7285 BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED, 7286 BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, 7287 null, 7288 metadata.getSubgroups().size(), 7289 // Bis sync states 7290 metadata.getSubgroups().stream() 7291 .map(e -> (long) 0x00000001) 7292 .collect(Collectors.toList()), 7293 metadata.getSubgroups().stream() 7294 .map(e -> e.getContentMetadata()) 7295 .collect(Collectors.toList())); 7296 7297 /* External broadcast check */ 7298 doReturn(new ArrayList<BluetoothLeBroadcastMetadata>()) 7299 .when(mLeAudioService) 7300 .getAllBroadcastMetadata(); 7301 7302 assertThat(mBassClientService.isLocalBroadcast(metadata)).isFalse(); 7303 assertThat(mBassClientService.isLocalBroadcast(receiveState)).isFalse(); 7304 7305 /* Local broadcast check */ 7306 doReturn(new ArrayList<BluetoothLeBroadcastMetadata>(Arrays.asList(metadata))) 7307 .when(mLeAudioService) 7308 .getAllBroadcastMetadata(); 7309 7310 assertThat(mBassClientService.isLocalBroadcast(metadata)).isTrue(); 7311 assertThat(mBassClientService.isLocalBroadcast(receiveState)).isTrue(); 7312 } 7313 verifyInitiatePaSyncTransferAndNoOthers()7314 private void verifyInitiatePaSyncTransferAndNoOthers() { 7315 expect.that(mStateMachines.size()).isEqualTo(2); 7316 for (BassClientStateMachine sm : mStateMachines.values()) { 7317 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 7318 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 7319 long count; 7320 if (sm.getDevice().equals(mCurrentDevice)) { 7321 count = 7322 messageCaptor.getAllValues().stream() 7323 .filter( 7324 m -> 7325 (m.what 7326 == BassClientStateMachine 7327 .INITIATE_PA_SYNC_TRANSFER) 7328 && (m.arg1 == TEST_SYNC_HANDLE) 7329 && (m.arg2 == TEST_SOURCE_ID)) 7330 .count(); 7331 assertThat(count).isEqualTo(1); 7332 count = 7333 messageCaptor.getAllValues().stream() 7334 .filter( 7335 m -> 7336 m.what 7337 != BassClientStateMachine 7338 .INITIATE_PA_SYNC_TRANSFER) 7339 .count(); 7340 assertThat(count).isEqualTo(0); 7341 } else if (sm.getDevice().equals(mCurrentDevice1)) { 7342 count = 7343 messageCaptor.getAllValues().stream() 7344 .filter( 7345 m -> 7346 (m.what 7347 == BassClientStateMachine 7348 .INITIATE_PA_SYNC_TRANSFER) 7349 && (m.arg1 == TEST_SYNC_HANDLE) 7350 && (m.arg2 == TEST_SOURCE_ID + 1)) 7351 .count(); 7352 assertThat(count).isEqualTo(1); 7353 count = 7354 messageCaptor.getAllValues().stream() 7355 .filter( 7356 m -> 7357 m.what 7358 != BassClientStateMachine 7359 .INITIATE_PA_SYNC_TRANSFER) 7360 .count(); 7361 assertThat(count).isEqualTo(0); 7362 } else { 7363 throw new AssertionError("Unexpected device"); 7364 } 7365 } 7366 } 7367 7368 @Test 7369 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) initiatePaSyncTransfer()7370 public void initiatePaSyncTransfer() { 7371 prepareSynchronizedPairAndStopSearching(); 7372 7373 // Sync info request force syncing to broadcaster and add sinks pending for PAST 7374 mBassClientService.syncRequestForPast(mCurrentDevice, TEST_BROADCAST_ID, TEST_SOURCE_ID); 7375 mBassClientService.syncRequestForPast( 7376 mCurrentDevice1, TEST_BROADCAST_ID, TEST_SOURCE_ID + 1); 7377 mInOrderMethodProxy 7378 .verify(mMethodProxy) 7379 .periodicAdvertisingManagerRegisterSync( 7380 any(), any(), anyInt(), anyInt(), any(), any()); 7381 7382 // Sync will INITIATE_PA_SYNC_TRANSFER 7383 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 7384 verifyInitiatePaSyncTransferAndNoOthers(); 7385 } 7386 7387 @Test 7388 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) InitiatePaSyncTransfer_concurrentWithResume()7389 public void InitiatePaSyncTransfer_concurrentWithResume() { 7390 prepareSynchronizedPairAndStopSearching(); 7391 7392 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 7393 7394 // Cache sinks for resume and set HOST_INTENTIONAL pause 7395 mBassClientService.handleUnicastSourceStreamStatusChange( 7396 0 /* STATUS_LOCAL_STREAM_REQUESTED */); 7397 injectRemoteSourceStateChanged(meta, /* isPaSynced */ false, /* isBisSynced */ false); 7398 7399 // Resume source will force syncing to broadcaster and put pending source to add 7400 mBassClientService.resumeReceiversSourceSynchronization(); 7401 mInOrderMethodProxy 7402 .verify(mMethodProxy) 7403 .periodicAdvertisingManagerRegisterSync( 7404 any(), any(), anyInt(), anyInt(), any(), any()); 7405 7406 // Sync info request add sinks pending for PAST 7407 mBassClientService.syncRequestForPast(mCurrentDevice, TEST_BROADCAST_ID, TEST_SOURCE_ID); 7408 mBassClientService.syncRequestForPast( 7409 mCurrentDevice1, TEST_BROADCAST_ID, TEST_SOURCE_ID + 1); 7410 7411 // Sync will send INITIATE_PA_SYNC_TRANSFER and remove pending source to add 7412 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 7413 verifyInitiatePaSyncTransferAndNoOthers(); 7414 } 7415 7416 @Test 7417 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) resumeSourceSynchronization_omitWhenPaSyncedOrRequested()7418 public void resumeSourceSynchronization_omitWhenPaSyncedOrRequested() { 7419 prepareSynchronizedPair(); 7420 7421 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 7422 7423 // Cache sinks for resume and set HOST_INTENTIONAL pause 7424 // Try resume while sync info requested 7425 mBassClientService.handleUnicastSourceStreamStatusChange( 7426 0 /* STATUS_LOCAL_STREAM_REQUESTED */); 7427 injectRemoteSourceStateChanged( 7428 meta, BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCINFO_REQUEST, false); 7429 checkNoResumeSynchronizationByHost(); 7430 7431 // Cache sinks for resume and set HOST_INTENTIONAL pause 7432 // Try resume while pa synced 7433 mBassClientService.handleUnicastSourceStreamStatusChange( 7434 0 /* STATUS_LOCAL_STREAM_REQUESTED */); 7435 injectRemoteSourceStateChanged(meta, /* isPaSynced */ true, /* isBisSynced */ false); 7436 checkNoResumeSynchronizationByHost(); 7437 7438 // Cache sinks for resume and set HOST_INTENTIONAL pause 7439 // Try resume while pa unsynced 7440 mBassClientService.handleUnicastSourceStreamStatusChange( 7441 0 /* STATUS_LOCAL_STREAM_REQUESTED */); 7442 injectRemoteSourceStateChanged(meta, /* isPaSynced */ false, /* isBisSynced */ false); 7443 checkResumeSynchronizationByHost(); 7444 } 7445 7446 @Test 7447 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) removeSource_duringSuspend()7448 public void removeSource_duringSuspend() { 7449 prepareSynchronizedPair(); 7450 7451 // Suspend receivers, HOST_INTENTIONAL 7452 mBassClientService.suspendReceiversSourceSynchronization(TEST_BROADCAST_ID); 7453 7454 // Remove source, HOST_INTENTIONAL 7455 mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); 7456 checkNoSinkPause(); 7457 verifyRemoveMessageAndInjectSourceRemoval(); 7458 7459 checkNoResumeSynchronizationByHost(); 7460 } 7461 7462 @Test 7463 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) stopReceivers_duringSuspend()7464 public void stopReceivers_duringSuspend() { 7465 prepareSynchronizedPair(); 7466 7467 // Suspend receivers, HOST_INTENTIONAL 7468 mBassClientService.suspendReceiversSourceSynchronization(TEST_BROADCAST_ID); 7469 7470 // Remove source, HOST_INTENTIONAL 7471 mBassClientService.stopReceiversSourceSynchronization(TEST_BROADCAST_ID); 7472 checkNoSinkPause(); 7473 verifyRemoveMessageAndInjectSourceRemoval(); 7474 7475 checkNoResumeSynchronizationByHost(); 7476 } 7477 7478 @Test 7479 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) multipleSinkMetadata_clearWhenSourceAddFailed()7480 public void multipleSinkMetadata_clearWhenSourceAddFailed() throws RemoteException { 7481 prepareConnectedDeviceGroup(); 7482 startSearchingForSources(); 7483 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 7484 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 7485 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 7486 verifyAddSourceForGroup(meta); 7487 prepareRemoteSourceState(meta, /* isPaSynced */ true, /* isBisSynced */ true); 7488 mBassClientService.stopSearchingForSources(); 7489 prepareRemoteSourceState(meta, /* isPaSynced */ false, /* isBisSynced */ false); 7490 for (BassClientStateMachine sm : mStateMachines.values()) { 7491 clearInvocations(sm); 7492 } 7493 7494 // Cache and resume ended with source add failed, should remove metadata 7495 mBassClientService.cacheSuspendingSources(TEST_BROADCAST_ID); 7496 mBassClientService.resumeReceiversSourceSynchronization(); 7497 onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); 7498 TestUtils.waitForLooperToFinishScheduledTask(mBassClientService.getCallbacks().getLooper()); 7499 verify(mCallback).onSourceLost(eq(TEST_BROADCAST_ID)); 7500 verify(mCallback) 7501 .onSourceAddFailed( 7502 eq(mCurrentDevice), 7503 eq(meta), 7504 eq(BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES)); 7505 verify(mCallback) 7506 .onSourceAddFailed( 7507 eq(mCurrentDevice1), 7508 eq(meta), 7509 eq(BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES)); 7510 7511 startSearchingForSources(); 7512 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 7513 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 7514 7515 // Cache and resume should not resume at all 7516 mBassClientService.cacheSuspendingSources(TEST_BROADCAST_ID); 7517 mBassClientService.resumeReceiversSourceSynchronization(); 7518 assertThat(mStateMachines.size()).isEqualTo(2); 7519 for (BassClientStateMachine sm : mStateMachines.values()) { 7520 verify(sm, never()).sendMessage(any()); 7521 } 7522 } 7523 7524 @Test 7525 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) multipleSinkMetadata_clearWhenSwitch()7526 public void multipleSinkMetadata_clearWhenSwitch() { 7527 prepareConnectedDeviceGroup(); 7528 startSearchingForSources(); 7529 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 7530 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 7531 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 7532 verifyAddSourceForGroup(meta); 7533 prepareRemoteSourceState(meta, /* isPaSynced */ false, /* isBisSynced */ false); 7534 7535 // Add another new broadcast source should remove old metadata during switch 7536 onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1); 7537 onSyncEstablished(mSourceDevice2, TEST_SYNC_HANDLE + 1); 7538 BluetoothLeBroadcastMetadata newMeta = createBroadcastMetadata(TEST_BROADCAST_ID + 1); 7539 mBassClientService.addSource(mCurrentDevice, newMeta, /* isGroupOp */ true); 7540 verifyAllGroupMembersGettingUpdateOrAddSource(newMeta); 7541 for (BassClientStateMachine sm : mStateMachines.values()) { 7542 clearInvocations(sm); 7543 } 7544 prepareRemoteSourceState(newMeta, /* isPaSynced */ false, /* isBisSynced */ false); 7545 7546 // Cache and resume should resume only new broadcast 7547 mBassClientService.cacheSuspendingSources(TEST_BROADCAST_ID + 1); 7548 mBassClientService.resumeReceiversSourceSynchronization(); 7549 // Verify that only one message per sink was sent 7550 for (BassClientStateMachine sm : mStateMachines.values()) { 7551 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 7552 verify(sm).sendMessage(messageCaptor.capture()); 7553 } 7554 // And this message is to resume broadcast 7555 verifyAllGroupMembersGettingUpdateOrAddSource(newMeta); 7556 } 7557 7558 @Test 7559 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) multipleSinkMetadata_clearWhenSwitch_duringSuspend()7560 public void multipleSinkMetadata_clearWhenSwitch_duringSuspend() { 7561 prepareConnectedDeviceGroup(); 7562 startSearchingForSources(); 7563 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 7564 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 7565 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 7566 verifyAddSourceForGroup(meta); 7567 prepareRemoteSourceState(meta, /* isPaSynced */ false, /* isBisSynced */ false); 7568 7569 /* Unicast would like to stream */ 7570 mBassClientService.handleUnicastSourceStreamStatusChange( 7571 3 /* STATUS_LOCAL_STREAM_REQUESTED_NO_CONTEXT_VALIDATE */); 7572 verifyModifyMessageAndInjectSourceModfified(); 7573 for (BassClientStateMachine sm : mStateMachines.values()) { 7574 clearInvocations(sm); 7575 } 7576 7577 // Add another new broadcast source should remove old metadata 7578 onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1); 7579 onSyncEstablished(mSourceDevice2, TEST_SYNC_HANDLE + 1); 7580 BluetoothLeBroadcastMetadata newMeta = createBroadcastMetadata(TEST_BROADCAST_ID + 1); 7581 mBassClientService.addSource(mCurrentDevice, newMeta, /* isGroupOp */ true); 7582 verifyAllGroupMembersGettingUpdateOrAddSource(newMeta); 7583 for (BassClientStateMachine sm : mStateMachines.values()) { 7584 clearInvocations(sm); 7585 } 7586 prepareRemoteSourceState(newMeta, /* isPaSynced */ false, /* isBisSynced */ false); 7587 7588 // Cache and resume should resume only new broadcast 7589 mBassClientService.cacheSuspendingSources(TEST_BROADCAST_ID + 1); 7590 mBassClientService.resumeReceiversSourceSynchronization(); 7591 // Verify that only one message per sink was sent 7592 for (BassClientStateMachine sm : mStateMachines.values()) { 7593 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 7594 verify(sm).sendMessage(messageCaptor.capture()); 7595 } 7596 // And this message is to resume broadcast 7597 verifyAllGroupMembersGettingUpdateOrAddSource(newMeta); 7598 } 7599 7600 @Test 7601 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) multipleSinkMetadata_clearWhenRemove()7602 public void multipleSinkMetadata_clearWhenRemove() { 7603 prepareConnectedDeviceGroup(); 7604 startSearchingForSources(); 7605 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 7606 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 7607 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 7608 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ false); 7609 mBassClientService.addSource(mCurrentDevice1, meta, /* isGroupOp */ false); 7610 for (BassClientStateMachine sm : mStateMachines.values()) { 7611 clearInvocations(sm); 7612 } 7613 prepareRemoteSourceState(meta, /* isPaSynced */ false, /* isBisSynced */ false); 7614 7615 // Remove source should remove metadata 7616 // Do not clear receive state 7617 mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID); 7618 for (BassClientStateMachine sm : mStateMachines.values()) { 7619 clearInvocations(sm); 7620 } 7621 7622 // Cache and resume should resume only one broadcaster 7623 mBassClientService.cacheSuspendingSources(TEST_BROADCAST_ID); 7624 mBassClientService.resumeReceiversSourceSynchronization(); 7625 assertThat(mStateMachines.size()).isEqualTo(2); 7626 for (BassClientStateMachine sm : mStateMachines.values()) { 7627 if (sm.getDevice().equals(mCurrentDevice)) { 7628 verify(sm, never()).sendMessage(any()); 7629 clearInvocations(sm); 7630 } else if (sm.getDevice().equals(mCurrentDevice1)) { 7631 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 7632 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 7633 7634 Message msg = 7635 messageCaptor.getAllValues().stream() 7636 .filter(m -> (m.what == BassClientStateMachine.UPDATE_BCAST_SOURCE)) 7637 .findFirst() 7638 .orElse(null); 7639 assertThat(msg).isNotNull(); 7640 clearInvocations(sm); 7641 } 7642 } 7643 7644 // Remove source should remove metadata 7645 // Do not clear receive state 7646 mBassClientService.removeSource(mCurrentDevice1, TEST_SOURCE_ID + 1); 7647 for (BassClientStateMachine sm : mStateMachines.values()) { 7648 clearInvocations(sm); 7649 } 7650 7651 // Cache and resume should not resume at all 7652 mBassClientService.cacheSuspendingSources(TEST_BROADCAST_ID); 7653 mBassClientService.resumeReceiversSourceSynchronization(); 7654 assertThat(mStateMachines.size()).isEqualTo(2); 7655 for (BassClientStateMachine sm : mStateMachines.values()) { 7656 verify(sm, never()).sendMessage(any()); 7657 } 7658 } 7659 7660 @Test 7661 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) multipleSinkMetadata_clearWhenAllDisconnected()7662 public void multipleSinkMetadata_clearWhenAllDisconnected() { 7663 prepareConnectedDeviceGroup(); 7664 startSearchingForSources(); 7665 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 7666 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 7667 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 7668 verifyAddSourceForGroup(meta); 7669 for (BassClientStateMachine sm : mStateMachines.values()) { 7670 clearInvocations(sm); 7671 } 7672 prepareRemoteSourceState(meta, /* isPaSynced */ false, /* isBisSynced */ false); 7673 7674 // Disconnect first sink not cause removing metadata 7675 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 7676 doReturn(false).when(mStateMachines.get(mCurrentDevice)).isConnected(); 7677 mBassClientService.connectionStateChanged( 7678 mCurrentDevice, STATE_CONNECTED, STATE_DISCONNECTED); 7679 injectRemoteSourceStateRemoval(mStateMachines.get(mCurrentDevice), TEST_SOURCE_ID); 7680 7681 // Connect again first sink 7682 doReturn(STATE_CONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 7683 doReturn(true).when(mStateMachines.get(mCurrentDevice)).isConnected(); 7684 prepareRemoteSourceState(meta, /* isPaSynced */ false, /* isBisSynced */ false); 7685 7686 // Cache and resume should resume all devices 7687 mBassClientService.cacheSuspendingSources(TEST_BROADCAST_ID); 7688 mBassClientService.resumeReceiversSourceSynchronization(); 7689 verifyAllGroupMembersGettingUpdateOrAddSource(meta); 7690 for (BassClientStateMachine sm : mStateMachines.values()) { 7691 clearInvocations(sm); 7692 } 7693 7694 // Disconnect first sink not cause removing metadata 7695 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 7696 doReturn(false).when(mStateMachines.get(mCurrentDevice)).isConnected(); 7697 mBassClientService.connectionStateChanged( 7698 mCurrentDevice, STATE_CONNECTED, STATE_DISCONNECTED); 7699 injectRemoteSourceStateRemoval(mStateMachines.get(mCurrentDevice), TEST_SOURCE_ID); 7700 7701 // Disconnect second sink cause remove metadata for both devices 7702 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice1)).getConnectionState(); 7703 doReturn(false).when(mStateMachines.get(mCurrentDevice1)).isConnected(); 7704 mBassClientService.connectionStateChanged( 7705 mCurrentDevice1, STATE_CONNECTED, STATE_DISCONNECTED); 7706 injectRemoteSourceStateRemoval(mStateMachines.get(mCurrentDevice1), TEST_SOURCE_ID + 1); 7707 7708 // Connect again both devices 7709 doReturn(STATE_CONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 7710 doReturn(true).when(mStateMachines.get(mCurrentDevice)).isConnected(); 7711 doReturn(STATE_CONNECTED).when(mStateMachines.get(mCurrentDevice1)).getConnectionState(); 7712 doReturn(true).when(mStateMachines.get(mCurrentDevice1)).isConnected(); 7713 prepareRemoteSourceState(meta, /* isPaSynced */ false, /* isBisSynced */ false); 7714 7715 // Cache and resume should not resume at all 7716 mBassClientService.cacheSuspendingSources(TEST_BROADCAST_ID); 7717 mBassClientService.resumeReceiversSourceSynchronization(); 7718 assertThat(mStateMachines.size()).isEqualTo(2); 7719 for (BassClientStateMachine sm : mStateMachines.values()) { 7720 verify(sm, never()).sendMessage(any()); 7721 } 7722 } 7723 7724 @Test 7725 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) multipleSinkMetadata_clearWhenAllDisconnected_duringSuspend()7726 public void multipleSinkMetadata_clearWhenAllDisconnected_duringSuspend() { 7727 prepareConnectedDeviceGroup(); 7728 startSearchingForSources(); 7729 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 7730 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 7731 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 7732 verifyAddSourceForGroup(meta); 7733 for (BassClientStateMachine sm : mStateMachines.values()) { 7734 clearInvocations(sm); 7735 } 7736 prepareRemoteSourceState(meta, /* isPaSynced */ false, /* isBisSynced */ false); 7737 7738 /* Unicast would like to stream */ 7739 mBassClientService.handleUnicastSourceStreamStatusChange( 7740 3 /* STATUS_LOCAL_STREAM_REQUESTED_NO_CONTEXT_VALIDATE */); 7741 verifyModifyMessageAndInjectSourceModfified(); 7742 for (BassClientStateMachine sm : mStateMachines.values()) { 7743 clearInvocations(sm); 7744 } 7745 7746 // Disconnect first sink not cause removing metadata 7747 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 7748 doReturn(false).when(mStateMachines.get(mCurrentDevice)).isConnected(); 7749 mBassClientService.connectionStateChanged( 7750 mCurrentDevice, STATE_CONNECTED, STATE_DISCONNECTED); 7751 injectRemoteSourceStateRemoval(mStateMachines.get(mCurrentDevice), TEST_SOURCE_ID); 7752 7753 // Connect again first sink 7754 doReturn(STATE_CONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 7755 doReturn(true).when(mStateMachines.get(mCurrentDevice)).isConnected(); 7756 prepareRemoteSourceState(meta, /* isPaSynced */ false, /* isBisSynced */ false); 7757 7758 // Cache and resume should resume all devices 7759 mBassClientService.cacheSuspendingSources(TEST_BROADCAST_ID); 7760 mBassClientService.resumeReceiversSourceSynchronization(); 7761 verifyAllGroupMembersGettingUpdateOrAddSource(meta); 7762 for (BassClientStateMachine sm : mStateMachines.values()) { 7763 clearInvocations(sm); 7764 } 7765 7766 /* Unicast would like to stream */ 7767 mBassClientService.handleUnicastSourceStreamStatusChange( 7768 3 /* STATUS_LOCAL_STREAM_REQUESTED_NO_CONTEXT_VALIDATE */); 7769 verifyModifyMessageAndInjectSourceModfified(); 7770 for (BassClientStateMachine sm : mStateMachines.values()) { 7771 clearInvocations(sm); 7772 } 7773 7774 // Disconnect first sink not cause removing metadata 7775 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 7776 doReturn(false).when(mStateMachines.get(mCurrentDevice)).isConnected(); 7777 mBassClientService.connectionStateChanged( 7778 mCurrentDevice, STATE_CONNECTED, STATE_DISCONNECTED); 7779 injectRemoteSourceStateRemoval(mStateMachines.get(mCurrentDevice), TEST_SOURCE_ID); 7780 7781 // Disconnect second sink cause remove metadata for both devices 7782 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice1)).getConnectionState(); 7783 doReturn(false).when(mStateMachines.get(mCurrentDevice1)).isConnected(); 7784 mBassClientService.connectionStateChanged( 7785 mCurrentDevice1, STATE_CONNECTED, STATE_DISCONNECTED); 7786 injectRemoteSourceStateRemoval(mStateMachines.get(mCurrentDevice1), TEST_SOURCE_ID + 1); 7787 7788 // Connect again both devices 7789 doReturn(STATE_CONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 7790 doReturn(true).when(mStateMachines.get(mCurrentDevice)).isConnected(); 7791 doReturn(STATE_CONNECTED).when(mStateMachines.get(mCurrentDevice1)).getConnectionState(); 7792 doReturn(true).when(mStateMachines.get(mCurrentDevice1)).isConnected(); 7793 prepareRemoteSourceState(meta, /* isPaSynced */ false, /* isBisSynced */ false); 7794 7795 // Cache and resume should not resume at all 7796 mBassClientService.cacheSuspendingSources(TEST_BROADCAST_ID); 7797 mBassClientService.resumeReceiversSourceSynchronization(); 7798 assertThat(mStateMachines.size()).isEqualTo(2); 7799 for (BassClientStateMachine sm : mStateMachines.values()) { 7800 verify(sm, never()).sendMessage(any()); 7801 } 7802 } 7803 7804 @Test 7805 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) multipleSinkMetadata_clearWhenRemove_oneDisconnectedFirst()7806 public void multipleSinkMetadata_clearWhenRemove_oneDisconnectedFirst() { 7807 prepareConnectedDeviceGroup(); 7808 startSearchingForSources(); 7809 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 7810 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 7811 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 7812 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ false); 7813 mBassClientService.addSource(mCurrentDevice1, meta, /* isGroupOp */ false); 7814 for (BassClientStateMachine sm : mStateMachines.values()) { 7815 clearInvocations(sm); 7816 } 7817 prepareRemoteSourceState(meta, /* isPaSynced */ false, /* isBisSynced */ false); 7818 7819 // Disconnect first sink not cause removing metadata 7820 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 7821 doReturn(false).when(mStateMachines.get(mCurrentDevice)).isConnected(); 7822 mBassClientService.connectionStateChanged( 7823 mCurrentDevice, STATE_CONNECTED, STATE_DISCONNECTED); 7824 injectRemoteSourceStateRemoval(mStateMachines.get(mCurrentDevice), TEST_SOURCE_ID); 7825 7826 // Remove second source should remove metadata for both 7827 // Do not clear receive state 7828 mBassClientService.removeSource(mCurrentDevice1, TEST_SOURCE_ID + 1); 7829 for (BassClientStateMachine sm : mStateMachines.values()) { 7830 clearInvocations(sm); 7831 } 7832 7833 // Connect again first sink 7834 doReturn(STATE_CONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 7835 doReturn(true).when(mStateMachines.get(mCurrentDevice)).isConnected(); 7836 prepareRemoteSourceState(meta, /* isPaSynced */ false, /* isBisSynced */ false); 7837 7838 // Cache and resume should not resume at all 7839 mBassClientService.cacheSuspendingSources(TEST_BROADCAST_ID); 7840 mBassClientService.resumeReceiversSourceSynchronization(); 7841 assertThat(mStateMachines.size()).isEqualTo(2); 7842 for (BassClientStateMachine sm : mStateMachines.values()) { 7843 verify(sm, never()).sendMessage(any()); 7844 } 7845 } 7846 7847 @Test 7848 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) multipleSinkMetadata_clearWhenRemove_oneDisconnectedFirst_duringSuspend()7849 public void multipleSinkMetadata_clearWhenRemove_oneDisconnectedFirst_duringSuspend() { 7850 prepareConnectedDeviceGroup(); 7851 startSearchingForSources(); 7852 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 7853 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 7854 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 7855 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ false); 7856 mBassClientService.addSource(mCurrentDevice1, meta, /* isGroupOp */ false); 7857 for (BassClientStateMachine sm : mStateMachines.values()) { 7858 clearInvocations(sm); 7859 } 7860 prepareRemoteSourceState(meta, /* isPaSynced */ false, /* isBisSynced */ false); 7861 7862 /* Unicast would like to stream */ 7863 mBassClientService.handleUnicastSourceStreamStatusChange( 7864 3 /* STATUS_LOCAL_STREAM_REQUESTED_NO_CONTEXT_VALIDATE */); 7865 verifyModifyMessageAndInjectSourceModfified(); 7866 for (BassClientStateMachine sm : mStateMachines.values()) { 7867 clearInvocations(sm); 7868 } 7869 7870 // Disconnect first sink not cause removing metadata 7871 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 7872 doReturn(false).when(mStateMachines.get(mCurrentDevice)).isConnected(); 7873 mBassClientService.connectionStateChanged( 7874 mCurrentDevice, STATE_CONNECTED, STATE_DISCONNECTED); 7875 injectRemoteSourceStateRemoval(mStateMachines.get(mCurrentDevice), TEST_SOURCE_ID); 7876 7877 // Remove second source should remove metadata for both 7878 // Do not clear receive state 7879 mBassClientService.removeSource(mCurrentDevice1, TEST_SOURCE_ID + 1); 7880 for (BassClientStateMachine sm : mStateMachines.values()) { 7881 clearInvocations(sm); 7882 } 7883 7884 // Connect again first sink 7885 doReturn(STATE_CONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 7886 doReturn(true).when(mStateMachines.get(mCurrentDevice)).isConnected(); 7887 prepareRemoteSourceState(meta, /* isPaSynced */ false, /* isBisSynced */ false); 7888 7889 // Cache and resume should not resume at all 7890 mBassClientService.cacheSuspendingSources(TEST_BROADCAST_ID); 7891 mBassClientService.resumeReceiversSourceSynchronization(); 7892 assertThat(mStateMachines.size()).isEqualTo(2); 7893 for (BassClientStateMachine sm : mStateMachines.values()) { 7894 verify(sm, never()).sendMessage(any()); 7895 } 7896 } 7897 7898 @Test 7899 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) clearPendingSourceToAdd_oneByOne_whenDisconnected()7900 public void clearPendingSourceToAdd_oneByOne_whenDisconnected() { 7901 prepareConnectedDeviceGroup(); 7902 startSearchingForSources(); 7903 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 7904 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 7905 7906 // Sync lost without triggering timeout to keep cache 7907 onSyncLost(); 7908 7909 // Add source force syncing to broadcaster and add sinks to pendingSourcesToAdd 7910 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 7911 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ false); 7912 mBassClientService.addSource(mCurrentDevice1, meta, /* isGroupOp */ false); 7913 7914 // Disconnect first sink should remove pendingSourceToAdd for it 7915 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 7916 doReturn(false).when(mStateMachines.get(mCurrentDevice)).isConnected(); 7917 mBassClientService.connectionStateChanged( 7918 mCurrentDevice, STATE_CONNECTED, STATE_DISCONNECTED); 7919 injectRemoteSourceStateRemoval(mStateMachines.get(mCurrentDevice), TEST_SOURCE_ID); 7920 7921 // Sync established should add source on only one sink 7922 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 7923 assertThat(mStateMachines.size()).isEqualTo(2); 7924 for (BassClientStateMachine sm : mStateMachines.values()) { 7925 if (sm.getDevice().equals(mCurrentDevice)) { 7926 verify(sm, never()).sendMessage(any()); 7927 } else if (sm.getDevice().equals(mCurrentDevice1)) { 7928 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 7929 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 7930 7931 Message msg = 7932 messageCaptor.getAllValues().stream() 7933 .filter(m -> (m.what == BassClientStateMachine.ADD_BCAST_SOURCE)) 7934 .findFirst() 7935 .orElse(null); 7936 assertThat(msg).isNotNull(); 7937 clearInvocations(sm); 7938 } else { 7939 throw new AssertionError("Unexpected device"); 7940 } 7941 } 7942 } 7943 7944 @Test 7945 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) clearPendingSourceToAdd_group_whenDisconnected()7946 public void clearPendingSourceToAdd_group_whenDisconnected() { 7947 prepareConnectedDeviceGroup(); 7948 startSearchingForSources(); 7949 onScanResult(mSourceDevice, TEST_BROADCAST_ID); 7950 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 7951 7952 // Sync lost without triggering timeout to keep cache 7953 onSyncLost(); 7954 7955 // Add source force syncing to broadcaster and add sinks to pendingSourcesToAdd 7956 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 7957 mBassClientService.addSource(mCurrentDevice, meta, /* isGroupOp */ true); 7958 7959 // Disconnect first sink should remove pendingSourceToAdd for it 7960 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 7961 doReturn(false).when(mStateMachines.get(mCurrentDevice)).isConnected(); 7962 mBassClientService.connectionStateChanged( 7963 mCurrentDevice, STATE_CONNECTED, STATE_DISCONNECTED); 7964 injectRemoteSourceStateRemoval(mStateMachines.get(mCurrentDevice), TEST_SOURCE_ID); 7965 7966 // Sync established should add source on only one sink 7967 onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); 7968 assertThat(mStateMachines.size()).isEqualTo(2); 7969 for (BassClientStateMachine sm : mStateMachines.values()) { 7970 if (sm.getDevice().equals(mCurrentDevice)) { 7971 verify(sm, never()).sendMessage(any()); 7972 } else if (sm.getDevice().equals(mCurrentDevice1)) { 7973 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 7974 verify(sm, atLeast(1)).sendMessage(messageCaptor.capture()); 7975 7976 Message msg = 7977 messageCaptor.getAllValues().stream() 7978 .filter(m -> (m.what == BassClientStateMachine.ADD_BCAST_SOURCE)) 7979 .findFirst() 7980 .orElse(null); 7981 assertThat(msg).isNotNull(); 7982 clearInvocations(sm); 7983 } else { 7984 throw new AssertionError("Unexpected device"); 7985 } 7986 } 7987 } 7988 7989 @Test 7990 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) doNotAllowDuplicatesInAddSelectSource()7991 public void doNotAllowDuplicatesInAddSelectSource() { 7992 prepareSynchronizedPairAndStopSearching(); 7993 7994 // Sync request for past force add to select source 7995 mBassClientService.syncRequestForPast(mCurrentDevice, TEST_BROADCAST_ID, TEST_SOURCE_ID); 7996 mInOrderMethodProxy 7997 .verify(mMethodProxy) 7998 .periodicAdvertisingManagerRegisterSync( 7999 any(), any(), anyInt(), anyInt(), any(), any()); 8000 8001 // Another sync request for past try add to select source again 8002 mBassClientService.syncRequestForPast( 8003 mCurrentDevice1, TEST_BROADCAST_ID, TEST_SOURCE_ID + 1); 8004 8005 // On sync failed should be no more sync registration 8006 onSyncEstablishedFailed(mSourceDevice, TEST_SYNC_HANDLE); 8007 mInOrderMethodProxy 8008 .verify(mMethodProxy, never()) 8009 .periodicAdvertisingManagerRegisterSync( 8010 any(), any(), anyInt(), anyInt(), any(), any()); 8011 } 8012 8013 @Test 8014 @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER) sinkDisconnectionDuringResuming()8015 public void sinkDisconnectionDuringResuming() { 8016 prepareSynchronizedPairAndStopSearching(); 8017 8018 BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); 8019 mBassClientService.suspendAllReceiversSourceSynchronization(); 8020 injectRemoteSourceStateChanged(meta, /* isPaSynced */ false, /* isBisSynced */ false); 8021 8022 // Prepare disconnection of one sink 8023 doReturn(STATE_DISCONNECTED).when(mStateMachines.get(mCurrentDevice)).getConnectionState(); 8024 doReturn(false).when(mStateMachines.get(mCurrentDevice)).isConnected(); 8025 doAnswer( 8026 invocation -> { 8027 mBassClientService.connectionStateChanged( 8028 mCurrentDevice, STATE_CONNECTED, STATE_DISCONNECTED); 8029 return null; 8030 }) 8031 .when(mMethodProxy) 8032 .periodicAdvertisingManagerRegisterSync( 8033 any(), any(), anyInt(), anyInt(), any(), any()); 8034 8035 mBassClientService.resumeReceiversSourceSynchronization(); 8036 } 8037 verifyConnectionStateIntent(BluetoothDevice device, int newState, int prevState)8038 private void verifyConnectionStateIntent(BluetoothDevice device, int newState, int prevState) { 8039 verifyIntentSent( 8040 hasAction(BluetoothLeBroadcastAssistant.ACTION_CONNECTION_STATE_CHANGED), 8041 hasExtra(BluetoothDevice.EXTRA_DEVICE, device), 8042 hasExtra(EXTRA_STATE, newState), 8043 hasExtra(EXTRA_PREVIOUS_STATE, prevState)); 8044 } 8045 8046 @SafeVarargs verifyIntentSent(Matcher<Intent>.... matchers)8047 private void verifyIntentSent(Matcher<Intent>... matchers) { 8048 mInOrder.verify(mAdapterService, timeout(1000)) 8049 .sendBroadcastMultiplePermissions( 8050 MockitoHamcrest.argThat(AllOf.allOf(matchers)), 8051 any(), 8052 any(BroadcastOptions.class)); 8053 } 8054 } 8055