ScanRecordpublic final class ScanRecord extends Object Represents a scan record from Bluetooth LE scan. |
Fields Summary |
---|
private static final String | TAG | private static final int | DATA_TYPE_FLAGS | private static final int | DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL | private static final int | DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE | private static final int | DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL | private static final int | DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE | private static final int | DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL | private static final int | DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE | private static final int | DATA_TYPE_LOCAL_NAME_SHORT | private static final int | DATA_TYPE_LOCAL_NAME_COMPLETE | private static final int | DATA_TYPE_TX_POWER_LEVEL | private static final int | DATA_TYPE_SERVICE_DATA | private static final int | DATA_TYPE_MANUFACTURER_SPECIFIC_DATA | private final int | mAdvertiseFlags | private final List | mServiceUuids | private final android.util.SparseArray | mManufacturerSpecificData | private final Map | mServiceData | private final int | mTxPowerLevel | private final String | mDeviceName | private final byte[] | mBytes |
Constructors Summary |
---|
private ScanRecord(List serviceUuids, android.util.SparseArray manufacturerData, Map serviceData, int advertiseFlags, int txPowerLevel, String localName, byte[] bytes)
mServiceUuids = serviceUuids;
mManufacturerSpecificData = manufacturerData;
mServiceData = serviceData;
mDeviceName = localName;
mAdvertiseFlags = advertiseFlags;
mTxPowerLevel = txPowerLevel;
mBytes = bytes;
|
Methods Summary |
---|
private static byte[] | extractBytes(byte[] scanRecord, int start, int length)
byte[] bytes = new byte[length];
System.arraycopy(scanRecord, start, bytes, 0, length);
return bytes;
| public int | getAdvertiseFlags()Returns the advertising flags indicating the discoverable mode and capability of the device.
Returns -1 if the flag field is not set.
return mAdvertiseFlags;
| public byte[] | getBytes()Returns raw bytes of scan record.
return mBytes;
| public java.lang.String | getDeviceName()Returns the local name of the BLE device. The is a UTF-8 encoded string.
return mDeviceName;
| public android.util.SparseArray | getManufacturerSpecificData()Returns a sparse array of manufacturer identifier and its corresponding manufacturer specific
data.
return mManufacturerSpecificData;
| public byte[] | getManufacturerSpecificData(int manufacturerId)Returns the manufacturer specific data associated with the manufacturer id. Returns
{@code null} if the {@code manufacturerId} is not found.
return mManufacturerSpecificData.get(manufacturerId);
| public java.util.Map | getServiceData()Returns a map of service UUID and its corresponding service data.
return mServiceData;
| public byte[] | getServiceData(android.os.ParcelUuid serviceDataUuid)Returns the service data byte array associated with the {@code serviceUuid}. Returns
{@code null} if the {@code serviceDataUuid} is not found.
if (serviceDataUuid == null) {
return null;
}
return mServiceData.get(serviceDataUuid);
| public java.util.List | getServiceUuids()Returns a list of service UUIDs within the advertisement that are used to identify the
bluetooth GATT services.
return mServiceUuids;
| public int | getTxPowerLevel()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
packet using the following equation:
pathloss = txPowerLevel - rssi
return mTxPowerLevel;
| public static android.bluetooth.le.ScanRecord | parseFromBytes(byte[] scanRecord)Parse scan record bytes to {@link ScanRecord}.
The format is defined in Bluetooth 4.1 specification, Volume 3, Part C, Section 11 and 18.
All numerical multi-byte entities and values shall use little-endian byte
order.
if (scanRecord == null) {
return null;
}
int currentPos = 0;
int advertiseFlag = -1;
List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
String localName = null;
int txPowerLevel = Integer.MIN_VALUE;
SparseArray<byte[]> manufacturerData = new SparseArray<byte[]>();
Map<ParcelUuid, byte[]> serviceData = new ArrayMap<ParcelUuid, byte[]>();
try {
while (currentPos < scanRecord.length) {
// length is unsigned int.
int length = scanRecord[currentPos++] & 0xFF;
if (length == 0) {
break;
}
// Note the length includes the length of the field type itself.
int dataLength = length - 1;
// fieldType is unsigned int.
int fieldType = scanRecord[currentPos++] & 0xFF;
switch (fieldType) {
case DATA_TYPE_FLAGS:
advertiseFlag = scanRecord[currentPos] & 0xFF;
break;
case DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL:
case DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE:
parseServiceUuid(scanRecord, currentPos,
dataLength, BluetoothUuid.UUID_BYTES_16_BIT, serviceUuids);
break;
case DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL:
case DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE:
parseServiceUuid(scanRecord, currentPos, dataLength,
BluetoothUuid.UUID_BYTES_32_BIT, serviceUuids);
break;
case DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL:
case DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE:
parseServiceUuid(scanRecord, currentPos, dataLength,
BluetoothUuid.UUID_BYTES_128_BIT, serviceUuids);
break;
case DATA_TYPE_LOCAL_NAME_SHORT:
case DATA_TYPE_LOCAL_NAME_COMPLETE:
localName = new String(
extractBytes(scanRecord, currentPos, dataLength));
break;
case DATA_TYPE_TX_POWER_LEVEL:
txPowerLevel = scanRecord[currentPos];
break;
case DATA_TYPE_SERVICE_DATA:
// The first two bytes of the service data are service data UUID in little
// endian. The rest bytes are service data.
int serviceUuidLength = BluetoothUuid.UUID_BYTES_16_BIT;
byte[] serviceDataUuidBytes = extractBytes(scanRecord, currentPos,
serviceUuidLength);
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.
int manufacturerId = ((scanRecord[currentPos + 1] & 0xFF) << 8) +
(scanRecord[currentPos] & 0xFF);
byte[] manufacturerDataBytes = extractBytes(scanRecord, currentPos + 2,
dataLength - 2);
manufacturerData.put(manufacturerId, manufacturerDataBytes);
break;
default:
// Just ignore, we don't handle such data type.
break;
}
currentPos += dataLength;
}
if (serviceUuids.isEmpty()) {
serviceUuids = null;
}
return new ScanRecord(serviceUuids, manufacturerData, serviceData,
advertiseFlag, txPowerLevel, localName, scanRecord);
} catch (Exception e) {
Log.e(TAG, "unable to parse scan record: " + Arrays.toString(scanRecord));
// As the record is invalid, ignore all the parsed results for this packet
// and return an empty record with raw scanRecord bytes in results
return new ScanRecord(null, null, null, -1, Integer.MIN_VALUE, null, scanRecord);
}
| private static int | parseServiceUuid(byte[] scanRecord, int currentPos, int dataLength, int uuidLength, java.util.List serviceUuids)
while (dataLength > 0) {
byte[] uuidBytes = extractBytes(scanRecord, currentPos,
uuidLength);
serviceUuids.add(BluetoothUuid.parseUuidFrom(uuidBytes));
dataLength -= uuidLength;
currentPos += uuidLength;
}
return currentPos;
| public java.lang.String | toString()
return "ScanRecord [mAdvertiseFlags=" + mAdvertiseFlags + ", mServiceUuids=" + mServiceUuids
+ ", mManufacturerSpecificData=" + BluetoothLeUtils.toString(mManufacturerSpecificData)
+ ", mServiceData=" + BluetoothLeUtils.toString(mServiceData)
+ ", mTxPowerLevel=" + mTxPowerLevel + ", mDeviceName=" + mDeviceName + "]";
|
|