flutter-permission-handler icon indicating copy to clipboard operation
flutter-permission-handler copied to clipboard

Is it possible to ask "which location level is currently available"?

Open gkrawiec opened this issue 4 years ago • 8 comments

As I understand this plugin, at least for the location permissions, I have to request the status of each possibility of permission level in order to see which my app has. for example, I have to first have to ask for the status of locationAlways, then ask for the status of LocationWhileInUse, etc, etc. This doesnt seem to be working as some respond with "undetermined".

Is there a way to just ask "which location level is available" and get a response such as "CurrentPermssion.LocationWhileInUse"? Am I missing something?

This plugin used to work fine until the rewrite a couple of months ago. Now I have these undetermined issues.

Any help will be appreciated. thanks.

gkrawiec avatar Jul 09 '20 21:07 gkrawiec

This is what I am doing right now for Android to get the answer, but I am new at programming so might not be the most efficient way.

    AppLocationPermissionLevel result;
    final PermissionState location = _status(await Permission.location.status);
    final PermissionState always =
        _status(await Permission.locationAlways.status);
    final PermissionState whileInUse =
        _status(await Permission.locationWhenInUse.status);
    if (location == PermissionState.undetermined) {
      result = AppLocationPermissionLevel.undetermined;
    } else if (always == PermissionState.granted) {
      result = AppLocationPermissionLevel.always;
    } else if ((always == PermissionState.undetermined ||
            always == PermissionState.denied) &&
        whileInUse == PermissionState.granted) {
      result = AppLocationPermissionLevel.whileInUse;
    } else if (always == PermissionState.permanentlyDenied &&
        whileInUse == PermissionState.granted) {
      result = AppLocationPermissionLevel.alwaysIsPermanentlyDenied;
    } else if (location == PermissionState.denied) {
      result = AppLocationPermissionLevel.denied;
    } else if (location == PermissionState.permanentlyDenied) {
      result = AppLocationPermissionLevel.permanentlyDenied;
    }

