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