16d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang/*
26d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * Copyright (C) 2014 The Android Open Source Project
36d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang *
46d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * Licensed under the Apache License, Version 2.0 (the "License");
56d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * you may not use this file except in compliance with the License.
66d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * You may obtain a copy of the License at
76d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang *
86d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang *      http://www.apache.org/licenses/LICENSE-2.0
96d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang *
106d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * Unless required by applicable law or agreed to in writing, software
116d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * distributed under the License is distributed on an "AS IS" BASIS,
126d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * See the License for the specific language governing permissions and
146d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * limitations under the License.
156d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang */
166d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
176d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangpackage android.bluetooth.le;
186d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
196d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangimport android.annotation.Nullable;
206d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangimport android.bluetooth.BluetoothUuid;
216d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangimport android.os.ParcelUuid;
226bf513d32db7fbc157681bd642e12a201cf20a89Wei Wangimport android.util.ArrayMap;
236d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangimport android.util.Log;
246bf513d32db7fbc157681bd642e12a201cf20a89Wei Wangimport android.util.SparseArray;
256d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
266d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangimport java.util.ArrayList;
276d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangimport java.util.Arrays;
286d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangimport java.util.List;
296bf513d32db7fbc157681bd642e12a201cf20a89Wei Wangimport java.util.Map;
306d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
316d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang/**
326d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang * Represents a scan record from Bluetooth LE scan.
336d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang */
346d81118032b92caa0f5cfebe11af02a98f819d5eWei Wangpublic final class ScanRecord {
356d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
366d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private static final String TAG = "ScanRecord";
376d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
386d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    // The following data type values are assigned by Bluetooth SIG.
396d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    // For more details refer to Bluetooth 4.1 specification, Volume 3, Part C, Section 18.
406d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private static final int DATA_TYPE_FLAGS = 0x01;
416d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL = 0x02;
426d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE = 0x03;
436d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL = 0x04;
446d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE = 0x05;
456d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL = 0x06;
466d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE = 0x07;
476d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private static final int DATA_TYPE_LOCAL_NAME_SHORT = 0x08;
486d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private static final int DATA_TYPE_LOCAL_NAME_COMPLETE = 0x09;
496d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private static final int DATA_TYPE_TX_POWER_LEVEL = 0x0A;
506d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private static final int DATA_TYPE_SERVICE_DATA = 0x16;
516d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;
526d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
536d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    // Flags of the advertising data.
546d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private final int mAdvertiseFlags;
556d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
566d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    @Nullable
576d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private final List<ParcelUuid> mServiceUuids;
586d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
596bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang    private final SparseArray<byte[]> mManufacturerSpecificData;
606d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
616bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang    private final Map<ParcelUuid, byte[]> mServiceData;
626d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
636d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    // Transmission power level(in dB).
646d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private final int mTxPowerLevel;
656d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
666d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    // Local name of the Bluetooth LE device.
67af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang    private final String mDeviceName;
686d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
69685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang    // Raw bytes of scan record.
70685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang    private final byte[] mBytes;
71685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang
726d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    /**
736d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * Returns the advertising flags indicating the discoverable mode and capability of the device.
746d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * Returns -1 if the flag field is not set.
756d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     */
766d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    public int getAdvertiseFlags() {
776d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        return mAdvertiseFlags;
786d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    }
796d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
806d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    /**
81af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang     * Returns a list of service UUIDs within the advertisement that are used to identify the
826bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang     * bluetooth GATT services.
836d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     */
846d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    public List<ParcelUuid> getServiceUuids() {
856d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        return mServiceUuids;
866d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    }
876d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
886d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    /**
896bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang     * Returns a sparse array of manufacturer identifier and its corresponding manufacturer specific
906bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang     * data.
916d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     */
926bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang    public SparseArray<byte[]> getManufacturerSpecificData() {
936bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang        return mManufacturerSpecificData;
946d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    }
956d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
966d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    /**
976bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang     * Returns the manufacturer specific data associated with the manufacturer id. Returns
986bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang     * {@code null} if the {@code manufacturerId} is not found.
996d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     */
1006bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang    @Nullable
1016bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang    public byte[] getManufacturerSpecificData(int manufacturerId) {
1026bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang        return mManufacturerSpecificData.get(manufacturerId);
1036d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    }
1046d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
1056d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    /**
1066bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang     * Returns a map of service UUID and its corresponding service data.
1076d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     */
1086bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang    public Map<ParcelUuid, byte[]> getServiceData() {
1096bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang        return mServiceData;
1106d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    }
1116d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
1126d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    /**
1136bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang     * Returns the service data byte array associated with the {@code serviceUuid}. Returns
1146bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang     * {@code null} if the {@code serviceDataUuid} is not found.
1156d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     */
1166bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang    @Nullable
1176bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang    public byte[] getServiceData(ParcelUuid serviceDataUuid) {
1186bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang        if (serviceDataUuid == null) {
1196bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang            return null;
1206bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang        }
1216bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang        return mServiceData.get(serviceDataUuid);
1226d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    }
1236d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
1246d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    /**
1256d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * Returns the transmission power level of the packet in dBm. Returns {@link Integer#MIN_VALUE}
1266d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * if the field is not set. This value can be used to calculate the path loss of a received
1276d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * packet using the following equation:
1286d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * <p>
1296d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * <code>pathloss = txPowerLevel - rssi</code>
1306d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     */
1316d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    public int getTxPowerLevel() {
1326d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        return mTxPowerLevel;
1336d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    }
1346d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
1356d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    /**
1366d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * Returns the local name of the BLE device. The is a UTF-8 encoded string.
1376d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     */
1386d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    @Nullable
139af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang    public String getDeviceName() {
140af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang        return mDeviceName;
1416d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    }
1426d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
143685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang    /**
144685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang     * Returns raw bytes of scan record.
145685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang     */
146685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang    public byte[] getBytes() {
147685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang        return mBytes;
148685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang    }
149685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang
1506d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private ScanRecord(List<ParcelUuid> serviceUuids,
1516bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang            SparseArray<byte[]> manufacturerData,
1526bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang            Map<ParcelUuid, byte[]> serviceData,
1536bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang            int advertiseFlags, int txPowerLevel,
154685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang            String localName, byte[] bytes) {
1556d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        mServiceUuids = serviceUuids;
1566bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang        mManufacturerSpecificData = manufacturerData;
1576d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        mServiceData = serviceData;
158af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang        mDeviceName = localName;
1596d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        mAdvertiseFlags = advertiseFlags;
1606d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        mTxPowerLevel = txPowerLevel;
161685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang        mBytes = bytes;
1626d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    }
1636d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
1646d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    /**
1656d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * Parse scan record bytes to {@link ScanRecord}.
1666d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * <p>
1676d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * The format is defined in Bluetooth 4.1 specification, Volume 3, Part C, Section 11 and 18.
1686d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * <p>
1696d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * All numerical multi-byte entities and values shall use little-endian <strong>byte</strong>
1706d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * order.
1716d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     *
1726d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     * @param scanRecord The scan record of Bluetooth LE advertisement and/or scan response.
173685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang     * @hide
1746d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang     */
1756d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    public static ScanRecord parseFromBytes(byte[] scanRecord) {
1766d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        if (scanRecord == null) {
1776d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            return null;
1786d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        }
1796d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
1806d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        int currentPos = 0;
1816d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        int advertiseFlag = -1;
1826d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
1836d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        String localName = null;
1846d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        int txPowerLevel = Integer.MIN_VALUE;
1856bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang
1866bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang        SparseArray<byte[]> manufacturerData = new SparseArray<byte[]>();
1876bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang        Map<ParcelUuid, byte[]> serviceData = new ArrayMap<ParcelUuid, byte[]>();
1886d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
1896d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        try {
1906d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            while (currentPos < scanRecord.length) {
1916d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                // length is unsigned int.
1926d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                int length = scanRecord[currentPos++] & 0xFF;
1936d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                if (length == 0) {
1946d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    break;
1956d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                }
1966d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                // Note the length includes the length of the field type itself.
1976d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                int dataLength = length - 1;
1986d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                // fieldType is unsigned int.
1996d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                int fieldType = scanRecord[currentPos++] & 0xFF;
2006d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                switch (fieldType) {
2016d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    case DATA_TYPE_FLAGS:
2026d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        advertiseFlag = scanRecord[currentPos] & 0xFF;
2036d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        break;
2046d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    case DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL:
2056d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    case DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE:
2066d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        parseServiceUuid(scanRecord, currentPos,
2076d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                                dataLength, BluetoothUuid.UUID_BYTES_16_BIT, serviceUuids);
2086d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        break;
2096d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    case DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL:
2106d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    case DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE:
2116d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        parseServiceUuid(scanRecord, currentPos, dataLength,
2126d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                                BluetoothUuid.UUID_BYTES_32_BIT, serviceUuids);
2136d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        break;
2146d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    case DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL:
2156d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    case DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE:
2166d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        parseServiceUuid(scanRecord, currentPos, dataLength,
2176d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                                BluetoothUuid.UUID_BYTES_128_BIT, serviceUuids);
2186d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        break;
2196d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    case DATA_TYPE_LOCAL_NAME_SHORT:
2206d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    case DATA_TYPE_LOCAL_NAME_COMPLETE:
2216d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        localName = new String(
2226d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                                extractBytes(scanRecord, currentPos, dataLength));
2236d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        break;
2246d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    case DATA_TYPE_TX_POWER_LEVEL:
2256d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        txPowerLevel = scanRecord[currentPos];
2266d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        break;
2276d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    case DATA_TYPE_SERVICE_DATA:
228ab2ed62f15d0dac0f8ef825ff2d3677c9ae18f44Wei Wang                        // The first two bytes of the service data are service data UUID in little
229ab2ed62f15d0dac0f8ef825ff2d3677c9ae18f44Wei Wang                        // endian. The rest bytes are service data.
2306d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        int serviceUuidLength = BluetoothUuid.UUID_BYTES_16_BIT;
2316d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        byte[] serviceDataUuidBytes = extractBytes(scanRecord, currentPos,
2326d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                                serviceUuidLength);
2336bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang                        ParcelUuid serviceDataUuid = BluetoothUuid.parseUuidFrom(
2346bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang                                serviceDataUuidBytes);
2356bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang                        byte[] serviceDataArray = extractBytes(scanRecord,
2366bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang                                currentPos + serviceUuidLength, dataLength - serviceUuidLength);
2376bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang                        serviceData.put(serviceDataUuid, serviceDataArray);
2386d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        break;
2396d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    case DATA_TYPE_MANUFACTURER_SPECIFIC_DATA:
2406d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        // The first two bytes of the manufacturer specific data are
2416d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        // manufacturer ids in little endian.
2426bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang                        int manufacturerId = ((scanRecord[currentPos + 1] & 0xFF) << 8) +
243ab2ed62f15d0dac0f8ef825ff2d3677c9ae18f44Wei Wang                                (scanRecord[currentPos] & 0xFF);
2446bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang                        byte[] manufacturerDataBytes = extractBytes(scanRecord, currentPos + 2,
245ab2ed62f15d0dac0f8ef825ff2d3677c9ae18f44Wei Wang                                dataLength - 2);
2466bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang                        manufacturerData.put(manufacturerId, manufacturerDataBytes);
2476d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        break;
2486d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    default:
2496d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        // Just ignore, we don't handle such data type.
2506d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                        break;
2516d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                }
2526d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                currentPos += dataLength;
2536d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            }
2546d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
2556d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            if (serviceUuids.isEmpty()) {
2566d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                serviceUuids = null;
2576d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            }
2586bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang            return new ScanRecord(serviceUuids, manufacturerData, serviceData,
2596bf513d32db7fbc157681bd642e12a201cf20a89Wei Wang                    advertiseFlag, txPowerLevel, localName, scanRecord);
260621085e50f59647d745d12488b88c41077d70ee9Prerepa Viswanadham        } catch (Exception e) {
2616d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            Log.e(TAG, "unable to parse scan record: " + Arrays.toString(scanRecord));
262621085e50f59647d745d12488b88c41077d70ee9Prerepa Viswanadham            // As the record is invalid, ignore all the parsed results for this packet
263621085e50f59647d745d12488b88c41077d70ee9Prerepa Viswanadham            // and return an empty record with raw scanRecord bytes in results
264621085e50f59647d745d12488b88c41077d70ee9Prerepa Viswanadham            return new ScanRecord(null, null, null, -1, Integer.MIN_VALUE, null, scanRecord);
2656d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        }
2666d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    }
2676d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
268685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang    @Override
269685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang    public String toString() {
270685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang        return "ScanRecord [mAdvertiseFlags=" + mAdvertiseFlags + ", mServiceUuids=" + mServiceUuids
271833559d9f3f0bd6ddb1cf9c1571975751830e045Wei Wang                + ", mManufacturerSpecificData=" + BluetoothLeUtils.toString(mManufacturerSpecificData)
272833559d9f3f0bd6ddb1cf9c1571975751830e045Wei Wang                + ", mServiceData=" + BluetoothLeUtils.toString(mServiceData)
273685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang                + ", mTxPowerLevel=" + mTxPowerLevel + ", mDeviceName=" + mDeviceName + "]";
274685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang    }
275685c1758902a42a7beb030d8bbaed3f7ce6f6135Wei Wang
276af74e66e29a518157cb78fcef4b4fc532b7f60b0Wei Wang    // Parse service UUIDs.
2776d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private static int parseServiceUuid(byte[] scanRecord, int currentPos, int dataLength,
2786d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            int uuidLength, List<ParcelUuid> serviceUuids) {
2796d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        while (dataLength > 0) {
2806d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            byte[] uuidBytes = extractBytes(scanRecord, currentPos,
2816d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang                    uuidLength);
2826d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            serviceUuids.add(BluetoothUuid.parseUuidFrom(uuidBytes));
2836d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            dataLength -= uuidLength;
2846d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang            currentPos += uuidLength;
2856d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        }
2866d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        return currentPos;
2876d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    }
2886d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang
2896d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    // Helper method to extract bytes from byte array.
2906d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    private static byte[] extractBytes(byte[] scanRecord, int start, int length) {
2916d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        byte[] bytes = new byte[length];
2926d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        System.arraycopy(scanRecord, start, bytes, 0, length);
2936d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang        return bytes;
2946d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang    }
2956d81118032b92caa0f5cfebe11af02a98f819d5eWei Wang}
296