diff options
author | Wei Wang <weiwa@google.com> | 2014-07-31 23:47:17 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-07-29 22:44:51 +0000 |
commit | 76f3cceea69cb8926ef2400e826cebbb99be8530 (patch) | |
tree | ac2c08c2a669cc53228f8e5d52b39f98563fa595 | |
parent | c9b5cd3caeb587077a7e86448c4efad3790ddc6a (diff) | |
parent | 3f7a39063ab7b3d7a38b773449ba2b37674e3458 (diff) | |
download | frameworks_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.txt | 19 | ||||
-rw-r--r-- | core/java/android/bluetooth/le/AdvertiseData.java | 162 | ||||
-rw-r--r-- | core/java/android/bluetooth/le/BluetoothLeAdvertiser.java | 8 | ||||
-rw-r--r-- | core/java/android/bluetooth/le/ScanFilter.java | 19 | ||||
-rw-r--r-- | core/java/android/bluetooth/le/ScanRecord.java | 89 | ||||
-rw-r--r-- | core/java/android/bluetooth/le/Utils.java | 126 | ||||
-rw-r--r-- | core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java | 8 | ||||
-rw-r--r-- | core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java | 8 |
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. |