summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWei Wang <weiwa@google.com>2014-07-31 23:47:17 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-07-29 22:44:51 +0000
commit76f3cceea69cb8926ef2400e826cebbb99be8530 (patch)
treeac2c08c2a669cc53228f8e5d52b39f98563fa595
parentc9b5cd3caeb587077a7e86448c4efad3790ddc6a (diff)
parent3f7a39063ab7b3d7a38b773449ba2b37674e3458 (diff)
downloadframeworks_base-76f3cceea69cb8926ef2400e826cebbb99be8530.zip
frameworks_base-76f3cceea69cb8926ef2400e826cebbb99be8530.tar.gz
frameworks_base-76f3cceea69cb8926ef2400e826cebbb99be8530.tar.bz2
Merge "Service data and manufacturer data can be repeated fields." into lmp-dev
-rw-r--r--api/current.txt19
-rw-r--r--core/java/android/bluetooth/le/AdvertiseData.java162
-rw-r--r--core/java/android/bluetooth/le/BluetoothLeAdvertiser.java8
-rw-r--r--core/java/android/bluetooth/le/ScanFilter.java19
-rw-r--r--core/java/android/bluetooth/le/ScanRecord.java89
-rw-r--r--core/java/android/bluetooth/le/Utils.java126
-rw-r--r--core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java8
-rw-r--r--core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java8
8 files changed, 270 insertions, 169 deletions
diff --git a/api/current.txt b/api/current.txt
index 74fdd31..dae70ef 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6580,22 +6580,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 {
@@ -6656,6 +6654,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);
@@ -6679,10 +6678,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();
}
diff --git a/core/java/android/bluetooth/le/AdvertiseData.java b/core/java/android/bluetooth/le/AdvertiseData.java
index b137eeb..843cd84 100644
--- a/core/java/android/bluetooth/le/AdvertiseData.java
+++ b/core/java/android/bluetooth/le/AdvertiseData.java
@@ -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.
- */
- public ParcelUuid getServiceDataUuid() {
- return mServiceDataUuid;
- }
-
- /**
- * Returns service data.
+ * Returns a map of 16-bit UUID and its corresponding 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);
}
}
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 4d128e7..8879da7 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -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.
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 30aaf2e..d1b93d2 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -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;
}
}
diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java
index e564c7d..e7f33ff1 100644
--- a/core/java/android/bluetooth/le/ScanRecord.java
+++ b/core/java/android/bluetooth/le/ScanRecord.java
@@ -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,40 +79,46 @@ 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;
+ public SparseArray<byte[]> getManufacturerSpecificData() {
+ return mManufacturerSpecificData;
}
/**
- * Returns the manufacturer specific data which is the content of manufacturer specific data
- * field.
+ * Returns the manufacturer specific data associated with the manufacturer id. Returns
+ * {@code null} if the {@code manufacturerId} is not found.
*/
- public byte[] getManufacturerSpecificData() {
- return mManufacturerSpecificData;
+ @Nullable
+ public byte[] getManufacturerSpecificData(int manufacturerId) {
+ return mManufacturerSpecificData.get(manufacturerId);
}
/**
- * Returns a 16-bit UUID of the service that the service data is associated with.
+ * Returns a map of service UUID and its corresponding service data.
*/
- public ParcelUuid getServiceDataUuid() {
- return mServiceDataUuid;
+ public Map<ParcelUuid, byte[]> getServiceData() {
+ return mServiceData;
}
/**
- * Returns service data.
+ * Returns the service data byte array associated with the {@code serviceUuid}. Returns
+ * {@code null} if the {@code serviceDataUuid} is not found.
*/
- public byte[] getServiceData() {
- return mServiceData;
+ @Nullable
+ public byte[] getServiceData(ParcelUuid serviceDataUuid) {
+ if (serviceDataUuid == null) {
+ return null;
+ }
+ return mServiceData.get(serviceDataUuid);
}
/**
@@ -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) {
diff --git a/core/java/android/bluetooth/le/Utils.java b/core/java/android/bluetooth/le/Utils.java
new file mode 100644
index 0000000..8598dd7
--- /dev/null
+++ b/core/java/android/bluetooth/le/Utils.java
@@ -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;
+ }
+}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java
index 5e451ca..e58d905 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java
@@ -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 =
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java
index ccdd90a..8b3db7e 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java
@@ -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.