Loading api/current.txt +5 −0 Original line number Diff line number Diff line Loading @@ -8689,6 +8689,8 @@ package android.bluetooth.le { method public byte[] getServiceData(); method public byte[] getServiceDataMask(); method public android.os.ParcelUuid getServiceDataUuid(); method public android.os.ParcelUuid getServiceSolicitationUuid(); method public android.os.ParcelUuid getServiceSolicitationUuidMask(); method public android.os.ParcelUuid getServiceUuid(); method public android.os.ParcelUuid getServiceUuidMask(); method public boolean matches(android.bluetooth.le.ScanResult); Loading @@ -8705,6 +8707,8 @@ package android.bluetooth.le { method public android.bluetooth.le.ScanFilter.Builder setManufacturerData(int, byte[], byte[]); method public android.bluetooth.le.ScanFilter.Builder setServiceData(android.os.ParcelUuid, byte[]); method public android.bluetooth.le.ScanFilter.Builder setServiceData(android.os.ParcelUuid, byte[], byte[]); method public android.bluetooth.le.ScanFilter.Builder setServiceSolicitationUuid(android.os.ParcelUuid); method public android.bluetooth.le.ScanFilter.Builder setServiceSolicitationUuid(android.os.ParcelUuid, android.os.ParcelUuid); method public android.bluetooth.le.ScanFilter.Builder setServiceUuid(android.os.ParcelUuid); method public android.bluetooth.le.ScanFilter.Builder setServiceUuid(android.os.ParcelUuid, android.os.ParcelUuid); } Loading @@ -8717,6 +8721,7 @@ package android.bluetooth.le { method public byte[] getManufacturerSpecificData(int); method public java.util.Map<android.os.ParcelUuid, byte[]> getServiceData(); method public byte[] getServiceData(android.os.ParcelUuid); method public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids(); method public java.util.List<android.os.ParcelUuid> getServiceUuids(); method public int getTxPowerLevel(); } core/java/android/bluetooth/le/ScanFilter.java +125 −5 Original line number Diff line number Diff line Loading @@ -57,6 +57,11 @@ public final class ScanFilter implements Parcelable { @Nullable private final ParcelUuid mServiceUuidMask; @Nullable private final ParcelUuid mServiceSolicitationUuid; @Nullable private final ParcelUuid mServiceSolicitationUuidMask; @Nullable private final ParcelUuid mServiceDataUuid; @Nullable Loading @@ -75,12 +80,15 @@ public final class ScanFilter implements Parcelable { private ScanFilter(String name, String deviceAddress, ParcelUuid uuid, ParcelUuid uuidMask, ParcelUuid serviceDataUuid, ParcelUuid uuidMask, ParcelUuid solicitationUuid, ParcelUuid solicitationUuidMask, ParcelUuid serviceDataUuid, byte[] serviceData, byte[] serviceDataMask, int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask) { mDeviceName = name; mServiceUuid = uuid; mServiceUuidMask = uuidMask; mServiceSolicitationUuid = solicitationUuid; mServiceSolicitationUuidMask = solicitationUuidMask; mDeviceAddress = deviceAddress; mServiceDataUuid = serviceDataUuid; mServiceData = serviceData; Loading Loading @@ -113,6 +121,14 @@ public final class ScanFilter implements Parcelable { dest.writeParcelable(mServiceUuidMask, flags); } } dest.writeInt(mServiceSolicitationUuid == null ? 0 : 1); if (mServiceSolicitationUuid != null) { dest.writeParcelable(mServiceSolicitationUuid, flags); dest.writeInt(mServiceSolicitationUuidMask == null ? 0 : 1); if (mServiceSolicitationUuidMask != null) { dest.writeParcelable(mServiceSolicitationUuidMask, flags); } } dest.writeInt(mServiceDataUuid == null ? 0 : 1); if (mServiceDataUuid != null) { dest.writeParcelable(mServiceDataUuid, flags); Loading Loading @@ -171,6 +187,17 @@ public final class ScanFilter implements Parcelable { builder.setServiceUuid(uuid, uuidMask); } } if (in.readInt() == 1) { ParcelUuid solicitationUuid = in.readParcelable( ParcelUuid.class.getClassLoader()); builder.setServiceSolicitationUuid(solicitationUuid); if (in.readInt() == 1) { ParcelUuid solicitationUuidMask = in.readParcelable( ParcelUuid.class.getClassLoader()); builder.setServiceSolicitationUuid(solicitationUuid, solicitationUuidMask); } } if (in.readInt() == 1) { ParcelUuid servcieDataUuid = in.readParcelable(ParcelUuid.class.getClassLoader()); Loading Loading @@ -231,6 +258,22 @@ public final class ScanFilter implements Parcelable { return mServiceUuidMask; } /** * Returns the filter set on the service Solicitation uuid. */ @Nullable public ParcelUuid getServiceSolicitationUuid() { return mServiceSolicitationUuid; } /** * Returns the filter set on the service Solicitation uuid mask. */ @Nullable public ParcelUuid getServiceSolicitationUuidMask() { return mServiceSolicitationUuidMask; } @Nullable public String getDeviceAddress() { return mDeviceAddress; Loading Loading @@ -288,7 +331,7 @@ public final class ScanFilter implements Parcelable { // Scan record is null but there exist filters on it. if (scanRecord == null && (mDeviceName != null || mServiceUuid != null || mManufacturerData != null || mServiceData != null)) { || mServiceData != null || mServiceSolicitationUuid != null)) { return false; } Loading @@ -303,6 +346,13 @@ public final class ScanFilter implements Parcelable { return false; } // solicitation UUID match. if (mServiceSolicitationUuid != null && !matchesServiceSolicitationUuids( mServiceSolicitationUuid, mServiceSolicitationUuidMask, scanRecord.getServiceSolicitationUuids())) { return false; } // Service data match if (mServiceDataUuid != null) { if (!matchesPartialData(mServiceData, mServiceDataMask, Loading Loading @@ -350,6 +400,36 @@ public final class ScanFilter implements Parcelable { return BitUtils.maskedEquals(data, uuid, mask); } /** * Check if the solicitation uuid pattern is contained in a list of parcel uuids. * */ private static boolean matchesServiceSolicitationUuids(ParcelUuid solicitationUuid, ParcelUuid parcelSolicitationUuidMask, List<ParcelUuid> solicitationUuids) { if (solicitationUuid == null) { return true; } if (solicitationUuids == null) { return false; } for (ParcelUuid parcelSolicitationUuid : solicitationUuids) { UUID solicitationUuidMask = parcelSolicitationUuidMask == null ? null : parcelSolicitationUuidMask.getUuid(); if (matchesServiceUuid(solicitationUuid.getUuid(), solicitationUuidMask, parcelSolicitationUuid.getUuid())) { return true; } } return false; } // Check if the solicitation uuid pattern matches the particular service solicitation uuid. private static boolean matchesServiceSolicitationUuid(UUID solicitationUuid, UUID solicitationUuidMask, UUID data) { return BitUtils.maskedEquals(data, solicitationUuid, solicitationUuidMask); } // Check whether the data pattern matches the parsed data. private boolean matchesPartialData(byte[] data, byte[] dataMask, byte[] parsedData) { if (parsedData == null || parsedData.length < data.length) { Loading @@ -376,6 +456,8 @@ public final class ScanFilter implements Parcelable { return "BluetoothLeScanFilter [mDeviceName=" + mDeviceName + ", mDeviceAddress=" + mDeviceAddress + ", mUuid=" + mServiceUuid + ", mUuidMask=" + mServiceUuidMask + ", mServiceSolicitationUuid=" + mServiceSolicitationUuid + ", mServiceSolicitationUuidMask=" + mServiceSolicitationUuidMask + ", mServiceDataUuid=" + Objects.toString(mServiceDataUuid) + ", mServiceData=" + Arrays.toString(mServiceData) + ", mServiceDataMask=" + Arrays.toString(mServiceDataMask) + ", mManufacturerId=" + mManufacturerId Loading @@ -391,7 +473,8 @@ public final class ScanFilter implements Parcelable { mServiceDataUuid, Arrays.hashCode(mServiceData), Arrays.hashCode(mServiceDataMask), mServiceUuid, mServiceUuidMask); mServiceUuid, mServiceUuidMask, mServiceSolicitationUuid, mServiceSolicitationUuidMask); } @Override Loading @@ -412,7 +495,10 @@ public final class ScanFilter implements Parcelable { && Objects.deepEquals(mServiceData, other.mServiceData) && Objects.deepEquals(mServiceDataMask, other.mServiceDataMask) && Objects.equals(mServiceUuid, other.mServiceUuid) && Objects.equals(mServiceUuidMask, other.mServiceUuidMask); && Objects.equals(mServiceUuidMask, other.mServiceUuidMask) && Objects.equals(mServiceSolicitationUuid, other.mServiceSolicitationUuid) && Objects.equals(mServiceSolicitationUuidMask, other.mServiceSolicitationUuidMask); } /** Loading @@ -435,6 +521,9 @@ public final class ScanFilter implements Parcelable { private ParcelUuid mServiceUuid; private ParcelUuid mUuidMask; private ParcelUuid mServiceSolicitationUuid; private ParcelUuid mServiceSolicitationUuidMask; private ParcelUuid mServiceDataUuid; private byte[] mServiceData; private byte[] mServiceDataMask; Loading Loading @@ -493,6 +582,36 @@ public final class ScanFilter implements Parcelable { return this; } /** * Set filter on service solicitation uuid. */ public Builder setServiceSolicitationUuid(ParcelUuid serviceSolicitationUuid) { mServiceSolicitationUuid = serviceSolicitationUuid; return this; } /** * Set filter on partial service Solicitation uuid. The {@code SolicitationUuidMask} is the * bit mask for the {@code serviceSolicitationUuid}. Set any bit in the mask to 1 to * indicate a match is needed for the bit in {@code serviceSolicitationUuid}, and 0 to * ignore that bit. * * @throws IllegalArgumentException If {@code serviceSolicitationUuid} is {@code null} but * {@code serviceSolicitationUuidMask} is not {@code null}. */ public Builder setServiceSolicitationUuid(ParcelUuid serviceSolicitationUuid, ParcelUuid solicitationUuidMask) { if (mServiceSolicitationUuidMask != null && mServiceSolicitationUuid == null) { throw new IllegalArgumentException( "SolicitationUuid is null while SolicitationUuidMask is not null!"); } mServiceSolicitationUuid = serviceSolicitationUuid; mServiceSolicitationUuidMask = solicitationUuidMask; return this; } /** * Set filtering on service data. * Loading Loading @@ -598,7 +717,8 @@ public final class ScanFilter implements Parcelable { */ public ScanFilter build() { return new ScanFilter(mDeviceName, mDeviceAddress, mServiceUuid, mUuidMask, mServiceUuid, mUuidMask, mServiceSolicitationUuid, mServiceSolicitationUuidMask, mServiceDataUuid, mServiceData, mServiceDataMask, mManufacturerId, mManufacturerData, mManufacturerDataMask); } Loading core/java/android/bluetooth/le/ScanRecord.java +50 −3 Original line number Diff line number Diff line Loading @@ -51,6 +51,9 @@ public final class ScanRecord { private static final int DATA_TYPE_SERVICE_DATA_16_BIT = 0x16; private static final int DATA_TYPE_SERVICE_DATA_32_BIT = 0x20; private static final int DATA_TYPE_SERVICE_DATA_128_BIT = 0x21; private static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_16_BIT = 0x14; private static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_32_BIT = 0x1F; private static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT = 0x15; private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF; // Flags of the advertising data. Loading @@ -58,6 +61,8 @@ public final class ScanRecord { @Nullable private final List<ParcelUuid> mServiceUuids; @Nullable private final List<ParcelUuid> mServiceSolicitationUuids; private final SparseArray<byte[]> mManufacturerSpecificData; Loading Loading @@ -88,6 +93,15 @@ public final class ScanRecord { return mServiceUuids; } /** * Returns a list of service solicitation UUIDs within the advertisement that are used to * identify the Bluetooth GATT services. */ @Nullable public List<ParcelUuid> getServiceSolicitationUuids() { return mServiceSolicitationUuids; } /** * Returns a sparse array of manufacturer identifier and its corresponding manufacturer specific * data. Loading Loading @@ -151,10 +165,12 @@ public final class ScanRecord { } private ScanRecord(List<ParcelUuid> serviceUuids, List<ParcelUuid> serviceSolicitationUuids, SparseArray<byte[]> manufacturerData, Map<ParcelUuid, byte[]> serviceData, int advertiseFlags, int txPowerLevel, String localName, byte[] bytes) { mServiceSolicitationUuids = serviceSolicitationUuids; mServiceUuids = serviceUuids; mManufacturerSpecificData = manufacturerData; mServiceData = serviceData; Loading Loading @@ -184,6 +200,7 @@ public final class ScanRecord { int currentPos = 0; int advertiseFlag = -1; List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>(); List<ParcelUuid> serviceSolicitationUuids = new ArrayList<ParcelUuid>(); String localName = null; int txPowerLevel = Integer.MIN_VALUE; Loading Loading @@ -220,6 +237,18 @@ public final class ScanRecord { parseServiceUuid(scanRecord, currentPos, dataLength, BluetoothUuid.UUID_BYTES_128_BIT, serviceUuids); break; case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_16_BIT: parseServiceSolicitationUuid(scanRecord, currentPos, dataLength, BluetoothUuid.UUID_BYTES_16_BIT, serviceSolicitationUuids); break; case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_32_BIT: parseServiceSolicitationUuid(scanRecord, currentPos, dataLength, BluetoothUuid.UUID_BYTES_32_BIT, serviceSolicitationUuids); break; case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT: parseServiceSolicitationUuid(scanRecord, currentPos, dataLength, BluetoothUuid.UUID_BYTES_128_BIT, serviceSolicitationUuids); break; case DATA_TYPE_LOCAL_NAME_SHORT: case DATA_TYPE_LOCAL_NAME_COMPLETE: localName = new String( Loading Loading @@ -265,19 +294,23 @@ public final class ScanRecord { if (serviceUuids.isEmpty()) { serviceUuids = null; } return new ScanRecord(serviceUuids, manufacturerData, serviceData, advertiseFlag, txPowerLevel, localName, scanRecord); if (serviceSolicitationUuids.isEmpty()) { serviceSolicitationUuids = null; } return new ScanRecord(serviceUuids, serviceSolicitationUuids, manufacturerData, serviceData, advertiseFlag, txPowerLevel, localName, scanRecord); } catch (Exception e) { Log.e(TAG, "unable to parse scan record: " + Arrays.toString(scanRecord)); // As the record is invalid, ignore all the parsed results for this packet // and return an empty record with raw scanRecord bytes in results return new ScanRecord(null, null, null, -1, Integer.MIN_VALUE, null, scanRecord); return new ScanRecord(null, null, null, null, -1, Integer.MIN_VALUE, null, scanRecord); } } @Override public String toString() { return "ScanRecord [mAdvertiseFlags=" + mAdvertiseFlags + ", mServiceUuids=" + mServiceUuids + ", mServiceSolicitationUuids=" + mServiceSolicitationUuids + ", mManufacturerSpecificData=" + BluetoothLeUtils.toString( mManufacturerSpecificData) + ", mServiceData=" + BluetoothLeUtils.toString(mServiceData) Loading @@ -297,6 +330,20 @@ public final class ScanRecord { return currentPos; } /** * Parse service Solicitation UUIDs. */ private static int parseServiceSolicitationUuid(byte[] scanRecord, int currentPos, int dataLength, int uuidLength, List<ParcelUuid> serviceSolicitationUuids) { while (dataLength > 0) { byte[] uuidBytes = extractBytes(scanRecord, currentPos, uuidLength); serviceSolicitationUuids.add(BluetoothUuid.parseUuidFrom(uuidBytes)); dataLength -= uuidLength; currentPos += uuidLength; } return currentPos; } // Helper method to extract bytes from byte array. private static byte[] extractBytes(byte[] scanRecord, int start, int length) { byte[] bytes = new byte[length]; Loading Loading
api/current.txt +5 −0 Original line number Diff line number Diff line Loading @@ -8689,6 +8689,8 @@ package android.bluetooth.le { method public byte[] getServiceData(); method public byte[] getServiceDataMask(); method public android.os.ParcelUuid getServiceDataUuid(); method public android.os.ParcelUuid getServiceSolicitationUuid(); method public android.os.ParcelUuid getServiceSolicitationUuidMask(); method public android.os.ParcelUuid getServiceUuid(); method public android.os.ParcelUuid getServiceUuidMask(); method public boolean matches(android.bluetooth.le.ScanResult); Loading @@ -8705,6 +8707,8 @@ package android.bluetooth.le { method public android.bluetooth.le.ScanFilter.Builder setManufacturerData(int, byte[], byte[]); method public android.bluetooth.le.ScanFilter.Builder setServiceData(android.os.ParcelUuid, byte[]); method public android.bluetooth.le.ScanFilter.Builder setServiceData(android.os.ParcelUuid, byte[], byte[]); method public android.bluetooth.le.ScanFilter.Builder setServiceSolicitationUuid(android.os.ParcelUuid); method public android.bluetooth.le.ScanFilter.Builder setServiceSolicitationUuid(android.os.ParcelUuid, android.os.ParcelUuid); method public android.bluetooth.le.ScanFilter.Builder setServiceUuid(android.os.ParcelUuid); method public android.bluetooth.le.ScanFilter.Builder setServiceUuid(android.os.ParcelUuid, android.os.ParcelUuid); } Loading @@ -8717,6 +8721,7 @@ package android.bluetooth.le { method public byte[] getManufacturerSpecificData(int); method public java.util.Map<android.os.ParcelUuid, byte[]> getServiceData(); method public byte[] getServiceData(android.os.ParcelUuid); method public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids(); method public java.util.List<android.os.ParcelUuid> getServiceUuids(); method public int getTxPowerLevel(); }
core/java/android/bluetooth/le/ScanFilter.java +125 −5 Original line number Diff line number Diff line Loading @@ -57,6 +57,11 @@ public final class ScanFilter implements Parcelable { @Nullable private final ParcelUuid mServiceUuidMask; @Nullable private final ParcelUuid mServiceSolicitationUuid; @Nullable private final ParcelUuid mServiceSolicitationUuidMask; @Nullable private final ParcelUuid mServiceDataUuid; @Nullable Loading @@ -75,12 +80,15 @@ public final class ScanFilter implements Parcelable { private ScanFilter(String name, String deviceAddress, ParcelUuid uuid, ParcelUuid uuidMask, ParcelUuid serviceDataUuid, ParcelUuid uuidMask, ParcelUuid solicitationUuid, ParcelUuid solicitationUuidMask, ParcelUuid serviceDataUuid, byte[] serviceData, byte[] serviceDataMask, int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask) { mDeviceName = name; mServiceUuid = uuid; mServiceUuidMask = uuidMask; mServiceSolicitationUuid = solicitationUuid; mServiceSolicitationUuidMask = solicitationUuidMask; mDeviceAddress = deviceAddress; mServiceDataUuid = serviceDataUuid; mServiceData = serviceData; Loading Loading @@ -113,6 +121,14 @@ public final class ScanFilter implements Parcelable { dest.writeParcelable(mServiceUuidMask, flags); } } dest.writeInt(mServiceSolicitationUuid == null ? 0 : 1); if (mServiceSolicitationUuid != null) { dest.writeParcelable(mServiceSolicitationUuid, flags); dest.writeInt(mServiceSolicitationUuidMask == null ? 0 : 1); if (mServiceSolicitationUuidMask != null) { dest.writeParcelable(mServiceSolicitationUuidMask, flags); } } dest.writeInt(mServiceDataUuid == null ? 0 : 1); if (mServiceDataUuid != null) { dest.writeParcelable(mServiceDataUuid, flags); Loading Loading @@ -171,6 +187,17 @@ public final class ScanFilter implements Parcelable { builder.setServiceUuid(uuid, uuidMask); } } if (in.readInt() == 1) { ParcelUuid solicitationUuid = in.readParcelable( ParcelUuid.class.getClassLoader()); builder.setServiceSolicitationUuid(solicitationUuid); if (in.readInt() == 1) { ParcelUuid solicitationUuidMask = in.readParcelable( ParcelUuid.class.getClassLoader()); builder.setServiceSolicitationUuid(solicitationUuid, solicitationUuidMask); } } if (in.readInt() == 1) { ParcelUuid servcieDataUuid = in.readParcelable(ParcelUuid.class.getClassLoader()); Loading Loading @@ -231,6 +258,22 @@ public final class ScanFilter implements Parcelable { return mServiceUuidMask; } /** * Returns the filter set on the service Solicitation uuid. */ @Nullable public ParcelUuid getServiceSolicitationUuid() { return mServiceSolicitationUuid; } /** * Returns the filter set on the service Solicitation uuid mask. */ @Nullable public ParcelUuid getServiceSolicitationUuidMask() { return mServiceSolicitationUuidMask; } @Nullable public String getDeviceAddress() { return mDeviceAddress; Loading Loading @@ -288,7 +331,7 @@ public final class ScanFilter implements Parcelable { // Scan record is null but there exist filters on it. if (scanRecord == null && (mDeviceName != null || mServiceUuid != null || mManufacturerData != null || mServiceData != null)) { || mServiceData != null || mServiceSolicitationUuid != null)) { return false; } Loading @@ -303,6 +346,13 @@ public final class ScanFilter implements Parcelable { return false; } // solicitation UUID match. if (mServiceSolicitationUuid != null && !matchesServiceSolicitationUuids( mServiceSolicitationUuid, mServiceSolicitationUuidMask, scanRecord.getServiceSolicitationUuids())) { return false; } // Service data match if (mServiceDataUuid != null) { if (!matchesPartialData(mServiceData, mServiceDataMask, Loading Loading @@ -350,6 +400,36 @@ public final class ScanFilter implements Parcelable { return BitUtils.maskedEquals(data, uuid, mask); } /** * Check if the solicitation uuid pattern is contained in a list of parcel uuids. * */ private static boolean matchesServiceSolicitationUuids(ParcelUuid solicitationUuid, ParcelUuid parcelSolicitationUuidMask, List<ParcelUuid> solicitationUuids) { if (solicitationUuid == null) { return true; } if (solicitationUuids == null) { return false; } for (ParcelUuid parcelSolicitationUuid : solicitationUuids) { UUID solicitationUuidMask = parcelSolicitationUuidMask == null ? null : parcelSolicitationUuidMask.getUuid(); if (matchesServiceUuid(solicitationUuid.getUuid(), solicitationUuidMask, parcelSolicitationUuid.getUuid())) { return true; } } return false; } // Check if the solicitation uuid pattern matches the particular service solicitation uuid. private static boolean matchesServiceSolicitationUuid(UUID solicitationUuid, UUID solicitationUuidMask, UUID data) { return BitUtils.maskedEquals(data, solicitationUuid, solicitationUuidMask); } // Check whether the data pattern matches the parsed data. private boolean matchesPartialData(byte[] data, byte[] dataMask, byte[] parsedData) { if (parsedData == null || parsedData.length < data.length) { Loading @@ -376,6 +456,8 @@ public final class ScanFilter implements Parcelable { return "BluetoothLeScanFilter [mDeviceName=" + mDeviceName + ", mDeviceAddress=" + mDeviceAddress + ", mUuid=" + mServiceUuid + ", mUuidMask=" + mServiceUuidMask + ", mServiceSolicitationUuid=" + mServiceSolicitationUuid + ", mServiceSolicitationUuidMask=" + mServiceSolicitationUuidMask + ", mServiceDataUuid=" + Objects.toString(mServiceDataUuid) + ", mServiceData=" + Arrays.toString(mServiceData) + ", mServiceDataMask=" + Arrays.toString(mServiceDataMask) + ", mManufacturerId=" + mManufacturerId Loading @@ -391,7 +473,8 @@ public final class ScanFilter implements Parcelable { mServiceDataUuid, Arrays.hashCode(mServiceData), Arrays.hashCode(mServiceDataMask), mServiceUuid, mServiceUuidMask); mServiceUuid, mServiceUuidMask, mServiceSolicitationUuid, mServiceSolicitationUuidMask); } @Override Loading @@ -412,7 +495,10 @@ public final class ScanFilter implements Parcelable { && Objects.deepEquals(mServiceData, other.mServiceData) && Objects.deepEquals(mServiceDataMask, other.mServiceDataMask) && Objects.equals(mServiceUuid, other.mServiceUuid) && Objects.equals(mServiceUuidMask, other.mServiceUuidMask); && Objects.equals(mServiceUuidMask, other.mServiceUuidMask) && Objects.equals(mServiceSolicitationUuid, other.mServiceSolicitationUuid) && Objects.equals(mServiceSolicitationUuidMask, other.mServiceSolicitationUuidMask); } /** Loading @@ -435,6 +521,9 @@ public final class ScanFilter implements Parcelable { private ParcelUuid mServiceUuid; private ParcelUuid mUuidMask; private ParcelUuid mServiceSolicitationUuid; private ParcelUuid mServiceSolicitationUuidMask; private ParcelUuid mServiceDataUuid; private byte[] mServiceData; private byte[] mServiceDataMask; Loading Loading @@ -493,6 +582,36 @@ public final class ScanFilter implements Parcelable { return this; } /** * Set filter on service solicitation uuid. */ public Builder setServiceSolicitationUuid(ParcelUuid serviceSolicitationUuid) { mServiceSolicitationUuid = serviceSolicitationUuid; return this; } /** * Set filter on partial service Solicitation uuid. The {@code SolicitationUuidMask} is the * bit mask for the {@code serviceSolicitationUuid}. Set any bit in the mask to 1 to * indicate a match is needed for the bit in {@code serviceSolicitationUuid}, and 0 to * ignore that bit. * * @throws IllegalArgumentException If {@code serviceSolicitationUuid} is {@code null} but * {@code serviceSolicitationUuidMask} is not {@code null}. */ public Builder setServiceSolicitationUuid(ParcelUuid serviceSolicitationUuid, ParcelUuid solicitationUuidMask) { if (mServiceSolicitationUuidMask != null && mServiceSolicitationUuid == null) { throw new IllegalArgumentException( "SolicitationUuid is null while SolicitationUuidMask is not null!"); } mServiceSolicitationUuid = serviceSolicitationUuid; mServiceSolicitationUuidMask = solicitationUuidMask; return this; } /** * Set filtering on service data. * Loading Loading @@ -598,7 +717,8 @@ public final class ScanFilter implements Parcelable { */ public ScanFilter build() { return new ScanFilter(mDeviceName, mDeviceAddress, mServiceUuid, mUuidMask, mServiceUuid, mUuidMask, mServiceSolicitationUuid, mServiceSolicitationUuidMask, mServiceDataUuid, mServiceData, mServiceDataMask, mManufacturerId, mManufacturerData, mManufacturerDataMask); } Loading
core/java/android/bluetooth/le/ScanRecord.java +50 −3 Original line number Diff line number Diff line Loading @@ -51,6 +51,9 @@ public final class ScanRecord { private static final int DATA_TYPE_SERVICE_DATA_16_BIT = 0x16; private static final int DATA_TYPE_SERVICE_DATA_32_BIT = 0x20; private static final int DATA_TYPE_SERVICE_DATA_128_BIT = 0x21; private static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_16_BIT = 0x14; private static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_32_BIT = 0x1F; private static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT = 0x15; private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF; // Flags of the advertising data. Loading @@ -58,6 +61,8 @@ public final class ScanRecord { @Nullable private final List<ParcelUuid> mServiceUuids; @Nullable private final List<ParcelUuid> mServiceSolicitationUuids; private final SparseArray<byte[]> mManufacturerSpecificData; Loading Loading @@ -88,6 +93,15 @@ public final class ScanRecord { return mServiceUuids; } /** * Returns a list of service solicitation UUIDs within the advertisement that are used to * identify the Bluetooth GATT services. */ @Nullable public List<ParcelUuid> getServiceSolicitationUuids() { return mServiceSolicitationUuids; } /** * Returns a sparse array of manufacturer identifier and its corresponding manufacturer specific * data. Loading Loading @@ -151,10 +165,12 @@ public final class ScanRecord { } private ScanRecord(List<ParcelUuid> serviceUuids, List<ParcelUuid> serviceSolicitationUuids, SparseArray<byte[]> manufacturerData, Map<ParcelUuid, byte[]> serviceData, int advertiseFlags, int txPowerLevel, String localName, byte[] bytes) { mServiceSolicitationUuids = serviceSolicitationUuids; mServiceUuids = serviceUuids; mManufacturerSpecificData = manufacturerData; mServiceData = serviceData; Loading Loading @@ -184,6 +200,7 @@ public final class ScanRecord { int currentPos = 0; int advertiseFlag = -1; List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>(); List<ParcelUuid> serviceSolicitationUuids = new ArrayList<ParcelUuid>(); String localName = null; int txPowerLevel = Integer.MIN_VALUE; Loading Loading @@ -220,6 +237,18 @@ public final class ScanRecord { parseServiceUuid(scanRecord, currentPos, dataLength, BluetoothUuid.UUID_BYTES_128_BIT, serviceUuids); break; case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_16_BIT: parseServiceSolicitationUuid(scanRecord, currentPos, dataLength, BluetoothUuid.UUID_BYTES_16_BIT, serviceSolicitationUuids); break; case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_32_BIT: parseServiceSolicitationUuid(scanRecord, currentPos, dataLength, BluetoothUuid.UUID_BYTES_32_BIT, serviceSolicitationUuids); break; case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT: parseServiceSolicitationUuid(scanRecord, currentPos, dataLength, BluetoothUuid.UUID_BYTES_128_BIT, serviceSolicitationUuids); break; case DATA_TYPE_LOCAL_NAME_SHORT: case DATA_TYPE_LOCAL_NAME_COMPLETE: localName = new String( Loading Loading @@ -265,19 +294,23 @@ public final class ScanRecord { if (serviceUuids.isEmpty()) { serviceUuids = null; } return new ScanRecord(serviceUuids, manufacturerData, serviceData, advertiseFlag, txPowerLevel, localName, scanRecord); if (serviceSolicitationUuids.isEmpty()) { serviceSolicitationUuids = null; } return new ScanRecord(serviceUuids, serviceSolicitationUuids, manufacturerData, serviceData, advertiseFlag, txPowerLevel, localName, scanRecord); } catch (Exception e) { Log.e(TAG, "unable to parse scan record: " + Arrays.toString(scanRecord)); // As the record is invalid, ignore all the parsed results for this packet // and return an empty record with raw scanRecord bytes in results return new ScanRecord(null, null, null, -1, Integer.MIN_VALUE, null, scanRecord); return new ScanRecord(null, null, null, null, -1, Integer.MIN_VALUE, null, scanRecord); } } @Override public String toString() { return "ScanRecord [mAdvertiseFlags=" + mAdvertiseFlags + ", mServiceUuids=" + mServiceUuids + ", mServiceSolicitationUuids=" + mServiceSolicitationUuids + ", mManufacturerSpecificData=" + BluetoothLeUtils.toString( mManufacturerSpecificData) + ", mServiceData=" + BluetoothLeUtils.toString(mServiceData) Loading @@ -297,6 +330,20 @@ public final class ScanRecord { return currentPos; } /** * Parse service Solicitation UUIDs. */ private static int parseServiceSolicitationUuid(byte[] scanRecord, int currentPos, int dataLength, int uuidLength, List<ParcelUuid> serviceSolicitationUuids) { while (dataLength > 0) { byte[] uuidBytes = extractBytes(scanRecord, currentPos, uuidLength); serviceSolicitationUuids.add(BluetoothUuid.parseUuidFrom(uuidBytes)); dataLength -= uuidLength; currentPos += uuidLength; } return currentPos; } // Helper method to extract bytes from byte array. private static byte[] extractBytes(byte[] scanRecord, int start, int length) { byte[] bytes = new byte[length]; Loading