Proxy
Proxy

Reputation: 41

Android BLE Scan never finds devices

Since a few days I try to implement an BLE connection in my APP. I know that the Device, I try to connect with, is full functional, so the problem must be my code.

I use the BluetoothLeScanner.startScan() method.
But the callback Method is never called.

   public void startScan() {
        if (bluetoothAdapter != null && bluetoothAdapter.isEnabled()) {
            isScanning = true;
            Handler mHandler = new Handler();
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mainActivityHandler.setMSG("Scan stopped");
                    isScanning = false;
                    leScanner.stopScan(scanCallback);
                }
            }, SCAN_TIME);

            mainActivityHandler.setMSG("Start scan");

            try {

                leScanner.startScan(scanCallback);
            } catch (Exception e) {
                mainActivityHandler.catchError(e);
            }

        } else mainActivityHandler.catchError(new Exception("Bluetooth not activated"));
    }

My CallbackMethod (dont know if I use gatt correctly, but this is a other question):

    private ScanCallback scanCallback = new ScanCallback() {


    @Override
    public void onBatchScanResults(List<ScanResult> results) {
        mainActivityHandler.setMSG("Callback");
        isScanning = false;
        try {

            mainActivityHandler.setMSG("Connected to " + results.get(0).getDevice().getName());
            gatt = results.get(0).getDevice().connectGatt(mainActivity, true, bluetoothGattCallback);

            BluetoothGattDescriptor descriptor;
            for (int i = 0; i < charIDs.length; i++) {
                gatt.setCharacteristicNotification(gatt.getService(serviceID[0]).getCharacteristic(charIDs[i]), true);

                descriptor = gatt.getService(serviceID[0]).getCharacteristic(charIDs[0]).getDescriptor(charIDs[i]);
                descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                gatt.writeDescriptor(descriptor);
            }
        } catch (Exception e) {
            mainActivityHandler.catchError(e);
        }

    }
};

Upvotes: 1

Views: 5267

Answers (2)

dglozano
dglozano

Reputation: 6607

The Problem

The problem is that you are only overriding the onBatchScanResults method and not onScanResult method. onBatchScanResults will only get triggered if:

  1. You have set the ScanSettings mode to ScanSettings.SCAN_MODE_LOW_POWER (this is the default) using the ScanSettings.Builder.
  2. You have set the report delay time to some value >0 using setReportDelay(long reportDelayMillis) in your ScanSettings.Builder.

reportDelayMillis - Delay of report in milliseconds. Set to 0 to be notified of results immediately. Values > 0 causes the scan results to be queued up and delivered after the requested delay or when the internal buffers fill up.

For example:

public void startScan(BluetoothLeScanner scanner) {
    ScanFilter filter = new ScanFilter.Builder().setDeviceName(null).build();

    ArrayList<ScanFilter> filters = new ArrayList<ScanFilter>();
                    filters.add(filter);

    ScanSettings settings = new ScanSettings.Builder()
                                .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
                                .setReportDelay(1l)
                                .build();

    Log.i(TAG,"The setting are "+settings.getReportDelayMillis());
    scanner.startScan(filters,settings,BLEScan);
}

The Solution

However, you probably just want to get the results once at a time and not a batch of results. To accomplish that, you don't have to modify the ScanSettings, you just need to override the onScanResult method in your ScanCallback and that will do the trick.

private ScanCallback mScanCallback =
        new ScanCallback() {

    public void onScanResult(int callbackType, ScanResult result) {
        System.out.println(result.getDevice().getName())
        // Do whatever you want
    };

    ...
};

The Alternative - RxAndroidBle

Anyway, I highly recommend using the library RxAndroidBle. It is very well maintained and it solves many of the BLE issues out of the box (scanning is maybe the less complicated part in BLE).

Using that library, the scanning can be done like this:

Disposable scanSubscription = rxBleClient.scanBleDevices(


    new ScanSettings.Builder()
            // .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) // change if needed
            // .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) // change if needed
            .build()
        // add filters if needed
)
    .subscribe(
        scanResult -> {
            // Process scan result here.
        },
        throwable -> {
            // Handle an error here.
        }
    );

// When done, just dispose.
scanSubscription.dispose();

Upvotes: 5

Pritish
Pritish

Reputation: 1368

Checklist:

Do you have the location enabled, make sure it is enabled specially for devices after Api 23.Also there is a free app nrfconnect (something which I used) Please download it and see it it detects the device.

Also this is what I had used

private void startScan() {
        try {
            if (!hasPermissions() || mScanning) {
                return;
            }

            List<ScanFilter> filters = new ArrayList<>();
            ScanSettings settings = new ScanSettings.Builder()
                    .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                    .build();
            mScanResults = new ArrayList<>();
            mScanCallback = new DeviceScanCallback();
            mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
            handleProgress(true, getString(R.string.lbl_scanning));
            mBluetoothLeScanner.startScan(filters, settings, mScanCallback);
            mScanning = true;
            final Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (activity == null || !isAdded()) {
                        return;
                    }
                    if (getResources() != null) {
                        handleProgress(false, getResources().getString(R.string.lbl_scanning));
                        stopScan();
                    }
                }
            }, 20000);
        } catch (Exception e) {
            Toast.makeText(activity, getString(R.string.scan_failed), Toast.LENGTH_LONG).show();
            e.printStackTrace();
        }
    }

// Class to utilize callback

     private class DeviceScanCallback extends ScanCallback {

        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            try {
                if (result != null && result.getScanRecord() != null && result.getScanRecord().getDeviceName() != null) {
                    Log.d("Device name", "" + result.getScanRecord().getDeviceName());
                    if (result.getScanRecord().getDeviceName().startsWith(ConstantClass.DEVICE_IDENTIFIER)) {
                        addScanResult(result);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            try {
                for (ScanResult result : results) {
                    Log.i("ScanResult - Results", result.toString() + " " + result.getDevice().getName());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onScanFailed(int errorCode) {
            Log.e(TAG, "BLE Scan Failed with code " + errorCode);
        }

        private void addScanResult(ScanResult result) {
            try {
                BluetoothDevice device = result.getDevice();
                if (mScanResults != null) {
                    mScanResults.add(device);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
}

Upvotes: 1

Related Questions