27

I'm trying to use the function BluatoothLeScanner.startScan instead of the deprecated one BluetoothAdapter.startLeScan. Yesterday I updated my Nexus 5 to Android 6.0 and since that moment my app does not work anymore. I firstly add the preferences required ACCESS_COARSE_LOCATION as found here, https://developer.android.com/about/versions/marshmallow/android-6.0-changes.html#behavior-hardware-id. Then I added the permission as described here: https://developer.android.com/training/permissions/requesting.html. But at the end it seems not working, it does not send back the ble devices.

This is my code:

manifest

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.stm.sensitronapp">
          <uses-sdk android:maxSdkVersion="23"/>
          <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

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

DeviceScanActivity

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
...

if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION)
            != PackageManager.PERMISSION_GRANTED){
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.ACCESS_COARSE_LOCATION)) {
        } else {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
                    MY_PERMISSIONS_REQUEST_ACCESS_COARSE);
        }
    }

// Device scan callback.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
            mScanCallback = new ScanCallback() {
                @Override
                public void onScanResult(int callbackType, ScanResult result) {
                    super.onScanResult(callbackType, result);
                    mLeDeviceListAdapter.addDevice(result.getDevice());
                    mLeDeviceListAdapter.notifyDataSetChanged();
                }
            };
        }
    } 
}
final BluetoothManager bluetoothManager =
            (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();

if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
        mSwipeRefreshLayout.setRefreshing(true);
        mLeDeviceListAdapter.clear();
        mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
        if(ContextCompat.checkSelfPermission(this,
                    Manifest.permission.ACCESS_COARSE_LOCATION ) == PackageManager.PERMISSION_GRANTED) {
                mBluetoothLeScanner.startScan(mScanCallback);
            }
        }

EDIT: to solve this problem I only turned on the GPS. It is easy to do it programmatically in this way.

