【问题标题】:RxAndroidBle - RxBleDevice getName() always returns nullRxAndroidBle - RxBleDevice getName() 总是返回 null
【发布时间】:2017-07-05 11:21:40
【问题描述】:

有以下代码

rxBleClient = RxBleClient.create(this);
        scanSubscription = rxBleClient.scanBleDevices(
                new ScanSettings.Builder()
                        .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
                        .build())
                .subscribe(new Observer<ScanResult>() {
                               @Override
                               public void onCompleted() {
                                   Log.d(TAG_BT, "Scan completed");
                               }

                               @Override
                               public void onError(Throwable e) {
                                   Log.d(TAG_BT, "Scan onError", e);
                               }

                               @Override
                               public void onNext(ScanResult scanResult) {
                                   RxBleDevice device = scanResult.getBleDevice();
                                   Log.d(TAG_BT, "Scan - " + device.getName());
                                   if (device.getName() != null &&
                                           device.getName().contains(
                                                   SMParameters.SM_BLUETOOTH_SSID_PREFIX)) {
                                       connectToDevice(device);
                                   }
                               }
                           }
                );

我在每个 onNext() 事件中得到的结果如下:

07-05 13:06:24.065 24390-24390/com.example.app D/TAG_BT: Scan - null
07-05 13:06:24.416 24390-24390/com.example.app D/TAG_BT: Scan - null
07-05 13:06:25.670 24390-24390/com.example.app D/TAG_BT: Scan - null
07-05 13:06:25.706 24390-24390/com.example.app D/TAG_BT: Scan - null
07-05 13:06:26.930 24390-24390/com.example.app D/TAG_BT: Scan - null
07-05 13:08:18.339 26550-26550/com.example.app D/TAG_BT: Scan - null
07-05 13:08:19.567 26550-26550/com.example.app D/TAG_BT: Scan - null
07-05 13:08:24.810 26550-26550/com.example.app D/TAG_BT: Scan - null
07-05 13:08:25.981 26550-26550/com.example.app D/TAG_BT: Scan - null
07-05 13:08:26.024 26550-26550/com.example.app D/TAG_BT: Scan - null
07-05 13:08:26.027 26550-26550/com.example.app D/TAG_BT: Scan - null
07-05 13:08:26.029 26550-26550/com.example.app D/TAG_BT: Scan - null
07-05 13:08:26.042 26550-26550/com.example.app D/TAG_BT: Scan - null
07-05 13:08:26.098 26550-26550/com.example.app D/TAG_BT: Scan - null
07-05 13:08:26.101 26550-26550/com.example.app D/TAG_BT: Scan - null
07-05 13:08:26.123 26550-26550/com.example.app D/TAG_BT: Scan - null
07-05 13:08:26.130 26550-26550/com.example.app D/TAG_BT: Scan - null
07-05 13:08:27.246 26550-26550/com.example.app D/TAG_BT: Scan - null
07-05 13:08:28.508 26550-26550/com.example.app D/TAG_BT: Scan - null

我是否遗漏了任何配置参数?不会抛出任何错误,所以如果有人有任何线索......

谢谢!

