Example #1
0
  /**
   * This function checks if the remote device is an AVCRP target and thus whether we should send
   * volume keys changes or not.
   *
   * @hide
   */
  public boolean shouldSendVolumeKeys(BluetoothDevice device) {
    if (isEnabled() && isValidDevice(device)) {
      ParcelUuid[] uuids = device.getUuids();
      if (uuids == null) return false;

      for (ParcelUuid uuid : uuids) {
        if (BluetoothUuid.isAvrcpTarget(uuid)) {
          return true;
        }
      }
    }
    return false;
  }
Example #2
0
 // Parse service UUIDs.
 private static int parseServiceUuid(
     byte[] scanRecord,
     int currentPos,
     int dataLength,
     int uuidLength,
     List<ParcelUuid> serviceUuids) {
   while (dataLength > 0) {
     byte[] uuidBytes = extractBytes(scanRecord, currentPos, uuidLength);
     serviceUuids.add(BluetoothUuid.parseUuidFrom(uuidBytes));
     dataLength -= uuidLength;
     currentPos += uuidLength;
   }
   return currentPos;
 }
Example #3
0
  /**
   * Parse scan record bytes to {@link ScanRecord}.
   *
   * <p>The format is defined in Bluetooth 4.1 specification, Volume 3, Part C, Section 11 and 18.
   *
   * <p>All numerical multi-byte entities and values shall use little-endian <strong>byte</strong>
   * order.
   *
   * @param scanRecord The scan record of Bluetooth LE advertisement and/or scan response.
   * @hide
   */
  public static ScanRecord parseFromBytes(byte[] scanRecord) {
    if (scanRecord == null) {
      return null;
    }

    int currentPos = 0;
    int advertiseFlag = -1;
    List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
    String localName = null;
    int txPowerLevel = Integer.MIN_VALUE;

    SparseArray<byte[]> manufacturerData = new SparseArray<byte[]>();
    Map<ParcelUuid, byte[]> serviceData = new ArrayMap<>();

    try {
      while (currentPos < scanRecord.length) {
        // length is unsigned int.
        int length = scanRecord[currentPos++] & 0xFF;
        if (length == 0) {
          break;
        }
        // Note the length includes the length of the field type itself.
        int dataLength = length - 1;
        // fieldType is unsigned int.
        int fieldType = scanRecord[currentPos++] & 0xFF;
        switch (fieldType) {
          case DATA_TYPE_FLAGS:
            advertiseFlag = scanRecord[currentPos] & 0xFF;
            break;
          case DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL:
          case DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE:
            parseServiceUuid(
                scanRecord, currentPos, dataLength, BluetoothUuid.UUID_BYTES_16_BIT, serviceUuids);
            break;
          case DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL:
          case DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE:
            parseServiceUuid(
                scanRecord, currentPos, dataLength, BluetoothUuid.UUID_BYTES_32_BIT, serviceUuids);
            break;
          case DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL:
          case DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE:
            parseServiceUuid(
                scanRecord, currentPos, dataLength, BluetoothUuid.UUID_BYTES_128_BIT, serviceUuids);
            break;
          case DATA_TYPE_LOCAL_NAME_SHORT:
          case DATA_TYPE_LOCAL_NAME_COMPLETE:
            localName = new String(extractBytes(scanRecord, currentPos, dataLength));
            break;
          case DATA_TYPE_TX_POWER_LEVEL:
            txPowerLevel = scanRecord[currentPos];
            break;
          case DATA_TYPE_SERVICE_DATA:
            // The first two bytes of the service data are service data UUID in little
            // endian. The rest bytes are service data.
            int serviceUuidLength = BluetoothUuid.UUID_BYTES_16_BIT;
            byte[] serviceDataUuidBytes = extractBytes(scanRecord, currentPos, serviceUuidLength);
            ParcelUuid serviceDataUuid = BluetoothUuid.parseUuidFrom(serviceDataUuidBytes);
            byte[] serviceDataArray =
                extractBytes(
                    scanRecord, currentPos + serviceUuidLength, dataLength - serviceUuidLength);
            serviceData.put(serviceDataUuid, serviceDataArray);
            break;
          case DATA_TYPE_MANUFACTURER_SPECIFIC_DATA:
            // The first two bytes of the manufacturer specific data are
            // manufacturer ids in little endian.
            int manufacturerId =
                ((scanRecord[currentPos + 1] & 0xFF) << 8) + (scanRecord[currentPos] & 0xFF);
            byte[] manufacturerDataBytes = extractBytes(scanRecord, currentPos + 2, dataLength - 2);
            manufacturerData.put(manufacturerId, manufacturerDataBytes);
            break;
          default:
            // Just ignore, we don't handle such data type.
            break;
        }
        currentPos += dataLength;
      }

      if (serviceUuids.isEmpty()) {
        serviceUuids = null;
      }
      return new ScanRecord(
          serviceUuids,
          manufacturerData,
          serviceData,
          advertiseFlag,
          txPowerLevel,
          localName,
          scanRecord);
    } catch (Exception e) {
      // Log.e(TAG, "unable to parse scan record: " + Arrays.toString(scanRecord));
      // As the record is invalid, ignore all the parsed results for this packet
      // and return an empty record with raw scanRecord bytes in results
      return new ScanRecord(null, null, null, -1, Integer.MIN_VALUE, null, scanRecord);
    }
  }