Using Log class to track Runtime show that onReceive() methode does not called,why ?
Register broadcast receiver dynamically
private void discoverDevices () {
Log.e("MOHAB","BEFORE ON RECEIVE");
mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
Log.e("MOHAB","ON RECEIVE");
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// Add the name and address to an array adapter to show in a ListView
Bluetooth b = new Bluetooth(device.getName(),device.getAddress());
list.add(b);
}
}
};
Log.e("MOHAB","create intentFilter");
// Register the BroadcastReceiver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
}
If the receiving class is not registered using in its manifest, you can dynamically instantiate and register a receiver by calling Context. registerReceiver(). Take a look at registerReceiver (BroadcastReceiver receiver, IntentFilter filter) for more info.
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)
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.
What you missed is that you need to start a device discovery
First, get the bluetooth adapter
BluetoothAdapter adapter = 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()
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-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android: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...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With