【问题讨论】:

    标签: android android-bluetooth rx-android rxandroidble


    【解决方案1】:

    BluetoothDevice 可能有一个null 名称,如果它没有被广播。您也可以从scanResult.getScanRecord().getDeviceName() 中查找名称,但也可以是null

    这个问题已经回答了 herehere

    【讨论】:

    • 阅读了这些答案,但由于这是一个包含蓝牙逻辑的库,它可能包含某种错误或错过配置。不管怎么说,还是要谢谢你。将密切关注 getScanRecord()
    • 库的源是开放的——你可以自己检查错误。
    【解决方案2】:

    我从 SDK 版本 27 复制了 android 源代码。并稍作更改。它的工作。

    public String getDeviceName(byte[] scanRecodeBytes){
        ScanRecord scanRecode = ScanRecord.parseFromBytes(scanRecodeBytes);
        return scanRecode.getDeviceName();
    }
    
    class ScanRecord {
    
    private static final String TAG = "ScanRecord";
    private static final int DATA_TYPE_FLAGS = 0x01;
    private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL = 0x02;
    private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE = 0x03;
    private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL = 0x04;
    private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE = 0x05;
    private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL = 0x06;
    private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE = 0x07;
    private static final int DATA_TYPE_LOCAL_NAME_SHORT = 0x08;
    private static final int DATA_TYPE_LOCAL_NAME_COMPLETE = 0x09;
    private static final int DATA_TYPE_TX_POWER_LEVEL = 0x0A;
    private static final int DATA_TYPE_SERVICE_DATA_16_BIT = 0x16;
    private static final int DATA_TYPE_SERVICE_DATA_32_BIT = 0x20;
    private static final int DATA_TYPE_SERVICE_DATA_128_BIT = 0x21;
    private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;
    
    /**
     * Flags of the advertising data.
     */
    private final int mAdvertiseFlags;
    
    @Nullable
    private final List<ParcelUuid> mServiceUuids;
    
    private final SparseArray<byte[]> mManufacturerSpecificData;
    
    private final Map<ParcelUuid, byte[]> mServiceData;
    private final int mTxPowerLevel;
    private final String mDeviceName;
    private final byte[] mBytes;
    int getAdvertiseFlags() {
        return mAdvertiseFlags;
    }
    List<ParcelUuid> getServiceUuids() {
        return mServiceUuids;
    }
    
    /**
     * Returns a sparse array of manufacturer identifier and its corresponding manufacturer specific
     * data.
     */
    SparseArray<byte[]> getManufacturerSpecificData() {
        return mManufacturerSpecificData;
    }
    
    /**
     * Returns the manufacturer specific data associated with the manufacturer id. Returns
     * {@code null} if the {@code manufacturerId} is not found.
     */
    @Nullable
    byte[] getManufacturerSpecificData(int manufacturerId) {
        return mManufacturerSpecificData.get(manufacturerId);
    }
    
    /**
     * Returns a map of service UUID and its corresponding service data.
     */
    Map<ParcelUuid, byte[]> getServiceData() {
        return mServiceData;
    }
    
    /**
     * Returns the service data byte array associated with the {@code serviceUuid}. Returns
     * {@code null} if the {@code serviceDataUuid} is not found.
     */
    @Nullable
    byte[] getServiceData(ParcelUuid serviceDataUuid) {
        if (serviceDataUuid == null) {
            return null;
        }
        return mServiceData.get(serviceDataUuid);
    }
    
    /**
     * Returns the transmission power level of the packet in dBm. Returns {@link Integer#MIN_VALUE}
     * if the field is not set. This value can be used to calculate the path loss of a received
     * packet using the following equation:
     * <p>
     * <code>pathloss = txPowerLevel - rssi</code>
     */
    int getTxPowerLevel() {
        return mTxPowerLevel;
    }
    
    /**
     * Returns the local name of the BLE device. The is a UTF-8 encoded string.
     */
    @Nullable
    String getDeviceName() {
        return mDeviceName;
    }
    
    /**
     * Returns raw bytes of scan record.
     */
    byte[] getBytes() {
        return mBytes;
    }
    
    private ScanRecord(@Nullable List<ParcelUuid> serviceUuids,
                       SparseArray<byte[]> manufacturerData,
                       Map<ParcelUuid, byte[]> serviceData,
                       int advertiseFlags, int txPowerLevel,
                       String localName, byte[] bytes) {
        mServiceUuids = serviceUuids;
        mManufacturerSpecificData = manufacturerData;
        mServiceData = serviceData;
        mDeviceName = localName;
        mAdvertiseFlags = advertiseFlags;
        mTxPowerLevel = txPowerLevel;
        mBytes = bytes;
    }
    
    /**
     * Parse scan record bytes to {@link android.bluetooth.le.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.
     */
    static ScanRecord parseFromBytes(byte[] scanRecord) {
        if (scanRecord == null) {
            return null;
        }
    
        int currentPos = 0;
        int advertiseFlag = -1;
        List<ParcelUuid> serviceUuids = new ArrayList<>();
        String localName = null;
        int txPowerLevel = Integer.MIN_VALUE;
    
        SparseArray<byte[]> manufacturerData = new SparseArray<>();
        Map<ParcelUuid, byte[]> serviceData = new HashMap<>(5);
    
        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;
                ParseData parseData = new ParseData(scanRecord, currentPos, advertiseFlag, serviceUuids, localName, txPowerLevel, manufacturerData, serviceData, dataLength, fieldType).invoke();
                advertiseFlag = parseData.getAdvertiseFlag();
                localName = parseData.getLocalName();
                txPowerLevel = parseData.getTxPowerLevel();
                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);
        }
    }
    
    @Override
    public String toString() {
        return "ScanRecord [mAdvertiseFlags=" + mAdvertiseFlags + ", mServiceUuids=" + mServiceUuids
                + ", mManufacturerSpecificData=" + BluetoothLeUtils.toString(mManufacturerSpecificData)
                + ", mServiceData=" + BluetoothLeUtils.toString(mServiceData)
                + ", mTxPowerLevel=" + mTxPowerLevel + ", mDeviceName=" + mDeviceName + "]";
    }
    
    /**
     * Parse service UUIDs.
     *
     * @param scanRecord   scanRecord
     * @param currentPos   currentPos
     * @param dataLength   dataLength
     * @param uuidLength   uuidLength
     * @param serviceUuids serviceUuids
     * @return currentPos
     */
    @SuppressWarnings("UnusedReturnValue")
    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;
    }
    
    /**
     * Helper method to extract bytes from byte array.
     *
     * @param scanRecord scanRecord
     * @param start start
     * @param length length
     * @return extract bytes
     */
    private static byte[] extractBytes(byte[] scanRecord, int start, int length) {
        byte[] bytes = new byte[length];
        System.arraycopy(scanRecord, start, bytes, 0, length);
        return bytes;
    }
    
    private static class ParseData {
        private byte[] scanRecord;
        private int currentPos;
        private int advertiseFlag;
        private List<ParcelUuid> serviceUuids;
        private String localName;
        private int txPowerLevel;
        private SparseArray<byte[]> manufacturerData;
        private Map<ParcelUuid, byte[]> serviceData;
        private int dataLength;
        private int fieldType;
    
        ParseData(byte[] scanRecord, int currentPos, int advertiseFlag, List<ParcelUuid> serviceUuids, String localName, int txPowerLevel, SparseArray<byte[]> manufacturerData, Map<ParcelUuid, byte[]> serviceData, int dataLength, int fieldType) {
            this.scanRecord = scanRecord;
            this.currentPos = currentPos;
            this.advertiseFlag = advertiseFlag;
            this.serviceUuids = serviceUuids;
            this.localName = localName;
            this.txPowerLevel = txPowerLevel;
            this.manufacturerData = manufacturerData;
            this.serviceData = serviceData;
            this.dataLength = dataLength;
            this.fieldType = fieldType;
        }
    
        int getAdvertiseFlag() {
            return advertiseFlag;
        }
    
        String getLocalName() {
            return localName;
        }
    
        int getTxPowerLevel() {
            return txPowerLevel;
        }
    
        ParseData invoke() {
            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_16_BIT:
                case DATA_TYPE_SERVICE_DATA_32_BIT:
                case DATA_TYPE_SERVICE_DATA_128_BIT:
                    int serviceUuidLength = BluetoothUuid.UUID_BYTES_16_BIT;
                    if (fieldType == DATA_TYPE_SERVICE_DATA_32_BIT) {
                        serviceUuidLength = BluetoothUuid.UUID_BYTES_32_BIT;
                    } else if (fieldType == DATA_TYPE_SERVICE_DATA_128_BIT) {
                        serviceUuidLength = BluetoothUuid.UUID_BYTES_128_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;
            }
            return this;
        }
    }
    

    }

    class BluetoothUuid {
    
    /**
     * See Bluetooth Assigned Numbers document - SDP section, to get the values of UUIDs
     * for the various services.
     * <p>
     * The following 128 bit values are calculated as:
     * uuid * 2^96 + BASE_UUID
     */
    static final ParcelUuid PARCEL_UUID =
            ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
    static final ParcelUuid AUDIO_SOURCE =
            ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
    static final ParcelUuid ADV_AUDIO_DIST =
            ParcelUuid.fromString("0000110D-0000-1000-8000-00805F9B34FB");
    static final ParcelUuid HSP =
            ParcelUuid.fromString("00001108-0000-1000-8000-00805F9B34FB");
    static final ParcelUuid HSP_AG =
            ParcelUuid.fromString("00001112-0000-1000-8000-00805F9B34FB");
    static final ParcelUuid HANDSFREE =
            ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB");
    static final ParcelUuid HANDSFREE_AG =
            ParcelUuid.fromString("0000111F-0000-1000-8000-00805F9B34FB");
    static final ParcelUuid AVRCP_CONTROLLER =
            ParcelUuid.fromString("0000110E-0000-1000-8000-00805F9B34FB");
    static final ParcelUuid AVRCP_TARGET =
            ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB");
    static final ParcelUuid OBEX_OBJECT_PUSH =
            ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb");
    static final ParcelUuid HID =
            ParcelUuid.fromString("00001124-0000-1000-8000-00805f9b34fb");
    static final ParcelUuid HOGP =
            ParcelUuid.fromString("00001812-0000-1000-8000-00805f9b34fb");
    static final ParcelUuid PANU =
            ParcelUuid.fromString("00001115-0000-1000-8000-00805F9B34FB");
    static final ParcelUuid NAP =
            ParcelUuid.fromString("00001116-0000-1000-8000-00805F9B34FB");
    static final ParcelUuid BNEP =
            ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB");
    static final ParcelUuid PBAP_PCE =
            ParcelUuid.fromString("0000112e-0000-1000-8000-00805F9B34FB");
    static final ParcelUuid PBAP_PSE =
            ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB");
    static final ParcelUuid MAP =
            ParcelUuid.fromString("00001134-0000-1000-8000-00805F9B34FB");
    static final ParcelUuid MNS =
            ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB");
    static final ParcelUuid MAS =
            ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
    static final ParcelUuid SAP =
            ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB");
    
    static final ParcelUuid BASE_UUID =
            ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
    
    /**
     * Length of bytes for 16 bit UUID
     */
    static final int UUID_BYTES_16_BIT = 2;
    /**
     * Length of bytes for 32 bit UUID
     */
    static final int UUID_BYTES_32_BIT = 4;
    /**
     * Length of bytes for 128 bit UUID
     */
    static final int UUID_BYTES_128_BIT = 16;
    
    static final ParcelUuid[] RESERVED_UUIDS = {
            PARCEL_UUID, AUDIO_SOURCE, ADV_AUDIO_DIST, HSP, HANDSFREE, AVRCP_CONTROLLER, AVRCP_TARGET,
            OBEX_OBJECT_PUSH, PANU, NAP, MAP, MNS, MAS, SAP};
    
    static boolean isAudioSource(ParcelUuid uuid) {
        return uuid.equals(AUDIO_SOURCE);
    }
    
    static boolean isAudioSink(ParcelUuid uuid) {
        return uuid.equals(PARCEL_UUID);
    }
    
    static boolean isAdvAudioDist(ParcelUuid uuid) {
        return uuid.equals(ADV_AUDIO_DIST);
    }
    
    static boolean isHandsfree(ParcelUuid uuid) {
        return uuid.equals(HANDSFREE);
    }
    
    static boolean isHeadset(ParcelUuid uuid) {
        return uuid.equals(HSP);
    }
    
    static boolean isAvrcpController(ParcelUuid uuid) {
        return uuid.equals(AVRCP_CONTROLLER);
    }
    
    static boolean isAvrcpTarget(ParcelUuid uuid) {
        return uuid.equals(AVRCP_TARGET);
    }
    
    static boolean isInputDevice(ParcelUuid uuid) {
        return uuid.equals(HID);
    }
    
    static boolean isPanu(ParcelUuid uuid) {
        return uuid.equals(PANU);
    }
    
    static boolean isNap(ParcelUuid uuid) {
        return uuid.equals(NAP);
    }
    
    static boolean isBnep(ParcelUuid uuid) {
        return uuid.equals(BNEP);
    }
    
    static boolean isMap(ParcelUuid uuid) {
        return uuid.equals(MAP);
    }
    
    static boolean isMns(ParcelUuid uuid) {
        return uuid.equals(MNS);
    }
    
    static boolean isMas(ParcelUuid uuid) {
        return uuid.equals(MAS);
    }
    
    static boolean isSap(ParcelUuid uuid) {
        return uuid.equals(SAP);
    }
    
    /**
     * Returns true if ParcelUuid is present in uuidArray
     *
     * @param uuidArray - Array of ParcelUuids
     * @param uuid      ParcelUuid
     */
    static boolean isUuidPresent(ParcelUuid[] uuidArray, ParcelUuid uuid) {
        boolean uuidArrayEmpty = uuidArray == null || uuidArray.length == 0;
        if (uuidArrayEmpty && uuid == null) {
            return true;
        }
    
        if (uuidArray == null) {
            return false;
        }
    
        for (ParcelUuid element : uuidArray) {
            if (element.equals(uuid)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * Returns true if there any common ParcelUuids in uuidA and uuidB.
     *
     * @param uuidA - List of ParcelUuids
     * @param uuidB - List of ParcelUuids
     */
    static boolean containsAnyUuid(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
        if (uuidA == null && uuidB == null) {
            return true;
        }
    
        if (uuidA == null) {
            return uuidB.length == 0;
        }
    
        if (uuidB == null) {
            return uuidA.length == 0;
        }
    
        HashSet<ParcelUuid> uuidSet = new HashSet<>(Arrays.asList(uuidA));
        for (ParcelUuid uuid : uuidB) {
            if (uuidSet.contains(uuid)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * Returns true if all the ParcelUuids in ParcelUuidB are present in
     * ParcelUuidA
     *
     * @param uuidA - Array of ParcelUuidsA
     * @param uuidB - Array of ParcelUuidsB
     */
    static boolean containsAllUuids(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
        if (uuidA == null && uuidB == null) {
            return true;
        }
    
        if (uuidA == null) {
            return uuidB.length == 0;
        }
    
        if (uuidB == null) {
            return true;
        }
    
        HashSet<ParcelUuid> uuidSet = new HashSet<>(Arrays.asList(uuidA));
        for (ParcelUuid uuid : uuidB) {
            if (!uuidSet.contains(uuid)) {
                return false;
            }
        }
        return true;
    }
    
    /**
     * Extract the Service Identifier or the actual uuid from the Parcel Uuid.
     * For example, if 0000110B-0000-1000-8000-00805F9B34FB is the parcel Uuid,
     * this function will return 110B
     *
     * @param parcelUuid ParcelUuid
     * @return the service identifier.
     */
    static int getServiceIdentifierFromParcelUuid(ParcelUuid parcelUuid) {
        UUID uuid = parcelUuid.getUuid();
        long value = (uuid.getMostSignificantBits() & 0x0000FFFF00000000L) >>> 32;
        return (int) value;
    }
    
    /**
     * Parse UUID from bytes. The {@code uuidBytes} can represent a 16-bit, 32-bit or 128-bit UUID,
     * but the returned UUID is always in 128-bit format.
     * Note UUID is little endian in Bluetooth.
     *
     * @param uuidBytes Byte representation of uuid.
     * @return {@link android.os.ParcelUuid} parsed from bytes.
     * @throws IllegalArgumentException If the {@code uuidBytes} cannot be parsed.
     */
    static ParcelUuid parseUuidFrom(byte[] uuidBytes) {
        if (uuidBytes == null) {
            throw new IllegalArgumentException("uuidBytes cannot be null");
        }
        int length = uuidBytes.length;
        if (length != UUID_BYTES_16_BIT && length != UUID_BYTES_32_BIT &&
                length != UUID_BYTES_128_BIT) {
            throw new IllegalArgumentException("uuidBytes length invalid - " + length);
        }
    
        // Construct a 128 bit UUID.
        if (length == UUID_BYTES_128_BIT) {
            ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN);
            long msb = buf.getLong(8);
            long lsb = buf.getLong(0);
            return new ParcelUuid(new UUID(msb, lsb));
        }
    
        // For 16 bit and 32 bit UUID we need to convert them to 128 bit value.
        // 128_bit_value = uuid * 2^96 + BASE_UUID
        long shortUuid;
        if (length == UUID_BYTES_16_BIT) {
            shortUuid = uuidBytes[0] & 0xFF;
            shortUuid += (uuidBytes[1] & 0xFF) << 8;
        } else {
            shortUuid = uuidBytes[0] & 0xFF;
            shortUuid += (uuidBytes[1] & 0xFF) << 8;
            shortUuid += (uuidBytes[2] & 0xFF) << 16;
            shortUuid += (uuidBytes[3] & 0xFF) << 24;
        }
        long msb = BASE_UUID.getUuid().getMostSignificantBits() + (shortUuid << 32);
        long lsb = BASE_UUID.getUuid().getLeastSignificantBits();
        return new ParcelUuid(new UUID(msb, lsb));
    }
    
    /**
     * Parse UUID to bytes. The returned value is shortest representation, a 16-bit, 32-bit or 128-bit UUID,
     * Note returned value is little endian (Bluetooth).
     *
     * @param uuid uuid to parse.
     * @return shortest representation of {@code uuid} as bytes.
     * @throws IllegalArgumentException If the {@code uuid} is null.
     */
    static byte[] uuidToBytes(ParcelUuid uuid) {
        if (uuid == null) {
            throw new IllegalArgumentException("uuid cannot be null");
        }
    
        if (is16BitUuid(uuid)) {
            byte[] uuidBytes = new byte[UUID_BYTES_16_BIT];
            int uuidVal = getServiceIdentifierFromParcelUuid(uuid);
            uuidBytes[0] = (byte) (uuidVal & 0xFF);
            uuidBytes[1] = (byte) ((uuidVal & 0xFF00) >> 8);
            return uuidBytes;
        }
    
        if (is32BitUuid(uuid)) {
            byte[] uuidBytes = new byte[UUID_BYTES_32_BIT];
            int uuidVal = getServiceIdentifierFromParcelUuid(uuid);
            uuidBytes[0] = (byte) (uuidVal & 0xFF);
            uuidBytes[1] = (byte) ((uuidVal & 0xFF00) >> 8);
            uuidBytes[2] = (byte) ((uuidVal & 0xFF0000) >> 16);
            uuidBytes[3] = (byte) ((uuidVal & 0xFF000000) >> 24);
            return uuidBytes;
        }
    
        // Construct a 128 bit UUID.
        long msb = uuid.getUuid().getMostSignificantBits();
        long lsb = uuid.getUuid().getLeastSignificantBits();
    
        byte[] uuidBytes = new byte[UUID_BYTES_128_BIT];
        ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN);
        buf.putLong(8, msb);
        buf.putLong(0, lsb);
        return uuidBytes;
    }
    
    /**
     * Check whether the given parcelUuid can be converted to 16 bit bluetooth uuid.
     *
     * @param parcelUuid ParcelUuid
     * @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise.
     */
    static boolean is16BitUuid(ParcelUuid parcelUuid) {
        UUID uuid = parcelUuid.getUuid();
        return uuid.getLeastSignificantBits() == BASE_UUID.getUuid().getLeastSignificantBits() && ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L);
    }
    
    
    /**
     * Check whether the given parcelUuid can be converted to 32 bit bluetooth uuid.
     *
     * @param parcelUuid ParcelUuid
     * @return true if the parcelUuid can be converted to 32 bit uuid, false otherwise.
     */
    static boolean is32BitUuid(ParcelUuid parcelUuid) {
        UUID uuid = parcelUuid.getUuid();
        return uuid.getLeastSignificantBits() == BASE_UUID.getUuid().getLeastSignificantBits() && !is16BitUuid(parcelUuid) && ((uuid.getMostSignificantBits() & 0xFFFFFFFFL) == 0x1000L);
    }
    

    }

    class BluetoothLeUtils {
    
    /**
     * Returns a string composed from a {@link android.util.SparseArray}.
     */
    static String toString(SparseArray<byte[]> array) {
        if (array == null) {
            return "null";
        }
        if (array.size() == 0) {
            return "{}";
        }
        StringBuilder buffer = new StringBuilder();
        buffer.append('{');
        for (int i = 0; i < array.size(); ++i) {
            buffer.append(array.keyAt(i)).append("=").append(Arrays.toString(array.valueAt(i)));
        }
        buffer.append('}');
        return buffer.toString();
    }
    
    /**
     * Returns a string composed from a {@link java.util.Map}.
     */
    static <T> String toString(Map<T, byte[]> map) {
        if (map == null) {
            return "null";
        }
        if (map.isEmpty()) {
            return "{}";
        }
        StringBuilder buffer = new StringBuilder();
        buffer.append('{');
        Iterator<Map.Entry<T, byte[]>> it = map.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<T, byte[]> entry = it.next();
            Object key = entry.getKey();
            //noinspection SuspiciousMethodCalls
            buffer.append(key).append("=").append(Arrays.toString(map.get(key)));
            if (it.hasNext()) {
                buffer.append(", ");
            }
        }
        buffer.append('}');
        return buffer.toString();
    }
    
    /**
     * Check whether two {@link android.util.SparseArray} equal.
     */
    static boolean equals(SparseArray<byte[]> array, SparseArray<byte[]> otherArray) {
        if (array == otherArray) {
            return true;
        }
        if (array == null || otherArray == null) {
            return false;
        }
        if (array.size() != otherArray.size()) {
            return false;
        }
    
        // Keys are guaranteed in ascending order when indices are in ascending order.
        for (int i = 0; i < array.size(); ++i) {
            if (array.keyAt(i) != otherArray.keyAt(i) ||
                    !Arrays.equals(array.valueAt(i), otherArray.valueAt(i))) {
                return false;
            }
        }
        return true;
    }
    
    /**
     * Check whether two {@link Map} equal.
     */
    static <T> boolean equals(Map<T, byte[]> map, Map<T, byte[]> otherMap) {
        if (map == otherMap) {
            return true;
        }
        if (map == null || otherMap == null) {
            return false;
        }
        if (map.size() != otherMap.size()) {
            return false;
        }
        Set<T> keys = map.keySet();
        if (!keys.equals(otherMap.keySet())) {
            return false;
        }
        for (T key : keys) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                if (!Objects.deepEquals(map.get(key), otherMap.get(key))) {
                    return false;
                }
            } else {
                byte[] bytes = map.get(key);
                byte[] bytes1 = otherMap.get(key);
                if (!Arrays.equals(bytes, bytes1)) {
                    return false;
                }
            }
        }
        return true;
    }
    
    /**
     * Ensure Bluetooth is turned on.
     *
     * @throws IllegalStateException If {@code adapter} is null or Bluetooth state is not
     *                               {@link android.bluetooth.BluetoothAdapter#STATE_ON}.
     */
    static void checkAdapterStateOn(BluetoothAdapter adapter) {
        if (adapter == null || adapter.getState() != BluetoothAdapter.STATE_ON) {
            throw new IllegalStateException("BT Adapter is not turned ON");
        }
    }
    

    }

    【讨论】:

      猜你喜欢
      • 2016-12-12
      • 2014-10-11
      • 1970-01-01
      • 1970-01-01
      • 2020-02-05
      • 2014-03-04
      • 2016-11-02
      • 2014-05-06
      • 2012-06-05
      相关资源
      最近更新 更多