I looked at the way that most devs handle Android runtime permissions and immediately after you are verifying that a permission is granted you are calling the API which requires that granted permission. Well I tried to do that but I got an exception thrown
Fatal Exception: java.lang.SecurityException Need android.permission.BLUETOOTH_CONNECT permission for android.content.AttributionSource@d1109f50: AdapterService getBondedDevices android.os.Parcel.createExceptionOrNull (Parcel.java:2426)
android.bluetooth.BluetoothAdapter.getBondedDevices (BluetoothAdapter.java:2491)
com.starmicronics.stario.a.b (a.java:19)
com.starmicronics.stario.StarIOPort.searchPrinter (StarIOPort.java:36)
com.dd.ddmerchant.printer.StarPrinterManager.init (StarPrinterManager.kt:72)
com.dd.ddmerchant.printer.StarPrinterManager.connect (StarPrinterManager.kt:43)
com.dd.ddmerchant.mainactivity.presentation.MainActivity$onRequestPermissionsResult$1.invoke (MainActivity.kt:701)
com.dd.ddmerchant.mainactivity.presentation.MainActivity$onRequestPermissionsResult$1.invoke (MainActivity.kt:698)
com.dd.ddmerchant.mainactivity.presentation.MainActivity$delay$$inlined$postDelayed$1.run (View.kt:412) android.os.Handler.handleCallback (Handler.java:938)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1003)
so I tried to add a delay before interacting with the API that requires the granted permission, however on some devices that delay isn't long enough and I still get this error above on certain devices (although the delay seems to mitigate the issue for most devices) which may have other things running which causes a delay. How do you recommend handling this situation?
I just tried this approach but the code gets complicated and it doesn't work for every situation.
Here is my Permission code
object Permissions {
@JvmStatic
fun checkRuntimePermission(
context: Activity,
permission: String,
isRationaleDialogHidden: Boolean,
showRationaleDialog: () -> Unit,
requestPermissionBlock: () -> Unit,
permissionGrantedBlock: () -> Unit
) {
when (checkSelfPermission(context, permission)) {
PackageManager.PERMISSION_DENIED -> {
if (ActivityCompat.shouldShowRequestPermissionRationale(context, permission)) {
if (isRationaleDialogHidden) {
showRationaleDialog()
}
} else {
requestPermissionBlock()
}
}
PackageManager.PERMISSION_GRANTED -> {
permissionGrantedBlock()
}
}
}
@JvmStatic
fun checkRuntimePermission(
context: Activity,
permission: String,
permissionDeniedBlock: () -> Unit,
permissionGrantedBlock: () -> Unit
) {
when (checkSelfPermission(context, permission)) {
PackageManager.PERMISSION_DENIED -> {
permissionDeniedBlock()
}
PackageManager.PERMISSION_GRANTED -> {
permissionGrantedBlock()
}
}
}
@JvmStatic
fun isPermissionGranted(grantResults: IntArray): Boolean {
var isPermissionGranted = true
grantResults.forEach {
if (it == PackageManager.PERMISSION_DENIED) {
isPermissionGranted = false
}
}
return isPermissionGranted
}
@JvmStatic
fun isFineLocationPermissionGranted(context: Context): Boolean {
return checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED
}
private fun checkSelfPermission(context: Context, permission: String) =
ActivityCompat.checkSelfPermission(context, permission)
}
Here is how I request the permission
val requestBluetoothConnectPermissionBlock: () -> Unit = {
ActivityCompat.requestPermissions(
this@DeviceListActivity,
arrayOf(Manifest.permission.BLUETOOTH_CONNECT),
BLUETOOTH_CONNECT_REQUEST_CODE
)
}
checkRuntimePermission(
context = this,
permission = Manifest.permission.BLUETOOTH_CONNECT,
isRationaleDialogHidden = isRationaleDialogHidden(),
showRationaleDialog = {
showRationaleDialog(requestBluetoothConnectPermissionBlock)
},
requestPermissionBlock = requestBluetoothConnectPermissionBlock,
permissionGrantedBlock = {
bluetoothConnectPermissionGranted = true
}
)
And here is the override of onRequestPermissionsResult()
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
BLUETOOTH_DISCOVERY_REQUEST_CODE -> {
if (isPermissionsAllowed(grantResults)) {
bluetoothDiscoveryPermissionGranted = true
} else {
Toast.makeText(
this,
getString(
R.string.cannot_set_up_printer_without_bluetooth_permissions
),
Toast.LENGTH_LONG
).show()
finish()
return
}
}
BLUETOOTH_CONNECT_REQUEST_CODE -> {
if (isPermissionsAllowed(grantResults)) {
bluetoothConnectPermissionGranted = true
} else {
Toast.makeText(
this,
getString(
R.string.cannot_set_up_printer_without_bluetooth_permissions
),
Toast.LENGTH_LONG
).show()
finish()
return
}
}
}
}
private fun isPermissionsAllowed(grantResults: IntArray): Boolean {
var isPermissionsAllowed = true
grantResults.forEach {
if (it == PackageManager.PERMISSION_DENIED) {
isPermissionsAllowed = false
}
}
return isPermissionsAllowed
}