Android Open Source - BetterBluetoothLE Async Bluetooth Le Scan






From Project

Back to project page BetterBluetoothLE.

License

The source code is released under:

MIT License

If you think the Android project BetterBluetoothLE listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package betterbluetoothle.async;
/*from w  ww  .  ja  v  a 2  s. c o m*/
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;

import org.jdeferred.Promise;
import org.jdeferred.impl.DeferredObject;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class AsyncBluetoothLeScan implements BluetoothAdapter.LeScanCallback {

    // Store result of scan for returning in a promise.
    public class ScanResult {
        public final BluetoothDevice device;
        public final int rssi;
        public final byte[] bytes;

        public ScanResult(BluetoothDevice device, int rssi, byte[] bytes) {
            this.device = device;
            this.rssi = rssi;
            this.bytes = bytes;
        }

        // UUID filtering in android 4.3 and 4.4 is broken.  See:
        //  http://stackoverflow.com/questions/18019161/startlescan-with-128-bit-uuids-doesnt-work-on-native-android-ble-implementation
        // This is a useful workaround to manually parse advertisement data.
        public List<UUID> parseUUIDs() {
            List<UUID> uuids = new ArrayList<UUID>();

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

                int type = bytes[offset++];
                switch (type) {
                    case 0x02: // Partial list of 16-bit UUIDs
                    case 0x03: // Complete list of 16-bit UUIDs
                        while (len > 1) {
                            int uuid16 = bytes[offset++];
                            uuid16 += (bytes[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(bytes, 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;
        }
    }

    private BluetoothAdapter adapter;
    private DeferredObject<Void, Void, ScanResult> scan;
    private UUID[] filter;

    public AsyncBluetoothLeScan(BluetoothAdapter adapter) {
        this.adapter = adapter;
    }

    // Start scanning for the specified UUIDs (or null for no filtering).  The returned promise will
    // notify of discovered devices through its progress notification.
    public Promise<Void, Void, ScanResult> start(UUID[] uuid) {
        if (scan != null && scan.isPending()) {
            scan.resolve(null);
        }
        scan = new DeferredObject<Void, Void, ScanResult>();
        filter = uuid;
        // Note the startLeScan overload that takes a list of UUIDs to filter is NOT used because
        // it is broken with custom UUID values.
        if (!adapter.startLeScan(this)) {
            scan.reject(null);
        }
        return scan.promise();
    }

    // Helpful overrides for no filter or a single filter.

    public Promise<Void, Void, ScanResult> start() {
        return start((UUID[])null);
    }

    public Promise<Void, Void, ScanResult> start(UUID uuid) {
        return start(new UUID[] { uuid });
    }

    // Stop the in progress scan.
    public void stop() {
        adapter.stopLeScan(this);
        if (scan != null && scan.isPending()) {
            scan.resolve(null);
        }
    }

    @Override
    public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
        // Notify deferred if scan is in progress.
        if (scan != null && scan.isPending()) {
            ScanResult result = new ScanResult(bluetoothDevice, i, bytes);
            if (filter == null) {
                // No filtering, notify of the new result.
                scan.notify(result);
            }
            else {
                // Manually filter service UUIDs if filtering is enabled (workaround for bug in 4.3/4.4)
                List<UUID> serviceUUIDs = result.parseUUIDs();
                for (UUID uuid : filter) {
                    if (serviceUUIDs.contains(uuid)) {
                        scan.notify(result);
                        return;
                    }
                }
            }
        }
    }
}




Java Source Code List

betterbluetoothle.async.AsyncBluetoothGatt.java
betterbluetoothle.async.AsyncBluetoothLeScan.java
betterbluetoothle.services.UART.java