StartLeScan с 128-битными UUID не работает в собственной реализации BLE на Android

У меня возникли проблемы с использованием startLeScan (новый UUID [] {MY_DESIRED_128_BIT_SERVICE_UUID}, обратный вызов) в новом введенном BLE API для Android 4.3 на мой Nexus 4.

Обратный вызов просто не вызван. Я все еще вижу входящие пакеты в журнале:

08-02 15:48:57.985: I/bt-hci(1051): btu_ble_process_adv_pkt
08-02 15:48:58.636: I/bt-hci(1051): BLE HCI(id=62) event = 0x02)

Если я не использую параметр для фильтрации для UUID, он работает. Мы используем специфичный для производителей 128-битный UUID для устройства нашей компании.

Теперь наше устройство предлагает больше услуг, чем я предоставляю в массиве. Но это не должно быть проблемой.

Кто-нибудь сталкивается с той же проблемой? Любые решения?

Edit

Есть несколько проблем, связанных с проверкой, этот вопрос обсуждает только один: Если у вас также есть проблемы со сканированием, прочитайте этот комментарий первый. Также имейте в виду, что мое устройство накладывает 16-битный и 128-битный UUID. Большинство из вас, ребята, используют 16-битные UUID, предоставляемые стандартом BLE, такие как частота сердечных сокращений, скорость и каденция.

Ответ 1

Это сообщила об ошибке, по крайней мере, в Android 4.3 JWR66Y:

  • Фильтрация работает, если я предоставляю свой 16-битный UUID
  • Фильтрация не возвращает результаты сканирования, если я предоставляю свой 128-битный UUID или если я предоставляю оба UUID

Моя настройка: мое устройство предлагает 2 UUID в рекламе (1 16bit и 1 128bit) и 4 UUID при обнаружении службы (1 128 бит и 3 16 бит).

Даже если он будет исправлен, я предупреждаю всех об использовании опции фильтра, предоставляемой Android. Для обратной совместимости и с момента ее разбиения на Samsung Galaxy S3 с Android 4.3

Ответ 2

Код

@Navin хорош, но он включает ошибку переполнения от исходного 16-битного кода Android. (Если либо байт больше 127, то он становится отрицательным целым.)

Здесь реализована реализация, которая исправляет эту ошибку и добавляет 128-битную поддержку:

private List<UUID> parseUuids(byte[] advertisedData) {
     List<UUID> uuids = new ArrayList<UUID>();

     ByteBuffer buffer = ByteBuffer.wrap(advertisedData).order(ByteOrder.LITTLE_ENDIAN);
     while (buffer.remaining() > 2) {
         byte length = buffer.get();
         if (length == 0) break;

         byte type = buffer.get();
         switch (type) {
             case 0x02: // Partial list of 16-bit UUIDs
             case 0x03: // Complete list of 16-bit UUIDs
                 while (length >= 2) {
                     uuids.add(UUID.fromString(String.format(
                             "%08x-0000-1000-8000-00805f9b34fb", buffer.getShort())));
                     length -= 2;
                 }
                 break;

             case 0x06: // Partial list of 128-bit UUIDs
             case 0x07: // Complete list of 128-bit UUIDs
                 while (length >= 16) {
                     long lsb = buffer.getLong();
                     long msb = buffer.getLong();
                     uuids.add(new UUID(msb, lsb));
                     length -= 16;
                 }
                 break;

             default:
                 buffer.position(buffer.position() + length - 1);
                 break;
         }
     }

     return uuids;
 }

Ответ 3

Попробуйте загрузить/отфильтровать устройство из объявленных 128-битных UUID:

