Loading android/app/src/com/android/bluetooth/hid/HidHostService.java +9 −3 Original line number Diff line number Diff line Loading @@ -519,10 +519,16 @@ public class HidHostService extends ProfileService { private void handleMessageOnVirtualUnplug(Message msg) { BluetoothDevice device = mAdapterService.getDeviceFromByte((byte[]) msg.obj); if (Flags.removeInputDeviceOnVup()) { updateConnectionState( device, getTransport(device), BluetoothProfile.STATE_DISCONNECTED); mInputDevices.remove(device); } else { int transport = msg.arg1; if (!checkTransport(device, transport, msg.what)) { return; } } int status = msg.arg2; broadcastVirtualUnplugStatus(device, status); } Loading android/app/src/com/android/bluetooth/le_scan/ScanFilterQueue.java +11 −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 = 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); } Loading Loading @@ -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; } } android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java +27 −13 Original line number Diff line number Diff line Loading @@ -396,6 +396,12 @@ public class AdapterServiceTest { } } private List<ProfileService> listOfMockServices() { return Flags.scanManagerRefactor() ? List.of(mMockGattService, mMockService, mMockService2) : List.of(mMockService, mMockService2); } static void offToBleOn( TestLooper looper, ProfileService gattService, Loading @@ -412,7 +418,6 @@ public class AdapterServiceTest { if (!Flags.scanManagerRefactor()) { TestUtils.syncHandler(looper, MESSAGE_PROFILE_SERVICE_REGISTERED); TestUtils.syncHandler(looper, MESSAGE_PROFILE_SERVICE_STATE_CHANGED); } Loading @@ -435,8 +440,8 @@ public class AdapterServiceTest { verifyStateChange(callback, STATE_ON, STATE_TURNING_OFF); if (!onlyGatt) { // Stop PBAP and PAN services assertThat(adapter.mSetProfileServiceStateCounter).isEqualTo(4); // Stop (if Flags.scanManagerRefactor GATT), PBAP, and PAN services assertThat(adapter.mSetProfileServiceStateCounter).isEqualTo(services.size() * 2); for (ProfileService service : services) { adapter.onProfileServiceStateChanged(service, STATE_OFF); Loading @@ -457,7 +462,7 @@ public class AdapterServiceTest { mAdapterService, mMockContext, onlyGatt, List.of(mMockService, mMockService2), listOfMockServices(), mNativeInterface); } Loading Loading @@ -486,8 +491,8 @@ public class AdapterServiceTest { verifyStateChange(callback, STATE_BLE_ON, STATE_TURNING_ON); if (!onlyGatt) { // Start Mock PBAP and PAN services assertThat(adapter.mSetProfileServiceStateCounter).isEqualTo(2); // Start Mock (if Flags.scanManagerRefactor GATT), PBAP, and PAN services assertThat(adapter.mSetProfileServiceStateCounter).isEqualTo(services.size()); for (ProfileService service : services) { adapter.addProfile(service); Loading @@ -514,7 +519,7 @@ public class AdapterServiceTest { mAdapterService, mMockContext, onlyGatt, List.of(mMockService, mMockService2), listOfMockServices(), mNativeInterface); } Loading @@ -539,8 +544,10 @@ public class AdapterServiceTest { TestUtils.syncHandler(looper, AdapterState.BLE_TURN_OFF); verifyStateChange(callback, STATE_BLE_ON, STATE_BLE_TURNING_OFF); if (!Flags.scanManagerRefactor()) { TestUtils.syncHandler(looper, MESSAGE_PROFILE_SERVICE_STATE_CHANGED); TestUtils.syncHandler(looper, MESSAGE_PROFILE_SERVICE_UNREGISTERED); } verify(nativeInterface).disable(); adapter.stateChangeCallback(AbstractionLayer.BT_STATE_OFF); Loading Loading @@ -589,6 +596,7 @@ public class AdapterServiceTest { * started and stopped. */ @Test @DisableFlags(Flags.FLAG_SCAN_MANAGER_REFACTOR) public void testEnableDisableOnlyGatt() { Context mockContext = mock(Context.class); Resources mockResources = mock(Resources.class); Loading @@ -611,6 +619,7 @@ public class AdapterServiceTest { /** Test: Don't start GATT Check whether the AdapterService quits gracefully */ @Test @DisableFlags(Flags.FLAG_SCAN_MANAGER_REFACTOR) public void testGattStartTimeout() { assertThat(mAdapterService.getState()).isEqualTo(STATE_OFF); Loading Loading @@ -646,6 +655,7 @@ public class AdapterServiceTest { /** Test: Don't stop GATT Check whether the AdapterService quits gracefully */ @Test @DisableFlags(Flags.FLAG_SCAN_MANAGER_REFACTOR) public void testGattStopTimeout() { doEnable(false); Loading @@ -655,7 +665,7 @@ public class AdapterServiceTest { mMockContext, mIBluetoothCallback, false, List.of(mMockService, mMockService2)); listOfMockServices()); mAdapterService.stopBle(); syncHandler(AdapterState.BLE_TURN_OFF); Loading Loading @@ -813,6 +823,7 @@ public class AdapterServiceTest { /** Test: Don't start a classic profile Check whether the AdapterService quits gracefully */ @Test @DisableFlags(Flags.FLAG_SCAN_MANAGER_REFACTOR) public void testProfileStartTimeout() { assertThat(mAdapterService.getState()).isEqualTo(STATE_OFF); Loading Loading @@ -855,6 +866,7 @@ public class AdapterServiceTest { /** Test: Don't stop a classic profile Check whether the AdapterService quits gracefully */ @Test @DisableFlags(Flags.FLAG_SCAN_MANAGER_REFACTOR) public void testProfileStopTimeout() { doEnable(false); Loading Loading @@ -911,14 +923,16 @@ public class AdapterServiceTest { mMockContext, mIBluetoothCallback, false, List.of(mMockService, mMockService2)); listOfMockServices()); // Do not call stopBle(). The Adapter should turn itself off. syncHandler(AdapterState.BLE_TURN_OFF); verifyStateChange(STATE_BLE_ON, STATE_BLE_TURNING_OFF, CONTEXT_SWITCH_MS); if (!Flags.scanManagerRefactor()) { syncHandler(MESSAGE_PROFILE_SERVICE_STATE_CHANGED); // stop GATT syncHandler(MESSAGE_PROFILE_SERVICE_UNREGISTERED); } verify(mNativeInterface).disable(); Loading android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanFilterQueueTest.java +104 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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() { Loading Loading @@ -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; } } flags/pairing.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -94,3 +94,13 @@ flag { purpose: PURPOSE_BUGFIX } } flag { name: "name_discovery_for_le_pairing" namespace: "bluetooth" description: "Perform LE name discovery for pairing if device name is not known" bug: "355095011" metadata { purpose: PURPOSE_BUGFIX } } Loading
android/app/src/com/android/bluetooth/hid/HidHostService.java +9 −3 Original line number Diff line number Diff line Loading @@ -519,10 +519,16 @@ public class HidHostService extends ProfileService { private void handleMessageOnVirtualUnplug(Message msg) { BluetoothDevice device = mAdapterService.getDeviceFromByte((byte[]) msg.obj); if (Flags.removeInputDeviceOnVup()) { updateConnectionState( device, getTransport(device), BluetoothProfile.STATE_DISCONNECTED); mInputDevices.remove(device); } else { int transport = msg.arg1; if (!checkTransport(device, transport, msg.what)) { return; } } int status = msg.arg2; broadcastVirtualUnplugStatus(device, status); } Loading
android/app/src/com/android/bluetooth/le_scan/ScanFilterQueue.java +11 −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 = 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); } Loading Loading @@ -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; } }
android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java +27 −13 Original line number Diff line number Diff line Loading @@ -396,6 +396,12 @@ public class AdapterServiceTest { } } private List<ProfileService> listOfMockServices() { return Flags.scanManagerRefactor() ? List.of(mMockGattService, mMockService, mMockService2) : List.of(mMockService, mMockService2); } static void offToBleOn( TestLooper looper, ProfileService gattService, Loading @@ -412,7 +418,6 @@ public class AdapterServiceTest { if (!Flags.scanManagerRefactor()) { TestUtils.syncHandler(looper, MESSAGE_PROFILE_SERVICE_REGISTERED); TestUtils.syncHandler(looper, MESSAGE_PROFILE_SERVICE_STATE_CHANGED); } Loading @@ -435,8 +440,8 @@ public class AdapterServiceTest { verifyStateChange(callback, STATE_ON, STATE_TURNING_OFF); if (!onlyGatt) { // Stop PBAP and PAN services assertThat(adapter.mSetProfileServiceStateCounter).isEqualTo(4); // Stop (if Flags.scanManagerRefactor GATT), PBAP, and PAN services assertThat(adapter.mSetProfileServiceStateCounter).isEqualTo(services.size() * 2); for (ProfileService service : services) { adapter.onProfileServiceStateChanged(service, STATE_OFF); Loading @@ -457,7 +462,7 @@ public class AdapterServiceTest { mAdapterService, mMockContext, onlyGatt, List.of(mMockService, mMockService2), listOfMockServices(), mNativeInterface); } Loading Loading @@ -486,8 +491,8 @@ public class AdapterServiceTest { verifyStateChange(callback, STATE_BLE_ON, STATE_TURNING_ON); if (!onlyGatt) { // Start Mock PBAP and PAN services assertThat(adapter.mSetProfileServiceStateCounter).isEqualTo(2); // Start Mock (if Flags.scanManagerRefactor GATT), PBAP, and PAN services assertThat(adapter.mSetProfileServiceStateCounter).isEqualTo(services.size()); for (ProfileService service : services) { adapter.addProfile(service); Loading @@ -514,7 +519,7 @@ public class AdapterServiceTest { mAdapterService, mMockContext, onlyGatt, List.of(mMockService, mMockService2), listOfMockServices(), mNativeInterface); } Loading @@ -539,8 +544,10 @@ public class AdapterServiceTest { TestUtils.syncHandler(looper, AdapterState.BLE_TURN_OFF); verifyStateChange(callback, STATE_BLE_ON, STATE_BLE_TURNING_OFF); if (!Flags.scanManagerRefactor()) { TestUtils.syncHandler(looper, MESSAGE_PROFILE_SERVICE_STATE_CHANGED); TestUtils.syncHandler(looper, MESSAGE_PROFILE_SERVICE_UNREGISTERED); } verify(nativeInterface).disable(); adapter.stateChangeCallback(AbstractionLayer.BT_STATE_OFF); Loading Loading @@ -589,6 +596,7 @@ public class AdapterServiceTest { * started and stopped. */ @Test @DisableFlags(Flags.FLAG_SCAN_MANAGER_REFACTOR) public void testEnableDisableOnlyGatt() { Context mockContext = mock(Context.class); Resources mockResources = mock(Resources.class); Loading @@ -611,6 +619,7 @@ public class AdapterServiceTest { /** Test: Don't start GATT Check whether the AdapterService quits gracefully */ @Test @DisableFlags(Flags.FLAG_SCAN_MANAGER_REFACTOR) public void testGattStartTimeout() { assertThat(mAdapterService.getState()).isEqualTo(STATE_OFF); Loading Loading @@ -646,6 +655,7 @@ public class AdapterServiceTest { /** Test: Don't stop GATT Check whether the AdapterService quits gracefully */ @Test @DisableFlags(Flags.FLAG_SCAN_MANAGER_REFACTOR) public void testGattStopTimeout() { doEnable(false); Loading @@ -655,7 +665,7 @@ public class AdapterServiceTest { mMockContext, mIBluetoothCallback, false, List.of(mMockService, mMockService2)); listOfMockServices()); mAdapterService.stopBle(); syncHandler(AdapterState.BLE_TURN_OFF); Loading Loading @@ -813,6 +823,7 @@ public class AdapterServiceTest { /** Test: Don't start a classic profile Check whether the AdapterService quits gracefully */ @Test @DisableFlags(Flags.FLAG_SCAN_MANAGER_REFACTOR) public void testProfileStartTimeout() { assertThat(mAdapterService.getState()).isEqualTo(STATE_OFF); Loading Loading @@ -855,6 +866,7 @@ public class AdapterServiceTest { /** Test: Don't stop a classic profile Check whether the AdapterService quits gracefully */ @Test @DisableFlags(Flags.FLAG_SCAN_MANAGER_REFACTOR) public void testProfileStopTimeout() { doEnable(false); Loading Loading @@ -911,14 +923,16 @@ public class AdapterServiceTest { mMockContext, mIBluetoothCallback, false, List.of(mMockService, mMockService2)); listOfMockServices()); // Do not call stopBle(). The Adapter should turn itself off. syncHandler(AdapterState.BLE_TURN_OFF); verifyStateChange(STATE_BLE_ON, STATE_BLE_TURNING_OFF, CONTEXT_SWITCH_MS); if (!Flags.scanManagerRefactor()) { syncHandler(MESSAGE_PROFILE_SERVICE_STATE_CHANGED); // stop GATT syncHandler(MESSAGE_PROFILE_SERVICE_UNREGISTERED); } verify(mNativeInterface).disable(); Loading
android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanFilterQueueTest.java +104 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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() { Loading Loading @@ -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; } }
flags/pairing.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -94,3 +94,13 @@ flag { purpose: PURPOSE_BUGFIX } } flag { name: "name_discovery_for_le_pairing" namespace: "bluetooth" description: "Perform LE name discovery for pairing if device name is not known" bug: "355095011" metadata { purpose: PURPOSE_BUGFIX } }