-
-
Notifications
You must be signed in to change notification settings - Fork 35
[android] "Can request only one set of permissions at a time." #53
Comments
I am calling |
Full logs:
|
Also my guess the bug is in returning the result for |
The following code is working now. uture<bool> _checkLocationPermission() async {
final checkPermission = await LocationPermissions().checkPermissionStatus();
printIfDebug("checkPermission: $checkPermission");
if (checkPermission == PermissionStatus.granted ||
checkPermission == PermissionStatus.restricted) return true;
return false;
}
Future<bool> _checkAndRequestLocationPermission() async {
// return true, if already have permission
if (await _checkLocationPermission()) return true;
// request permission
PermissionStatus requestPermission = PermissionStatus.unknown;
int count = 0;
while (requestPermission == PermissionStatus.unknown && count < 20) {
requestPermission = await LocationPermissions().requestPermissions();
printIfDebug("requestPermission: $requestPermission");
await Future.delayed(Duration(seconds: 1));
count++;
}
// check if permission was given
final hasPermission = await _checkLocationPermission();
// if no permission and "showShowPermissionRationale" then go to settings and return false
if (!hasPermission &&
await LocationPermissions().shouldShowRequestPermissionRationale()) {
// if shouldRequest false, then open app settings and return false
// TODO UI that shows why this permission is required
await LocationPermissions().openAppSettings();
return false;
}
return hasPermission;
} Basically have added a while loop that keeps on requesting until it return unkown status. The correct behaviour should be that the method returns proper status in one attempt without loop. Could the bug be because of Acitivyt going inactive/pause when asking for permission causing detachment? |
@daadu , I run into the same issue as you. In my case, I created quickly a prototype of an activity as an experiment. This activity would check each permission, ask the user to allow it, and if there was any permission that wasn't a allowed, then a dialog would show up. The dialog would explain the user why that permission was needed request again for that permission. Note: I wouldn't be surprise that there is an error in the code below since I created in a rush class PermissionsActivity : AppCompatActivity() {
companion object {
private val TAG = PermissionsActivity::class.java.simpleName
private const val ACCESS_NETWORK_STATE_CODE : Int = 100
private const val CHANGE_NETWORK_STATE_CODE : Int = 101
private const val ACCESS_INTERNET_CODE : Int = 102
private const val ACCESS_CAMERA_CODE : Int = 103
private const val ACCESS_COARSE_LOCATION_CODE : Int = 104
private const val ACCESS_FINE_LOCATION_CODE : Int = 105
private const val ACCESS_BACKGROUND_LOCATION_CODE: Int = 106
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_permissions)
requestPermissions()
confirmPermissions()
}
private fun requestPermissions(){
if (!hasPermission(Manifest.permission.ACCESS_NETWORK_STATE)) requestAccessNetwork()
if (!hasPermission(Manifest.permission.CHANGE_NETWORK_STATE)) requestChangeNetwork()
if (!hasPermission(Manifest.permission.CAMERA)) requestCamera()
if (!hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)) requestFineLocation()
if (!hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)
&& !hasPermission(Manifest.permission.ACCESS_COARSE_LOCATION)) requestCoarseLocation()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (!hasPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION)) requestBackgroundLocation()
}
}
private fun hasPermission(id: String): Boolean {
return ActivityCompat.checkSelfPermission(this, id) == PackageManager.PERMISSION_GRANTED
}
private fun requestAccessNetwork(){
requestPermission(
Manifest.permission.ACCESS_NETWORK_STATE,
ACCESS_NETWORK_STATE_CODE
)
}
private fun requestPermission(permission: String, code: Int){
ActivityCompat.requestPermissions(
this,
arrayOf(permission),
code
)
}
private fun requestChangeNetwork(){
requestPermission(
Manifest.permission.CHANGE_NETWORK_STATE,
CHANGE_NETWORK_STATE_CODE
)
}
private fun requestCamera(){
requestPermission(
Manifest.permission.CAMERA,
ACCESS_CAMERA_CODE
)
}
private fun requestCoarseLocation(){
requestPermission(
Manifest.permission.ACCESS_COARSE_LOCATION,
ACCESS_COARSE_LOCATION_CODE
)
}
private fun requestFineLocation(){
requestPermission(
Manifest.permission.ACCESS_FINE_LOCATION,
ACCESS_FINE_LOCATION_CODE
)
}
@RequiresApi(Build.VERSION_CODES.Q)
private fun requestBackgroundLocation(){
requestPermission(
Manifest.permission.ACCESS_BACKGROUND_LOCATION,
ACCESS_BACKGROUND_LOCATION_CODE
)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String?>,
grantResults: IntArray,
) {
Log.d(TAG, "onRequestPermissionsResult()")
when (requestCode) {
ACCESS_NETWORK_STATE_CODE ->
if (wasPermissionGranted(grantResults)) {
changeTintToGreen(R.id.imageViewNetworkAccess)
} else {
showDialog(
"Access Network State Permission",
"Allow access network state permission to talk to the server",
requestAccessNetwork()
)
}
CHANGE_NETWORK_STATE_CODE ->
if (wasPermissionGranted(grantResults)) {
changeTintToGreen(R.id.imageViewNetworkAccess)
} else {
showDialog(
"Change Network State Permission",
"Allow change network state permission to talk to the server",
requestAccessNetwork()
)
}
ACCESS_INTERNET_CODE ->
if (wasPermissionGranted(grantResults)) {
changeTintToGreen(R.id.imageViewInternetAccess)
} else {
showDialog(
"Access Internet Permission",
"Allow access internet permission to talk to the server",
requestAccessNetwork()
)
}
ACCESS_CAMERA_CODE ->
if (wasPermissionGranted(grantResults)) {
changeTintToGreen(R.id.imageViewCameraAccess)
} else {
showDialog(
"Access Camera Permission",
"Allow access camera permission to scan QR barcodes",
requestAccessNetwork()
)
}
ACCESS_FINE_LOCATION_CODE ->
if (wasPermissionGranted(grantResults)) {
changeTintToGreen(R.id.imageViewBackgroundLocationAccess)
} else {
showDialog(
"Access Fine Location Permission",
"Allow access to fine location permission for fine location",
requestAccessNetwork()
)
}
ACCESS_COARSE_LOCATION_CODE ->
if (wasPermissionGranted(grantResults)) {
changeTintToGreen(R.id.imageViewCoarseLocationAccess)
} else {
showDialog(
"Access Coarse Location Permission",
"Allow access to coarse location permission for general location",
requestAccessNetwork()
)
}
ACCESS_BACKGROUND_LOCATION_CODE ->
if (wasPermissionGranted(grantResults)) {
changeTintToGreen(R.id.imageViewNetworkAccess)
} else {
showDialog(
"Access Background Location Permission",
"Allow access to background location permission for fine and general location in Android 10+",
requestAccessNetwork()
)
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
private fun wasPermissionGranted(grantResults: IntArray): Boolean {
return grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED
}
private fun changeTintToGreen(id: Int){
findViewById<ImageView>(id).setColorFilter(
ContextCompat.getColor(
this,
R.color.green),
android.graphics.PorterDuff.Mode.MULTIPLY
);
}
private fun showDialog(title: String, message: String, callback: Unit){
AlertDialog.Builder(this)
.setTitle(title)
.setMessage(message)
.setPositiveButton("Allow") { _, _ ->
callback
}
.setNegativeButton("Cancel") { dialog, _ ->
dialog.dismiss()
setResult(RESULT_CANCELED, Intent())
finish()
}
.create()
.show()
}
private fun confirmPermissions() {
var result = true
result = result and hasPermission(Manifest.permission.ACCESS_NETWORK_STATE)
result = result and hasPermission(Manifest.permission.CHANGE_NETWORK_STATE)
result = result and hasPermission(Manifest.permission.CAMERA)
result = result and hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)
if (!hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {
result = result and hasPermission(Manifest.permission.ACCESS_COARSE_LOCATION)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
result = result and hasPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
}
if (result){
setResult(RESULT_OK, Intent())
} else {
setResult(RESULT_CANCELED, Intent())
}
finish()
}
} Personally, it would be great that the Android API would take care of asking the user for the permissions automatically based on what is in the |
π Bug Report
Calling
await LocationPermissions().requestPermissions();
with both "Fine" and "Coarse" permission inAndroidManifest.xml
gives theCan request only one set of permissions at a time.
in the logs. Also, givingPermissionStatus.denied
(even if approved) whencheckPermissions
called after awaitingrequestPermissions
.Expected behaviour
The error/warning should not come in and correct status should be returned by
checkPermissions
afterrequestPermissions
is called.Reproduction steps
Code to reproduce:
This is how it it is used for checking access for location before calling
WifiManager.startScan
api on androidConfiguration
Android SDK: 28
Version:
^3.0.0
Platform:
The text was updated successfully, but these errors were encountered: