Revert "Revert "Service data and manufacturer data can be repeated fields.""
This reverts commit 14c797702543bb5ced989565d90abcfa55c7db46.
This commit is contained in:
@@ -6582,22 +6582,20 @@ package android.bluetooth.le {
|
||||
method public int describeContents();
|
||||
method public boolean getIncludeDeviceName();
|
||||
method public boolean getIncludeTxPowerLevel();
|
||||
method public int getManufacturerId();
|
||||
method public byte[] getManufacturerSpecificData();
|
||||
method public byte[] getServiceData();
|
||||
method public android.os.ParcelUuid getServiceDataUuid();
|
||||
method public android.util.SparseArray<byte[]> getManufacturerSpecificData();
|
||||
method public java.util.Map<android.os.ParcelUuid, byte[]> getServiceData();
|
||||
method public java.util.List<android.os.ParcelUuid> getServiceUuids();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
}
|
||||
|
||||
public static final class AdvertiseData.Builder {
|
||||
ctor public AdvertiseData.Builder();
|
||||
method public android.bluetooth.le.AdvertiseData.Builder addManufacturerData(int, byte[]);
|
||||
method public android.bluetooth.le.AdvertiseData.Builder addServiceData(android.os.ParcelUuid, byte[]);
|
||||
method public android.bluetooth.le.AdvertiseData.Builder addServiceUuid(android.os.ParcelUuid);
|
||||
method public android.bluetooth.le.AdvertiseData build();
|
||||
method public android.bluetooth.le.AdvertiseData.Builder setIncludeDeviceName(boolean);
|
||||
method public android.bluetooth.le.AdvertiseData.Builder setIncludeTxPowerLevel(boolean);
|
||||
method public android.bluetooth.le.AdvertiseData.Builder setManufacturerData(int, byte[]);
|
||||
method public android.bluetooth.le.AdvertiseData.Builder setServiceData(android.os.ParcelUuid, byte[]);
|
||||
}
|
||||
|
||||
public final class AdvertiseSettings implements android.os.Parcelable {
|
||||
@@ -6658,6 +6656,7 @@ package android.bluetooth.le {
|
||||
method public int getManufacturerId();
|
||||
method public byte[] getServiceData();
|
||||
method public byte[] getServiceDataMask();
|
||||
method public android.os.ParcelUuid getServiceDataUuid();
|
||||
method public android.os.ParcelUuid getServiceUuid();
|
||||
method public android.os.ParcelUuid getServiceUuidMask();
|
||||
method public boolean matches(android.bluetooth.le.ScanResult);
|
||||
@@ -6681,10 +6680,10 @@ package android.bluetooth.le {
|
||||
method public int getAdvertiseFlags();
|
||||
method public byte[] getBytes();
|
||||
method public java.lang.String getDeviceName();
|
||||
method public int getManufacturerId();
|
||||
method public byte[] getManufacturerSpecificData();
|
||||
method public byte[] getServiceData();
|
||||
method public android.os.ParcelUuid getServiceDataUuid();
|
||||
method public android.util.SparseArray<byte[]> getManufacturerSpecificData();
|
||||
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> getServiceUuids();
|
||||
method public int getTxPowerLevel();
|
||||
}
|
||||
|
||||
@@ -17,14 +17,15 @@
|
||||
package android.bluetooth.le;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.bluetooth.BluetoothUuid;
|
||||
import android.os.Parcel;
|
||||
import android.os.ParcelUuid;
|
||||
import android.os.Parcelable;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -42,27 +43,18 @@ public final class AdvertiseData implements Parcelable {
|
||||
@Nullable
|
||||
private final List<ParcelUuid> mServiceUuids;
|
||||
|
||||
private final int mManufacturerId;
|
||||
@Nullable
|
||||
private final byte[] mManufacturerSpecificData;
|
||||
|
||||
@Nullable
|
||||
private final ParcelUuid mServiceDataUuid;
|
||||
@Nullable
|
||||
private final byte[] mServiceData;
|
||||
|
||||
private final SparseArray<byte[]> mManufacturerSpecificData;
|
||||
private final Map<ParcelUuid, byte[]> mServiceData;
|
||||
private final boolean mIncludeTxPowerLevel;
|
||||
private final boolean mIncludeDeviceName;
|
||||
|
||||
private AdvertiseData(List<ParcelUuid> serviceUuids,
|
||||
ParcelUuid serviceDataUuid, byte[] serviceData,
|
||||
int manufacturerId,
|
||||
byte[] manufacturerSpecificData, boolean includeTxPowerLevel,
|
||||
SparseArray<byte[]> manufacturerData,
|
||||
Map<ParcelUuid, byte[]> serviceData,
|
||||
boolean includeTxPowerLevel,
|
||||
boolean includeDeviceName) {
|
||||
mServiceUuids = serviceUuids;
|
||||
mManufacturerId = manufacturerId;
|
||||
mManufacturerSpecificData = manufacturerSpecificData;
|
||||
mServiceDataUuid = serviceDataUuid;
|
||||
mManufacturerSpecificData = manufacturerData;
|
||||
mServiceData = serviceData;
|
||||
mIncludeTxPowerLevel = includeTxPowerLevel;
|
||||
mIncludeDeviceName = includeDeviceName;
|
||||
@@ -77,32 +69,17 @@ public final class AdvertiseData implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the manufacturer identifier, which is a non-negative number assigned by Bluetooth
|
||||
* SIG.
|
||||
* Returns an array of manufacturer Id and the corresponding manufacturer specific data. The
|
||||
* manufacturer id is a non-negative number assigned by Bluetooth SIG.
|
||||
*/
|
||||
public int getManufacturerId() {
|
||||
return mManufacturerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the manufacturer specific data which is the content of manufacturer specific data
|
||||
* field. The first 2 bytes of the data contain the company id.
|
||||
*/
|
||||
public byte[] getManufacturerSpecificData() {
|
||||
public SparseArray<byte[]> getManufacturerSpecificData() {
|
||||
return mManufacturerSpecificData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a 16-bit UUID of the service that the service data is associated with.
|
||||
* Returns a map of 16-bit UUID and its corresponding service data.
|
||||
*/
|
||||
public ParcelUuid getServiceDataUuid() {
|
||||
return mServiceDataUuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns service data.
|
||||
*/
|
||||
public byte[] getServiceData() {
|
||||
public Map<ParcelUuid, byte[]> getServiceData() {
|
||||
return mServiceData;
|
||||
}
|
||||
|
||||
@@ -125,8 +102,8 @@ public final class AdvertiseData implements Parcelable {
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mServiceUuids, mManufacturerId, mManufacturerSpecificData,
|
||||
mServiceDataUuid, mServiceData, mIncludeDeviceName, mIncludeTxPowerLevel);
|
||||
return Objects.hash(mServiceUuids, mManufacturerSpecificData, mServiceData,
|
||||
mIncludeDeviceName, mIncludeTxPowerLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,20 +119,17 @@ public final class AdvertiseData implements Parcelable {
|
||||
}
|
||||
AdvertiseData other = (AdvertiseData) obj;
|
||||
return Objects.equals(mServiceUuids, other.mServiceUuids) &&
|
||||
mManufacturerId == other.mManufacturerId &&
|
||||
Objects.deepEquals(mManufacturerSpecificData, other.mManufacturerSpecificData) &&
|
||||
Objects.equals(mServiceDataUuid, other.mServiceDataUuid) &&
|
||||
Objects.deepEquals(mServiceData, other.mServiceData) &&
|
||||
Utils.equals(mManufacturerSpecificData, other.mManufacturerSpecificData) &&
|
||||
Utils.equals(mServiceData, other.mServiceData) &&
|
||||
mIncludeDeviceName == other.mIncludeDeviceName &&
|
||||
mIncludeTxPowerLevel == other.mIncludeTxPowerLevel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AdvertiseData [mServiceUuids=" + mServiceUuids + ", mManufacturerId="
|
||||
+ mManufacturerId + ", mManufacturerSpecificData="
|
||||
+ Arrays.toString(mManufacturerSpecificData) + ", mServiceDataUuid="
|
||||
+ mServiceDataUuid + ", mServiceData=" + Arrays.toString(mServiceData)
|
||||
return "AdvertiseData [mServiceUuids=" + mServiceUuids + ", mManufacturerSpecificData="
|
||||
+ Utils.toString(mManufacturerSpecificData) + ", mServiceData="
|
||||
+ Utils.toString(mServiceData)
|
||||
+ ", mIncludeTxPowerLevel=" + mIncludeTxPowerLevel + ", mIncludeDeviceName="
|
||||
+ mIncludeDeviceName + "]";
|
||||
}
|
||||
@@ -169,21 +143,30 @@ public final class AdvertiseData implements Parcelable {
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeList(mServiceUuids);
|
||||
|
||||
dest.writeInt(mManufacturerId);
|
||||
if (mManufacturerSpecificData == null) {
|
||||
dest.writeInt(0);
|
||||
} else {
|
||||
dest.writeInt(1);
|
||||
dest.writeInt(mManufacturerSpecificData.length);
|
||||
dest.writeByteArray(mManufacturerSpecificData);
|
||||
// mManufacturerSpecificData could not be null.
|
||||
dest.writeInt(mManufacturerSpecificData.size());
|
||||
for (int i = 0; i < mManufacturerSpecificData.size(); ++i) {
|
||||
dest.writeInt(mManufacturerSpecificData.keyAt(i));
|
||||
byte[] data = mManufacturerSpecificData.valueAt(i);
|
||||
if (data == null) {
|
||||
dest.writeInt(0);
|
||||
} else {
|
||||
dest.writeInt(1);
|
||||
dest.writeInt(data.length);
|
||||
dest.writeByteArray(data);
|
||||
}
|
||||
}
|
||||
dest.writeParcelable(mServiceDataUuid, flags);
|
||||
if (mServiceData == null) {
|
||||
dest.writeInt(0);
|
||||
} else {
|
||||
dest.writeInt(1);
|
||||
dest.writeInt(mServiceData.length);
|
||||
dest.writeByteArray(mServiceData);
|
||||
dest.writeInt(mServiceData.size());
|
||||
for (ParcelUuid uuid : mServiceData.keySet()) {
|
||||
dest.writeParcelable(uuid, flags);
|
||||
byte[] data = mServiceData.get(uuid);
|
||||
if (data == null) {
|
||||
dest.writeInt(0);
|
||||
} else {
|
||||
dest.writeInt(1);
|
||||
dest.writeInt(data.length);
|
||||
dest.writeByteArray(data);
|
||||
}
|
||||
}
|
||||
dest.writeByte((byte) (getIncludeTxPowerLevel() ? 1 : 0));
|
||||
dest.writeByte((byte) (getIncludeDeviceName() ? 1 : 0));
|
||||
@@ -209,20 +192,26 @@ public final class AdvertiseData implements Parcelable {
|
||||
builder.addServiceUuid(uuid);
|
||||
}
|
||||
}
|
||||
int manufacturerId = in.readInt();
|
||||
if (in.readInt() == 1) {
|
||||
int manufacturerDataLength = in.readInt();
|
||||
byte[] manufacturerData = new byte[manufacturerDataLength];
|
||||
in.readByteArray(manufacturerData);
|
||||
builder.setManufacturerData(manufacturerId, manufacturerData);
|
||||
int manufacturerSize = in.readInt();
|
||||
for (int i = 0; i < manufacturerSize; ++i) {
|
||||
int manufacturerId = in.readInt();
|
||||
if (in.readInt() == 1) {
|
||||
int manufacturerDataLength = in.readInt();
|
||||
byte[] manufacturerData = new byte[manufacturerDataLength];
|
||||
in.readByteArray(manufacturerData);
|
||||
builder.addManufacturerData(manufacturerId, manufacturerData);
|
||||
}
|
||||
}
|
||||
ParcelUuid serviceDataUuid = in.readParcelable(
|
||||
ParcelUuid.class.getClassLoader());
|
||||
if (in.readInt() == 1) {
|
||||
int serviceDataLength = in.readInt();
|
||||
byte[] serviceData = new byte[serviceDataLength];
|
||||
in.readByteArray(serviceData);
|
||||
builder.setServiceData(serviceDataUuid, serviceData);
|
||||
int serviceDataSize = in.readInt();
|
||||
for (int i = 0; i < serviceDataSize; ++i) {
|
||||
ParcelUuid serviceDataUuid = in.readParcelable(
|
||||
ParcelUuid.class.getClassLoader());
|
||||
if (in.readInt() == 1) {
|
||||
int serviceDataLength = in.readInt();
|
||||
byte[] serviceData = new byte[serviceDataLength];
|
||||
in.readByteArray(serviceData);
|
||||
builder.addServiceData(serviceDataUuid, serviceData);
|
||||
}
|
||||
}
|
||||
builder.setIncludeTxPowerLevel(in.readByte() == 1);
|
||||
builder.setIncludeDeviceName(in.readByte() == 1);
|
||||
@@ -236,13 +225,8 @@ public final class AdvertiseData implements Parcelable {
|
||||
public static final class Builder {
|
||||
@Nullable
|
||||
private List<ParcelUuid> mServiceUuids = new ArrayList<ParcelUuid>();
|
||||
private int mManufacturerId = -1;
|
||||
@Nullable
|
||||
private byte[] mManufacturerSpecificData;
|
||||
@Nullable
|
||||
private ParcelUuid mServiceDataUuid;
|
||||
@Nullable
|
||||
private byte[] mServiceData;
|
||||
private SparseArray<byte[]> mManufacturerSpecificData = new SparseArray<byte[]>();
|
||||
private Map<ParcelUuid, byte[]> mServiceData = new ArrayMap<ParcelUuid, byte[]>();
|
||||
private boolean mIncludeTxPowerLevel;
|
||||
private boolean mIncludeDeviceName;
|
||||
|
||||
@@ -268,18 +252,17 @@ public final class AdvertiseData implements Parcelable {
|
||||
* @throws IllegalArgumentException If the {@code serviceDataUuid} or {@code serviceData} is
|
||||
* empty.
|
||||
*/
|
||||
public Builder setServiceData(ParcelUuid serviceDataUuid, byte[] serviceData) {
|
||||
public Builder addServiceData(ParcelUuid serviceDataUuid, byte[] serviceData) {
|
||||
if (serviceDataUuid == null || serviceData == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"serviceDataUuid or serviceDataUuid is null");
|
||||
}
|
||||
mServiceDataUuid = serviceDataUuid;
|
||||
mServiceData = serviceData;
|
||||
mServiceData.put(serviceDataUuid, serviceData);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set manufacturer specific data.
|
||||
* Add manufacturer specific data.
|
||||
* <p>
|
||||
* Please refer to the Bluetooth Assigned Numbers document provided by the <a
|
||||
* href="https://www.bluetooth.org">Bluetooth SIG</a> for a list of existing company
|
||||
@@ -290,7 +273,7 @@ public final class AdvertiseData implements Parcelable {
|
||||
* @throws IllegalArgumentException If the {@code manufacturerId} is negative or
|
||||
* {@code manufacturerSpecificData} is null.
|
||||
*/
|
||||
public Builder setManufacturerData(int manufacturerId, byte[] manufacturerSpecificData) {
|
||||
public Builder addManufacturerData(int manufacturerId, byte[] manufacturerSpecificData) {
|
||||
if (manufacturerId < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"invalid manufacturerId - " + manufacturerId);
|
||||
@@ -298,8 +281,7 @@ public final class AdvertiseData implements Parcelable {
|
||||
if (manufacturerSpecificData == null) {
|
||||
throw new IllegalArgumentException("manufacturerSpecificData is null");
|
||||
}
|
||||
mManufacturerId = manufacturerId;
|
||||
mManufacturerSpecificData = manufacturerSpecificData;
|
||||
mManufacturerSpecificData.put(manufacturerId, manufacturerSpecificData);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -324,9 +306,7 @@ public final class AdvertiseData implements Parcelable {
|
||||
* Build the {@link AdvertiseData}.
|
||||
*/
|
||||
public AdvertiseData build() {
|
||||
return new AdvertiseData(mServiceUuids,
|
||||
mServiceDataUuid,
|
||||
mServiceData, mManufacturerId, mManufacturerSpecificData,
|
||||
return new AdvertiseData(mServiceUuids, mManufacturerSpecificData, mServiceData,
|
||||
mIncludeTxPowerLevel, mIncludeDeviceName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,13 +209,13 @@ public final class BluetoothLeAdvertiser {
|
||||
num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT;
|
||||
}
|
||||
}
|
||||
if (data.getServiceDataUuid() != null) {
|
||||
for (ParcelUuid uuid : data.getServiceData().keySet()) {
|
||||
size += OVERHEAD_BYTES_PER_FIELD + SERVICE_DATA_UUID_LENGTH
|
||||
+ byteLength(data.getServiceData());
|
||||
+ byteLength(data.getServiceData().get(uuid));
|
||||
}
|
||||
if (data.getManufacturerId() > 0) {
|
||||
for (int i = 0; i < data.getManufacturerSpecificData().size(); ++i) {
|
||||
size += OVERHEAD_BYTES_PER_FIELD + MANUFACTURER_SPECIFIC_DATA_LENGTH +
|
||||
byteLength(data.getManufacturerSpecificData());
|
||||
byteLength(data.getManufacturerSpecificData().valueAt(i));
|
||||
}
|
||||
if (data.getIncludeTxPowerLevel()) {
|
||||
size += OVERHEAD_BYTES_PER_FIELD + 1; // tx power level value is one byte.
|
||||
|
||||
@@ -181,7 +181,7 @@ public final class ScanFilter implements Parcelable {
|
||||
byte[] serviceDataMask = new byte[serviceDataMaskLength];
|
||||
in.readByteArray(serviceDataMask);
|
||||
builder.setServiceData(
|
||||
servcieDataUuid, serviceData, serviceDataMask);
|
||||
servcieDataUuid, serviceData, serviceDataMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -242,9 +242,6 @@ public final class ScanFilter implements Parcelable {
|
||||
return mServiceDataMask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Nullable
|
||||
public ParcelUuid getServiceDataUuid() {
|
||||
return mServiceDataUuid;
|
||||
@@ -303,19 +300,17 @@ public final class ScanFilter implements Parcelable {
|
||||
}
|
||||
|
||||
// Service data match
|
||||
if (mServiceData != null) {
|
||||
if (!Objects.equals(mServiceDataUuid, scanRecord.getServiceDataUuid()) ||
|
||||
!matchesPartialData(mServiceData, mServiceDataMask,
|
||||
scanRecord.getServiceData())) {
|
||||
if (mServiceDataUuid != null) {
|
||||
if (!matchesPartialData(mServiceData, mServiceDataMask,
|
||||
scanRecord.getServiceData(mServiceDataUuid))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Manufacturer data match.
|
||||
if (mManufacturerData != null) {
|
||||
if (mManufacturerId != scanRecord.getManufacturerId() ||
|
||||
!matchesPartialData(mManufacturerData,
|
||||
mManufacturerDataMask, scanRecord.getManufacturerSpecificData())) {
|
||||
if (mManufacturerId >= 0) {
|
||||
if (!matchesPartialData(mManufacturerData, mManufacturerDataMask,
|
||||
scanRecord.getManufacturerSpecificData(mManufacturerId))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,14 @@ package android.bluetooth.le;
|
||||
import android.annotation.Nullable;
|
||||
import android.bluetooth.BluetoothUuid;
|
||||
import android.os.ParcelUuid;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents a scan record from Bluetooth LE scan.
|
||||
@@ -53,14 +56,9 @@ public final class ScanRecord {
|
||||
@Nullable
|
||||
private final List<ParcelUuid> mServiceUuids;
|
||||
|
||||
private final int mManufacturerId;
|
||||
@Nullable
|
||||
private final byte[] mManufacturerSpecificData;
|
||||
private final SparseArray<byte[]> mManufacturerSpecificData;
|
||||
|
||||
@Nullable
|
||||
private final ParcelUuid mServiceDataUuid;
|
||||
@Nullable
|
||||
private final byte[] mServiceData;
|
||||
private final Map<ParcelUuid, byte[]> mServiceData;
|
||||
|
||||
// Transmission power level(in dB).
|
||||
private final int mTxPowerLevel;
|
||||
@@ -81,42 +79,48 @@ public final class ScanRecord {
|
||||
|
||||
/**
|
||||
* Returns a list of service UUIDs within the advertisement that are used to identify the
|
||||
* bluetooth gatt services.
|
||||
* bluetooth GATT services.
|
||||
*/
|
||||
public List<ParcelUuid> getServiceUuids() {
|
||||
return mServiceUuids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the manufacturer identifier, which is a non-negative number assigned by Bluetooth
|
||||
* SIG.
|
||||
* Returns a sparse array of manufacturer identifier and its corresponding manufacturer specific
|
||||
* data.
|
||||
*/
|
||||
public int getManufacturerId() {
|
||||
return mManufacturerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the manufacturer specific data which is the content of manufacturer specific data
|
||||
* field.
|
||||
*/
|
||||
public byte[] getManufacturerSpecificData() {
|
||||
public SparseArray<byte[]> getManufacturerSpecificData() {
|
||||
return mManufacturerSpecificData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a 16-bit UUID of the service that the service data is associated with.
|
||||
* Returns the manufacturer specific data associated with the manufacturer id. Returns
|
||||
* {@code null} if the {@code manufacturerId} is not found.
|
||||
*/
|
||||
public ParcelUuid getServiceDataUuid() {
|
||||
return mServiceDataUuid;
|
||||
@Nullable
|
||||
public byte[] getManufacturerSpecificData(int manufacturerId) {
|
||||
return mManufacturerSpecificData.get(manufacturerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns service data.
|
||||
* Returns a map of service UUID and its corresponding service data.
|
||||
*/
|
||||
public byte[] getServiceData() {
|
||||
public Map<ParcelUuid, byte[]> getServiceData() {
|
||||
return mServiceData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the service data byte array associated with the {@code serviceUuid}. Returns
|
||||
* {@code null} if the {@code serviceDataUuid} is not found.
|
||||
*/
|
||||
@Nullable
|
||||
public byte[] getServiceData(ParcelUuid serviceDataUuid) {
|
||||
if (serviceDataUuid == null) {
|
||||
return null;
|
||||
}
|
||||
return mServiceData.get(serviceDataUuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transmission power level of the packet in dBm. Returns {@link Integer#MIN_VALUE}
|
||||
* if the field is not set. This value can be used to calculate the path loss of a received
|
||||
@@ -144,14 +148,12 @@ public final class ScanRecord {
|
||||
}
|
||||
|
||||
private ScanRecord(List<ParcelUuid> serviceUuids,
|
||||
ParcelUuid serviceDataUuid, byte[] serviceData,
|
||||
int manufacturerId,
|
||||
byte[] manufacturerSpecificData, int advertiseFlags, int txPowerLevel,
|
||||
SparseArray<byte[]> manufacturerData,
|
||||
Map<ParcelUuid, byte[]> serviceData,
|
||||
int advertiseFlags, int txPowerLevel,
|
||||
String localName, byte[] bytes) {
|
||||
mServiceUuids = serviceUuids;
|
||||
mManufacturerId = manufacturerId;
|
||||
mManufacturerSpecificData = manufacturerSpecificData;
|
||||
mServiceDataUuid = serviceDataUuid;
|
||||
mManufacturerSpecificData = manufacturerData;
|
||||
mServiceData = serviceData;
|
||||
mDeviceName = localName;
|
||||
mAdvertiseFlags = advertiseFlags;
|
||||
@@ -168,7 +170,6 @@ public final class ScanRecord {
|
||||
* order.
|
||||
*
|
||||
* @param scanRecord The scan record of Bluetooth LE advertisement and/or scan response.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static ScanRecord parseFromBytes(byte[] scanRecord) {
|
||||
@@ -181,10 +182,9 @@ public final class ScanRecord {
|
||||
List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
|
||||
String localName = null;
|
||||
int txPowerLevel = Integer.MIN_VALUE;
|
||||
ParcelUuid serviceDataUuid = null;
|
||||
byte[] serviceData = null;
|
||||
int manufacturerId = -1;
|
||||
byte[] manufacturerSpecificData = null;
|
||||
|
||||
SparseArray<byte[]> manufacturerData = new SparseArray<byte[]>();
|
||||
Map<ParcelUuid, byte[]> serviceData = new ArrayMap<ParcelUuid, byte[]>();
|
||||
|
||||
try {
|
||||
while (currentPos < scanRecord.length) {
|
||||
@@ -230,16 +230,20 @@ public final class ScanRecord {
|
||||
int serviceUuidLength = BluetoothUuid.UUID_BYTES_16_BIT;
|
||||
byte[] serviceDataUuidBytes = extractBytes(scanRecord, currentPos,
|
||||
serviceUuidLength);
|
||||
serviceDataUuid = BluetoothUuid.parseUuidFrom(serviceDataUuidBytes);
|
||||
serviceData = extractBytes(scanRecord, currentPos + 2, dataLength - 2);
|
||||
ParcelUuid serviceDataUuid = BluetoothUuid.parseUuidFrom(
|
||||
serviceDataUuidBytes);
|
||||
byte[] serviceDataArray = extractBytes(scanRecord,
|
||||
currentPos + serviceUuidLength, dataLength - serviceUuidLength);
|
||||
serviceData.put(serviceDataUuid, serviceDataArray);
|
||||
break;
|
||||
case DATA_TYPE_MANUFACTURER_SPECIFIC_DATA:
|
||||
// The first two bytes of the manufacturer specific data are
|
||||
// manufacturer ids in little endian.
|
||||
manufacturerId = ((scanRecord[currentPos + 1] & 0xFF) << 8) +
|
||||
int manufacturerId = ((scanRecord[currentPos + 1] & 0xFF) << 8) +
|
||||
(scanRecord[currentPos] & 0xFF);
|
||||
manufacturerSpecificData = extractBytes(scanRecord, currentPos + 2,
|
||||
byte[] manufacturerDataBytes = extractBytes(scanRecord, currentPos + 2,
|
||||
dataLength - 2);
|
||||
manufacturerData.put(manufacturerId, manufacturerDataBytes);
|
||||
break;
|
||||
default:
|
||||
// Just ignore, we don't handle such data type.
|
||||
@@ -251,9 +255,8 @@ public final class ScanRecord {
|
||||
if (serviceUuids.isEmpty()) {
|
||||
serviceUuids = null;
|
||||
}
|
||||
return new ScanRecord(serviceUuids, serviceDataUuid, serviceData,
|
||||
manufacturerId, manufacturerSpecificData, advertiseFlag, txPowerLevel,
|
||||
localName, scanRecord);
|
||||
return new ScanRecord(serviceUuids, manufacturerData, serviceData,
|
||||
advertiseFlag, txPowerLevel, localName, scanRecord);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
Log.e(TAG, "unable to parse scan record: " + Arrays.toString(scanRecord));
|
||||
return null;
|
||||
@@ -263,13 +266,11 @@ public final class ScanRecord {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ScanRecord [mAdvertiseFlags=" + mAdvertiseFlags + ", mServiceUuids=" + mServiceUuids
|
||||
+ ", mManufacturerId=" + mManufacturerId + ", mManufacturerSpecificData="
|
||||
+ Arrays.toString(mManufacturerSpecificData) + ", mServiceDataUuid="
|
||||
+ mServiceDataUuid + ", mServiceData=" + Arrays.toString(mServiceData)
|
||||
+ ", mManufacturerSpecificData=" + Utils.toString(mManufacturerSpecificData)
|
||||
+ ", mServiceData=" + Utils.toString(mServiceData)
|
||||
+ ", mTxPowerLevel=" + mTxPowerLevel + ", mDeviceName=" + mDeviceName + "]";
|
||||
}
|
||||
|
||||
|
||||
// Parse service UUIDs.
|
||||
private static int parseServiceUuid(byte[] scanRecord, int currentPos, int dataLength,
|
||||
int uuidLength, List<ParcelUuid> serviceUuids) {
|
||||
|
||||
126
core/java/android/bluetooth/le/Utils.java
Normal file
126
core/java/android/bluetooth/le/Utils.java
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.bluetooth.le;
|
||||
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Helper class for Bluetooth LE utils.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class Utils {
|
||||
|
||||
/**
|
||||
* Returns a string composed from a {@link SparseArray}.
|
||||
*/
|
||||
static String toString(SparseArray<byte[]> array) {
|
||||
if (array == null) {
|
||||
return "null";
|
||||
}
|
||||
if (array.size() == 0) {
|
||||
return "{}";
|
||||
}
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append('{');
|
||||
for (int i = 0; i < array.size(); ++i) {
|
||||
buffer.append(array.keyAt(i)).append("=").append(array.valueAt(i));
|
||||
}
|
||||
buffer.append('}');
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string composed from a {@link Map}.
|
||||
*/
|
||||
static <T> String toString(Map<T, byte[]> map) {
|
||||
if (map == null) {
|
||||
return "null";
|
||||
}
|
||||
if (map.isEmpty()) {
|
||||
return "{}";
|
||||
}
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append('{');
|
||||
Iterator<Map.Entry<T, byte[]>> it = map.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<T, byte[]> entry = it.next();
|
||||
Object key = entry.getKey();
|
||||
buffer.append(key).append("=").append(Arrays.toString(map.get(key)));
|
||||
if (it.hasNext()) {
|
||||
buffer.append(", ");
|
||||
}
|
||||
}
|
||||
buffer.append('}');
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether two {@link SparseArray} equal.
|
||||
*/
|
||||
static boolean equals(SparseArray<byte[]> array, SparseArray<byte[]> otherArray) {
|
||||
if (array == otherArray) {
|
||||
return true;
|
||||
}
|
||||
if (array == null || otherArray == null) {
|
||||
return false;
|
||||
}
|
||||
if (array.size() != otherArray.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Keys are guaranteed in ascending order when indices are in ascending order.
|
||||
for (int i = 0; i < array.size(); ++i) {
|
||||
if (array.keyAt(i) != otherArray.keyAt(i) ||
|
||||
!Arrays.equals(array.valueAt(i), otherArray.valueAt(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether two {@link Map} equal.
|
||||
*/
|
||||
static <T> boolean equals(Map<T, byte[]> map, Map<T, byte[]> otherMap) {
|
||||
if (map == otherMap) {
|
||||
return true;
|
||||
}
|
||||
if (map == null || otherMap == null) {
|
||||
return false;
|
||||
}
|
||||
if (map.size() != otherMap.size()) {
|
||||
return false;
|
||||
}
|
||||
Set<T> keys = map.keySet();
|
||||
if (!keys.equals(otherMap.keySet())) {
|
||||
return false;
|
||||
}
|
||||
for (T key : keys) {
|
||||
if (!Objects.deepEquals(map.get(key), otherMap.get(key))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ public class AdvertiseDataTest extends TestCase {
|
||||
byte[] manufacturerData = new byte[0];
|
||||
AdvertiseData data =
|
||||
mAdvertiseDataBuilder.setIncludeDeviceName(true)
|
||||
.setManufacturerData(manufacturerId, manufacturerData).build();
|
||||
.addManufacturerData(manufacturerId, manufacturerData).build();
|
||||
data.writeToParcel(parcel, 0);
|
||||
parcel.setDataPosition(0);
|
||||
AdvertiseData dataFromParcel =
|
||||
@@ -81,7 +81,7 @@ public class AdvertiseDataTest extends TestCase {
|
||||
byte[] serviceData = new byte[0];
|
||||
AdvertiseData data =
|
||||
mAdvertiseDataBuilder.setIncludeDeviceName(true)
|
||||
.setServiceData(uuid, serviceData).build();
|
||||
.addServiceData(uuid, serviceData).build();
|
||||
data.writeToParcel(parcel, 0);
|
||||
parcel.setDataPosition(0);
|
||||
AdvertiseData dataFromParcel =
|
||||
@@ -117,7 +117,7 @@ public class AdvertiseDataTest extends TestCase {
|
||||
AdvertiseData data =
|
||||
mAdvertiseDataBuilder.setIncludeDeviceName(true)
|
||||
.addServiceUuid(uuid).addServiceUuid(uuid2)
|
||||
.setManufacturerData(manufacturerId, manufacturerData).build();
|
||||
.addManufacturerData(manufacturerId, manufacturerData).build();
|
||||
|
||||
data.writeToParcel(parcel, 0);
|
||||
parcel.setDataPosition(0);
|
||||
@@ -134,7 +134,7 @@ public class AdvertiseDataTest extends TestCase {
|
||||
(byte) 0xF0, 0x00, 0x02, 0x15 };
|
||||
AdvertiseData data =
|
||||
mAdvertiseDataBuilder.setIncludeDeviceName(true)
|
||||
.setServiceData(uuid, serviceData).build();
|
||||
.addServiceData(uuid, serviceData).build();
|
||||
data.writeToParcel(parcel, 0);
|
||||
parcel.setDataPosition(0);
|
||||
AdvertiseData dataFromParcel =
|
||||
|
||||
@@ -53,13 +53,13 @@ public class ScanRecordTest extends TestCase {
|
||||
assertEquals("Ped", data.getDeviceName());
|
||||
assertEquals(-20, data.getTxPowerLevel());
|
||||
|
||||
assertEquals(0x00e0, data.getManufacturerId());
|
||||
assertTrue(data.getManufacturerSpecificData().get(0x00E0) != null);
|
||||
assertArrayEquals(new byte[] {
|
||||
0x02, 0x15 }, data.getManufacturerSpecificData());
|
||||
0x02, 0x15 }, data.getManufacturerSpecificData().get(0x00E0));
|
||||
|
||||
assertEquals(uuid2, data.getServiceDataUuid());
|
||||
assertTrue(data.getServiceData().containsKey(uuid2));
|
||||
assertArrayEquals(new byte[] {
|
||||
0x50, 0x64 }, data.getServiceData());
|
||||
0x50, 0x64 }, data.getServiceData().get(uuid2));
|
||||
}
|
||||
|
||||
// Assert two byte arrays are equal.
|
||||
|
||||
Reference in New Issue
Block a user