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