Android 12 bluetooth permissions confusion
Targeting Android 12 my working solution is to declare the permissions in this way:
Like you said, BLUETOOTH_SCAN is not sufficient and you need BLUETOOTH_CONNECT (also if you decide, like me, to ask to the user to enable Bluetooth starting a new startActivityForResult with action BluetoothAdapter.ACTION_REQUEST_ENABLE)
If the BLUETOOTH_CONNECT permission needs to be requested at runtime what is the correct full way to do it? Meaning checking if it’s already granted then requesting it if it’s not. I have no Android 12 device so no way to test this code.
To improve @AndreasGobs answer, below the code to test if the connection with a device is viable or not based on current available permissions. In the manifest I’ve set that the COARSE and FINE location permissions must be limited to max API 30. Tested on Android 6, 8.1, 11 and 12 devices. I hope this will be useful.
/** * - API < S * - Check ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION permissions * - API < O * - Check has GPS * - Check GPS enabled * - API >= S * - Check BLUETOOTH_SCAN permission * - Check BLUETOOTH_CONNECT permission * - Check Bluetooth enabled */ private boolean canConnect() < Timber.d("canConnect called"); ListdeniedPermissions = new ArrayList<>(); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) < if (!checkPermission(Manifest.permission.ACCESS_COARSE_LOCATION)) deniedPermissions.add(Manifest.permission.ACCESS_COARSE_LOCATION); if (!checkPermission(Manifest.permission.ACCESS_FINE_LOCATION)) deniedPermissions.add(Manifest.permission.ACCESS_FINE_LOCATION); if(deniedPermissions.isEmpty())< if (!MmcDeviceCapabilities.hasLocationGps() //check if the device has GPS || Build.VERSION.SDK_INT < Build.VERSION_CODES.O || MmcDeviceCapabilities.isGpsEnabled())< //check if the GPS is enabled if(MmcDeviceCapabilities.bluetoothEnabled()) //check if bluetooth is enabled return true; else < requestEnableBluetooth(); //method to request enable bluetooth return false; >> else < Timber.d("Request enable GPS"); requestEnableGps(); //method to request enable GPS (improving devices scan) return false; >> else < Timber.d("Request GPS permissions"); requestRuntimePermissions( "Bluetooth GPS request", "GPS permissions request rationale", GPS_PERMISSIONS_CODE, deniedPermissions.toArray(new String[0])); return false; >> else < // Build.VERSION_CODES.S or later if(!checkPermission(Manifest.permission.BLUETOOTH_SCAN)) deniedPermissions.add(Manifest.permission.BLUETOOTH_SCAN); if(!checkPermission(Manifest.permission.BLUETOOTH_CONNECT)) deniedPermissions.add(Manifest.permission.BLUETOOTH_CONNECT); if(deniedPermissions.isEmpty()) if(MmcDeviceCapabilities.bluetoothEnabled()) //check if bluetooth is enabled return true; else < requestEnableBluetooth(); //method to request enable bluetooth return false; >else < Timber.d("Request bluetooth permissions"); requestRuntimePermissions( "Bluetooth permissions request", "Bluetooth permissions request rationale", CONNECT_PERMISSIONS_CODE, deniedPermissions.toArray(new String[0])); return false; >> > /** * This method checks if a runtime permission has been granted. * @param permission The permission to check. * @return TRUE
if the permission has been granted, FALSE
otherwise. */ @SuppressWarnings("BooleanMethodIsAlwaysInverted") private boolean checkPermission(@NonNull String permission) < return ActivityCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED; >private void requestRuntimePermissions(@NonNull String title, @NonNull String description, int requestCode, @NonNull String. permissions) < if (ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[0])) < AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); builder .setTitle(title) .setMessage(description) .setCancelable(false) .setNegativeButton(android.R.string.no, (dialog, id) ->< //do nothing >) .setPositiveButton(android.R.string.ok, (dialog, id) -> ActivityCompat.requestPermissions(this, permissions, requestCode)); showDialog(builder); //method to show a dialog > else ActivityCompat.requestPermissions(this, permissions, requestCode); >
java.lang.SecurityException: Need android.permission.BLUETOOTH_CONNECT permission for AttributionSource
Please understand that the question may be a little dizzy because it’s my first time asking a question. Also, please understand that grammar may be strange because I am not good at English and use a translator. I’m a person who is making apps using java in Android studios. There was a continuous error trying to use Bluetooth. There were so many errors that I could easily find a solution, but it didn’t apply to me. Error Log
Process: org.techtown.push.bluetoothtest2, PID: 10852 java.lang.RuntimeException: Unable to start activity ComponentInfo: java.lang.SecurityException: Need android.permission.BLUETOOTH_CONNECT permission for AttributionSource < uid = 10158, packageName = org.techtown.push.bluetoothtest2, attributionTag = null, token = android.os.BinderProxy@f43a396, next = null >: AdapterService getBondedDevices at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3635) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3792) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:201) at android.os.Looper.loop(Looper.java:288) at android.app.ActivityThread.main(ActivityThread.java:7839) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003) Caused by: java.lang.SecurityException: Need android.permission.BLUETOOTH_CONNECT permission for AttributionSource < uid = 10158, packageName = org.techtown.push.bluetoothtest2, attributionTag = null, token = android.os.BinderProxy@f43a396, next = null >: AdapterService getBondedDevices at android.os.Parcel.createExceptionOrNull(Parcel.java:2425) at android.os.Parcel.createException(Parcel.java:2409) at android.os.Parcel.readException(Parcel.java:2392) at android.os.Parcel.readException(Parcel.java:2334) at android.bluetooth.IBluetooth$Stub$Proxy.getBondedDevices(IBluetooth.java:3077) at android.bluetooth.BluetoothAdapter.getBondedDevices(BluetoothAdapter.java:2491) at org.techtown.push.bluetoothtest2.MainActivity.showPairedDevicesListDialog(MainActivity.java:300) at org.techtown.push.bluetoothtest2.MainActivity.onCreate(MainActivity.java:80) at android.app.Activity.performCreate(Activity.java:8051) at android.app.Activity.performCreate(Activity.java:8031) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1329) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3608) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3792) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:201) at android.os.Looper.loop(Looper.java:288) at android.app.ActivityThread.main(ActivityThread.java:7839) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Caused by: java.lang.SecurityException: Need android.permission.BLUETOOTH_CONNECT permission for AttributionSource < uid = 10158, packageName = org.techtown.push.bluetoothtest2, attributionTag = null, token = android.os.BinderProxy@f43a396, next = null >: AdapterService getBondedDevices
I applied it because I saw that I needed «android.permission.BLUETOOTH_CONNECT permission.» However, errors continue to occur. Am I misunderstanding something? Or did I make a mistake in mainactivty.java? For your information, I made it like this when I made a project.
If there is no problem with the file you wrote down, please tell me to review the Java code again. Thank you.
Android 12 New Bluetooth Permissions
Bluetooth is the main dependency of our app. So, We already try to implement new Android 12 Bluetooth permissions. Our only resource is Android developers New Bluetooth permissions in Android 12. There is just saying add permissions
I add and I got runtime permissions for both and of course location(usual as pre 12)).
There is no other change in my codebase. Should be? I don’t know. So, the problem is my app can’t find the BLE device. I couldn’t find the reason. Do you have any suggestions or resources?
i am trying to add these permissions too but they dont exist in android studio. i only see the old ones (BLUETOOTH, BLUETOOTH_ADMIN, BLUETOOTH_ADMIN_PRIVILEGED). i set my targetSdkVersion to «S», my compileSdkVersion to «android-S», and my buildToolsVersion to «3.0.0-rc5». any idea?
I can see. My settings like this: compileSdkVersion «android-S» buildToolsVersion «30.0.3» targetSdkVersion 31
12 Answers 12
100% working solution : no need any 3rd party plugin
Kotlin code: //check android12+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) < requestMultiplePermissions.launch(arrayOf( Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT)) >else < val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) requestBluetooth.launch(enableBtIntent) >. private var requestBluetooth = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) < result ->if (result.resultCode == RESULT_OK) < //granted >else < //deny >> private val requestMultiplePermissions = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) < permissions ->permissions.entries.forEach < Log.d("test006", "$= $") > >
Not totally working for me, I’m on Android 10. I don’t see any popup asking for permissions, I immediately get to the part where the permissions are granted.
The application gets crashed if you Don’t allow permission for the first time. After that not able to get the permission dialog and got crashed every time.
In the manifest, add the following permissions:
Then, before executing a Bluetooth function, check the permission:
//--------------------------Java-------------------------- if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_DENIED) < if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) < ActivityCompat.requestPermissions(MainActivity.this, new String[], 2); return; > > //--------------------------Kotlin-------------------------- if (ContextCompat.checkSelfPermission(this@MainActivity, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_DENIED) < if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) < ActivityCompat.requestPermissions(this@MainActivity, arrayOf(Manifest.permission.BLUETOOTH_CONNECT), 2) return >>
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_DENIED) < if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) < ActivityCompat.requestPermissions(MainActivity.this, new String[], 2); return; > > mBTSocket.connect();
I just added to the manifest:
and then I requested those permissions from Main Activity as any other. For requesting permission I am using library
implementation 'pub.devrel:easypermissions:3.0.0'
then you can just call this function
public static final String[] BLUETOOTH_PERMISSIONS_S = < Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT>;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) < if (!EasyPermissions.hasPermissions(this, BLUETOOTH_PERMISSIONS_S)) < EasyPermissions.requestPermissions(this, message, yourRequestCode,BLUETOOTH_PERMISSIONS_S); >>
and override onRequestPermissionResult
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
UPDATE FOR JETPACK COMPOSE
If you are using jetpack compose you can handle it like this:
Create a list of your permissions inside of rememberMultiplePermissionState function
rememberMultiplePermissionsState( permissions = listOf( Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN ) )
Then observe a lifecycle events and on resume launch permission request
val lifecycleOwner = LocalLifecycleOwner.current DisposableEffect(key1 = lifecycleOwner, effect = < val observer = LifecycleEventObserver < _, event ->if(event == Lifecycle.Event.ON_START) < permissionsState.launchMultiplePermissionRequest() >> lifecycleOwner.lifecycle.addObserver(observer) onDispose < lifecycleOwner.lifecycle.removeObserver(observer) >>)
Observe the permission state
permissionsState.permissions.forEach < permissionState ->when(permissionState.permission) < Manifest.permission.ACCESS_FINE_LOCATION -> < when < permissionState.hasPermission -><> > > > > >
No particular reason, we were using in the old java project. Since we migrated to kotlin and compose we stopped using it.
It happens with Android 12 and Android 13. Adding new permissions could not solve the issue in my case: I have all related permissions set up for bluetooth and WiFi:
Manual solution(Screenshot added): Go to settings of the app and click on permissions. You will see Allowd and Denied(Not allowed) permissions. There will be «Nearby devices» permission in the «Not allowed» permissions list. Allow that one and the app will work without probem in Android 12 and Android 13.
If you want your app to initiate device discovery or manipulate Bluetooth settings, you must declare the BLUETOOTH_ADMIN permission in addition to the BLUETOOTH permission. Most apps need this permission solely for the ability to discover local Bluetooth devices. Don’t use the other abilities granted by this permission unless the app is a «power manager» that modifies Bluetooth settings upon user request. Declare the Bluetooth permission(s) in your app manifest file
from developer android we see you have to add
in your manifest file but you did not add it to discover other devices i think this is the resource of your problem
Thanks for your answer Barney and sorry for didn’t mention it before but BLUETOOTH_ADMIN is already added. It is not working with that also.
I had an error with BLUETOOTH_ADVERTISING missing in the android manifest when switching to Android 12
Basically, I just added checkSelfPermission(Manifest.permission.BLUETOOTH) == PackageManager.PERMISSION_GRANTED in my conditions where startAdvertising was called.
In android 12, after adding below line is working fine for me.
On Android 13, I followed the top voted answer and it fixed my «Bluetooth Scan» request issue. However, I was getting a new error for «Bluetooth Connect». After spending some time I was able to figure out that in Android 13, they made Bluetooth Connect a runtime request, so just having it in the manifest file isn’t enough. I had to overwrite my OnCreate in my MainActivity.cs file, so that it could get the permission at runtime.
private const int REQUEST_FINE_LOCATION_PERMISSION = 100; private const int REQUEST_BLUETOOTH_SCAN_PERMISSION = 101; private const int REQUEST_BACKGROUND_LOCATION_PERMISSION = 102; private const int REQUEST_BLUETOOTH_CONNECT_PERMISSION= 103; protected override void OnCreate(Bundle savedInstanceState) < base.OnCreate(savedInstanceState); RequestedOrientation = ScreenOrientation.Portrait; // Request the ACCESS_FINE_LOCATION permission at runtime if (CheckSelfPermission(Manifest.Permission.AccessFineLocation) != Permission.Granted) < RequestPermissions(new string[] < Manifest.Permission.AccessFineLocation >, REQUEST_FINE_LOCATION_PERMISSION); > if (CheckSelfPermission(Manifest.Permission.AccessBackgroundLocation) != Permission.Granted) < RequestPermissions(new string[] < Manifest.Permission.AccessBackgroundLocation >, REQUEST_BACKGROUND_LOCATION_PERMISSION); > // Request the BLUETOOTH_SCAN permission at runtime if (CheckSelfPermission(Manifest.Permission.BluetoothScan) != Permission.Granted) < RequestPermissions(new string[] < Manifest.Permission.BluetoothScan >, REQUEST_BLUETOOTH_SCAN_PERMISSION); > //Request the BLUETOOTH_CONNECT permission at runtime if (CheckSelfPermission(Manifest.Permission.BluetoothConnect) != Permission.Granted) < RequestPermissions(new string[] < Manifest.Permission.BluetoothConnect >, REQUEST_BLUETOOTH_CONNECT_PERMISSION); > >
Once I added the runtime permission, it began to work on Android 13.