I'm developing a flutter application, I need to manage the permission request, but I don't know how to treat a particular occurrence:
If I deny two times the same permission through the popup it could be impossible approve it later 'cause the popup will not appair again.
Future<void> requestStoragePermission() async{
var status = await Permission.storage.status;
if(status.isPermanentlyDenied){
await AppSettings.openAppSettings();
} else {
await Permission.storage.request();
}
}
I don't understand how to distinguish when the permission has not yet been granted or when it has been refused several times because the function: Permission.storage.status always returns "denied".
****** EDIT ******
The problem arises when the user refuses the same permission several times (2 times) because the permissions request popup is no longer shown, in which case it is necessary to manually open the application settings and modify the permissions by hand. I have to make sure that: the first two times I request permissions with the popup then I should open the settings screen
I have always managed my permissions using two statuses granted and limited (used only for iOS14+). These two permissions are the only truethy statuses. All the others are falsey statuses.
the permission_handler package handles a lot of logic for you already. Before it makes the request, it will check the status to see if it is already defined. If it is, then it will return the status. If the permission has never been requested, then it will request the permission.
Personally, I set up a generic method for a permission request, to keep things DRY.
Future<bool> requestPermission(Permission setting) async {
// setting.request() will return the status ALWAYS
// if setting is already requested, it will return the status
final _result = await setting.request();
switch (_result) {
case PermissionStatus.granted:
case PermissionStatus.limited:
return true;
case PermissionStatus.denied:
case PermissionStatus.restricted:
case PermissionStatus.permanentlyDenied:
return false;
}
}
I then make a request like
final canUseStorage = await requestPermission(Permission.storage);
if (canUseStorage) {
// do something with storage
}
If you have UI that is dependent on a status from Permission, then you still call Permission.storage.status.
[EDIT]
At the moment, you can't track how many times the request pop-up has been shown via permission_handler. It only returns the status. You would need to take the user to the settings depending on the returned status value.
Side Note
Instead of taking the user directly to the settings. Maybe you show a pop up saying "Looks like we don't have permission...", with a button that the user can tap to go to the settings, provides the user with some context as to why they need to go to their settings. And it's also a better user experience!
Related
How can I programmatically determine whether the "Remove permissions if app is unused" setting is enabled or disabled for a particular app?
You can check whether the user has enabled or not, and you can also request them to disable it.
Check if the user has it enabled:
val future: ListenableFuture<Int> =
PackageManagerCompat.getUnusedAppRestrictionsStatus(context)
future.addListener(
{ onResult(future.get()) },
ContextCompat.getMainExecutor(context)
)
fun onResult(appRestrictionsStatus: Int) {
when (appRestrictionsStatus) {
// Status could not be fetched. Check logs for details.
ERROR -> { }
// Restrictions do not apply to your app on this device.
FEATURE_NOT_AVAILABLE -> { }
// Restrictions have been disabled by the user for your app.
DISABLED -> { }
// If the user doesn't start your app for months, its permissions
// will be revoked and/or it will be hibernated.
// See the API_* constants for details.
API_30_BACKPORT, API_30, API_31 ->
handleRestrictions(appRestrictionsStatus)
}
}
ask to disable it:
fun handleRestrictions(appRestrictionsStatus: Int) {
// If your app works primarily in the background, you can ask the user
// to disable these restrictions. Check if you have already asked the
// user to disable these restrictions. If not, you can show a message to
// the user explaining why permission auto-reset and Hibernation should be
// disabled. Tell them that they will now be redirected to a page where
// they can disable these features.
Intent intent = IntentCompat.createManageUnusedAppRestrictionsIntent
(context, packageName)
// Must use startActivityForResult(), not startActivity(), even if
// you don't use the result code returned in onActivityResult().
startActivityForResult(intent, REQUEST_CODE)
}
Source: https://android-developers.googleblog.com/2021/09/making-permissions-auto-reset-available.html
That's a great question and I'm still trying to determine what that even means.
It appears on my Bixby app that came installed on my Samsung. It goes off at random at least 4 times an hour.
I've disabled it many times and I feel "remove permissions if app is unused" is worded in such a confusing way intentionally with the intention to be invasive.
This question is about permission handler package.
There are 2 methods in the library to check for a permission's status, for example in case of the microphone we can call:
PermissionStatus status1 = await Permission.microphone.status //call 1
PermissionStatus status2 = await Permission.microphone.request() //call 2
suppose a user presses the 'dont ask again' when he is prompted to grant the permission.
Now If:
we make call 1 to get the permission status, we should expect to get PermissionStatus.permanentlyDenied but the result is PermissionStatus.denied
we make call 2 to get the permission status, we expect to get PermissionStatus.permanentlyDenied and without the dialouge appearing again to the user, and this is exactly what happens
So call 2 works as intended but call 1 works as if there are only 2 states for a permission that can be returned from this call: granted or denied. But then how can we get the real status of the permission (for example it may be deniedPermanently) without calling request() in this case? Is this a bug or is this the intended behaviour? Sometimes I need to just check the status of the permission but I don't want to open a permission dialouge to the user, how to do that?
I will explain my use-case breifly:
I call the Permission.microphone.request() first time and then update my widget's state, then if the app (in android: activity) is paused, in the didChangeAppLifecycleState method which comes from the WidgetsBindingObserver mixin, I do check if the permission was revoked or permanently denied using Permission.microphone.status, but the problem is that this method is returning a denied status even when the permission is permanentlyDenied, and the correct return value which is permanentlyDenied is only returned if I call Permission.microphone.request()
code demo:
PermissionStatus result = await Permission.microphone.request();//this returns permanentlyDenied without opening the dialouge => ok
PermissionStatus result = await Permission.microphone.status;//this returns denied even if the status was permanently denied without opening the dialouge => NOT OK
I wonder how to open permission setting for specific app in Flutter? I search on internet but no article show me how to do that, just some solutions for android, like this. Open app permission settings
hi there try this code to ask for permission and open app settings like for location with the help of permission_handler(https://pub.dev/packages/permission_handler) package
Future<void> _request_permission(context,Function fn)async{
final Permission location_permission=Permission.location;
bool location_status=false;
bool ispermanetelydenied= await location_permission.isPermanentlyDenied;
if(ispermanetelydenied) {
print("denied");
await openAppSettings();
}else{
var location_statu = await location_permission.request();
location_status=location_statu.isGranted;
print(location_status);
}
}
Here this function allows you to open the app setting and manage permission in the case user permanently denied the permission
openAppSettings();
thanks
#azad-prajapat
And when I look at the package code I found this
/// Opens the app settings page.
///
/// Returns [true] if the app settings page could be opened, otherwise
/// [false].
Future<bool> openAppSettings() {
throw UnimplementedError('openAppSettings() has not been implemented.');
}
I started learning about how I can request app permissions from the Google Documentation. This is basically the code that I'm trying to execute.
// Register the permissions callback, which handles the user's response to the
// system permissions dialog. Save the return value, an instance of
// ActivityResultLauncher. You can use either a val, as shown in this snippet,
// or a lateinit var in your onAttach() or onCreate() method.
val requestPermissionLauncher =
registerForActivityResult(RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
// Permission is granted. Continue the action or workflow in your
// app.
} else {
// Explain to the user that the feature is unavailable because the
// features requires a permission that the user has denied. At the
// same time, respect the user's decision. Don't link to system
// settings in an effort to convince the user to change their
// decision.
}
}
Unfortunately, whenever I'm trying to write the registerForActivityResult(...) part, Android Studio keeps highlighting it as an error.
There's another step that I need to perform along with this. It tells me to add this dependency. Even after doing that, Android Studio still shows me that it shows an error. Can anyone tell me why this happens?
You're missing the following
// Kotlin
implementation 'androidx.activity:activity-ktx:1.2.0-beta01'
implementation 'androidx.fragment:fragment-ktx:1.3.0-beta01'
I'm trying to get the user to enable the location group permission for my app with Cordova's hasPermission/requestPermission methods, but the results are confusing...
When I call hasPermission with ACCESS_FINE_LOCATION, it always returns true. Calling this on Manifest.permission_group.LOCATION seems to return true/false appropriately.
Calling requestPermission with Manifest.permission_group.LOCATION doesn't present a system dialog, so I'm calling this with ACCESS_FINE_LOCATION to get the dialog.
The dialog Allow button turns on the Location group permission for my app and calls onRequestPermissionResult with PackageManager.PERMISSION_GRANTED, but the Deny button also returns ...GRANTED, leaving the Location group permission off.
For illustration, here's my current code:
private void checkPermissions() {
if (!cordova.hasPermission(Manifest.permission_group.LOCATION)) {
cordova.requestPermission(this, PERMISSION_RUNTIME_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION);
}
}
#Override
public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) throws JSONException {
if (permissions.length != 1 || grantResults.length != 1 || !Manifest.permission.ACCESS_FINE_LOCATION.equals(permissions[0])) {
throw new RuntimeException("Unexpected permission results " + Arrays.toString(permissions) + ", " + Arrays.toString(grantResults));
}
int result = grantResults[0];
String action = null;
switch (result) {
case PackageManager.PERMISSION_DENIED:
action = Constants.ACTION_RUNTIME_PERMISSION_DENIED;
break;
case PackageManager.PERMISSION_GRANTED:
action = Constants.ACTION_RUNTIME_PERMISSION_GRANTED;
break;
default:
throw new RuntimeException("Unexpected permission result int " + result);
}
Intent i = new Intent(action);
i.putExtra("permission", Constants.EXTRA_RUNTIME_PERMISSION_NOTIFICATION_ID);
getContext().sendBroadcast(i);
}
What's the right way to handle this? Sometimes using an individual permission and sometimes using a group with these methods doesn't seem right - I would expect this to be consistent. My guess is that the PERMISSION_GRANTED after the DENY button is pushed on the dialog is because I'm requesting an individual permission, which is on even though the group is off; is there a way to detect that the user denied the request?
I have a lot of questions there which basically boil down to "how do I either get the user to enable the Location group permission when it's off or know when they decline"?
If it helps, my android-targetSdkVersion is set to 22, and I'm using Cordova 6.1.1.
If it helps, my android-targetSdkVersion is set to 22, and I'm using Cordova 6.1.1.
Android run-time permissions were only introduced in API 23, so if your android-targetSdkVersion is set to 22, run-time permissions code will always return GRANTED for any permission, since permissions are granted at installation time via the manifest.
However, if your app is displaying runtime permissions dialogs, I'm guessing that you must be building against API 23 and using cordova-android#5+ for the Android platform.
Regarding permission groups vs individual permissions, you should read the Android documentation regarding runtime permissions:
The dialog box shown by the system describes the permission group your app needs access to; it does not list the specific permission. For example, if you request the READ_CONTACTS permission, the system dialog box just says your app needs access to the device's contacts. The user only needs to grant permission once for each permission group. If your app requests any other permissions in that group (that are listed in your app manifest), the system automatically grants them. When you request the permission, the system calls your onRequestPermissionsResult() callback method and passes PERMISSION_GRANTED, the same way it would if the user had explicitly granted your request through the system dialog box.
So in your case, requesting ACCESS_FINE_LOCATION grants access to all permissions in the LOCATION group (you can find the full list of groups and permissions here).
the Deny button also returns ...GRANTED, leaving the Location group permission off.
This should not return GRANTED. If the Deny button is pressed, access will be DENIED to that entire permission group (including the requested permission). The logic in your code snippet looks OK to handle this, so I would use the step-through debugger in Android Studio to see exactly what is happening in your code here.