garrettb
garrettb

Reputation: 309

How to programmatically read and open Bluetooth location permission setting for Android app

I am designing an app in Android Studio. It scans for BLE (Bluettoth Low Energy) devices.

As soon as I try to scan I get the following popup message:

Location permission required

Starting from Android M (6.0), the system requires apps to be granted location access in order to scan for BLE devices.

There is no OK button or anything.

Is there a way to add (Kotlin) code, before scanning, to

(a) check if Bluetooth Location Permission has already been granted by the user for this app, and

(b) if not yet granted, to programmatically launch/open the settings page for the user

Thanks in advance

Garrett

EXTRA INFORMATION / QUESTION ADDED......

Thank you user18309290 for your response.

I went through the documentation, and together with other examples I found, I cobbled together the following code, which works and maybe doesn’t work.

Behaviour:

The very first time the app is launched, the Android OS prompts the user to allow access to the device's location:

Allow YourApp to access this device's location?
While using the app
Only this time
Don't allow

So, I selected "Don't allow", so that I could test my code

From then on, the Alert Dialog pops up, notifying the user that the device requirs location access. When the user selects "OK", the relevant permission(s) are requested. However, the result of the requestPermissions() call is always PERMISSION_DENIED.

Now, what I don’t know is if this is the correct / expected behaviour of my code, or not.

When requestPermissions() is called, should this prompt the Android OS to display the location options to the user (While using the app | Only this time | Don't allow) or does this call just reflect the current setting?

Is there a separate call my code needs to make to actually get the OS to launch the location setting option?

I have detailed my code below.

<!-- Request legacy Bluetooth permissions on older devices. -->
    <uses-permission android:name="android.permission.BLUETOOTH"
        android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
        android:maxSdkVersion="30" />

    <!-- Needed only if your app looks for Bluetooth devices.
         If your app doesn't use Bluetooth scan results to derive physical
         location information, you can strongly assert that your app
         doesn't derive physical location. -->
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />

    <!-- Needed only if your app makes the device discoverable to Bluetooth
         devices. -->
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

    <!-- Needed only if your app communicates with already-paired Bluetooth
         devices. -->
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

    <!-- Needed only if your app uses Bluetooth scan results to derive physical location. -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

In MainActivity.kt:

private fun requestLocationPermission() {
    if (isLocationPermissionGranted) {
        return
    }
    runOnUiThread {

        val builder = AlertDialog.Builder(this, R.style.AlertDialogCustom)
        builder.setMessage("Starting from Android M (6.0), the system requires apps to be granted " +
            "location access in order to scan for BLE devices.\n" +
            "Open Bluetooth settings for this app now?")
            .setPositiveButton(android.R.string.ok,
                DialogInterface.OnClickListener { dialog, id ->
                    requestBlePermissions(this, LOCATION_PERMISSION_REQUEST_CODE)
                })
            .setNegativeButton(android.R.string.cancel,
                DialogInterface.OnClickListener { dialog, id ->
                    // do something
                })
            .setTitle("Location permission required")
        // Create the AlertDialog
        val alertDialog: AlertDialog = builder.create()
        // Set other dialog properties
        alertDialog.setCancelable(false)
        alertDialog.show()
    }
}

fun requestBlePermissions(activity: Activity?, requestCode: Int) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        ActivityCompat.requestPermissions(
            activity!!,
            ANDROID_12_BLE_PERMISSIONS,
            requestCode
        )
    } else {
        ActivityCompat.requestPermissions(
            activity!!,
            BLE_PERMISSIONS,
            requestCode
        )
    }
 }

private val BLE_PERMISSIONS = arrayOf(
    Manifest.permission.ACCESS_COARSE_LOCATION,
    Manifest.permission.ACCESS_FINE_LOCATION
)

private val ANDROID_12_BLE_PERMISSIONS = arrayOf(
    Manifest.permission.BLUETOOTH_SCAN,
    Manifest.permission.BLUETOOTH_CONNECT,
    Manifest.permission.ACCESS_COARSE_LOCATION,
    Manifest.permission.ACCESS_FINE_LOCATION
)


override fun onRequestPermissionsResult(
      requestCode: Int,
      permissions: Array<out String>,
      grantResults: IntArray
  ) {
  super.onRequestPermissionsResult(requestCode, permissions, grantResults)
  when (requestCode) {
      LOCATION_PERMISSION_REQUEST_CODE -> {
      if (grantResults.firstOrNull() == PackageManager.PERMISSION_DENIED) {
        requestLocationPermission()
      } else {
        startBleScan()
      }
    }
  }
}

Upvotes: 1

Views: 1612

Answers (1)

user18309290
user18309290

Reputation: 8340

Here are instructions on how to request location permission: Request location access at runtime.

Note that from Android 12 or higher permissions for BLE usage has changed. Location permission is replaced with BLUETOOTH_SCAN. See details Bluetooth permissions.

Upvotes: 2

Related Questions