Bluetooth Low Energy startScan on Android 6.0 does not find devices

Jacopo Tosi picture Jacopo Tosi · Oct 9, 2015 · Viewed 42.4k times · Source

I'm developing an application with Bluetooth Low Energy using Nexus 5. It worked on Lollipop and now it is not working on Marshmallow. I set the ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION permissions in the manifest and on runTime in the Activity.

This is the list of ScanFilters:

mScanFilterTest = new ScanFilter.Builder().build();
mScanFilter = new ArrayList<ScanFilter>();
mScanFilter.add(mScanFilterTest);

These are the settings:

mScanSettings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_POWER).setReportDelay(0)
                .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES).build();

These are my callbacks:

 mBLEScan = new ScanCallback() {
     @Override
     public void onScanResult(int callbackType, ScanResult result) {
         super.onScanResult(callbackType, result);
         Log.i(TAG, "******************************************");
         Log.i(TAG, "The scan result " + result);
         Log.i(TAG, "------------------------------------------");
         }
     };

This is my call:

mBluetoothLeScanner.startScan(mScanFilter, mScanSettings, mBLEScan);

It starts the scan but does not find any device. Please help me!!!!

Answer

V-PTR picture V-PTR · Oct 9, 2015

I struggled with the same issue. To fix it you have to enable "Location" (GPS) in the settings of the phone as well as request location permission in the app at runtime. Both need to be done for scanning to work properly.

To request the location permission put the following in a dialog or the likes:

yourActivity.requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, yourPermissionRequestCode);

and implement:

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults){
    if(requestCode == yourPermissionRequestCode)
    {
        ... //Do something based on grantResults
    }
}

in yourActivity and handle whatever the user selects. You also need to do the following to turn on your device's location services:

Intent enableLocationIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
yourActivity.startActivityForResult(enableLocationIntent, yourServiceRequestCode);

You can check if the user turned on the location services by implementing:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    if(requestCode == yourServiceRequestCode)
    {
        ...//Do whatever you need to
    }
}

in yourActivity. You can also manually turn on location (GPS) services by doing:

Enter phone settings -> Select "Location" -> Then turn it on

It should look like this in the Phone settings:

Location (GPS) services enabled in Phone Settings

Or like this in the quick-settings drop down:

Location (GPS) services enabled in drop down settings

Once the user has enabled the permission and started location services then you should start scanning. I've noticed that if you are already scanning while you enable the permission/turn on the location service it will still not put anything in your onScanResults

I'm not sure if this is a bug or a "feature" for iBeacons/Bluetooth advertising (NOTE: advertising as in selling products not the technical Bluetooth advertising) to allow companies to see your location and direct you to where they want.

Hope this fixes your problem!

EDIT I meant to add: you only need this for SCANNING. Once you are connected to the BLE device you can shut off the location service on your phone and you will still be connected to your devices. However, you cannot then discover or connect to any new devices and all advertising devices will drop from the onScanResults