I have created an app in which I want to discover Bluetooth devices and connect to one of them.
This app works perfectly fine on a smartphone with Android 10 and a smartphone with Android 12. However, I have a problem on a tablet with Android 11.
I have all needed permissions in the manifest. (Note: I have tried it both with and without android:maxSdkVersion="28"
for the ACCESS_COARSE_LOCATION
permission)
<!--Before Android 12-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<!--From Android 12-->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
But when it comes to using BluetoothAdapter.startDiscovery()
, there seems to be a problem, since it returns false
when used on the Android 11 tablet.
public void startDiscoveryOfBTDevices() {
Log.d(TAG, "startDiscoveryOfBTDevices: Looking for unpaired devices.");
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
Log.d(TAG, "startDiscoveryOfBTDevices: Canceling discovery.");
}
if (mBluetoothAdapter.startDiscovery()) {
Log.d(TAG, "DISCOVERY STARTED");
IntentFilter discoverDevicesIntent = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(broadcastReceiver2, discoverDevicesIntent);
Log.d(TAG, "AFTER: " + discoverDevicesIntent);
} else {
Log.d(TAG, "DISCOVERY DOESN'T WORK");
}
}
I check for and request all the needed location and bluetooth permissions on runtime. And I even checked the location permissions directly before calling startDiscovery
, just to make sure:
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "NOT GRANTED");
return;
}
That was all fine.
I even checked if it was caused by the GPS_PROVIDER not being turned on, as suggested in this answer, but no change in behavior. The smartphones with Android 10 and Android 12 worked fine, but the tablet with Android 11 didn't, although all three devices had the GPS disabled.
I did all of those things based on answers of similar questions here on SO and Google.
Now my question is, if there is a way to find out what causes the error in startDiscovery
. Is there something like an error object or log, which could give me more information?
In case it might be important, the problem occurs on a Teclast M40 Pro with Android 11.
EDIT
I looked into the source code for startDiscovery
:
public boolean startDiscovery() {
if (getState() != STATE_ON) return false;
try {
synchronized(mManagerCallback) {
if (mService != null) return mService.startDiscovery();
}
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
Looking at it, you can see, that there are only two places from which it returns false
.
I checked the state directly before calling startDiscovery
with BluetoothAdapter.getState()
and it returned 12, which is the value of the constant STATE_ON
. So, that doesn't seem to be the place from where it returns false
.
That means, it returns false
at the end of the function. But that should only occur, if there is a RemoteException, which gets caught, or if mService == null
, if I understand the code correctly.
I didn't see any error from the BluetoothAdapter in Logcat, so mService
would need to be null
. But the only time it becomes null
is in onBluetoothServiceDown
. And as far as I could find out, that only occurs, when
But Bluetooth is on, and it is the initial try to discover Bluetooth devices.
So, I am still not closer to knowing, why it returns false
.
EDIT #2
I realized through Kozmotronik's comment, that I didn't point out the following before.
I check if the Bluetooth is active, before calling startDiscoveryOfBTDevices()
with the following function:
public void checkBluetooth() {
if (mBluetoothAdapter == null) {
Log.d(TAG, "checkBluetooth: Does not have BT capabilities.");
} else if (!mBluetoothAdapter.isEnabled()) {
Log.d(TAG, "checkBluetooth: enabling BT.");
Intent enableBTIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivity(enableBTIntent);
IntentFilter BTIntent = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(broadcastReceiver1, BTIntent);
} else {
Log.d(TAG, "checkBluetooth: BT already on.");
// Start discovery
startDiscoveryOfBTDevices();
}
}
I got it to work after manually turning on location services.
I am not sure, why it was necessary to turn them on manually, since it worked fine on my phones without having to turn them on manually.
The permissions to access location were given correctly. But it seems, that it isn't possible to use the location services on this tablet, if they haven't been turned on, even if the permissions were given.