FileDocCategorySizeDatePackage
ScanRecord.javaAPI DocAndroid 5.1 API11888Thu Mar 12 22:22:10 GMT 2015android.bluetooth.le

ScanRecord

public 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 intgetAdvertiseFlags()
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.StringgetDeviceName()
Returns the local name of the BLE device. The is a UTF-8 encoded string.

        return mDeviceName;
    
public android.util.SparseArraygetManufacturerSpecificData()
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.MapgetServiceData()
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.ListgetServiceUuids()
Returns a list of service UUIDs within the advertisement that are used to identify the bluetooth GATT services.

        return mServiceUuids;
    
public intgetTxPowerLevel()
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.ScanRecordparseFromBytes(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.

param
scanRecord The scan record of Bluetooth LE advertisement and/or scan response.
hide

        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 intparseServiceUuid(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.StringtoString()

        return "ScanRecord [mAdvertiseFlags=" + mAdvertiseFlags + ", mServiceUuids=" + mServiceUuids
                + ", mManufacturerSpecificData=" + BluetoothLeUtils.toString(mManufacturerSpecificData)
                + ", mServiceData=" + BluetoothLeUtils.toString(mServiceData)
                + ", mTxPowerLevel=" + mTxPowerLevel + ", mDeviceName=" + mDeviceName + "]";