Register Broadcast Receiver Dynamically Does Not Work - Bluetoothdevice.action_found
Solution 1:
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:receivingIntent {
act=android.bluetooth.device.action.FOUNDflg=0x10(hasextras) }
toProcessRecord{9007:com.examplepackage}(pid=9007,uid=10492)requiresandroid.permission.ACCESS_COARSE_LOCATIONduetosendercom.android.bluetooth(uid1002)
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-permissionandroid:name="android.permission.BLUETOOTH" /><uses-permissionandroid:name="android.permission.BLUETOOTH_ADMIN" /><uses-permissionandroid:name="android.permission.ACCESS_COARSE_LOCATION" />
Ensure you have run-time permission for
ACCESS_COARSE_LOCATION
protectedvoidcheckLocationPermission() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, newString[]{Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_COARSE_LOCATION); } } @OverridepublicvoidonRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { caseREQUEST_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 callBluetoothAdapter.startDiscovery()
protectedvoidproceedDiscovery() { 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)
Solution 2:
I was having a similar problem with a Broadcast Receiver. Then I found this: https://developer.android.com/about/versions/marshmallow/android-6.0-changes.html#behavior-hardware-id
Basically, on 6.0 you must use the location permission to scan for Bluetooth devices.
Solution 3:
What you missed is that you need to start a device discovery
First, get the bluetooth adapter
BluetoothAdapteradapter= BluetoothAdapter.getDefaultAdapter();
After that, you start the discovery by calling
mBtAdapter.startDiscovery();
You should read the details here as well, e.g. about cancelDiscovery()
http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery%28%29
P.S. Also, it is suggested to use context.getSystemService(Context.BLUETOOTH_SERVICE)
to get the BluetoothAdapter on API 18+, according to official doc.
To get a BluetoothAdapter representing the local Bluetooth adapter, when running on JELLY_BEAN_MR1 and below, call the static getDefaultAdapter() method; when running on JELLY_BEAN_MR2 and higher, retrieve it through getSystemService(Class) with BLUETOOTH_SERVICE.
Edit:
Be reminded that you need BLUETOOTH_ADMIN permission to startDiscovery()
Solution 4:
As replied by experts, you may please check the following points to get ACTION_FOUND work in Android 6 and above, 1. In addition to setting permissions of BLUETOOTH and BLUETOOTH_ADMIN, try
<uses-permissionandroid:name="android.permission.ACCESS_COARSE_LOCATION" /><uses-permissionandroid:name="android.permission.ACCESS_FINE_LOCATION" />
Sometimes these two may not be needed, but it worked for me. Also you have to seek user permissions dynamically using the codes
int MY_PERMISSIONS_REQUEST = 200;
int permissions=ContextCompat.checkSelfPermission (this,Manifest.permission.ACCESS_FINE_LOCATION);
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST);
Now write your codes for performing the required operation. I have added one startDiscovery() method just after this. Surely, this will work for you... Happy coding...
Solution 5:
i dont know if your code is correct in getting bluetooth device. here is what i feel about your code is. intialising and registering BroadcastReceiver inside a function is a bad idea. you should do it outside onCreate()
method.
here's the thing you need to do in your code
as about registering Reciver that has to be done in onCreate()
like this
registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
following with initializing or reciever
privatefinalBroadcastReceivermReceiver=newBroadcastReceiver() {
@OverridepublicvoidonReceive(Context context, Intent intent) {
Log.e("MOHAB","ON RECEIVE");
Stringaction= intent.getAction();
// When discovery finds a deviceif (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the IntentBluetoothDevicedevice= intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// Add the name and address to an array adapter to show in a ListViewBluetoothb=newBluetooth(device.getName(),device.getAddress());
list.add(b);
}
}
};
unregister reciver in onPause()
do not forget that
and in your discoverDevices()
just return the list
of devices added by reciver for every call of that fumction;
Post a Comment for "Register Broadcast Receiver Dynamically Does Not Work - Bluetoothdevice.action_found"