Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 96a9eb24 authored by Omair Kamil's avatar Omair Kamil Committed by Automerger Merge Worker
Browse files

Merge "Add bumble test for scanning with service data filter." into main am: b0acd0f4

parents 2d714fc8 b0acd0f4
Loading
Loading
Loading
Loading
+7 −7
Original line number Original line Diff line number Diff line
@@ -256,8 +256,8 @@ import java.util.UUID;
                serviceDataMask = new byte[serviceData.length];
                serviceDataMask = new byte[serviceData.length];
                Arrays.fill(serviceDataMask, (byte) 0xFF);
                Arrays.fill(serviceDataMask, (byte) 0xFF);
            }
            }
            serviceData = concate(serviceDataUuid, serviceData);
            serviceData = concatenate(serviceDataUuid, serviceData);
            serviceDataMask = concate(serviceDataUuid, serviceDataMask);
            serviceDataMask = concatenate(serviceDataUuid, serviceDataMask);
            if (serviceData != null && serviceDataMask != null) {
            if (serviceData != null && serviceDataMask != null) {
                addServiceData(serviceData, serviceDataMask);
                addServiceData(serviceData, serviceDataMask);
            }
            }
@@ -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);
        byte[] uuid = BluetoothUuid.uuidToBytes(serviceDataUuid);


        int dataLen = uuid.length + (serviceData == null ? 0 : serviceData.length);
        int dataLen = uuid.length + (serviceData == null ? 0 : serviceData.length);
@@ -301,11 +301,11 @@ import java.util.UUID;
        if (dataLen > MAX_LEN_PER_FIELD) {
        if (dataLen > MAX_LEN_PER_FIELD) {
            return null;
            return null;
        }
        }
        byte[] concated = new byte[dataLen];
        byte[] concatenated = new byte[dataLen];
        System.arraycopy(uuid, 0, concated, 0, uuid.length);
        System.arraycopy(uuid, 0, concatenated, 0, uuid.length);
        if (serviceData != null) {
        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;
    }
    }
}
}
+75 −21
Original line number Original line Diff line number Diff line
@@ -41,11 +41,12 @@ import android.os.ParcelUuid;
import android.util.Log;
import android.util.Log;


import androidx.test.core.app.ApplicationProvider;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;


import com.android.compatibility.common.util.AdoptShellPermissionsRule;
import com.android.compatibility.common.util.AdoptShellPermissionsRule;


import com.google.protobuf.ByteString;
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.Rule;
import org.junit.Test;
import org.junit.Test;
@@ -63,7 +64,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import java.util.stream.Stream;


