16

I am working with android BLE (Bluetooth Low Energy). I am having trouble in scanning BLE device using
startLeScan(UUID[] serviceUuids, BluetoothAdapter.LeScanCallback callback) method
while startLeScan(BluetoothAdapter.LeScanCallback callback) is working fine.
When i use filter to scan specific serviceUUIDs , the callback is not executing. I am testing with samsung galaxy s6.
I want to know whether this issue is device specific or there is some bug in scaning function.

Rashwan L
  • 38,237
  • 7
  • 103
  • 107
Akhilesh Kumar
  • 796
  • 1
  • 5
  • 12
  • Galaxy s6 has 5.0+ OS so you need to use ScanResult Listener,,,startLeScan is deprecated..Check Documentaion – IshRoid Dec 03 '15 at 11:46
  • same problem with `BluetoothLeScanner.startScan (List filters, ScanSettings settings, ScanCallback callback)` method – Akhilesh Kumar Dec 03 '15 at 11:48
  • then you should post the code,,, because the method should work , problem with in your code,,, – IshRoid Dec 03 '15 at 11:49
  • I am just logging Strings in callback (nothing complicated) but not working. If i use another scanning function having no filter then callback get executed.
    but it does not mean i am specifying may be wrong service UUID.
    – Akhilesh Kumar Dec 03 '15 at 11:55

4 Answers4

14

I'm pretty sure it's not device specific. First of all as IshArt mentioned you should use startScan from Android 5.0 on.

startScan(List<ScanFilter> filters, ScanSettings settings, ScanCallback callback)

From my experience the implementation of Scanfilters works fine if you go for MAC addresses but other filter setup parameters are problematic:

ScanFilter filter = new ScanFilter.Builder().setDeviceAddress(deviceMacAddress).build();
filters.add(filter);

If that is not an option for you, you can also implement your own filter. If you leave the filters list for the startScan() empty, it ignores all filtering and receives everything. Then in the callback you can write your own method to check whether the result meets your requirements or not.

Chris
  • 4,238
  • 4
  • 28
  • 49
  • +1 on the setDeviceAddress working, but the Service filter may work too if you use a separate filter and add that separately as shown in the update of my answer. It is definitely device specific if you add multiple conditions per ScanFilter. The Galaxy S6 doesn't work at all if I add both service and mac address conditions to one scan. It works well with two ScanFilters one with each condition. – Bryan Bryce Dec 12 '17 at 03:29
3

This is a specific problem I've found with the Samsung Galaxy S6. I use the newer scanner API and only support devices on Android 5.0+. My testing has shown the S4, (haven't tested S5), S7, and S8 all work; I don't know why the S6 has issues.

The workaround it is, lamentably, to just filter manually on mac address after the devices are found.

Update

This fixed my issues above that I was having with the Galaxy S6.

Previously, I was adding two conditions to the same ScanFilter like this (Kotlin):

ScanFilter.Builder()
    .setServiceUuid(BluetoothBlind.Service.ParcelUUID)
    .setDeviceAddress(macAddress)
    .build()

Changing it to split the conditions into multiple filters fixes it:

ScanFilter.Builder()
    .setDeviceAddress(macAddress)
    .build()

ScanFilter.Builder()
    .setServiceUuid(BluetoothBlind.Service.ParcelUUID)
    .build()
Bryan Bryce
  • 1,310
  • 1
  • 16
  • 29
  • 1
    Can confirm my S6 on Android 7 fails to properly filter on Service UUID. No choice but to filter manually on all devices now. – Kevin Nov 03 '17 at 21:39
  • 1
    This is completely wrong behavior. I cant tell u there is more devices not only samsung s6 which doesnt filter properly. How can this pass any tests and be released among people? This is crime against developers! – Kebab Krabby Jun 05 '19 at 13:08
2

The issue with BLE filtered scanning is a known issue. See https://github.com/iDevicesInc/SweetBlue/wiki/Android-BLE-Issues for this and other BLE issues. The conclusion is simple: "You have to scan for all devices and do filtering yourself."

p2pkit
  • 1,159
  • 8
  • 11
0

there's 2 scan method:

//Device scan callback Lollipop and above
    private ScanCallback generateScanCallback(){

        if(apiVersion> Build.VERSION_CODES.KITKAT) {
            ScanCallback mScanCallback = new ScanCallback() {
                @Override
                public void onScanResult(int callbackType, ScanResult result) {
                    super.onScanResult(callbackType, result);
                    final BluetoothDevice device = result.getDevice();
                    getActivity().runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Log.e(TAG, "running scan " + device.getAddress());
                            if (device.getAddress().equals(mDeviceAddress)) {
                                Log.e(TAG, "device founded, trying to connect");
                                scanLeDevice(false);
                                Intent gattServiceIntent = new Intent(mContext, BluetoothLeService.class);
                                mContext.bindService(gattServiceIntent, mServiceConnection, mContext.BIND_AUTO_CREATE);
                                mIndicationText.setText(mContext.getString(R.string.waiting));
                            }
                        }
                    });
                }
            };
            return mScanCallback;
        }
        return null;
    }


// Device scan callback KITKAT and below.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
    new BluetoothAdapter.LeScanCallback() {

        @Override
        public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Log.e(TAG,"running scan "+device.getType());
                    if(device.getAddress().equals(mDeviceAddress)){
                        Log.e(TAG, "device founded, trying to connect");
                        scanLeDevice(false);
                        Intent gattServiceIntent = new Intent(mContext, BluetoothLeService.class);
                        mContext.bindService(gattServiceIntent, mServiceConnection, mContext.BIND_AUTO_CREATE);
                        mIndicationText.setText(mContext.getString(R.string.waiting));
                    }
                }
            });
        }
    };

and than:

if(apiVersion> Build.VERSION_CODES.KITKAT) {
    scanner = mBluetoothAdapter.getBluetoothLeScanner();
    // Device scan callback LOLLIPOP
    scanner.startScan(generateScanCallback());
} else {
    mBluetoothAdapter.startLeScan(mLeScanCallback);
}

you can customize your scan method as you want but you must know that there's 2 scan method one for android 5 and above and one for the other android OS

Tiago
  • 2,871
  • 4
  • 23
  • 39
Fakher
  • 2,098
  • 3
  • 29
  • 45