Android SDK 23+ Permissions in Services - android

I would like to update my project to SDK 23, but I have different services running in the background to receive data, store them, send etc...
So if I update the project I also have to change the permission requesting. Now I am wondering where the best place to do this is.
Just at the moment received data should be saved?
But this would be pretty abstract for the user, especially if a config file or something needs to be transfered and the user gains nothing noticable from this.
Before starting the service just request all permissions the service requires?
This makes the whole concept absurd because it would be the same as so far...
So thank you for your input!

If I got the concept right, permissions should not be requested before they are really used.
Correct, bearing in mind that the request is part of your user experience and therefore needs to be tied to the UI. Besides, from a technical standpoint, you can only request a permission from an Activity.
My general rule of thumb is: postpone requesting the permission until the user takes some positive step that will lead down a code path that requires that permission.
In some apps, that "positive step" is simply launching the app, as the permissions are needed right away. In that case, you check for the permissions in onCreate() of your launcher activity.
In other apps, that "positive step" might be the user clicking on an action bar item, or on a nav drawer item, or on a button, or on a RecyclerView item, etc. In that case, you can delay asking for the permission until the user clicks that thing, so users who never click it will never have to be asked for the permission.
So, look at when and how your service is started. That will determine what the user's "positive step" is that should be tied into your requesting the needed permissions.

Related

Is there a reliable way to determine if `requestPermissions` will actually display the prompt?

I need to migrate our Android app to be compatible with Android 13. I was following this doc to enable the permission to send push notifications. However we have a different workflow to request the permission than what is recommended in the doc. For example, we do not want to show the OS prompt upfront without displaying an educational UI, even at the first time we request the permission.
In the doc:
If your app targets Android 13 or higher, your app has complete control over when the permission dialog is displayed.
Apparently this is not true. I created an empty project to verify the behaviour of requestPermissions and here is my findings:
If permission is enabled, the prompt won't be displayed.
If permission is not enabled, I have two chances to click the "Don't allow" button. After that, calling requestPermissions will return immediately.
What I'm currently trying is a hacky way around this, and very likely to break:
When the user clicks either the "Allow" or "Don't allow" button, set a "has_shown" flag.
When either "has_shown" flag is set or shouldShowRequestPermissionRationale returns true, we decide the OS prompt can be displayed and display the educational UI.
Checking which button the user clicks is hacky on its own. What I'm doing is verify if either of the following satisfies:
grantResults passed into the callback indicates PERMISSION_GRANTED.
shouldShowRequestPermissionRationale returns true.
The flag is stored in SharedPreferences, so all this is based on the premise that the user never clears the storage.
Is there a better way I can achieve this?

Do not allow users to deny app permissions

