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