• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.bluetooth.le;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SuppressLint;
23 import android.annotation.SystemApi;
24 import android.bluetooth.BluetoothUuid;
25 import android.compat.annotation.UnsupportedAppUsage;
26 import android.os.ParcelUuid;
27 import android.util.ArrayMap;
28 import android.util.Log;
29 import android.util.SparseArray;
30 
31 import java.lang.annotation.Retention;
32 import java.lang.annotation.RetentionPolicy;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.function.Predicate;
39 
40 /**
41  * Represents a scan record from Bluetooth LE scan.
42  */
43 @SuppressLint("AndroidFrameworkBluetoothPermission")
44 public final class ScanRecord {
45 
46     private static final String TAG = "ScanRecord";
47 
48     /** @hide */
49     @IntDef(prefix = "DATA_TYPE_", value = {
50         DATA_TYPE_FLAGS,
51         DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL,
52         DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE,
53         DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL,
54         DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE,
55         DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL,
56         DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE,
57         DATA_TYPE_LOCAL_NAME_SHORT,
58         DATA_TYPE_LOCAL_NAME_COMPLETE,
59         DATA_TYPE_TX_POWER_LEVEL,
60         DATA_TYPE_CLASS_OF_DEVICE,
61         DATA_TYPE_SIMPLE_PAIRING_HASH_C,
62         DATA_TYPE_SIMPLE_PAIRING_RANDOMIZER_R,
63         DATA_TYPE_DEVICE_ID,
64         DATA_TYPE_SECURITY_MANAGER_OUT_OF_BAND_FLAGS,
65         DATA_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE,
66         DATA_TYPE_SERVICE_SOLICITATION_UUIDS_16_BIT,
67         DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT,
68         DATA_TYPE_SERVICE_DATA_16_BIT,
69         DATA_TYPE_PUBLIC_TARGET_ADDRESS,
70         DATA_TYPE_RANDOM_TARGET_ADDRESS,
71         DATA_TYPE_APPEARANCE,
72         DATA_TYPE_ADVERTISING_INTERVAL,
73         DATA_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS,
74         DATA_TYPE_LE_ROLE,
75         DATA_TYPE_SIMPLE_PAIRING_HASH_C_256,
76         DATA_TYPE_SIMPLE_PAIRING_RANDOMIZER_R_256,
77         DATA_TYPE_SERVICE_SOLICITATION_UUIDS_32_BIT,
78         DATA_TYPE_SERVICE_DATA_32_BIT,
79         DATA_TYPE_SERVICE_DATA_128_BIT,
80         DATA_TYPE_LE_SECURE_CONNECTIONS_CONFIRMATION_VALUE,
81         DATA_TYPE_LE_SECURE_CONNECTIONS_RANDOM_VALUE,
82         DATA_TYPE_URI,
83         DATA_TYPE_INDOOR_POSITIONING,
84         DATA_TYPE_TRANSPORT_DISCOVERY_DATA,
85         DATA_TYPE_LE_SUPPORTED_FEATURES,
86         DATA_TYPE_CHANNEL_MAP_UPDATE_INDICATION,
87         DATA_TYPE_PB_ADV,
88         DATA_TYPE_MESH_MESSAGE,
89         DATA_TYPE_MESH_BEACON,
90         DATA_TYPE_BIG_INFO,
91         DATA_TYPE_BROADCAST_CODE,
92         DATA_TYPE_RESOLVABLE_SET_IDENTIFIER,
93         DATA_TYPE_ADVERTISING_INTERVAL_LONG,
94         DATA_TYPE_3D_INFORMATION_DATA,
95         DATA_TYPE_MANUFACTURER_SPECIFIC_DATA,
96     })
97     @Retention(RetentionPolicy.SOURCE)
98     public @interface AdvertisingDataType {}
99 
100     /**
101      * Data type is not set for the filter. Will not filter advertising data type.
102      */
103     public static final int DATA_TYPE_NONE = -1;
104     /**
105      * Data type is Flags, see the Bluetooth Generic Access Profile for more details.
106      */
107     public static final int DATA_TYPE_FLAGS = 0x01;
108     /**
109      * Data type is Incomplete List of 16-bit Service Class UUIDs, see the Bluetooth Generic Access
110      * Profile for the details.
111      */
112     public static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL = 0x02;
113     /**
114      * Data type is Complete List of 16-bit Service Class UUIDs, see the Bluetooth Generic Access
115      * Profile for more details.
116      */
117     public static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE = 0x03;
118     /**
119      * Data type is Incomplete List of 32-bit Service Class UUIDs, see the Bluetooth Generic Access
120      * Profile for the details.
121      */
122     public static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL = 0x04;
123     /**
124      * Data type is Complete List of 32-bit Service Class UUIDs, see the Bluetooth Generic Access
125      * Profile for more details.
126      */
127     public static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE = 0x05;
128     /**
129      * Data type is Incomplete List of 128-bit Service Class UUIDs, see the Bluetooth Generic Access
130      * Profile for the details.
131      */
132     public static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL = 0x06;
133     /**
134      * Data type is Complete List of 128-bit Service Class UUIDs, see the Bluetooth Generic Access
135      * Profile for more details.
136      */
137     public static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE = 0x07;
138     /**
139      * Data type is Shortened Local Name, see the Bluetooth Generic Access Profile for more details.
140      */
141     public static final int DATA_TYPE_LOCAL_NAME_SHORT = 0x08;
142     /**
143      * Data type is Complete Local Name, see the Bluetooth Generic Access Profile for more details.
144      */
145     public static final int DATA_TYPE_LOCAL_NAME_COMPLETE = 0x09;
146     /**
147      * Data type is Tx Power Level, see the Bluetooth Generic Access Profile for more details.
148      */
149     public static final int DATA_TYPE_TX_POWER_LEVEL = 0x0A;
150     /**
151      * Data type is Class of Device, see the Bluetooth Generic Access Profile for more details.
152      */
153     public static final int DATA_TYPE_CLASS_OF_DEVICE = 0x0D;
154     /**
155      * Data type is Simple Pairing Hash C, see the Bluetooth Generic Access Profile for more
156      * details.
157      */
158     public static final int DATA_TYPE_SIMPLE_PAIRING_HASH_C = 0x0E;
159     /**
160      * Data type is Simple Pairing Randomizer R, see the Bluetooth Generic Access Profile for more
161      * details.
162      */
163     public static final int DATA_TYPE_SIMPLE_PAIRING_RANDOMIZER_R = 0x0F;
164     /**
165      * Data type is Device ID, see the Bluetooth Generic Access Profile for more details.
166      */
167     public static final int DATA_TYPE_DEVICE_ID = 0x10;
168     /**
169      * Data type is Security Manager Out of Band Flags, see the Bluetooth Generic Access Profile for
170      * more details.
171      */
172     public static final int DATA_TYPE_SECURITY_MANAGER_OUT_OF_BAND_FLAGS = 0x11;
173     /**
174      * Data type is Slave Connection Interval Range, see the Bluetooth Generic Access Profile for
175      * more details.
176      */
177     public static final int DATA_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE = 0x12;
178     /**
179      * Data type is List of 16-bit Service Solicitation UUIDs, see the Bluetooth Generic Access
180      * Profile for more details.
181      */
182     public static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_16_BIT = 0x14;
183     /**
184      * Data type is List of 128-bit Service Solicitation UUIDs, see the Bluetooth Generic Access
185      * Profile for more details.
186      */
187     public static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT = 0x15;
188     /**
189      * Data type is Service Data - 16-bit UUID, see the Bluetooth Generic Access Profile for more
190      * details.
191      */
192     public static final int DATA_TYPE_SERVICE_DATA_16_BIT = 0x16;
193     /**
194      * Data type is Public Target Address, see the Bluetooth Generic Access Profile for more
195      * details.
196      */
197     public static final int DATA_TYPE_PUBLIC_TARGET_ADDRESS = 0x17;
198     /**
199      * Data type is Random Target Address, see the Bluetooth Generic Access Profile for more
200      * details.
201      */
202     public static final int DATA_TYPE_RANDOM_TARGET_ADDRESS = 0x18;
203     /**
204      * Data type is Appearance, see the Bluetooth Generic Access Profile for more details.
205      */
206     public static final int DATA_TYPE_APPEARANCE = 0x19;
207     /**
208      * Data type is Advertising Interval, see the Bluetooth Generic Access Profile for more details.
209      */
210     public static final int DATA_TYPE_ADVERTISING_INTERVAL = 0x1A;
211     /**
212      * Data type is LE Bluetooth Device Address, see the Bluetooth Generic Access Profile for more
213      * details.
214      */
215     public static final int DATA_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS = 0x1B;
216     /**
217      * Data type is LE Role, see the Bluetooth Generic Access Profile for more details.
218      */
219     public static final int DATA_TYPE_LE_ROLE = 0x1C;
220     /**
221      * Data type is Simple Pairing Hash C-256, see the Bluetooth Generic Access Profile for more
222      * details.
223      */
224     public static final int DATA_TYPE_SIMPLE_PAIRING_HASH_C_256 = 0x1D;
225     /**
226      * Data type is Simple Pairing Randomizer R-256, see the Bluetooth Generic Access Profile for
227      * more details.
228      */
229     public static final int DATA_TYPE_SIMPLE_PAIRING_RANDOMIZER_R_256 = 0x1E;
230     /**
231      * Data type is List of 32-bit Service Solicitation UUIDs, see the Bluetooth Generic Access
232      * Profile for more details.
233      */
234     public static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_32_BIT = 0x1F;
235     /**
236      * Data type is Service Data - 32-bit UUID, see the Bluetooth Generic Access Profile for more
237      * details.
238      */
239     public static final int DATA_TYPE_SERVICE_DATA_32_BIT = 0x20;
240     /**
241      * Data type is Service Data - 128-bit UUID, see the Bluetooth Generic Access Profile for more
242      * details.
243      */
244     public static final int DATA_TYPE_SERVICE_DATA_128_BIT = 0x21;
245     /**
246      * Data type is LE Secure Connections Confirmation Value, see the Bluetooth Generic Access
247      * Profile for more details.
248      */
249     public static final int DATA_TYPE_LE_SECURE_CONNECTIONS_CONFIRMATION_VALUE = 0x22;
250     /**
251      * Data type is LE Secure Connections Random Value, see the Bluetooth Generic Access Profile for
252      * more details.
253      */
254     public static final int DATA_TYPE_LE_SECURE_CONNECTIONS_RANDOM_VALUE = 0x23;
255     /**
256      * Data type is URI, see the Bluetooth Generic Access Profile for more details.
257      */
258     public static final int DATA_TYPE_URI = 0x24;
259     /**
260      * Data type is Indoor Positioning, see the Bluetooth Generic Access Profile for more details.
261      */
262     public static final int DATA_TYPE_INDOOR_POSITIONING = 0x25;
263     /**
264      * Data type is Transport Discovery Data, see the Bluetooth Generic Access Profile for more
265      * details.
266      */
267     public static final int DATA_TYPE_TRANSPORT_DISCOVERY_DATA = 0x26;
268     /**
269      * Data type is LE Supported Features, see the Bluetooth Generic Access Profile for more
270      * details.
271      */
272     public static final int DATA_TYPE_LE_SUPPORTED_FEATURES = 0x27;
273     /**
274      * Data type is Channel Map Update Indication, see the Bluetooth Generic Access Profile for more
275      * details.
276      */
277     public static final int DATA_TYPE_CHANNEL_MAP_UPDATE_INDICATION = 0x28;
278     /**
279      * Data type is PB-ADV, see the Bluetooth Generic Access Profile for more details.
280      */
281     public static final int DATA_TYPE_PB_ADV = 0x29;
282     /**
283      * Data type is Mesh Message, see the Bluetooth Generic Access Profile for more details.
284      */
285     public static final int DATA_TYPE_MESH_MESSAGE = 0x2A;
286     /**
287      * Data type is Mesh Beacon, see the Bluetooth Generic Access Profile for more details.
288      */
289     public static final int DATA_TYPE_MESH_BEACON = 0x2B;
290     /**
291      * Data type is BIGInfo, see the Bluetooth Generic Access Profile for more details.
292      */
293     public static final int DATA_TYPE_BIG_INFO = 0x2C;
294     /**
295      * Data type is Broadcast_Code, see the Bluetooth Generic Access Profile for more details.
296      */
297     public static final int DATA_TYPE_BROADCAST_CODE = 0x2D;
298     /**
299      * Data type is Resolvable Set Identifier, see the Bluetooth Generic Access Profile for more
300      * details.
301      */
302     public static final int DATA_TYPE_RESOLVABLE_SET_IDENTIFIER = 0x2E;
303     /**
304      * Data type is Advertising Interval - long, see the Bluetooth Generic Access Profile for more
305      * details.
306      */
307     public static final int DATA_TYPE_ADVERTISING_INTERVAL_LONG = 0x2F;
308     /**
309      * Data type is 3D Information Data, see the Bluetooth Generic Access Profile for more details.
310      */
311     public static final int DATA_TYPE_3D_INFORMATION_DATA = 0x3D;
312     /**
313      * Data type is Manufacturer Specific Data, see the Bluetooth Generic Access Profile for more
314      * details.
315      */
316     public static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;
317 
318     // Flags of the advertising data.
319     private final int mAdvertiseFlags;
320 
321     @Nullable
322     private final List<ParcelUuid> mServiceUuids;
323     @Nullable
324     private final List<ParcelUuid> mServiceSolicitationUuids;
325 
326     private final SparseArray<byte[]> mManufacturerSpecificData;
327 
328     private final Map<ParcelUuid, byte[]> mServiceData;
329 
330     // Transmission power level(in dB).
331     private final int mTxPowerLevel;
332 
333     // Local name of the Bluetooth LE device.
334     private final String mDeviceName;
335 
336     // Raw bytes of scan record.
337     private final byte[] mBytes;
338 
339     private final HashMap<Integer, byte[]> mAdvertisingDataMap;
340 
341     // Transport Discovery data.
342     private final TransportDiscoveryData mTransportDiscoveryData;
343 
344     /**
345      * Returns the advertising flags indicating the discoverable mode and capability of the device.
346      * Returns -1 if the flag field is not set.
347      */
getAdvertiseFlags()348     public int getAdvertiseFlags() {
349         return mAdvertiseFlags;
350     }
351 
352     /**
353      * Returns a list of service UUIDs within the advertisement that are used to identify the
354      * bluetooth GATT services.
355      */
getServiceUuids()356     public List<ParcelUuid> getServiceUuids() {
357         return mServiceUuids;
358     }
359 
360     /**
361      * Returns a list of service solicitation UUIDs within the advertisement that are used to
362      * identify the Bluetooth GATT services.
363      */
364     @NonNull
getServiceSolicitationUuids()365     public List<ParcelUuid> getServiceSolicitationUuids() {
366         return mServiceSolicitationUuids;
367     }
368 
369     /**
370      * Returns a sparse array of manufacturer identifier and its corresponding manufacturer specific
371      * data.
372      */
getManufacturerSpecificData()373     public SparseArray<byte[]> getManufacturerSpecificData() {
374         return mManufacturerSpecificData;
375     }
376 
377     /**
378      * Returns the manufacturer specific data associated with the manufacturer id. Returns
379      * {@code null} if the {@code manufacturerId} is not found.
380      */
381     @Nullable
getManufacturerSpecificData(int manufacturerId)382     public byte[] getManufacturerSpecificData(int manufacturerId) {
383         if (mManufacturerSpecificData == null) {
384             return null;
385         }
386         return mManufacturerSpecificData.get(manufacturerId);
387     }
388 
389     /**
390      * Returns a map of service UUID and its corresponding service data.
391      */
getServiceData()392     public Map<ParcelUuid, byte[]> getServiceData() {
393         return mServiceData;
394     }
395 
396     /**
397      * Returns the service data byte array associated with the {@code serviceUuid}. Returns
398      * {@code null} if the {@code serviceDataUuid} is not found.
399      */
400     @Nullable
getServiceData(ParcelUuid serviceDataUuid)401     public byte[] getServiceData(ParcelUuid serviceDataUuid) {
402         if (serviceDataUuid == null || mServiceData == null) {
403             return null;
404         }
405         return mServiceData.get(serviceDataUuid);
406     }
407 
408     /**
409      * Returns the transmission power level of the packet in dBm. Returns {@link Integer#MIN_VALUE}
410      * if the field is not set. This value can be used to calculate the path loss of a received
411      * packet using the following equation:
412      * <p>
413      * <code>pathloss = txPowerLevel - rssi</code>
414      */
getTxPowerLevel()415     public int getTxPowerLevel() {
416         return mTxPowerLevel;
417     }
418 
419     /**
420      * Returns the local name of the BLE device. This is a UTF-8 encoded string.
421      */
422     @Nullable
getDeviceName()423     public String getDeviceName() {
424         return mDeviceName;
425     }
426 
427 
428     /**
429      * Returns a map of advertising data type and its corresponding advertising data.
430      * The values of advertising data type are defined in the Bluetooth Generic Access Profile
431      * (https://www.bluetooth.com/specifications/assigned-numbers/)
432      */
getAdvertisingDataMap()433     public @NonNull Map<Integer, byte[]> getAdvertisingDataMap() {
434         return mAdvertisingDataMap;
435     }
436 
437     /**
438      * Returns Transport Discovery data, {@code null} if Transport Discovery data is not found.
439      *
440      * @hide
441      */
442     @SystemApi
443     @Nullable
getTransportDiscoveryData()444     public TransportDiscoveryData getTransportDiscoveryData() {
445         return mTransportDiscoveryData;
446     }
447 
448     /**
449      * Returns raw bytes of scan record.
450      */
getBytes()451     public byte[] getBytes() {
452         return mBytes;
453     }
454 
455     /**
456      * Test if any fields contained inside this scan record are matched by the
457      * given matcher.
458      *
459      * @hide
460      */
matchesAnyField(@onNull Predicate<byte[]> matcher)461     public boolean matchesAnyField(@NonNull Predicate<byte[]> matcher) {
462         int pos = 0;
463         while (pos < mBytes.length) {
464             final int length = mBytes[pos] & 0xFF;
465             if (length == 0) {
466                 break;
467             }
468             if (matcher.test(Arrays.copyOfRange(mBytes, pos, pos + length + 1))) {
469                 return true;
470             }
471             pos += length + 1;
472         }
473         return false;
474     }
475 
ScanRecord(List<ParcelUuid> serviceUuids, List<ParcelUuid> serviceSolicitationUuids, SparseArray<byte[]> manufacturerData, Map<ParcelUuid, byte[]> serviceData, int advertiseFlags, int txPowerLevel, String localName, HashMap<Integer, byte[]> advertisingDataMap, TransportDiscoveryData transportDiscoveryData, byte[] bytes)476     private ScanRecord(List<ParcelUuid> serviceUuids,
477             List<ParcelUuid> serviceSolicitationUuids,
478             SparseArray<byte[]> manufacturerData,
479             Map<ParcelUuid, byte[]> serviceData,
480             int advertiseFlags, int txPowerLevel,
481             String localName, HashMap<Integer, byte[]> advertisingDataMap,
482             TransportDiscoveryData transportDiscoveryData, byte[] bytes) {
483         mServiceSolicitationUuids = serviceSolicitationUuids;
484         mServiceUuids = serviceUuids;
485         mManufacturerSpecificData = manufacturerData;
486         mServiceData = serviceData;
487         mDeviceName = localName;
488         mAdvertiseFlags = advertiseFlags;
489         mTxPowerLevel = txPowerLevel;
490         mAdvertisingDataMap = advertisingDataMap;
491         mTransportDiscoveryData = transportDiscoveryData;
492         mBytes = bytes;
493     }
494 
495     /**
496      * Parse scan record bytes to {@link ScanRecord}.
497      * <p>
498      * The format is defined in Bluetooth 4.1 specification, Volume 3, Part C, Section 11 and 18.
499      * <p>
500      * All numerical multi-byte entities and values shall use little-endian <strong>byte</strong>
501      * order.
502      *
503      * @param scanRecord The scan record of Bluetooth LE advertisement and/or scan response.
504      * @hide
505      */
506     @UnsupportedAppUsage
parseFromBytes(byte[] scanRecord)507     public static ScanRecord parseFromBytes(byte[] scanRecord) {
508         if (scanRecord == null) {
509             return null;
510         }
511 
512         int currentPos = 0;
513         int advertiseFlag = -1;
514         List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
515         List<ParcelUuid> serviceSolicitationUuids = new ArrayList<ParcelUuid>();
516         String localName = null;
517         int txPowerLevel = Integer.MIN_VALUE;
518 
519         SparseArray<byte[]> manufacturerData = new SparseArray<byte[]>();
520         Map<ParcelUuid, byte[]> serviceData = new ArrayMap<ParcelUuid, byte[]>();
521         HashMap<Integer, byte[]> advertisingDataMap = new HashMap<Integer, byte[]>();
522 
523         TransportDiscoveryData transportDiscoveryData = null;
524 
525         try {
526             while (currentPos < scanRecord.length) {
527                 // length is unsigned int.
528                 int length = scanRecord[currentPos++] & 0xFF;
529                 if (length == 0) {
530                     break;
531                 }
532                 // Note the length includes the length of the field type itself.
533                 int dataLength = length - 1;
534                 // fieldType is unsigned int.
535                 int fieldType = scanRecord[currentPos++] & 0xFF;
536                 byte[] advertisingData = extractBytes(scanRecord, currentPos, dataLength);
537                 advertisingDataMap.put(fieldType, advertisingData);
538                 switch (fieldType) {
539                     case DATA_TYPE_FLAGS:
540                         advertiseFlag = scanRecord[currentPos] & 0xFF;
541                         break;
542                     case DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL:
543                     case DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE:
544                         parseServiceUuid(scanRecord, currentPos,
545                                 dataLength, BluetoothUuid.UUID_BYTES_16_BIT, serviceUuids);
546                         break;
547                     case DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL:
548                     case DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE:
549                         parseServiceUuid(scanRecord, currentPos, dataLength,
550                                 BluetoothUuid.UUID_BYTES_32_BIT, serviceUuids);
551                         break;
552                     case DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL:
553                     case DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE:
554                         parseServiceUuid(scanRecord, currentPos, dataLength,
555                                 BluetoothUuid.UUID_BYTES_128_BIT, serviceUuids);
556                         break;
557                     case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_16_BIT:
558                         parseServiceSolicitationUuid(scanRecord, currentPos, dataLength,
559                                 BluetoothUuid.UUID_BYTES_16_BIT, serviceSolicitationUuids);
560                         break;
561                     case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_32_BIT:
562                         parseServiceSolicitationUuid(scanRecord, currentPos, dataLength,
563                                 BluetoothUuid.UUID_BYTES_32_BIT, serviceSolicitationUuids);
564                         break;
565                     case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT:
566                         parseServiceSolicitationUuid(scanRecord, currentPos, dataLength,
567                                 BluetoothUuid.UUID_BYTES_128_BIT, serviceSolicitationUuids);
568                         break;
569                     case DATA_TYPE_LOCAL_NAME_SHORT:
570                     case DATA_TYPE_LOCAL_NAME_COMPLETE:
571                         localName = new String(
572                                 extractBytes(scanRecord, currentPos, dataLength));
573                         break;
574                     case DATA_TYPE_TX_POWER_LEVEL:
575                         txPowerLevel = scanRecord[currentPos];
576                         break;
577                     case DATA_TYPE_SERVICE_DATA_16_BIT:
578                     case DATA_TYPE_SERVICE_DATA_32_BIT:
579                     case DATA_TYPE_SERVICE_DATA_128_BIT:
580                         int serviceUuidLength = BluetoothUuid.UUID_BYTES_16_BIT;
581                         if (fieldType == DATA_TYPE_SERVICE_DATA_32_BIT) {
582                             serviceUuidLength = BluetoothUuid.UUID_BYTES_32_BIT;
583                         } else if (fieldType == DATA_TYPE_SERVICE_DATA_128_BIT) {
584                             serviceUuidLength = BluetoothUuid.UUID_BYTES_128_BIT;
585                         }
586 
587                         byte[] serviceDataUuidBytes = extractBytes(scanRecord, currentPos,
588                                 serviceUuidLength);
589                         ParcelUuid serviceDataUuid = BluetoothUuid.parseUuidFrom(
590                                 serviceDataUuidBytes);
591                         byte[] serviceDataArray = extractBytes(scanRecord,
592                                 currentPos + serviceUuidLength, dataLength - serviceUuidLength);
593                         serviceData.put(serviceDataUuid, serviceDataArray);
594                         break;
595                     case DATA_TYPE_MANUFACTURER_SPECIFIC_DATA:
596                         // The first two bytes of the manufacturer specific data are
597                         // manufacturer ids in little endian.
598                         int manufacturerId = ((scanRecord[currentPos + 1] & 0xFF) << 8)
599                                 + (scanRecord[currentPos] & 0xFF);
600                         byte[] manufacturerDataBytes = extractBytes(scanRecord, currentPos + 2,
601                                 dataLength - 2);
602                         manufacturerData.put(manufacturerId, manufacturerDataBytes);
603                         break;
604                     case DATA_TYPE_TRANSPORT_DISCOVERY_DATA:
605                         // -1 / +1 to include the type in the extract
606                         byte[] transportDiscoveryDataBytes =
607                                 extractBytes(scanRecord, currentPos - 1, dataLength + 1);
608                         transportDiscoveryData =
609                                 new TransportDiscoveryData(transportDiscoveryDataBytes);
610                         break;
611 
612                     default:
613                         // Just ignore, we don't handle such data type.
614                         break;
615                 }
616                 currentPos += dataLength;
617             }
618 
619             if (serviceUuids.isEmpty()) {
620                 serviceUuids = null;
621             }
622             return new ScanRecord(serviceUuids, serviceSolicitationUuids, manufacturerData,
623                     serviceData, advertiseFlag, txPowerLevel, localName, advertisingDataMap,
624                     transportDiscoveryData, scanRecord);
625         } catch (Exception e) {
626             Log.e(TAG, "unable to parse scan record: " + Arrays.toString(scanRecord));
627             // As the record is invalid, ignore all the parsed results for this packet
628             // and return an empty record with raw scanRecord bytes in results
629             return new ScanRecord(null, null, null, null, -1, Integer.MIN_VALUE, null,
630                     advertisingDataMap, null, scanRecord);
631         }
632     }
633 
634     @Override
toString()635     public String toString() {
636         return "ScanRecord [mAdvertiseFlags=" + mAdvertiseFlags + ", mServiceUuids=" + mServiceUuids
637                 + ", mServiceSolicitationUuids=" + mServiceSolicitationUuids
638                 + ", mManufacturerSpecificData="
639                 + BluetoothLeUtils.toString(mManufacturerSpecificData)
640                 + ", mServiceData=" + BluetoothLeUtils.toString(mServiceData)
641                 + ", mTxPowerLevel=" + mTxPowerLevel + ", mDeviceName=" + mDeviceName
642                 + ", mTransportDiscoveryData=" + mTransportDiscoveryData + "]";
643     }
644 
645     // Parse service UUIDs.
parseServiceUuid(byte[] scanRecord, int currentPos, int dataLength, int uuidLength, List<ParcelUuid> serviceUuids)646     private static int parseServiceUuid(byte[] scanRecord, int currentPos, int dataLength,
647             int uuidLength, List<ParcelUuid> serviceUuids) {
648         while (dataLength > 0) {
649             byte[] uuidBytes = extractBytes(scanRecord, currentPos,
650                     uuidLength);
651             serviceUuids.add(BluetoothUuid.parseUuidFrom(uuidBytes));
652             dataLength -= uuidLength;
653             currentPos += uuidLength;
654         }
655         return currentPos;
656     }
657 
658     /**
659      * Parse service Solicitation UUIDs.
660      */
parseServiceSolicitationUuid(byte[] scanRecord, int currentPos, int dataLength, int uuidLength, List<ParcelUuid> serviceSolicitationUuids)661     private static int parseServiceSolicitationUuid(byte[] scanRecord, int currentPos,
662             int dataLength, int uuidLength, List<ParcelUuid> serviceSolicitationUuids) {
663         while (dataLength > 0) {
664             byte[] uuidBytes = extractBytes(scanRecord, currentPos, uuidLength);
665             serviceSolicitationUuids.add(BluetoothUuid.parseUuidFrom(uuidBytes));
666             dataLength -= uuidLength;
667             currentPos += uuidLength;
668         }
669         return currentPos;
670     }
671 
672     // Helper method to extract bytes from byte array.
extractBytes(byte[] scanRecord, int start, int length)673     private static byte[] extractBytes(byte[] scanRecord, int start, int length) {
674         byte[] bytes = new byte[length];
675         System.arraycopy(scanRecord, start, bytes, 0, length);
676         return bytes;
677     }
678 }
679