If your app needs a dangerous permission, you must check whether you have that permission every time you perform an operation that requires that permission.
https://developer.android.com/training/permissions/requesting
(in the case of API 23 and above)
Does it mean:
The permission dialog will popup every time that operation is about to be performed to grant permission.
Just to ContextCompat.checkSelfPermission() (programmatically) if permission is granted, if so then no permission dialog will popup.
or something else...
Why I need this answer:
I have a service that works in background multiple times a day(requesting location) NON-CONTINUOUSLY, lets say 3 times/day, does this mean that runtime permission dialog has to show up 3 times a day whenever my service is going to perform its work -or- it has to show up only the first time my service starts and then it checks programmatically (only) the remaining 2 times if permission was granted ? (same question above reformed here).
does this mean that runtime permission dialog has to show up 3 times a day whenever my service is going to perform its work
Probably not.
it has to show up only the first time my service starts and then it checks programmatically (only) the remaining 2 times if permission was granted ?
Probably not.
The quote from the documentation means that you need to call ContextCompat.checkSelfPermission() before you try performing an operation that needs a runtime permission (dangerous permissions). This does not display any UI. It merely lets you know whether or not you hold the permission.
If you do not hold the permission, you will to request the permission from the user before you will be able to do whatever it is that you are trying to do. That needs to be performed from an activity or fragment, using requestPermissions().
In your case, before you schedule the background work (WorkManager, JobScheduler, etc.), use requestPermissions(), and only schedule that work if the user grants you your desired permission(s).
However, it is possible that the user will revoke the granted permissions. That is why your background work will need to call checkSelfPermission(). If that indicates that you do not hold the permission, you will need to raise a Notification that leads the user to your UI, where you can once again requestPermissions().
It means you need to call checkSelfPermission each time, and make sure the user didn't remove your permission (because if they did the action will fail, either with an error return or an exception). However if that returns false, the only way to get permission is to show the dialog. Or you can just not do whatever you were planning to.
Related
For the new runtime permissions Android has come up for version 13, how many times can I invoke the system dialog box? Even with the rationale screen, can I invoke it infinitely or is there a limit for every user?
Bumped up the SDK to 33 and OS running on 13.
There is no strict limit, but there is an option to check "Don't ask again" when denying permissions. In that case you will not be able to display permission requests again(for the given permission).
When the system asks the user to grant a permission, the user has
the option of telling the system not to ask for that permission again.
In that case, any time an app uses requestPermissions() to ask for
that permission again, the system immediately denies the request.
The system calls your onRequestPermissionsResult() callback method and
passes PERMISSION_DENIED, the same way it would if the user had
explicitly rejected your request again. This means that when you call
requestPermissions(), you cannot assume that any direct interaction
with the user has taken place.
User can cancel a permission request by hitting the "Back" button. And since Android 11, user can also clicking on the outside of the permission dialog to cancel. When a permission is canceled, the permission is not granted, and shouldShowPermissionRationale() will return false, which means app can call requestPermissions() again.
When user choose "Don't ask again", or deny twice for a permission in Android 11, shouldShowPermissionRationale() will also return false. But how can I distinguish "Don't ask again" from the "Canceled" state?
I need to distinguish these two states is because that if user canceled a permission before, I know that I still have the chance to prompt the system permission dialog to them. But if user choose not to ask for a permission again, I need to guide them to the app info page to grant the permission manually.
It's not a direct solution to this problem because there appears to be no way to get that.
However, I have realised that there is a method where Android will tell us if we need to show RationaleDialog to our user without any work from our end (before I was under impression we need to keep track of this ourselves).
Just call activity.shouldShowRequestPermissionRationale(permission) and it will take care of all back calls itself.
I couldn't find any information about what happens when the user disables an app's permission while the app is running.
Is the application re-initilized?
I saw that in some apps if a Dialog or BottomSheet is open while I disable the permission, the dialog is no longer displayed when I return to the app.
Can anyone explain what happens in-detail when a permission is denied at runtime? Or does anyone have some useful links for me?
I would be especially interested in which lifecycle events are called when returning to the app.
When a previously granted permission is revoked through settings, the app is force stopped. You can see this by watching your app in the debugger. The app process is marked DEAD as soon as the permission is revoked.
Returning to the app will launch it from the main activity. I've never really looked into why this happens, but I assume it's because when a granted permission is revoked, the user could be deep into the app at a place where it is assumed the permission is granted. When the permission is revoked, there's no way to know if the screen they are currently in is even valid anymore.
Upon returning to the app, the app's state is restored and your current activity will be restarted, similar to a configuration change. If the activity you are in assumes a certain permission is granted, you should probably check that permission again in onCreate() to make sure you have it.
Simply put, That depends on what the app is trying to do when it needs permission.
For example: If we live in a country that requires you to be an adult to watch any video on YouTube, nothing will work with Location permissions denied
Another example: If you want to take photos using your phone via an app, the Camera permission should be permitted.
Under some circumstances, just part functions of app can not be used, but at an Extreme case, app would throw Security Exception and crash.
According to your point :
I saw that in some apps if a Dialog or BottomSheet is open while I
disable the permission, the dialog is no longer displayed when I
return to the app.
There is no lifecycle callback about what you do once permission is denied, but there's method on ActivityCompat which gives you flag if you want to show your own Dialog/BottomSheet
So, you can call shouldShowRequestPermissionRationale() method from ActivityCompat & make your own logic work when it's true.
shouldShowRequestPermissionRationale :
Gets whether you should show UI with rationale for requesting a permission. You should do this only if you do not have the permission and the context in which the permission is requested does not clearly communicate to the user what would be the benefit from granting this permission.
For example,
if you write a camera app, requesting the camera permission would be expected by the user and no rationale for why it is requested is needed.
If however, the app needs location for tagging photos then a non-tech savvy user may wonder how location is related to taking photos. In this case you may choose to show UI with rationale of requesting this permission.
While disabling permission for first time will give you callback in onRequestPermissionResult() method.
I am implementing a service that uses LocationManager to get and utilize the tablet location. This service is start and stop from an activity.
The latest Android requires that permissions are requested on runtime. Now I have managed to do this on an activity by using requestPermission in onCreate , checkSelfPermission everytime I use some Location manager function, and adding the requestPermission function and overriding the onRequestPermissionResult.
It works great.
Now for my service I need to do the same, but these functions seems to work only for activities. How can I activate permissions in a Service?
just in case, I have already asked for permissions in the activity that starts and stops the services
How can I activate permissions in a Service?
You don't. You activate (i.e., request) permissions from an activity. That is not negotiable.
Ideally, you request permissions before the activity starts the service or does something that will eventually cause the service to start (e.g., schedules the job with JobScheduler).
If you determine that your service no longer has the necessary permissions — perhaps the user revoked them from Settings — you could raise a Notification that leads the user to an activity where you re-request the permissions.
It is technically possible for a service to start an activity which requests the permissions. Usually, this is not a good idea, as you may not know what the user is doing at that moment, and the user may be unhappy to have you interrupt them with this permission request.
How can I activate permissions in a Service?
You can't request for permissions from services. Permissions should be asked explicitly which should be visible to the user in UI. However you can ask permission from activity and, if succeed, you can access those resources until user again turned off permission for your app.
how can you "transfer" these permissions to the service?
Permission is assigned for the entire app, so you don't need to transfer it from one activity to another or from one activity to service. Once you get a permission in an Activity, that permission is assigned to the entire app and your services can access the resources then after. cheers :)
with Androids new permission system, I was wondering how to implement it right. The tutorials about how and when to use the permissions seem to be pretty clear. However, I don't know who requests the permissions and where to request them.
So, basically my question is: should the Activity, who starts another Activity request the permission beforehand or should the Activity which requires the permission place the request?
If the Activity which requires the permission should request for it, should I call requestForPermission inside onCreate or in onStart?
Though it seems to be very simple questions, I haven't found any hints in the documentation.
Thanks.
should the Activity, who starts another Activity request the permission beforehand or should the Activity which requires the permission place the request?
That is up to you. The main guidance is that there should be a clear tie from something the user does to your request for permissions:
If your app needs certain permissions to do anything meaningful, ask for them when your app starts up, perhaps after any sort of "welcome" presentation to advise them about why you need the permissions.
If your app needs certain permissions to do something based on the user performing some in-app action, like tapping on an action bar item or ListView row, ask for the permission when the user performs that action.
Asking for permissions at semi-random points in the app will simply lead to user confusion ("what did I do? why is it asking me this? and why are these questions appearing in an Stack Overflow answer?!?").
If your app can't function properly without a particular permission might be good to have a welcome permission flow where you explain why need the permissions and ask for the grants. For example : Google maps and location permission
If some specific parts of the app need a separate permission you can call the permission check just before doing a method call that needs permission. In this case you can create a wrapper for your function that needs contact permission and always call that wrapper instead of the actual method. For example : Google maps and microphone permission when you try to use the search with voice functionality
More details http://inthecheesefactory.com/blog/things-you-need-to-know-about-android-m-permission-developer-edition/en
also check out https://github.com/permissions-dispatcher/PermissionsDispatcher could reduce a lot of permission code.
When ever your X task struck due to some "Y" permission then only ask for permission. There is no point of asking in onCreate or onStart method.
if you ask for "Y" permission at the start of Activity then there is no difference between Android M and below model. Exploit the beauty of Android M. for example if your require storage permission for creating a temp it's better make a temp file in App internal area i.e /data/data/your package name/files/ rather than asking for storage permission to users. Overall my point is exploit these options as much as you before it become necessary condition to ask for "Y" permission.
Regarding Activity concern , your task must be running be over some fragment or activity let that activity handle the onRequestPermission results.