private List<UUID> parseUUIDs(final byte[] advertisedData) {
    List<UUID> uuids = new ArrayList<UUID>();

    int offset = 0;
    while (offset < (advertisedData.length - 2)) {
        int len = advertisedData[offset++];
        if (len == 0)
            break;

        int type = advertisedData[offset++];
        switch (type) {
        case 0x02: // Partial list of 16-bit UUIDs
        case 0x03: // Complete list of 16-bit UUIDs
            while (len > 1) {
                int uuid16 = advertisedData[offset++];
                uuid16 += (advertisedData[offset++] << 8);
                len -= 2;
                uuids.add(UUID.fromString(String.format(
                        "%08x-0000-1000-8000-00805f9b34fb", uuid16)));
            }
            break;
        case 0x06:// Partial list of 128-bit UUIDs
        case 0x07:// Complete list of 128-bit UUIDs
            // Loop through the advertised 128-bit UUID's.
            while (len >= 16) {
                try {
                    // Wrap the advertised bits and order them.
                    ByteBuffer buffer = ByteBuffer.wrap(advertisedData,
                            offset++, 16).order(ByteOrder.LITTLE_ENDIAN);
                    long mostSignificantBit = buffer.getLong();
                    long leastSignificantBit = buffer.getLong();
                    uuids.add(new UUID(leastSignificantBit,
                            mostSignificantBit));
                } catch (IndexOutOfBoundsException e) {
                    // Defensive programming.
                    Log.e(LOG_TAG, e.toString());
                    continue;
                } finally {
                    // Move the offset to read the next uuid.
                    offset += 15;
                    len -= 16;
                }
            }
            break;
        default:
            offset += (len - 1);
            break;
        }
    }

    return uuids;
}

Ответ 4

Хотя 4.3, похоже, не поддерживает фильтрацию по 128-битным UUID, эти UUID, вероятно, присутствуют в байте [] scanRecord, возвращаемом LeScanCallback.

Вероятно, правильный способ проанализировать эти данные, но если вы получаете одни и те же данные каждый раз, когда вы можете фильтровать результаты вручную, найдя смещения UUID, которые вы ищете. Вы можете сделать это, распечатав данные сканирования в журнал (как шестую строку) и ищите интересующие вас UUID (они, вероятно, будут следовать за 0x06 или 0x07 и будут отменены). После того, как вы найдете смещение, не должно быть слишком сложно настроить базовый фильтр.

Вот простой пример, который фильтрует один UUID (использует Apache Commons Lang для ArrayUtils и найденный метод by-by-hex здесь, но при необходимости вы можете заменить свой собственный код)

public static boolean hasMyService(byte[] scanRecord) {

    // UUID we want to filter by (without hyphens)
    final String myServiceID = "0000000000001000800000805F9B34FB";

    // The offset in the scan record. In my case the offset was 13; it will probably be different for you
    final int serviceOffset = 13; 

    try{

        // Get a 16-byte array of what may or may not be the service we're filtering for
        byte[] service = ArrayUtils.subarray(scanRecord, serviceOffset, serviceOffset + 16);

        // The bytes are probably in reverse order, so we need to fix that
        ArrayUtils.reverse(service);

        // Get the hex string
        String discoveredServiceID = bytesToHex(service);

        // Compare against our service
        return myServiceID.equals(discoveredServiceID);

    } catch (Exception e){
        return false;
    }

}

Ответ 5

Вы уверены, что периферийное устройство перечисляет указанный UUID службы в рекламных данных или данных ответа сканирования?

Ответ 6

Лучший способ перечислить UUID службы из результата сканирования - это скопировать именно метод parseFromBytes из ScanRecord.java, который находится внутри android.bluetooth.le (убедитесь, что у вас есть последний Android SDK), измените возврат к списку ParcelUuid, так как единственное, что нам нужно,

    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 = 0x16;
    private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;

    public static List<ParcelUuid> 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 HashMap<ParcelUuid, byte[]>();

        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, 2, 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;
            }

//            Log.i("SERVICE UUIDS", parcelUuidToString(serviceUuids));
        } 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 serviceUuids;
    }

Вам нужно будет импортировать BluetoothUuid.java из того же пакета:

import java.util.UUID;
import android.os.ParcelUuid;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.HashSet;
/**
 * Static helper methods and constants to decode the ParcelUuid of remote devices.
 *  @hide
 */