iOS seems much simpler, but i dont think its possible to identify the temporary always option (the one that has 2 popups with the second one appearing at a random time...I am referring to this https://hypertrack.com/blog/2020/06/24/impact-of-ios13-ios14-location-permissions-on-background-location-access/ )

gkrawiec avatar Jul 22 '20 15:07 gkrawiec

Hi @gkrawiec If you need to know if your app has a certain permission, for examplePermission.locationAlways, you need to call Permission.locationAlways.request() first. This will request the permission and should return the status after the user has chosen from the pop-up. Permission.location.status wil return granted if either Permission.locationAlways or Permission.locationWhileInUse has been granted.

Let me know if this answers your question and/or you have any other questions!

Sempakonka avatar Jan 04 '21 10:01 Sempakonka

But according to this I have to make 3 different requests to find the permission that is available. Why not just ask "which location permission is granted"?

gkrawiec avatar Jan 04 '21 15:01 gkrawiec

I don't think a funtionality for that is currently availible. Permission.locationAlways and Permission.locationWhileInUse are actually two diffrent permissions (Permission.Location is identical to permission.locationWhileInUse in Android according to documentation). To make such a funtionality you would for example need extra return values from android to distinguish between permission level.
To anwer your question, you could try something like this:

   var locationAlwaysStatus = await Permission.locationAlways.status;
   var locationWhileInUseStatus = await Permission.locationWhenInUse.status;
   if (locationAlwaysStatus == PermissionStatus.granted) {
     // LocationAlways is available
   } else if (locationWhileInUseStatus == PermissionStatus.granted) {
     // LocationWhileInUse is available, LocationAlways is either denied or not determined 
   } else {
     // No location permission level has been granted
   }

Sempakonka avatar Jan 05 '21 11:01 Sempakonka

Because of the undertermined issue, there are way more options. In my previous comment I put what I was doing to get the result https://github.com/Baseflow/flutter-permission-handler/issues/349#issuecomment-662530239

You should think about adding this "what is the current permission?" feature to the package. It doesnt make much sense to have to ask each one when one is simply interested in a single answer.

thank you.

I don't think a funtionality for that is currently availible. Permission.locationAlways and Permission.locationWhileInUse are actually two diffrent permissions (Permission.Location is identical to permission.locationWhileInUse in Android according to documentation). To make such a funtionality you would for example need extra return values from android to distinguish between permission level. To anwer your question, you could try something like this:

   var locationAlwaysStatus = await Permission.locationAlways.status;
   var locationWhileInUseStatus = await Permission.locationWhenInUse.status;
   if (locationAlwaysStatus == PermissionStatus.granted) {
     // LocationAlways is available
   } else if (locationWhileInUseStatus == PermissionStatus.granted) {
     // LocationWhileInUse is available, LocationAlways is either denied or not determined 
   } else {
     // No location permission level has been granted
   }

gkrawiec avatar Jan 05 '21 11:01 gkrawiec

Hi @gkrawiec,, those undetermined issues will be gone in the newest version of the plugin (undetermined status is removed since version ^6.0.0 as mentioned in the changelog). To answer your question about if there is a way to ask which level of location is allowed, the answer is yes and no.

As mentioned before by SemPakonka:

Permission.Location is identical to permission.locationWhileInUse in Android according to documentation

This means that if you allow the Permission.location permission, Permission.locationWhileInUse will also have the status of granted. This also goes for the other way around of course.

So if you want to know what kind of level 'location level' your app has you can start by requesting the Permission.locationAlways.status. if this one is granted, you will also get granted back from the other location permissions (locationWhileInUse or location). If you get a denied back you can check for one of the other 2 location permissions, see if one of them is granted (remember, if one of those 2 has the status granted the other one is granted as well).

So yes, you can ask the status for the location permissions, but you can not call a method that will return which one is granted and which one is denied. I personally don't see the need to built this in, since a simple check can already determine which permission is granted and which not, and you know which permission have been asked when requesting the user for a location permission since the descriptions in the dialogs are clear.

If you do want to know which permission is granted out of the 3 location permission, a simple check like this will work:

void _askPermission() async {

    await Permission.locationWhenInUse.request();

    if (await Permission.locationAlways.status == PermissionStatus.granted){
      print('location Awlays is granted, other 2 permissions are granted for sure if this one is granted');
      print(await Permission.locationWhenInUse.status);
      print(await Permission.location.status);
    } else if (await Permission.locationWhenInUse.status == PermissionStatus.granted ||
               await Permission.location.status == PermissionStatus.granted) {
      print('locationAlways is not granted, but locationWhenInUse and location are both granted');
      print(await Permission.locationAlways.status);
      print(await Permission.locationWhenInUse.status);
      print(await Permission.location.status);
    } else {
      print('No location permission is granted');
    }
}

Let me know if this answered your question!

JDDV avatar Aug 12 '21 14:08 JDDV

Apps need to behave differently depending on whether they can run in the background or "whileInUse". So I need to run this check every single time. This is fine. I did solve it (look at my post earlier in this thread). I do not understand why you cannot include this in the API so the simple check of three permissions is done by the package's API. That would be even simpler.

I am learning programming. So maybe you can explain to me why you believe this is unnecessary. Isnt one of the points of the API for the plugin to abstract commonly used features so that everybody doesnt have to code the same thing over and over again?

thanks.

gkrawiec avatar Aug 15 '21 12:08 gkrawiec

Hi @gkrawiec, I don't think it's the permission handlers job to tell you which location level is granted and which not by calling a method that will run that check. Because a simple .status will already tell you the status The reason why is because it can be done in a simple if/else if statement with an optional else (see example below).

if (await Permission.locationAlways.status == PermissionStatus.granted){
    // Behave as it should with Permission.locationAlways permission allowed.
} else if (await Permission.locationWhenInUse.status == PermissionStatus.granted) {
   // Behave as it should with Permission.location or Permission.locationWhenInUse is granted.
} else {
  // Optional else statement where you can try to; Open App Settings, request permission, show error dialog etc.
}

This is a simple statement which is not an unnecessary amount of lines in your code.

If I were to add a method you could call to see what location permission is granted with just one call, it should return something like a list or map with the current statusses of the three permissions. Causing you to make a function to loop through the list or something to check the statusses.

Or I could return the 'highest' level of permission which is granted, so you can call a method that will return the 'highest' location permission level that is granted. But still you have to check which permission it is then in the code. causing you to write the same amount of lines or probably even more lines then the simple if/else if example I gave.

Isnt one of the points of the API for the plugin to abstract commonly used features so that everybody doesnt have to code the same thing over and over again?

This is true of course, but in this case you end up with the same amount of lines that you have to write to check the current permission status, and which one is granted or not. So the reason to built in such functionality seems a bit unnecessary to me, but if you have a better idea which uses less lines of code instead of the if/else if statement I would love to hear it of course!

JDDV avatar Aug 19 '21 08:08 JDDV