Reputation: 147
I have implemented Runtime Permission. For testing purpose I have denied location permission and then again I have denied the permission with "Never to ask again" checkbox. Now there is the problem. OnRequestPermissionResult is being called again and again from the system. For this, I can't show a dialog or snackbar on the screen properly. Here is my implementation. Where is the problem?
Checking location permission
override fun onResume() {
super.onResume()
if (checkLocationPermission())
startLocationUpdates()
updateUI()
}
This is my location update call
@SuppressLint("MissingPermission")
private fun startLocationUpdates() {
// Begin by checking if the device has the necessary location settings.
mLocationSettingsClient.checkLocationSettings(mLocationSettingsRequest)
.addOnSuccessListener(this, {
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
updateUI()
})
.addOnFailureListener(this, {
handlingLocationClientSettingsFailure(it)
});
}
private fun handlingLocationClientSettingsFailure(it: Exception) {
val apiException = it as ApiException
when (apiException.statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> {
try {
Lg.d(TAG, "Inside start location update method FAILURE: REQUIRED")
// Show the dialog by calling startResolutionForResult(), and check the
// result in onActivityResult().
val rae = it as ResolvableApiException
rae.startResolutionForResult(this@MainActivity, REQUEST_CHECK_SETTINGS);
} catch (sie: IntentSender.SendIntentException) {
Log.i(TAG, "PendingIntent unable to execute request.");
}
}
LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> {
val errorMessage = "Location settings are inadequate, and cannot be " +
"fixed here. Fix in Settings.";
Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show();
mRequestingLocationUpdates = false;
}
}
updateUI()
}
override fun onStop() {
super.onStop()
stopLocationUpdates()
}
private fun stopLocationUpdates() {
if (!mRequestingLocationUpdates) {
Lg.d(TAG, "Permission Denied! So No op!!!")
return
}
mFusedLocationClient.removeLocationUpdates(mLocationCallback)
.addOnCompleteListener(this) { mRequestingLocationUpdates = false }
}
private val MY_PERMISSIONS_REQUEST_LOCATION = 99;
private fun startLocationPermissionRequest() {
ActivityCompat.requestPermissions(this@MainActivity,
arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION),
MY_PERMISSIONS_REQUEST_LOCATION);
}
private fun checkLocationPermission(): Boolean {
if (ContextCompat.checkSelfPermission(this@MainActivity, ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(this@MainActivity, ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
android.Manifest.permission.ACCESS_FINE_LOCATION)) {
showSnackbar(R.string.location_permission_rationale,
android.R.string.ok,
View.OnClickListener {
startLocationPermissionRequest()
})
} else {
// No explanation needed, we can request the permission.
startLocationPermissionRequest()
}
return false
} else {
// Permission has already been granted
return true
}
}
@SuppressLint("NeedOnRequestPermissionsResult")
override fun onRequestPermissionsResult(requestCode: Int,
permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
MY_PERMISSIONS_REQUEST_LOCATION -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// location-related task you need to do.
if (ContextCompat.checkSelfPermission(this@MainActivity, ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(this@MainActivity, ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
) {
setLocationEnabled()
startLocationUpdates()
}
} else {
val showRationale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
shouldShowRequestPermissionRationale(permissions[0])
} else {
TODO("VERSION.SDK_INT < M")
}
if (!showRationale) {
// user also CHECKED "never ask again"
// you can either enable some fall back,
// disable features of your app
// or open another dialog explaining
// again the permission and directing to
// the app setting
showingNecessaryMsgForLocationPermissionDenied()
} else {
// user did NOT check "never ask again"
// this is a good place to explain the user
// why you need the permission and ask if he wants
// to accept it (the rationale)
}
}
return
}
// other 'case' lines to check for other
// permissions this app might request
}
}
private fun showingNecessaryMsgForLocationPermissionDenied() {
Lg.d("TestTag", "Called")
MaterialDialog.Builder(this)
.title("Permission")
.content(R.string.permission_denied_explanation)
.onPositive { dialog, which ->
// Build intent that displays the App settings screen.
val intent = Intent().apply {
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
data = Uri.fromParts("package", APPLICATION_ID, null)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
startActivity(intent)
}
.positiveText(R.string.ok)
.show()
}
In this showingNecessaryMsgForLocationPermissionDenied() function I put a log, in my logcat I see that this function called again and again. How to stop it? Here is the logcat screentshot
I want to show this dialog when user denied permission. But I can't draw this smoothly for the above problem.
Note: I have tested the google repository of location update project. Same problem
Upvotes: 2
Views: 1512
Reputation: 326
Based on the documentation of Activity.requestPermissions
This method may start an activity allowing the user to choose which permissions to grant and which to reject. Hence, you should be prepared that your activity may be paused and resumed. Further, granting some permissions may require a restart of your application.
In this code, you are calling checkLocationPermission()
in onResume()
. Then from checkLocationPermission()
call goes to requestPermissions
which takes Activity in onPasue()
. After onRequestPermissionsResult()
, onResume()
gets called again, creating infinte loop.
I would suggest having a boolean variable to decide if to call to checkLocationPermission()
required.
var isRequestRequired = true;
override fun onResume() {
super.onResume()
if (isRequestRequired && checkLocationPermission())
startLocationUpdates()
updateUI()
}
then update isRequestRequired
to false before showingNecessaryMsgForLocationPermissionDenied()
isRequestRequired = false
showingNecessaryMsgForLocationPermissionDenied()
This will stop onResume()
from calling checkLocationPermission()
again and again
Upvotes: 6