2

I am developing an Android app (the app runs on Android 6): I want the app to send a notification to the user when it is near a BLE device (a device that I have at home). So I continuously scan, I scan through a service (which is running in the background). It works well when the phone screen is on; but, when the screen turns off, a few seconds later the application can no longer find the BLE (the scan is still running, but there is no callback.

if (enable) {
            if (mScanning) return;
            // Stops scanning after a pre-defined scan period.
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (!mScanning) return;
                    try {
                        mScanning = false;
                        mBluetoothLeScanner.stopScan(mScanCallback);
                        Log.i(TAG_LOG, "Stop scanning after pre-defined scan periode");

                    } catch (Exception e){Log.e(TAG_LOG,"mBluetoothLeScanner.stopScan Exception:=>"+e.getMessage());}
                }
            }, SCAN_PERIOD);

            mScanning = true;
            mBluetoothLeScanner.startScan(filters, settings, mScanCallback);
            Log.i(TAG_LOG, "Start scanning ....");
        }



 private ScanCallback mScanCallback = new ScanCallback() {
    //When a BLE advertisement has been found
    @Override
    public void onScanResult(int callbackType, ScanResult result) {
        super.onScanResult(callbackType, result);
        Log.i(TAG_LOG, "Name: "+result.getDevice().getName()+". Adresse: "+result.getDevice().getAddress()+". Rssi: "+result.getRssi());
        //scanDevices(false);
        if(result.getDevice().getName() != null && result.getDevice().getName().toString().equals(deviceName)){
            mDeviceAdress = result.getDevice().getAddress();
            mDevice = mBluetoothAdapter.getRemoteDevice(mDeviceAdress);
            Log.i(TAG_LOG, "Device found");
            scanDevices(false);
        }
    }

1 Answers1

2

You can't make this work. Scanning is a very expensive operation that Android won't allow in the background. Instead, make an attempt to connect to the device. I had success doing this in a WorkManager job, running every 15 minutes. Battery drain was negligible and it was pretty reliable. Note that a connection state 0x85 usually represents the device being out of range, and 0x80 means a different device is already connected to it (or the phone is already connected to too many different devices). Full error list is at https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/master/stack/include/gatt_api.h#27

Hack5
  • 3,244
  • 17
  • 37
  • Thank you @Hack5. Okay, I'm going to try that method. But can make an attempt to to connect every 3 seconds for exemple? I want my app to react immediately as soon as the user is next to the BLE device. – barkigandal Jul 18 '20 at 17:10
  • You can't make connection attempts every 3 seconds unless your app is open and in the foreground. If it is, you can just put the connection attempts in a loop. Remember there's no way for the user to know when the device in in range, so 10 seconds either way probably makes little difference. – Hack5 Jul 19 '20 at 10:00
  • The connection attempts also ailled when the phone is in doze mode. If the screen is on, the connection is successful but if the screen turn off, a few moments later, the connection attempts fail (in the BluetoothGattCallback, the onConnectionStateChange methode return "status = 257") – barkigandal Jul 19 '20 at 10:32
  • As I said, you won't be able to make connection attempts if the screen is off, unless your job is running in a WorkManager or a foreground service with a wakelock. The latter will drain the battery very badly, so you should poll every 15 minutes with a WorkManager job. – Hack5 Jul 19 '20 at 10:39