49

I'm currently working on a little app to get started with the services that the Bluetooth Android API can provide.

Edit -> Answer:

It seems that the issue was due to the specific Nexus 5 devices. Seems like their bluetooth receiver doesn't work well. Solution below should work for other devices

Remark:

  1. I’ve read the documentation here: http://developer.android.com/guide/topics/connectivity/bluetooth.html as well as the following source code of this tutorial http://www.londatiga.net/it/programming/android/how-to-programmatically-scan-or-discover-android-bluetooth-device/ located on github under /lorensiuswlt/AndroBluetooth

  2. I’ve finished almost all the features that interested me (such as check for adapter existence, enable/disable the blueooth, querying paired divices, set the adapter discoverable).

Issue:

Actually no device is found when i launch the .onDiscovery() method, even though devices are found from Settings/Bluetooth on my Nexus 5.

Here is how I handle it:

public class MainActivity extends AppCompatActivity {
private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

...

protected void onCreate(Bundle savedInstanceState) {
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(mReceiver, filter); 
}

The filter is working well as far as i could try, i.e ACTION_STATE_CHANGED (on bluetooth enabling) and the two ACTION_DISCOVERY_***.

The following method is then successfuly called:

public void onDiscovery(View view)
{
    mBluetoothAdapter.startDiscovery();
}

And then i have my bluetooth receiver:

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();

        if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
            final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);

            if (state == BluetoothAdapter.STATE_ON) {
                showToast("ACTION_STATE_CHANGED: STATE_ON");
            }
        }

        else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
            mDeviceList = new ArrayList<>();
            showToast("ACTION_DISCOVERY_STARTED");
            mProgressDlg.show();
        }

        else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action) && !bluetoothSwitchedOFF) {
            mProgressDlg.dismiss();
            showToast("ACTION_DISCOVERY_FINISHED");

            Intent newIntent = new Intent(MainActivity.this, DeviceListActivity.class);

            newIntent.putParcelableArrayListExtra("device.list", mDeviceList);

            startActivity(newIntent);
        }

        else if (BluetoothDevice.ACTION_FOUND.equals(action)) {// When discovery finds a device
            // Get the BluetoothDevice object from the Intent
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            mDeviceList.add(device);
            showToast("Device found = " + device.getName());
        }
    }
};

I don't have any issue coming out the logcat and didn't notice any trouble during the test I did. The only problem is that no device is discovered at the end of the scan, when many discoverable ones are available arround.

I tried to not put too much code in order to not flood the topic. Ask me if you need more.

Thanks for reading me, and thanks in advance for you answers.

Amesys
  • 816
  • 2
  • 10
  • 19
  • I had the location permission in my manifest using Nexus 5 and I was not finding any devices. The missing thing for me was not asking for location permission in the MainActivity (or whatever activity hosting the search) before searching for devices. That solved the issue for me – Khash Sep 01 '19 at 19:30

3 Answers3

88

What version of Android are you running this on? If it is Android 6.x, I believe you need to add the ACCESS_FINE_LOCATION permission to your manifest. For example:

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

I had a similar issue and this fixed it for me.

UPDATE: Adding documentation direct from Google on this:

To access the hardware identifiers of nearby external devices via Bluetooth and Wi-Fi scans, your app must now have the ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permissions

UPDATE 2020: We recently updated our application to target SDK Version 29. In doing this, our application stopped being able to discover Bluetooth devices again. We have been using ACCESS_COARSE_LOCATION since this answer was originally written. Changing to ACCESS_FINE_LOCATION appears to fix the issue. I now recommend developers try ACCESS_FINE_LOCATION if targeting 29+. Answer updated to reflect this.

nverbeek
  • 1,882
  • 17
  • 20
  • 1
    That did not work, and I honestly don't see why it would, since this permission is about using Android's Network Location Provider. Are you sure this is what fixed your issud? – Amesys Jan 23 '16 at 21:59
  • Yes. We had bluetooth working fully on Android 5 and the only issue in upgrading to 6 was not finding bluetooth devices during discovery. It didn't make sense to us either. We are using the `startDiscovery()` method, same as you. – nverbeek Jan 24 '16 at 14:40
  • Do you also have the `BLUETOOTH` and `BLUETOOTH_ADMIN` permissions specified? I imagine you do, but thought I'd ask. – nverbeek Jan 24 '16 at 14:43
  • Indeed i have, ok I guess that the issue is due to the Nexus 5 phones, since i tried with two others N5 and it also failed, but worked on my friend's Xperia. I'm gonna accept your answer still, thanks for it! – Amesys Jan 24 '16 at 15:05
  • 3
    @nverbeek Thank you for solution! Maybe you also should mention that it is not sufficient just to set permission in manifest, but also need to request it in runtime, as both permissions require this. – Viacheslav Oct 03 '16 at 14:45
  • 1
    Thank you, Strange how the Bluetooth documentation at https://developer.android.com/guide/topics/connectivity/bluetooth.html does not mention this – Joe Maher Jan 27 '17 at 02:42
  • I was using Nexus 5 phone for this bluetooth test which I was following Android's bluetooth guide (https://developer.android.com/guide/topics/connectivity/bluetooth.html#SettingUp) and I was not seeing any devices from the app. I did have the location permission in the manifest, but I did not ask for it in the app before start scanning. Once I asked for location and granted permission, the problem was solved – Khash Sep 01 '19 at 19:28
