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

Commit d82be229 authored by Omair Kamil's avatar Omair Kamil Committed by Gerrit Code Review
Browse files

Merge "Send the correct mask for service data to the native layer." into main

parents 4f65db84 ec737cf6
Loading
Loading
Loading
Loading
+11 −7
Original line number Diff line number Diff line
@@ -256,8 +256,8 @@ import java.util.UUID;
                serviceDataMask = new byte[serviceData.length];
                Arrays.fill(serviceDataMask, (byte) 0xFF);
            }
            serviceData = concatenate(serviceDataUuid, serviceData);
            serviceDataMask = concatenate(serviceDataUuid, serviceDataMask);
            serviceData = concatenate(serviceDataUuid, serviceData, false);
            serviceDataMask = concatenate(serviceDataUuid, serviceDataMask, true);
            if (serviceData != null && serviceDataMask != null) {
                addServiceData(serviceData, serviceDataMask);
            }
@@ -293,19 +293,23 @@ import java.util.UUID;
        }
    }

    private byte[] concatenate(ParcelUuid serviceDataUuid, byte[] serviceData) {
    private byte[] concatenate(ParcelUuid serviceDataUuid, byte[] serviceData, boolean isMask) {
        byte[] uuid = BluetoothUuid.uuidToBytes(serviceDataUuid);

        int dataLen = uuid.length + (serviceData == null ? 0 : serviceData.length);
        int dataLen = uuid.length + serviceData.length;
        // If data is too long, don't add it to hardware scan filter.
        if (dataLen > MAX_LEN_PER_FIELD) {
            return null;
        }
        byte[] concatenated = new byte[dataLen];
        if (isMask) {
            // For the UUID portion of the mask fill it with 0xFF to indicate that all bits of the
            // UUID need to match the service data filter.
            Arrays.fill(concatenated, 0, uuid.length, (byte) 0xFF);
        } else {
            System.arraycopy(uuid, 0, concatenated, 0, uuid.length);
        if (serviceData != null) {
            System.arraycopy(serviceData, 0, concatenated, uuid.length, serviceData.length);
        }
        System.arraycopy(serviceData, 0, concatenated, uuid.length, serviceData.length);
        return concatenated;
    }
}
+104 −0
Original line number Diff line number Diff line
@@ -18,12 +18,15 @@ package com.android.bluetooth.le_scan;

import static com.google.common.truth.Truth.assertThat;

import android.bluetooth.BluetoothUuid;
import android.bluetooth.le.ScanFilter;
import android.os.ParcelUuid;

import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import com.google.common.primitives.Bytes;

import org.junit.Test;
import org.junit.runner.RunWith;

@@ -33,6 +36,14 @@ import java.util.UUID;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ScanFilterQueueTest {
    private static final String TEST_UUID_STRING = "00001805-0000-1000-8000-00805f9b34fb";
    private static final String UNMATCHED_UUID_STRING = "00001815-0000-1000-8000-00805f9b34fb";
    private static final byte[] TEST_SERVICE_DATA = new byte[] {(byte) 0x18, (byte) 0x0F};
    private static final byte[] PARTIALLY_MATCHED_SERVICE_DATA =
            new byte[] {(byte) 0x08, (byte) 0x0F, (byte) 0xAB, (byte) 0xCD};
    private static final byte[] UNMATCHED_SERVICE_DATA = new byte[] {(byte) 0x08, (byte) 0x0E};
    private static final byte[] PARTIAL_SERVICE_DATA_MASK = new byte[] {(byte) 0x00, (byte) 0xFF};
    private static final byte[] FULL_SERVICE_DATA_MASK = new byte[] {(byte) 0xFF, (byte) 0xFF};

    @Test
    public void scanFilterQueueParams() {
@@ -195,4 +206,97 @@ public class ScanFilterQueueTest {
        int numOfEntries = 7;
        assertThat(queue.toArray().length).isEqualTo(numOfEntries);
    }

    @Test
    public void serviceDataFilterNoMask1() {
        ScanFilter filter =
                new ScanFilter.Builder()
                        .setServiceData(ParcelUuid.fromString(TEST_UUID_STRING), TEST_SERVICE_DATA)
                        .build();
        testServiceDataFilter(filter, false);
    }

    @Test
    public void serviceDataFilterWithFullMask() {
        ScanFilter filter =
                new ScanFilter.Builder()
                        .setServiceData(
                                ParcelUuid.fromString(TEST_UUID_STRING),
                                TEST_SERVICE_DATA,
                                FULL_SERVICE_DATA_MASK)
                        .build();
        testServiceDataFilter(filter, false);
    }

    @Test
    public void serviceDataFilterWithPartialMask() {
        ScanFilter filter =
                new ScanFilter.Builder()
                        .setServiceData(
                                ParcelUuid.fromString(TEST_UUID_STRING),
                                TEST_SERVICE_DATA,
                                PARTIAL_SERVICE_DATA_MASK)
                        .build();
        testServiceDataFilter(filter, true);
    }

    private void testServiceDataFilter(ScanFilter filter, boolean partialServiceDataMatchResult) {
        ScanFilterQueue queue = new ScanFilterQueue();
        queue.addScanFilter(filter);
        ScanFilterQueue.Entry entry = queue.pop();
        assertThat(entry.type).isEqualTo(ScanFilterQueue.TYPE_SERVICE_DATA);
        assertThat(entry.data)
                .isEqualTo(
                        Bytes.concat(
                                BluetoothUuid.uuidToBytes(ParcelUuid.fromString(TEST_UUID_STRING)),
                                TEST_SERVICE_DATA));
        assertThat(
                        serviceDataMatches(
                                entry.data,
                                Bytes.concat(
                                        BluetoothUuid.uuidToBytes(
                                                ParcelUuid.fromString(TEST_UUID_STRING)),
                                        TEST_SERVICE_DATA),
                                entry.data_mask))
                .isTrue();
        assertThat(
                        serviceDataMatches(
                                entry.data,
                                Bytes.concat(
                                        BluetoothUuid.uuidToBytes(
                                                ParcelUuid.fromString(UNMATCHED_UUID_STRING)),
                                        TEST_SERVICE_DATA),
                                entry.data_mask))
                .isFalse();
        assertThat(
                        serviceDataMatches(
                                entry.data,
                                Bytes.concat(
                                        BluetoothUuid.uuidToBytes(
                                                ParcelUuid.fromString(TEST_UUID_STRING)),
                                        UNMATCHED_SERVICE_DATA),
                                entry.data_mask))
                .isFalse();
        assertThat(
                        serviceDataMatches(
                                entry.data,
                                Bytes.concat(
                                        BluetoothUuid.uuidToBytes(
                                                ParcelUuid.fromString(TEST_UUID_STRING)),
                                        PARTIALLY_MATCHED_SERVICE_DATA),
                                entry.data_mask))
                .isEqualTo(partialServiceDataMatchResult);
    }

    private boolean serviceDataMatches(byte[] filterData, byte[] resultData, byte[] mask) {
        if (filterData.length > resultData.length || filterData.length != mask.length) {
            return false;
        }
        for (int i = 0; i < filterData.length; i++) {
            if ((filterData[i] & mask[i]) != (resultData[i] & mask[i])) {
                return false;
            }
        }
        return true;
    }
}