android BTLE scan callback seemingly not called

792 views Asked by At

I want to run a BTLE scan within a ViewModel. I'm not sure if this is the best approach but it is a good learning experiment for me. I did manage to successfully list my BT devices when running the scan in a more simple setup.

Permissions BLUETOOTH BLUETOOTH_ADMIN and ACCESS_COARSE_LOCATION are set in the Manifest.

I have a checkPermissions method in my main settings activity that checks for permissions, and requests permissions if needed. I also have an override for onRequestPermissionsResult. The location permissions shows in my app's permissions. Those methods are more or less a copy/paste of open-source projects (see this).

So well, my scan doesn't work. The log in my callback never shows in my logs. There is no error, the only suspicious thing I'm seeing in the logs is this: D/BluetoothLeScanner: onScannerRegistered() - status=0 scannerId=12 mScannerId=0.

My ViewModel looks like this:

interface ScanningStatus {
    void setCurrentlyScanning(boolean updatedStatus);
    boolean getCurrentlyScanning();
}


public class SettingsScanningViewModel extends AndroidViewModel {
    private MutableLiveData<ArrayList<BluetoothDevice>> mDeviceList;
    private ArrayList<BluetoothDevice> mInternalDeviceList;
    private MutableLiveData<Boolean> mIsScanning;

    private static final String TAG = "viewmodel";

    private BluetoothManager mBtManager;
    private BluetoothAdapter mBtAdapter;
    private BluetoothLeScanner mBleScanner;
    private static final long SCAN_PERIOD = 5000;


    public SettingsScanningViewModel(Application mApplication) {
        super(mApplication);
        mDeviceList = new MutableLiveData<>();
        mInternalDeviceList = new ArrayList<>();
        mIsScanning = new MutableLiveData<>();

        mBtManager = (BluetoothManager) mApplication.getSystemService(Context.BLUETOOTH_SERVICE);
        mBtAdapter = mBtManager.getAdapter();
        mBleScanner = mBtAdapter.getBluetoothLeScanner();
    }


    MutableLiveData<ArrayList<BluetoothDevice>> getBtDevices() {
        return mDeviceList;
    }


    MutableLiveData<Boolean> getScanningStatus() {
        return mIsScanning;
    }


    private void flushList() {
        mInternalDeviceList.clear();
        mDeviceList.setValue(mInternalDeviceList);
    }


    private void injectIntoList(BluetoothDevice btDevice) {
        mInternalDeviceList.add(btDevice);
        mDeviceList.setValue(mInternalDeviceList);
    }


    private ScanCallback scanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            Log.d(TAG, "in callback");
            BluetoothDevice mDevice = result.getDevice();
            if (!mInternalDeviceList.contains(mDevice) && mDevice.getName() != null) {
                injectIntoList(mDevice);
            }
        }

        @Override
        public void onScanFailed(int errorCode) {
            Log.d(TAG, "onScanFailed: " + errorCode);
        }
    };


    private ScanningStatus scanningStatus = new ScanningStatus() {
        @Override
        public void setCurrentlyScanning(boolean status) {
            mIsScanning.setValue(status);
        }

        public boolean getCurrentlyScanning() {
            return mIsScanning.getValue();
        }
    };


    void doBtScan() {
        Log.d(TAG, "flush list first");
        flushList();
        Log.d(TAG, "starting scan with scanCallback " + scanCallback);
        scanningStatus.setCurrentlyScanning(true);
        mBleScanner.startScan(scanCallback);
        Log.d(TAG, "scan should be running for " + SCAN_PERIOD);

        Handler handler = new Handler();
        handler.postDelayed(() -> {
            mBleScanner.stopScan(scanCallback);
            scanningStatus.setCurrentlyScanning(false);
            }, SCAN_PERIOD);
    }
}

I am really not sure what is wrong. Is it because I'm creating new BluetoothManager, BluetoothAdapter and BluetoothLeScanner in my ViewModel compared with the main activity where I initiate and request permissions? If so, how could I re-use these same objects?

Thank you.

2

There are 2 answers

0
AudioBubble On

OKKKKKKKKKKKK another instance of trying to find out what's wrong for hours, posting, then 2mn later finding out by myself.

Looks like ACCESS_COARSE_LOCATION is not enough and ACCESS_FINE_LOCATION is needed. So I suppose I must be using a different SDK than previously!

Thank you.

0
aliraza12636 On

These three steps worked for me.

  1. GPS should be turned on (write some code to turn it on if not already).

  2. both ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION permissions should be declared in manifest and asked at runtime.

  3. and the most important is the below answer talking about ScanSettings

https://stackoverflow.com/a/53831870/10432212