76

Bit late to the party but this may come in handy for other people.

You need to do two things

  1. Add <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

or <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

to your AndroidManifest.xml

  1. Make sure you're requesting the permission on runtime as well for Android 6.0 Devices by using something like this

    int MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION = 1; 
    ActivityCompat.requestPermissions(this,
            new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
            MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION);
    

    just before mBluetoothAdapter.startDiscovery();

If you don't do step 2 you won't be able to get any Hardware Identifier info on device with Android >= 6.0

UPDATE/EDIT:
Example with Android Version check and alert dialog as warning

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {  // Only ask for these permissions on runtime when running Android 6.0 or higher
    switch (ContextCompat.checkSelfPermission(getBaseContext(), Manifest.permission.ACCESS_COARSE_LOCATION)) {
        case PackageManager.PERMISSION_DENIED:
            ((TextView) new AlertDialog.Builder(this)
                    .setTitle("Runtime Permissions up ahead")
                    .setMessage(Html.fromHtml("<p>To find nearby bluetooth devices please click \"Allow\" on the runtime permissions popup.</p>" +
                            "<p>For more info see <a href=\"http://developer.android.com/about/versions/marshmallow/android-6.0-changes.html#behavior-hardware-id\">here</a>.</p>"))
                    .setNeutralButton("Okay", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            if (ContextCompat.checkSelfPermission(getBaseContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                                ActivityCompat.requestPermissions(DeviceListActivity.this,
                                        new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
                                        REQUEST_ACCESS_COARSE_LOCATION);
                            }
                        }
                    })
                    .show()
                    .findViewById(android.R.id.message))
                    .setMovementMethod(LinkMovementMethod.getInstance());       // Make the link clickable. Needs to be called after show(), in order to generate hyperlinks
            break;
        case PackageManager.PERMISSION_GRANTED:
            break;
    }
}
fr4gus
  • 396
  • 7
  • 18
Nils
  • 898
  • 6
  • 9
  • 5
    worked for me but then startDiscovery() should return false in case it can't get access. It still returns true which is a bit misleading ... – mallaudin May 21 '16 at 17:52
  • 1
    That may be because it does get acces to scan, but not to retrieve information about the devices itself. https://developer.android.com/about/versions/marshmallow/android-6.0-changes.html#behavior-hardware-id – Nils May 23 '16 at 08:41
  • 3
    Ive been banging my head against a wall for 3 days trying to get it to wark. then found this post, followed step 2 and bingo!! it works. Thanks – NoLiver92 Jun 14 '16 at 18:21
  • 2
    I had a lot of unresolved references when adding this code to my project but it was the missing link - Thanks! – ChronoFish Mar 12 '17 at 01:14
  • 1
    i didt give loc permission. after granting loc permission.. it works – Nishanth S Babu Jan 30 '18 at 04:54
  • 2
    I wasn't forced to use the "step 2" on my personal android device with Android 8.0.0 . Instead, on another devices, I was forced to request the permission in that way. So, I think that the "step 2" is not mandatory for all devices with Android >= 6.0 . It requires further investigation... – bitfox Mar 11 '19 at 10:38
  • 1
    Adding step 2 to my app fixed the discovery issue. Many thanks! – BHouwens Dec 17 '19 at 09:30
0

As with new android version things are changed a bit Older android version like android 10 needs FINE_LOCATION where as newer android version like android 12 works with COARSE_LOCATION also. hence my advice is to ask for FINE_LOCATION permission which will work in both. don't ask COAR_LOCATION and FINE_LOCATION simultaneously otherwise it will not work with android 12 and greater if user select coarse location at app start up.

Sadique Khan
  • 230
  • 3
  • 9