public final class BluetoothUuid {
    /* See Bluetooth Assigned Numbers document - SDP section, to get the values of UUIDs
     * for the various services.
     *
     * The following 128 bit values are calculated as:
     *  uuid * 2^96 + BASE_UUID
     */
    public static final ParcelUuid AudioSink =
            ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid AudioSource =
            ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid AdvAudioDist =
            ParcelUuid.fromString("0000110D-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid HSP =
            ParcelUuid.fromString("00001108-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid HSP_AG =
            ParcelUuid.fromString("00001112-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid Handsfree =
            ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid Handsfree_AG =
            ParcelUuid.fromString("0000111F-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid AvrcpController =
            ParcelUuid.fromString("0000110E-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid AvrcpTarget =
            ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid ObexObjectPush =
            ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb");
    public static final ParcelUuid Hid =
            ParcelUuid.fromString("00001124-0000-1000-8000-00805f9b34fb");
    public static final ParcelUuid Hogp =
            ParcelUuid.fromString("00001812-0000-1000-8000-00805f9b34fb");
    public static final ParcelUuid PANU =
            ParcelUuid.fromString("00001115-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid NAP =
            ParcelUuid.fromString("00001116-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid BNEP =
            ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid PBAP_PCE =
            ParcelUuid.fromString("0000112e-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid PBAP_PSE =
            ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid MAP =
            ParcelUuid.fromString("00001134-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid MNS =
            ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid MAS =
            ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid SAP =
            ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB");

    public static final ParcelUuid BASE_UUID =
            ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
    /** Length of bytes for 16 bit UUID */
    public static final int UUID_BYTES_16_BIT = 2;
    /** Length of bytes for 32 bit UUID */
    public static final int UUID_BYTES_32_BIT = 4;
    /** Length of bytes for 128 bit UUID */
    public static final int UUID_BYTES_128_BIT = 16;
    public static final ParcelUuid[] RESERVED_UUIDS = {
            AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
            ObexObjectPush, PANU, NAP, MAP, MNS, MAS, SAP};
    public static boolean isAudioSource(ParcelUuid uuid) {
        return uuid.equals(AudioSource);
    }
    public static boolean isAudioSink(ParcelUuid uuid) {
        return uuid.equals(AudioSink);
    }
    public static boolean isAdvAudioDist(ParcelUuid uuid) {
        return uuid.equals(AdvAudioDist);
    }
    public static boolean isHandsfree(ParcelUuid uuid) {
        return uuid.equals(Handsfree);
    }
    public static boolean isHeadset(ParcelUuid uuid) {
        return uuid.equals(HSP);
    }
    public static boolean isAvrcpController(ParcelUuid uuid) {
        return uuid.equals(AvrcpController);
    }
    public static boolean isAvrcpTarget(ParcelUuid uuid) {
        return uuid.equals(AvrcpTarget);
    }
    public static boolean isInputDevice(ParcelUuid uuid) {
        return uuid.equals(Hid);
    }
    public static boolean isPanu(ParcelUuid uuid) {
        return uuid.equals(PANU);
    }
    public static boolean isNap(ParcelUuid uuid) {
        return uuid.equals(NAP);
    }
    public static boolean isBnep(ParcelUuid uuid) {
        return uuid.equals(BNEP);
    }
    public static boolean isMap(ParcelUuid uuid) {
        return uuid.equals(MAP);
    }
    public static boolean isMns(ParcelUuid uuid) {
        return uuid.equals(MNS);
    }
    public static boolean isMas(ParcelUuid uuid) {
        return uuid.equals(MAS);
    }
    public static boolean isSap(ParcelUuid uuid) {
        return uuid.equals(SAP);
    }
    /**
     * Returns true if ParcelUuid is present in uuidArray
     *
     * @param uuidArray - Array of ParcelUuids
     * @param uuid
     */
    public static boolean isUuidPresent(ParcelUuid[] uuidArray, ParcelUuid uuid) {
        if ((uuidArray == null || uuidArray.length == 0) && 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
     *
     */
    public static boolean containsAnyUuid(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
        if (uuidA == null && uuidB == null) return true;
        if (uuidA == null) {
            return uuidB.length == 0 ? true : false;
        }
        if (uuidB == null) {
            return uuidA.length == 0 ? true : false;
        }
        HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid> (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
     *
     */
    public static boolean containsAllUuids(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
        if (uuidA == null && uuidB == null) return true;
        if (uuidA == null) {
            return uuidB.length == 0 ? true : false;
        }
        if (uuidB == null) return true;
        HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid> (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
     * @return the service identifier.
     */
    public 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 ParcelUuid} parsed from bytes.
     * @throws IllegalArgumentException If the {@code uuidBytes} cannot be parsed.
     */
    public 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.
     */
    public 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
     * @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise.
     */
    public static boolean is16BitUuid(ParcelUuid parcelUuid) {
        UUID uuid = parcelUuid.getUuid();
        if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
            return false;
        }
        return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L);
    }
    /**
     * Check whether the given parcelUuid can be converted to 32 bit bluetooth uuid.
     *
     * @param parcelUuid
     * @return true if the parcelUuid can be converted to 32 bit uuid, false otherwise.
     */
    public static boolean is32BitUuid(ParcelUuid parcelUuid) {
        UUID uuid = parcelUuid.getUuid();
        if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
            return false;
        }
        if (is16BitUuid(parcelUuid)) {
            return false;
        }
        return ((uuid.getMostSignificantBits() & 0xFFFFFFFFL) == 0x1000L);
    }

Из моего тестирования результаты дают именно то, что я хочу.

Ответ 7

Вам нужно добавить служебный UUID в рекламные данные как ссылку

Затем вы можете попробовать снова startLeScan (UUID [], обратный вызов).

Мне удалось добиться этого метода для обнаружения термометра с определенным UUID [0x1809]

Это работает для меня.

Ответ 8

Мой опыт в том, что я должен был предоставить КАЖДУЮ услугу, которую я хочу подключить к подаркам, а не только к тому, с чем я связан. В результате я обнаружил, что обнаружил сервис после сканирования, чтобы обойти это.

Ответ 9

128-битное UUID LE-сканирование работало на Samsung S5, под управлением Android 4.4.2; но да, это не работает на Nexus 4, 7. Протестировано на 4.4.2, 4.4.3, 4.4.4.

Ответ 10

Я нашел ошибку в Android-источнике 5.x, но не присутствовал в 6.x.

В этом файле есть функция: http://androidxref.com/5.1.1_r6/xref/external/bluetooth/bluedroid/bta/dm/bta_dm_api.c#1560 используется для передачи 32-битной data_mask в bluetooth le рекламный пакет и сканирующий ответ. Но структура "tBTA_DM_API_SET_ADV_CONFIG;" управляйте 16-битным значением! Поэтому измените UINT16 на UINT32 dor data_mask, перекомпилируйте Android, и он будет работать. понижение в должности http://androidxref.com/5.1.1_r6/xref/external/bluetooth/bluedroid/bta/dm/bta_dm_int.h#594

Ответ 11

Я столкнулся с той же проблемой с SensorTag от TI, используя мой N7 2013 с Android 4.3.

То, что я нашел для работы, - запустить LeScan, подождать секунду, остановить его и перезапустить.

        if(!mBluetoothAdapter.startLeScan(mBleScanCallback)){
            L.e("could not start scan action");
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {}
        mBluetoothAdapter.stopLeScan(mBleScanCallback);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {}
        mBluetoothAdapter.startLeScan(mBleScanCallback);

Также я заметил, что иногда соединение не установлено (это может быть или не быть связано с реализацией прошивки или закрытием соединения должным образом). Точно так же кажется, что попытка повторного подключения к gatt, похоже, делает трюк.

Использование этих обходных решений действительно разочаровывает...