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