Loading android/app/src/com/android/bluetooth/le_scan/ScanFilterQueue.java +7 −7 Original line number Diff line number Diff line Loading @@ -256,8 +256,8 @@ import java.util.UUID; serviceDataMask = new byte[serviceData.length]; Arrays.fill(serviceDataMask, (byte) 0xFF); } serviceData = concate(serviceDataUuid, serviceData); serviceDataMask = concate(serviceDataUuid, serviceDataMask); serviceData = concatenate(serviceDataUuid, serviceData); serviceDataMask = concatenate(serviceDataUuid, serviceDataMask); if (serviceData != null && serviceDataMask != null) { addServiceData(serviceData, serviceDataMask); } Loading Loading @@ -293,7 +293,7 @@ import java.util.UUID; } } private byte[] concate(ParcelUuid serviceDataUuid, byte[] serviceData) { private byte[] concatenate(ParcelUuid serviceDataUuid, byte[] serviceData) { byte[] uuid = BluetoothUuid.uuidToBytes(serviceDataUuid); int dataLen = uuid.length + (serviceData == null ? 0 : serviceData.length); Loading @@ -301,11 +301,11 @@ import java.util.UUID; if (dataLen > MAX_LEN_PER_FIELD) { return null; } byte[] concated = new byte[dataLen]; System.arraycopy(uuid, 0, concated, 0, uuid.length); byte[] concatenated = new byte[dataLen]; System.arraycopy(uuid, 0, concatenated, 0, uuid.length); if (serviceData != null) { System.arraycopy(serviceData, 0, concated, uuid.length, serviceData.length); System.arraycopy(serviceData, 0, concatenated, uuid.length, serviceData.length); } return concated; return concatenated; } } framework/tests/bumble/src/android/bluetooth/LeScanningTest.java +75 −21 Original line number Diff line number Diff line Loading @@ -41,11 +41,12 @@ import android.os.ParcelUuid; import android.util.Log; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.compatibility.common.util.AdoptShellPermissionsRule; import com.google.protobuf.ByteString; import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import org.junit.Rule; import org.junit.Test; Loading @@ -63,7 +64,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; @RunWith(AndroidJUnit4.class) @RunWith(TestParameterInjector.class) public class LeScanningTest { private static final String TAG = "LeScanningTest"; private static final int TIMEOUT_SCANNING_MS = 2000; Loading @@ -71,6 +72,8 @@ public class LeScanningTest { private static final String TEST_ADDRESS_RANDOM_STATIC = "F0:43:A8:23:10:11"; private static final String ACTION_DYNAMIC_RECEIVER_SCAN_RESULT = "android.bluetooth.test.ACTION_DYNAMIC_RECEIVER_SCAN_RESULT"; private static final byte[] TEST_SERVICE_DATA = {(byte) 0xAA, (byte) 0xBB, (byte) 0xCC}; private static final String TEST_UUID_SUFFIX = "-0000-1000-8000-00805f9b34fb"; @Rule public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule(); Loading @@ -92,7 +95,8 @@ public class LeScanningTest { .build(); List<ScanResult> results = startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES); startScanning( scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES, /* isLegacy= */ true); assertThat(results).isNotNull(); assertThat(results.get(0).getScanRecord().getServiceUuids().get(0)) Loading @@ -114,7 +118,8 @@ public class LeScanningTest { .build(); List<ScanResult> results = startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES); startScanning( scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES, /* isLegacy= */ true); assertThat(results).isNotEmpty(); assertThat(results.get(0).getDevice().getAddress()).isEqualTo(TEST_ADDRESS_RANDOM_STATIC); Loading Loading @@ -295,7 +300,7 @@ public class LeScanningTest { AdvertiseRequest.newBuilder() .setConnectable(false) .setOwnAddressType(OwnAddressType.PUBLIC); advertiseWithBumble(requestBuilder); advertiseWithBumble(requestBuilder, true); ScanFilter scanFilter = new ScanFilter.Builder() Loading @@ -303,7 +308,8 @@ public class LeScanningTest { .build(); List<ScanResult> results = startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES); startScanning( scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES, /* isLegacy= */ true); assertThat(results).isNotNull(); assertThat(results.get(0).isConnectable()).isFalse(); Loading @@ -324,7 +330,7 @@ public class LeScanningTest { .setConnectable(false) .setOwnAddressType(OwnAddressType.PUBLIC) .setScanResponseData(scanResponse); advertiseWithBumble(requestBuilder); advertiseWithBumble(requestBuilder, true); ScanFilter scanFilter = new ScanFilter.Builder() Loading @@ -332,7 +338,8 @@ public class LeScanningTest { .build(); List<ScanResult> results = startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES); startScanning( scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES, /* isLegacy= */ true); assertThat(results).isNotNull(); assertThat(results.get(0).isConnectable()).isFalse(); Loading @@ -340,7 +347,46 @@ public class LeScanningTest { .isEqualTo(payload); } private List<ScanResult> startScanning(ScanFilter scanFilter, int callbackType) { @Test public void startBleScan_withServiceData() { advertiseWithBumbleWithServiceData(); ScanFilter scanFilter = new ScanFilter.Builder() .setServiceData(ParcelUuid.fromString(TEST_UUID_STRING), TEST_SERVICE_DATA) .build(); List<ScanResult> results = startScanning( scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES, /* isLegacy= */ false); assertThat(results).isNotNull(); assertThat(results.get(0).getScanRecord().getServiceUuids().get(0)) .isEqualTo(ParcelUuid.fromString(TEST_UUID_STRING)); } // Test against UUIDs that are close to TEST_UUID_STRING, one that has a few bits unset and one // that has an extra bit set. @Test public void startBleScan_withServiceData_uuidDoesntMatch( @TestParameter({"00001800", "00001815"}) String uuid) { advertiseWithBumbleWithServiceData(); ScanFilter scanFilter = new ScanFilter.Builder() .setServiceData( ParcelUuid.fromString(uuid + TEST_UUID_SUFFIX), TEST_SERVICE_DATA) .build(); List<ScanResult> results = startScanning( scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES, /* isLegacy= */ false); assertThat(results).isNull(); } private List<ScanResult> startScanning( ScanFilter scanFilter, int callbackType, boolean isLegacy) { CompletableFuture<List<ScanResult>> future = new CompletableFuture<>(); List<ScanResult> scanResults = new ArrayList<>(); Loading @@ -348,6 +394,7 @@ public class LeScanningTest { new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .setCallbackType(callbackType) .setLegacy(isLegacy) .build(); ScanCallback scanCallback = Loading @@ -366,14 +413,9 @@ public class LeScanningTest { + ", 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); if (callbackType != ScanSettings.CALLBACK_TYPE_ALL_MATCHES || scanResults.size() > 1) { future.complete(scanResults); } } Loading @@ -395,6 +437,19 @@ public class LeScanningTest { return result; } private void advertiseWithBumbleWithServiceData() { AdvertiseRequest.Builder requestBuilder = AdvertiseRequest.newBuilder().setOwnAddressType(OwnAddressType.PUBLIC); HostProto.DataTypes.Builder dataTypeBuilder = HostProto.DataTypes.newBuilder(); dataTypeBuilder.addCompleteServiceClassUuids128(TEST_UUID_STRING); dataTypeBuilder.putServiceDataUuid128( TEST_UUID_STRING, ByteString.copyFrom(TEST_SERVICE_DATA)); requestBuilder.setData(dataTypeBuilder.build()); advertiseWithBumble(requestBuilder, false); } private void advertiseWithBumble(String serviceUuid, OwnAddressType addressType) { AdvertiseRequest.Builder requestBuilder = AdvertiseRequest.newBuilder().setOwnAddressType(addressType); Loading @@ -405,12 +460,11 @@ public class LeScanningTest { requestBuilder.setData(dataTypeBuilder.build()); } advertiseWithBumble(requestBuilder); advertiseWithBumble(requestBuilder, true); } private void advertiseWithBumble(AdvertiseRequest.Builder requestBuilder) { // Bumble currently only supports legacy advertising. requestBuilder.setLegacy(true); private void advertiseWithBumble(AdvertiseRequest.Builder requestBuilder, boolean isLegacy) { requestBuilder.setLegacy(isLegacy); // Collect and ignore responses. StreamObserverSpliterator<AdvertiseResponse> responseObserver = new StreamObserverSpliterator<>(); Loading Loading
android/app/src/com/android/bluetooth/le_scan/ScanFilterQueue.java +7 −7 Original line number Diff line number Diff line Loading @@ -256,8 +256,8 @@ import java.util.UUID; serviceDataMask = new byte[serviceData.length]; Arrays.fill(serviceDataMask, (byte) 0xFF); } serviceData = concate(serviceDataUuid, serviceData); serviceDataMask = concate(serviceDataUuid, serviceDataMask); serviceData = concatenate(serviceDataUuid, serviceData); serviceDataMask = concatenate(serviceDataUuid, serviceDataMask); if (serviceData != null && serviceDataMask != null) { addServiceData(serviceData, serviceDataMask); } Loading Loading @@ -293,7 +293,7 @@ import java.util.UUID; } } private byte[] concate(ParcelUuid serviceDataUuid, byte[] serviceData) { private byte[] concatenate(ParcelUuid serviceDataUuid, byte[] serviceData) { byte[] uuid = BluetoothUuid.uuidToBytes(serviceDataUuid); int dataLen = uuid.length + (serviceData == null ? 0 : serviceData.length); Loading @@ -301,11 +301,11 @@ import java.util.UUID; if (dataLen > MAX_LEN_PER_FIELD) { return null; } byte[] concated = new byte[dataLen]; System.arraycopy(uuid, 0, concated, 0, uuid.length); byte[] concatenated = new byte[dataLen]; System.arraycopy(uuid, 0, concatenated, 0, uuid.length); if (serviceData != null) { System.arraycopy(serviceData, 0, concated, uuid.length, serviceData.length); System.arraycopy(serviceData, 0, concatenated, uuid.length, serviceData.length); } return concated; return concatenated; } }
framework/tests/bumble/src/android/bluetooth/LeScanningTest.java +75 −21 Original line number Diff line number Diff line Loading @@ -41,11 +41,12 @@ import android.os.ParcelUuid; import android.util.Log; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.compatibility.common.util.AdoptShellPermissionsRule; import com.google.protobuf.ByteString; import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import org.junit.Rule; import org.junit.Test; Loading @@ -63,7 +64,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; @RunWith(AndroidJUnit4.class) @RunWith(TestParameterInjector.class) public class LeScanningTest { private static final String TAG = "LeScanningTest"; private static final int TIMEOUT_SCANNING_MS = 2000; Loading @@ -71,6 +72,8 @@ public class LeScanningTest { private static final String TEST_ADDRESS_RANDOM_STATIC = "F0:43:A8:23:10:11"; private static final String ACTION_DYNAMIC_RECEIVER_SCAN_RESULT = "android.bluetooth.test.ACTION_DYNAMIC_RECEIVER_SCAN_RESULT"; private static final byte[] TEST_SERVICE_DATA = {(byte) 0xAA, (byte) 0xBB, (byte) 0xCC}; private static final String TEST_UUID_SUFFIX = "-0000-1000-8000-00805f9b34fb"; @Rule public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule(); Loading @@ -92,7 +95,8 @@ public class LeScanningTest { .build(); List<ScanResult> results = startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES); startScanning( scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES, /* isLegacy= */ true); assertThat(results).isNotNull(); assertThat(results.get(0).getScanRecord().getServiceUuids().get(0)) Loading @@ -114,7 +118,8 @@ public class LeScanningTest { .build(); List<ScanResult> results = startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES); startScanning( scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES, /* isLegacy= */ true); assertThat(results).isNotEmpty(); assertThat(results.get(0).getDevice().getAddress()).isEqualTo(TEST_ADDRESS_RANDOM_STATIC); Loading Loading @@ -295,7 +300,7 @@ public class LeScanningTest { AdvertiseRequest.newBuilder() .setConnectable(false) .setOwnAddressType(OwnAddressType.PUBLIC); advertiseWithBumble(requestBuilder); advertiseWithBumble(requestBuilder, true); ScanFilter scanFilter = new ScanFilter.Builder() Loading @@ -303,7 +308,8 @@ public class LeScanningTest { .build(); List<ScanResult> results = startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES); startScanning( scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES, /* isLegacy= */ true); assertThat(results).isNotNull(); assertThat(results.get(0).isConnectable()).isFalse(); Loading @@ -324,7 +330,7 @@ public class LeScanningTest { .setConnectable(false) .setOwnAddressType(OwnAddressType.PUBLIC) .setScanResponseData(scanResponse); advertiseWithBumble(requestBuilder); advertiseWithBumble(requestBuilder, true); ScanFilter scanFilter = new ScanFilter.Builder() Loading @@ -332,7 +338,8 @@ public class LeScanningTest { .build(); List<ScanResult> results = startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES); startScanning( scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES, /* isLegacy= */ true); assertThat(results).isNotNull(); assertThat(results.get(0).isConnectable()).isFalse(); Loading @@ -340,7 +347,46 @@ public class LeScanningTest { .isEqualTo(payload); } private List<ScanResult> startScanning(ScanFilter scanFilter, int callbackType) { @Test public void startBleScan_withServiceData() { advertiseWithBumbleWithServiceData(); ScanFilter scanFilter = new ScanFilter.Builder() .setServiceData(ParcelUuid.fromString(TEST_UUID_STRING), TEST_SERVICE_DATA) .build(); List<ScanResult> results = startScanning( scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES, /* isLegacy= */ false); assertThat(results).isNotNull(); assertThat(results.get(0).getScanRecord().getServiceUuids().get(0)) .isEqualTo(ParcelUuid.fromString(TEST_UUID_STRING)); } // Test against UUIDs that are close to TEST_UUID_STRING, one that has a few bits unset and one // that has an extra bit set. @Test public void startBleScan_withServiceData_uuidDoesntMatch( @TestParameter({"00001800", "00001815"}) String uuid) { advertiseWithBumbleWithServiceData(); ScanFilter scanFilter = new ScanFilter.Builder() .setServiceData( ParcelUuid.fromString(uuid + TEST_UUID_SUFFIX), TEST_SERVICE_DATA) .build(); List<ScanResult> results = startScanning( scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES, /* isLegacy= */ false); assertThat(results).isNull(); } private List<ScanResult> startScanning( ScanFilter scanFilter, int callbackType, boolean isLegacy) { CompletableFuture<List<ScanResult>> future = new CompletableFuture<>(); List<ScanResult> scanResults = new ArrayList<>(); Loading @@ -348,6 +394,7 @@ public class LeScanningTest { new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .setCallbackType(callbackType) .setLegacy(isLegacy) .build(); ScanCallback scanCallback = Loading @@ -366,14 +413,9 @@ public class LeScanningTest { + ", 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); if (callbackType != ScanSettings.CALLBACK_TYPE_ALL_MATCHES || scanResults.size() > 1) { future.complete(scanResults); } } Loading @@ -395,6 +437,19 @@ public class LeScanningTest { return result; } private void advertiseWithBumbleWithServiceData() { AdvertiseRequest.Builder requestBuilder = AdvertiseRequest.newBuilder().setOwnAddressType(OwnAddressType.PUBLIC); HostProto.DataTypes.Builder dataTypeBuilder = HostProto.DataTypes.newBuilder(); dataTypeBuilder.addCompleteServiceClassUuids128(TEST_UUID_STRING); dataTypeBuilder.putServiceDataUuid128( TEST_UUID_STRING, ByteString.copyFrom(TEST_SERVICE_DATA)); requestBuilder.setData(dataTypeBuilder.build()); advertiseWithBumble(requestBuilder, false); } private void advertiseWithBumble(String serviceUuid, OwnAddressType addressType) { AdvertiseRequest.Builder requestBuilder = AdvertiseRequest.newBuilder().setOwnAddressType(addressType); Loading @@ -405,12 +460,11 @@ public class LeScanningTest { requestBuilder.setData(dataTypeBuilder.build()); } advertiseWithBumble(requestBuilder); advertiseWithBumble(requestBuilder, true); } private void advertiseWithBumble(AdvertiseRequest.Builder requestBuilder) { // Bumble currently only supports legacy advertising. requestBuilder.setLegacy(true); private void advertiseWithBumble(AdvertiseRequest.Builder requestBuilder, boolean isLegacy) { requestBuilder.setLegacy(isLegacy); // Collect and ignore responses. StreamObserverSpliterator<AdvertiseResponse> responseObserver = new StreamObserverSpliterator<>(); Loading