15

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

}
Derek Fung
  • 8,171
  • 1
  • 25
  • 28
Error
  • 820
  • 1
  • 11
  • 34

7 Answers7

43

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:

  1. 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" />
    
  2. 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;
        }
    }
    

    }

  3. 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)

Ivan Bartsov
  • 19,664
  • 7
  • 61
  • 59
13

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.

siniux
  • 131
  • 4
8

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()

Derek Fung
  • 8,171
  • 1
  • 25
  • 28
6

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...

Jilson P Jose
  • 61
  • 1
  • 4
4

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

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        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);
            }
        }
    };

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;

Jolson Da Costa
  • 1,095
  • 1
  • 12
  • 31
  • 1
    public void regigsterReceiver () { IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter); } How i register receiver – Error Sep 18 '15 at 17:12
0

Posting this as a answer, as I cant comment with my current Rep level.

Do you have the Bluetooth permisson include in you AndroidManifest.xml?

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

If not, try(and research) each one separately as I don't recall the importance of each one.

If you do have these, please include more of you code, so it will be possible to diagnose your issue.

lkjsdf23
  • 19
  • 2
  • 2
    the problem not with bluetooth code and i am using those permissions . issue is the onReceive does not called – Error Sep 18 '15 at 16:47
0

I found that the device I was developing on (Galaxy S4) needed to be restarted before the broadcasts continued to be received.

However, in my case I had been receiving them without issue until they (randomly?) stopped being received and no matter what I did (close app, reinstall app) the broadcasts weren't being received.

TheIT
  • 11,919
  • 4
  • 64
  • 56