@RunWith(AndroidJUnit4.class)
@RunWith(TestParameterInjector.class)
public class LeScanningTest {
public class LeScanningTest {
    private static final String TAG = "LeScanningTest";
    private static final String TAG = "LeScanningTest";
    private static final int TIMEOUT_SCANNING_MS = 2000;
    private static final int TIMEOUT_SCANNING_MS = 2000;
@@ -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 TEST_ADDRESS_RANDOM_STATIC = "F0:43:A8:23:10:11";
    private static final String ACTION_DYNAMIC_RECEIVER_SCAN_RESULT =
    private static final String ACTION_DYNAMIC_RECEIVER_SCAN_RESULT =
            "android.bluetooth.test.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();
    @Rule public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule();


@@ -92,7 +95,8 @@ public class LeScanningTest {
                        .build();
                        .build();


        List<ScanResult> results =
        List<ScanResult> results =
                startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
                startScanning(
                        scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES, /* isLegacy= */ true);


        assertThat(results).isNotNull();
        assertThat(results).isNotNull();
        assertThat(results.get(0).getScanRecord().getServiceUuids().get(0))
        assertThat(results.get(0).getScanRecord().getServiceUuids().get(0))
@@ -114,7 +118,8 @@ public class LeScanningTest {
                        .build();
                        .build();


        List<ScanResult> results =
        List<ScanResult> results =
                startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
                startScanning(
                        scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES, /* isLegacy= */ true);


        assertThat(results).isNotEmpty();
        assertThat(results).isNotEmpty();
        assertThat(results.get(0).getDevice().getAddress()).isEqualTo(TEST_ADDRESS_RANDOM_STATIC);
        assertThat(results.get(0).getDevice().getAddress()).isEqualTo(TEST_ADDRESS_RANDOM_STATIC);
@@ -295,7 +300,7 @@ public class LeScanningTest {
                AdvertiseRequest.newBuilder()
                AdvertiseRequest.newBuilder()
                        .setConnectable(false)
                        .setConnectable(false)
                        .setOwnAddressType(OwnAddressType.PUBLIC);
                        .setOwnAddressType(OwnAddressType.PUBLIC);
        advertiseWithBumble(requestBuilder);
        advertiseWithBumble(requestBuilder, true);


        ScanFilter scanFilter =
        ScanFilter scanFilter =
                new ScanFilter.Builder()
                new ScanFilter.Builder()
@@ -303,7 +308,8 @@ public class LeScanningTest {
                        .build();
                        .build();


        List<ScanResult> results =
        List<ScanResult> results =
                startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
                startScanning(
                        scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES, /* isLegacy= */ true);


        assertThat(results).isNotNull();
        assertThat(results).isNotNull();
        assertThat(results.get(0).isConnectable()).isFalse();
        assertThat(results.get(0).isConnectable()).isFalse();
@@ -324,7 +330,7 @@ public class LeScanningTest {
                        .setConnectable(false)
                        .setConnectable(false)
                        .setOwnAddressType(OwnAddressType.PUBLIC)
                        .setOwnAddressType(OwnAddressType.PUBLIC)
                        .setScanResponseData(scanResponse);
                        .setScanResponseData(scanResponse);
        advertiseWithBumble(requestBuilder);
        advertiseWithBumble(requestBuilder, true);


        ScanFilter scanFilter =
        ScanFilter scanFilter =
                new ScanFilter.Builder()
                new ScanFilter.Builder()
@@ -332,7 +338,8 @@ public class LeScanningTest {
                        .build();
                        .build();


        List<ScanResult> results =
        List<ScanResult> results =
                startScanning(scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
                startScanning(
                        scanFilter, ScanSettings.CALLBACK_TYPE_ALL_MATCHES, /* isLegacy= */ true);


        assertThat(results).isNotNull();
        assertThat(results).isNotNull();
        assertThat(results.get(0).isConnectable()).isFalse();
        assertThat(results.get(0).isConnectable()).isFalse();
@@ -340,7 +347,46 @@ public class LeScanningTest {
                .isEqualTo(payload);
                .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<>();
        CompletableFuture<List<ScanResult>> future = new CompletableFuture<>();
        List<ScanResult> scanResults = new ArrayList<>();
        List<ScanResult> scanResults = new ArrayList<>();


@@ -348,6 +394,7 @@ public class LeScanningTest {
                new ScanSettings.Builder()
                new ScanSettings.Builder()
                        .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                        .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                        .setCallbackType(callbackType)
                        .setCallbackType(callbackType)
                        .setLegacy(isLegacy)
                        .build();
                        .build();


        ScanCallback scanCallback =
        ScanCallback scanCallback =
@@ -366,14 +413,9 @@ public class LeScanningTest {
                                        + ", service uuids: "
                                        + ", service uuids: "
                                        + result.getScanRecord().getServiceUuids());
                                        + 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);
                        scanResults.add(result);
                        if (callbackType != ScanSettings.CALLBACK_TYPE_ALL_MATCHES
                                || scanResults.size() > 1) {
                            future.complete(scanResults);
                            future.complete(scanResults);
                        }
                        }
                    }
                    }
@@ -395,6 +437,19 @@ public class LeScanningTest {
        return result;
        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) {
    private void advertiseWithBumble(String serviceUuid, OwnAddressType addressType) {
        AdvertiseRequest.Builder requestBuilder =
        AdvertiseRequest.Builder requestBuilder =
                AdvertiseRequest.newBuilder().setOwnAddressType(addressType);
                AdvertiseRequest.newBuilder().setOwnAddressType(addressType);
@@ -405,12 +460,11 @@ public class LeScanningTest {
            requestBuilder.setData(dataTypeBuilder.build());
            requestBuilder.setData(dataTypeBuilder.build());
        }
        }


        advertiseWithBumble(requestBuilder);
        advertiseWithBumble(requestBuilder, true);
    }
    }


    private void advertiseWithBumble(AdvertiseRequest.Builder requestBuilder) {
    private void advertiseWithBumble(AdvertiseRequest.Builder requestBuilder, boolean isLegacy) {
        // Bumble currently only supports legacy advertising.
        requestBuilder.setLegacy(isLegacy);
        requestBuilder.setLegacy(true);
        // Collect and ignore responses.
        // Collect and ignore responses.
        StreamObserverSpliterator<AdvertiseResponse> responseObserver =
        StreamObserverSpliterator<AdvertiseResponse> responseObserver =
                new StreamObserverSpliterator<>();
                new StreamObserverSpliterator<>();