Loading framework/tests/bumble/bumble_config.json +2 −1 Original line number Diff line number Diff line { "advertising_interval": 200, "address": "51:F7:A8:75:AC:5E", "classic_enabled": true "classic_enabled": true, "irk": "1F66F4B5F0C742F807DD0DDBF64E9213" } framework/tests/bumble/src/android/bluetooth/LeScanningTest.java +52 −19 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.bluetooth; import static com.google.common.io.BaseEncoding.base16; import static com.google.common.truth.Truth.assertThat; import android.bluetooth.le.BluetoothLeScanner; Loading Loading @@ -43,6 +44,7 @@ import java.util.concurrent.TimeUnit; import pandora.HostProto; import pandora.HostProto.AdvertiseRequest; import pandora.HostProto.AdvertiseResponse; import pandora.HostProto.OwnAddressType; @RunWith(AndroidJUnit4.class) public class LeScanningTest { Loading @@ -53,14 +55,24 @@ public class LeScanningTest { @Rule public final PandoraDevice mBumble = new PandoraDevice(); private static final String TEST_ADDRESS_RANDOM_STATIC = "F0:43:A8:23:10:11"; // IRK must match what's defined in bumble_config.json private static final byte[] TEST_IRK = base16().decode("1F66F4B5F0C742F807DD0DDBF64E9213"); private final String TEST_UUID_STRING = "00001805-0000-1000-8000-00805f9b34fb"; @Test public void startBleScan_withCallbackTypeAllMatches() { advertiseWithBumble(TEST_UUID_STRING); advertiseWithBumble(TEST_UUID_STRING, OwnAddressType.PUBLIC); ScanFilter scanFilter = new ScanFilter.Builder() .setServiceUuid(ParcelUuid.fromString(TEST_UUID_STRING)) .build(); List<ScanResult> results = startScanning(TEST_UUID_STRING, ScanSettings.CALLBACK_TYPE_ALL_MATCHES).join(); startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES).join(); assertThat(results.get(0).getScanRecord().getServiceUuids().get(0)) .isEqualTo(ParcelUuid.fromString(TEST_UUID_STRING)); Loading @@ -68,8 +80,27 @@ public class LeScanningTest { .isEqualTo(ParcelUuid.fromString(TEST_UUID_STRING)); } @Test public void scanForIrkIdentityAddress_withCallbackTypeAllMatches() { advertiseWithBumble(null, OwnAddressType.RANDOM); ScanFilter scanFilter = new ScanFilter.Builder() .setDeviceAddress( TEST_ADDRESS_RANDOM_STATIC, BluetoothDevice.ADDRESS_TYPE_RANDOM, TEST_IRK) .build(); List<ScanResult> results = startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES).join(); assertThat(results).isNotEmpty(); assertThat(results.get(0).getDevice().getAddress()).isEqualTo(TEST_ADDRESS_RANDOM_STATIC); } private CompletableFuture<List<ScanResult>> startScanning( String serviceUuid, int callbackType) { ScanFilter scanFilter, int callbackType) { CompletableFuture<List<ScanResult>> future = new CompletableFuture<>(); List<ScanResult> scanResults = new ArrayList<>(); Loading @@ -86,11 +117,6 @@ public class LeScanningTest { .setCallbackType(callbackType) .build(); List<ScanFilter> scanFilters = new ArrayList<>(); ScanFilter scanFilter = new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString(serviceUuid)).build(); scanFilters.add(scanFilter); ScanCallback scanCallback = new ScanCallback() { @Override Loading @@ -102,11 +128,17 @@ public class LeScanningTest { + callbackType + ", service uuids: " + result.getScanRecord().getServiceUuids()); if (callbackType == ScanSettings.CALLBACK_TYPE_ALL_MATCHES) { if (scanResults.size() < 2) { scanResults.add(result); } else { future.complete(scanResults); } } else { scanResults.add(result); future.complete(scanResults); } } @Override Loading @@ -116,24 +148,25 @@ public class LeScanningTest { } }; leScanner.startScan(scanFilters, scanSettings, scanCallback); leScanner.startScan(List.of(scanFilter), scanSettings, scanCallback); // Make sure completableFuture object completes with null after some timeout return future.completeOnTimeout(null, TIMEOUT_SCANNING_MS, TimeUnit.MILLISECONDS); } private void advertiseWithBumble(String serviceUuid) { HostProto.DataTypes dataType = HostProto.DataTypes.newBuilder() .addCompleteServiceClassUuids128(serviceUuid) .build(); private void advertiseWithBumble(String serviceUuid, OwnAddressType addressType) { AdvertiseRequest.Builder requestBuilder = AdvertiseRequest.newBuilder().setLegacy(true).setOwnAddressType(addressType); AdvertiseRequest request = AdvertiseRequest.newBuilder().setLegacy(true).setData(dataType).build(); if (serviceUuid != null) { HostProto.DataTypes.Builder dataTypeBuilder = HostProto.DataTypes.newBuilder(); dataTypeBuilder.addCompleteServiceClassUuids128(serviceUuid); requestBuilder.setData(dataTypeBuilder.build()); } StreamObserverSpliterator<AdvertiseResponse> responseObserver = new StreamObserverSpliterator<>(); mBumble.host().advertise(request, responseObserver); mBumble.host().advertise(requestBuilder.build(), responseObserver); } } Loading
framework/tests/bumble/bumble_config.json +2 −1 Original line number Diff line number Diff line { "advertising_interval": 200, "address": "51:F7:A8:75:AC:5E", "classic_enabled": true "classic_enabled": true, "irk": "1F66F4B5F0C742F807DD0DDBF64E9213" }
framework/tests/bumble/src/android/bluetooth/LeScanningTest.java +52 −19 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.bluetooth; import static com.google.common.io.BaseEncoding.base16; import static com.google.common.truth.Truth.assertThat; import android.bluetooth.le.BluetoothLeScanner; Loading Loading @@ -43,6 +44,7 @@ import java.util.concurrent.TimeUnit; import pandora.HostProto; import pandora.HostProto.AdvertiseRequest; import pandora.HostProto.AdvertiseResponse; import pandora.HostProto.OwnAddressType; @RunWith(AndroidJUnit4.class) public class LeScanningTest { Loading @@ -53,14 +55,24 @@ public class LeScanningTest { @Rule public final PandoraDevice mBumble = new PandoraDevice(); private static final String TEST_ADDRESS_RANDOM_STATIC = "F0:43:A8:23:10:11"; // IRK must match what's defined in bumble_config.json private static final byte[] TEST_IRK = base16().decode("1F66F4B5F0C742F807DD0DDBF64E9213"); private final String TEST_UUID_STRING = "00001805-0000-1000-8000-00805f9b34fb"; @Test public void startBleScan_withCallbackTypeAllMatches() { advertiseWithBumble(TEST_UUID_STRING); advertiseWithBumble(TEST_UUID_STRING, OwnAddressType.PUBLIC); ScanFilter scanFilter = new ScanFilter.Builder() .setServiceUuid(ParcelUuid.fromString(TEST_UUID_STRING)) .build(); List<ScanResult> results = startScanning(TEST_UUID_STRING, ScanSettings.CALLBACK_TYPE_ALL_MATCHES).join(); startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES).join(); assertThat(results.get(0).getScanRecord().getServiceUuids().get(0)) .isEqualTo(ParcelUuid.fromString(TEST_UUID_STRING)); Loading @@ -68,8 +80,27 @@ public class LeScanningTest { .isEqualTo(ParcelUuid.fromString(TEST_UUID_STRING)); } @Test public void scanForIrkIdentityAddress_withCallbackTypeAllMatches() { advertiseWithBumble(null, OwnAddressType.RANDOM); ScanFilter scanFilter = new ScanFilter.Builder() .setDeviceAddress( TEST_ADDRESS_RANDOM_STATIC, BluetoothDevice.ADDRESS_TYPE_RANDOM, TEST_IRK) .build(); List<ScanResult> results = startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES).join(); assertThat(results).isNotEmpty(); assertThat(results.get(0).getDevice().getAddress()).isEqualTo(TEST_ADDRESS_RANDOM_STATIC); } private CompletableFuture<List<ScanResult>> startScanning( String serviceUuid, int callbackType) { ScanFilter scanFilter, int callbackType) { CompletableFuture<List<ScanResult>> future = new CompletableFuture<>(); List<ScanResult> scanResults = new ArrayList<>(); Loading @@ -86,11 +117,6 @@ public class LeScanningTest { .setCallbackType(callbackType) .build(); List<ScanFilter> scanFilters = new ArrayList<>(); ScanFilter scanFilter = new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString(serviceUuid)).build(); scanFilters.add(scanFilter); ScanCallback scanCallback = new ScanCallback() { @Override Loading @@ -102,11 +128,17 @@ public class LeScanningTest { + callbackType + ", service uuids: " + result.getScanRecord().getServiceUuids()); if (callbackType == ScanSettings.CALLBACK_TYPE_ALL_MATCHES) { if (scanResults.size() < 2) { scanResults.add(result); } else { future.complete(scanResults); } } else { scanResults.add(result); future.complete(scanResults); } } @Override Loading @@ -116,24 +148,25 @@ public class LeScanningTest { } }; leScanner.startScan(scanFilters, scanSettings, scanCallback); leScanner.startScan(List.of(scanFilter), scanSettings, scanCallback); // Make sure completableFuture object completes with null after some timeout return future.completeOnTimeout(null, TIMEOUT_SCANNING_MS, TimeUnit.MILLISECONDS); } private void advertiseWithBumble(String serviceUuid) { HostProto.DataTypes dataType = HostProto.DataTypes.newBuilder() .addCompleteServiceClassUuids128(serviceUuid) .build(); private void advertiseWithBumble(String serviceUuid, OwnAddressType addressType) { AdvertiseRequest.Builder requestBuilder = AdvertiseRequest.newBuilder().setLegacy(true).setOwnAddressType(addressType); AdvertiseRequest request = AdvertiseRequest.newBuilder().setLegacy(true).setData(dataType).build(); if (serviceUuid != null) { HostProto.DataTypes.Builder dataTypeBuilder = HostProto.DataTypes.newBuilder(); dataTypeBuilder.addCompleteServiceClassUuids128(serviceUuid); requestBuilder.setData(dataTypeBuilder.build()); } StreamObserverSpliterator<AdvertiseResponse> responseObserver = new StreamObserverSpliterator<>(); mBumble.host().advertise(request, responseObserver); mBumble.host().advertise(requestBuilder.build(), responseObserver); } }