Jacopo Tosi
  • 752
  • 2
  • 7
  • 9
  • I have the same issue. Have you found any workarounds? I'm thinking of trying the new scanning api but it's a pain to keep compatibility between both since they work so much differently. – Matt Wolfe Oct 14 '15 at 07:15
  • 6
    Yes, look here, there is the solution: [Bluetooth Low Energy startScan on Android 6.0 does not find devices](http://stackoverflow.com/questions/33043582/bluetooth-low-energy-startscan-on-android-6-0-does-not-find-devices) However, the solution is: add permissions in the manifest, add permissions at runTime in the activity with the ScanDevice, turn ON the GPS. Is incredible to think but my problem was the GPS off – Jacopo Tosi Oct 14 '15 at 10:10
  • 2
    I just tested with GPS turned on and it worked (I was on a tablet which had it off).. This is crazy that we must have GPS turned on in order to scan for BLE devices, what if the device doesn't even have a GPS chip in it? A bug needs to get filed immediately. I would think the fitbit guys and others making BLE devices for the masses would have hit google with these questions already. – Matt Wolfe Oct 14 '15 at 15:56
  • 3
    WTF, enabling GPS on Android 6.0 makes the scanner finding BLE devices. Now I understand why the permission `ACCESS_COARSE_LOCATION` is required. Google, WTF?!? – Lars Blumberg Dec 07 '15 at 14:29
  • 4 years later and still the same problem with GPS... – BjornW May 09 '19 at 16:32
  • In my case `disabling battery optimization` for the app solved the problem. – J. Ouwehand Nov 18 '21 at 08:03

6 Answers6

27

if permissions granted, have a try: turn ON the GPS.

qinmiao
  • 5,559
  • 5
  • 36
  • 39
  • 1
    But why so? I am only accessing Bluetooth? P.S: your solution does work though – Usman khan Mar 24 '16 at 15:40
  • 1
    Android 6.0 Changes:To provide users with greater data protection, starting in this release, Android removes programmatic access to the device’s local hardware identifier for apps using the Wi-Fi and Bluetooth APIs. – qinmiao Mar 25 '16 at 05:58
  • Would be nice, but in my case it is not an option to turn on GPS, in order to receive beacon advertisements. You simply can't find a working explanation, what GPS is used for, when the task is to receive bluetooth signals... ;-) – Anticro Dec 01 '16 at 08:35
10

Is you app prompting for Location permission on startup? If it's not, handle the code somewhere else so that it is being prompted.

Also you can check this to test if your app is working fine:

Open Settings > Apps > YourApplication > Permissions and enable Location and then try to scan for results.

Location will be listed under permissions only if you have provided ACCESS_COARSE_LOCATION on manifest.

Kamal Kishore
  • 399
  • 4
  • 6
  • 1
    I added Location permissions, but it is not working. It starts the scanning but it does not reply anything in the callback. – Jacopo Tosi Oct 12 '15 at 08:12
  • i've added 'fine' and 'coarse' permissions but still no luck. discovery callback is not fired. Marshmallow on Nexus 9. i've checked Location is allowed in android settings for the app. I can see the device is found but callback is not fired. Also i can check it's fired on Lollipop. Any solution? – 4ntoine Dec 03 '15 at 07:47
  • 2
    I can confirm that. After adding ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION to the Manifest AND enabling Location in the phone, BLE scan works. I've tested it on Nexus 6 with Android 6.0 and it works. – Piotr Wittchen Dec 11 '15 at 14:14
  • Old, but ...The standard way to add the permissions is have the user give the app permission on a first time start up. It's a pain to implement. – Brian Reinhold Dec 04 '20 at 22:27
4

Using the solutions provided above works but the side effect is that you have to have location services turned on for something that doesn't need it. An ugly and unsatisfying work around is to specify the target version in your manifest to

android:targetSdkVersion="21"

It allows scanning on my Nexus 7 even though the installed version is 6.0.1. I do not know what the side effects are of targeting a lower version than the installed version but at least scanning works. Might be the only solution for GPS-less devices (if such devices exist).

Google should be crucified for this.

Brian Reinhold
  • 2,313
  • 3
  • 27
  • 46
0

One - not perfect answer, is that you can still use the same old method BT scan method, once you have the new runtime Location permission enabled.

            mBluetoothAdapter.startDiscovery();

.......

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

                if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                BluetoothDevice device = (BluetoothDevice) intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

                mDeviceList.add(device);


            }
        }
    };
aiden_fry
  • 304
  • 3
  • 9
  • 1
    That's the classic Bluetooth scan. OP is talking about LE scan. – Mackovich Mar 21 '16 at 16:15
  • 1
    I'm sorry if you got the wrong impression. I am just pointing that there is absolutely no relation between Bluetooth Classic Discovery and Bluetooth Low Energy Scan. Those two scans are completely different. The first scan will never return BLE devices unless there are dual mode and discoverable. And finally, you don't need location permission and enabled for Classic Bluetooth Discovery (just tried that today). – Mackovich Mar 22 '16 at 21:00
  • But the 'classic' search for devices in the standard settings options also scans for BTLE devices. So it discovers both classic and BTLE devices. The down side is that the only next step one can take is to pair with the device. Thus one cannot connect to BTLE devices that don't pair using this approach. – Brian Reinhold Feb 07 '17 at 00:39
0

It's an old question, but I will answer to help someone.
Unfortunately, the combination of ACCESS_COARSE_LOCATION and targetSdkVersion 22 does not work on some devices.
This is not a good method, but I have solved it in the following way without using runtime permissions (ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION)

  1. Set your 'targetSdkVersion' to 19 (I think maybe api19 ~ api22 will be possible)
  2. Add the following permission to your manifest file

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

tested to Android 4.4 ~ 7.1.1

Andromer
  • 123
  • 2
  • 12
-3

Set your 'minSdkVersion' to 18 targetSdkVersion 22

Rest
  • 17
  • 5