Apart from the fact that starting with Android 6.0 you have to have the ACCESS_COARSE_LOCATION
permission to receive ACTION_FOUND
(as @siniux already mentioned), there's another related thing:
ACCESS_COARSE_LOCATION
is among dangerous permissions that you have to explicitly request from user at run time (another security improvement that came in 6.0).
To diagnose, you can run adb logcat | grep BroadcastQueue
, and see something like this:
W/BroadcastQueue: Permission Denial: receiving Intent {
act=android.bluetooth.device.action.FOUND flg=0x10 (has extras) }
to ProcessRecord{9007:com.examplepackage} (pid=9007, uid=10492)
requires android.permission.ACCESS_COARSE_LOCATION due to sender
com.android.bluetooth (uid 1002)
So, the correct procedure for BT device discovery on Marshmallow is as follows:
Have ACCESS_COARSE_LOCATION
permission requirement in manifest along with usual bluetooth permissions:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Ensure you have run-time permission for ACCESS_COARSE_LOCATION
protected void checkLocationPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
REQUEST_COARSE_LOCATION);
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_COARSE_LOCATION: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
proceedDiscovery(); // --->
} else {
//TODO re-request
}
break;
}
}
}
Register a broadcast receiver for ACTION_FOUND
and call BluetoothAdapter.startDiscovery()
protected void proceedDiscovery() {
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothDevice.ACTION_NAME_CHANGED);
registerReceiver(mReceiver, filter);
mBluetoothAdapter.startDiscovery();
}
Funny thing about ACTION_NAME_CHANGED
. Although 6.0 won't deliver you ACTION_FOUND
without the permission for coarse location, you'll still get ACTION_NAME_CHANGED
events, which are usually teamed up with ACTION_FOUND
when devices are discovered. I.e. you get both events, so without the permission, you can still handle ACTION_NAME_CHANGED
for pretty much the same behavior. (Gurus, correct me if I'm wrong)