My whole app relies on the fact that location permissions is granted, but when the permissions dialog opens up, there is a button to deny access. Is there a way to remove the deny button, and only allow them to either exit the app or allow the permissions?
I don't think this is allowed as it is overriding an android system feature. Even if you could figure it out it would probably technically violate the Google Play Store terms. (So, you'd have to turn to another market to release to...)
You should just create the UI clear to the user that the location permission is necessary and then display some sort of error message if they deny that, show them a prompt to allow it again before being able to use the app.
You can read more about it here, notice the lines:
Apps that monitor or track a user's behavior on a device must comply with these requirements:
...
Apps must not hide or cloak tracking behavior or attempt to mislead users about such functionality.
This page explains why and how to show your user why your app needs a certain permission.
In short, without resorting to an off brand kernel of android found on the web or something, you probably can't very easily and shouldn't anyway. (For both moral reasons, legal ones, and because like you can just show a dialog box to explain to the user why they should allow the permission... not that hard. If they want to use your app then they will allow it. Simple as that.)
I don't think it is possible. You can't hide the deny option in the app permission option.
the whole point of google giving these option was to try to protect user privacy.
The best option would be to convince the user why they should allow you the location permission.
And now Google has enforced a more strict policy for the app developer. And any unethical way can make your app banned or even worse your dev account ban.
No, I don't think so that you can take control over the allow and deny options in permission because
All the permissions are divided into two categories normal and dangerous permission (also called Runtime permission), the normal permission are automatically granted as you install the app but the dangerous permission needs a runtime permission from API level 23 (Marshmallow) and here's the lame catch for you since the pre Marshmallow devices doesn't had any concept like Runtime permission, so the solution you want will only work in pre Marshmallow devices (and obviously that's not what you want)
The permission dialog isn't handled by the application, the OS takes care of this.
Here's the official link to the Android guide to App Permissions
You can't control the permission request, but.
You could have a view that prompt user to enable location permission which will prompt the location service to be switch on if it is not switched on and allow permission to your app to access location data.
In your application class, you can create a listener that listens for the status of the location service, if its on or off. you can also check if permission is given on by the user to access location in the listener. so at any point, the status change. your listener acts accordingly

What to do when missing requirements to use app

In my android app there are certain requirements required in order to use the app (Internet access, GPS, etc.). Now I haven't really found anything dealing with this so I don't know if its a mute point or not. A user can leave your app at any time and turn things off/on on the phone. If I am checking to ensure that data access is available as well GPS in the app oncreate and onresume and just tell the user they need to switch it on, would that probably be enough? I'm thinking not. I'm thinking of redirecting the user to a new layout telling them what is missing and what needs to be done in order to use the app. This layout would also include a button for them to continue once settings are turned on. Is this a good idea or bad? I don't know if there is a better way of handling this or not so all input is appreciated. What do you do?
You might find some of your answers in Find Success on Google Play. If a user performs an action without satisfying all of the requirements, you could present a dialog explaining to the user what the requirements are and why they are necessary. You might also provide a link to redirect the user to the proper settings.
EDIT: The best practices in this situation are probably similar to Requesting Permissions at Run Time. Permissions Best Practices suggests something similar to what you are proposing, which is to show some sort of message or tutorial explaining to the user what is required and why, and then redirecting the user to the appropriate settings.
EDIT: One more example: That Android Documentation shows you how to use the Settings API to check which settings are enabled, and present the Location Settings dialog for the user to update their settings with a single tap. See Prompt the User to Change Location Settings

Can a service request for permission in Android M?

I figured that in M requestPermissions() can only be called by an Activity class. I have an app that has no UI screen. It runs as a background service. Does this mean that I have to put a spinner screen if checkSelfPermissions returns denied?
I have an app that has no UI screen.
Then it will never run, unless it is preinstalled on an Android device or custom ROM, or it is a plugin to some other app. Otherwise, your app will remain in the stopped state forever. Pretty much every app distributed through normal channels, including the Play Store, needs an activity.
Does this mean that I have to put a spinner screen if checkSelfPermissions returns denied?
I do not know what "a spinner screen" is. AFAIK, the recommended pattern for a service needing a runtime permission that it does not have is to:
Raise a Notification, to let the user know that the service cannot do its work without this permission.
Have the Notification trigger an Activity that can call requestPermissions(). Optionally, this activity can have Theme.Translucent.NoTitleBar, so the only visible UI is the permission dialog.
If onRequestPermissionResult() indicates that you have the permission, the activity can tell the service to go ahead (e.g., via a call to startService()), then finish() itself. If onRequestPermissionResult() indicates that the user denied the permission, do whatever makes sense (e.g., show the Notification again, gracefully shut down, suggest to the user that the user uninstall the app).

Handle permissions change while in app

I am having a hard time understanding the right way to handle a user changing a permission while my app is still running in the background.
In my app I have a location class that registers for location changes and when the location changes the status is sent to a server. However this runs in the background.
When my app is launched I check with the user if its ok to use location services and if so I proceed with setting up that class. However the user can background my app and go into settings and remove that permission. I can, and will certainly check that the permission is enabled in my location class before asking for a location from the location service to avoid a crash. However I am not in an activity when a location comes in so I am not sure how to prompt them that my app needs location services.
EDIT:
It does seem that android restarts your app if a permission has been revoked in settings. However I have confirmed that as of now android does NOT restart your app if a permission was granted though settings.
I read somewhere that your app gets killed when the user changes the permissions on Android-M so you can be sure that this won't change while your app is running. It will been killed when this changes.
As reference check this video: https://www.youtube.com/watch?v=f17qe9vZ8RM
However I am not in an activity when a location comes in so I am not sure how to prompt them that my app needs location services.
Raise a Notification, alerting the user that your app cannot do its intended work without the permission that they revoked. Have the Notification tie into an Activity via a PendingIntent where the user will be able to grant that permission.
Along with CommonsWare suggestion, you can have the onProviderDisabled() to know which provider (gps, network) has been disabled and accordingly requestLocationUpdate() for the one that is still enabled. If both are disabled, see if at least Cell Location is of useful for your app. If so, you can send Cell Location at least till user see notification and re-enable the permission.Use PhoneStateListener to do that.
I would like to try a more modern 2020+ answer to the core question:
However I am not in an activity when a location comes in so I am not sure how to prompt them that my app needs location services.
However I am not in an activity when a location comes in so I am not sure how to prompt them that my app needs location services.
If you are in a normal end user environment:
Respect the users choice to revoke the permission and only display the missing permissions to the user if she opens your activity.
On modern devices your service needs to display a notification in the bar to even be allowed to continue running - change the notification to show the problem.
You are allowed to just ask for most permissions but the user has the ability to deny on the 2nd attempt. After that you get auto-no without anything displayed.
Some permissions (e.g. write settings and overlay) can be accessed by opening the settingspages for this directly - which can be done from a service but will be seen as harassment.
If you are in a work environment:
Best use an official mdm solution (COPE).There you can totally zombiefy your devices allowing nothing or anything and pretty much anything in between. User cannot even enter settings if you dissallow or not even turn the device off or.. you name it.
And apps can get all permissions they need and be installed automatically from the getgo.
For both (eben in mdm sometimes a more powerful user might be wanted):
Please build an extra Activity or Fragment (if you have one that uses those) dedicated to display why your app needs a permission and a button for the user to initiate the request/opening of settings.
It may be much work but users and google will be happy :)

Categories

Resources