bluetooth lowenergy – BluetoothLeScanner.startScan with Android 6.0 does not discover devices-ThrowExceptions

Exception or error:

I’m trying to use the function BluatoothLeScanner.startScan instead of the deprecated one BluetoothAdapter.startLeScan.
Yesterday I updated my Nexus 5 to Android 6.0 and since that moment my app does not work anymore.
I firstly add the preferences required ACCESS_COARSE_LOCATION as found here, https://developer.android.com/about/versions/marshmallow/android-6.0-changes.html#behavior-hardware-id.
Then I added the permission as described here: https://developer.android.com/training/permissions/requesting.html.
But at the end it seems not working, it does not send back the ble devices.

This is my code:

manifest

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.stm.sensitronapp">
          <uses-sdk android:maxSdkVersion="23"/>
          <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

          <uses-permission android:name="android.permission.BLUETOOTH"/>
          <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
          <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>`

DeviceScanActivity

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
...

if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION)
            != PackageManager.PERMISSION_GRANTED){
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.ACCESS_COARSE_LOCATION)) {
        } else {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
                    MY_PERMISSIONS_REQUEST_ACCESS_COARSE);
        }
    }

// Device scan callback.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
            mScanCallback = new ScanCallback() {
                @Override
                public void onScanResult(int callbackType, ScanResult result) {
                    super.onScanResult(callbackType, result);
                    mLeDeviceListAdapter.addDevice(result.getDevice());
                    mLeDeviceListAdapter.notifyDataSetChanged();
                }
            };
        }
    } 
}
final BluetoothManager bluetoothManager =
            (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();

if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
        mSwipeRefreshLayout.setRefreshing(true);
        mLeDeviceListAdapter.clear();
        mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
        if(ContextCompat.checkSelfPermission(this,
                    Manifest.permission.ACCESS_COARSE_LOCATION ) == PackageManager.PERMISSION_GRANTED) {
                mBluetoothLeScanner.startScan(mScanCallback);
            }
        }

EDIT: to solve this problem I only turned on the GPS. It is easy to do it programmatically in this way.

How to solve:

if permissions granted, have a try: turn ON the GPS.

###

Is you app prompting for Location permission on startup? If it’s not, handle the code somewhere else so that it is being prompted.

Also you can check this to test if your app is working fine:

Open Settings > Apps > YourApplication > Permissions
and enable Location and then try to scan for results.

Location will be listed under permissions only if you have provided ACCESS_COARSE_LOCATION on manifest.

###

Using the solutions provided above works but the side effect is that you have to have location services turned on for something that doesn’t need it. An ugly and unsatisfying work around is to specify the target version in your manifest to

android:targetSdkVersion=”21″

It allows scanning on my Nexus 7 even though the installed version is 6.0.1. I do not know what the side effects are of targeting a lower version than the installed version but at least scanning works. Might be the only solution for GPS-less devices (if such devices exist).

Google should be crucified for this.

###

One – not perfect answer, is that you can still use the same old method BT scan method, once you have the new runtime Location permission enabled.

            mBluetoothAdapter.startDiscovery();

…….

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

                if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                BluetoothDevice device = (BluetoothDevice) intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

                mDeviceList.add(device);


            }
        }
    };

###

It’s an old question, but I will answer to help someone.
Unfortunately, the combination of ACCESS_COARSE_LOCATION and targetSdkVersion 22 does not work on some devices.
This is not a good method, but I have solved it in the following way without using runtime permissions (ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION)

  1. Set your ‘targetSdkVersion’ to 19 (I think maybe api19 ~ api22 will be possible)
  2. Add the following permission to your manifest file

    <uses-permission android:name="android.permission.READ_OWNER_DATA" />
    <uses-permission android:name="android.permission.WRITE_OWNER_DATA" />
    

tested to Android 4.4 ~ 7.1.1

###

Set your ‘minSdkVersion’ to 18
targetSdkVersion 22

Leave a Reply

Your email address will not be published. Required fields are marked *