In Android Marshmallow, permissions should be requested at runtime when they are needed, instead of all at once when an app is installed. However, I can only seem to request permissions from an Activity, which is a problem since my app contains only Services. (Why is that, you might ask? The app has an Android Wear watch face bundled inside, and all the phone does is look up photos nearby to send to the watch - no Activity needed. But it does require location permissions.)
So, is there any way to request permissions from a Service? Or somehow force the permissions to be granted at install time as in the past?
requestPermission() can only be called from an Activity and not a Service (unlike checkPermission() that only requires PackageManager). So you need to do some extra work to get around that; you do need to provide an Activity in your app and, for example, your Service can check for permissions it needs and if they have not been granted yet, it can create a notification and that can inform user with a descriptive short message as to why there is a notification and what needs to happen when they click on the notification, etc.
I agree, this is very troublesome for services, I think you should report an issue on Android Developer Preview page for this.
At the moment, I think the best solution is to check for permission on service, and show notification if the permission is missing. Even better, create an DialogActivity to request for permission when users press on the notification.
Have a look at PermissionEverywhere library. It allows you to request permission from any context.
It creates a notification clicking on which it opens up an activity asking for permission.
Sample code from library's github page:-
#Override
protected Boolean doInBackground(Void... params) {
PermissionResponse response = PermissionEverywhere.getPermission(getApplicationContext(),
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQ_CODE,
"Notification title",
"This app needs a write permission",
R.mipmap.ic_launcher)
.call();
//waits..
boolean isGranted = response.isGranted();
if(isGranted){ //changed from isGrante to isGranted
// Do stuff
}
}
There is a very simple library that allows doing exactly this. You can check for permissions from anywhere (even from a service), based on whether the app is in foreground or background, it either shows normal dialog or generates a notification asking for permissions. The code is really easy to understand and it's really easy to use too.
Do give it a try: Android Permissions
You can use ResultReceiver to create a receiver of the users answer, then pass it as callback to the Activity, through notification's PendingIntent.
Reference
Related
I have an Android app on Play store for 8 years. Recently Google release Android S or 12 introduce some limit with Foreground service launch restrictions
https://developer.android.com/about/versions/12/behavior-changes-12#foreground-service-launch-restrictions
and
Exact alarm permission
https://developer.android.com/about/versions/12/behavior-changes-12#exact-alarm-permission
In the app I use foreground service and alarm clock to schedule update weather data from the cloud and device sensor and send notification to user, update the widget.
But they said: Exact alarms should only be used for user-facing features so if I continue use those API, it is safe (with Google Play policy)?
I ask this because other solution like sticky notification with foreground service and workmanager not work as my requirements.
if you are testing android 12 then don't forget to add this line to Manifest
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
Yes, the android.permission.SCHEDULE_EXACT_ALARM it's safe to use, on Android 12 this permission is automatically granted by the Android system but on Android 13 you need to check if the user has granted this permission.
So you need to add the permission to the manifest
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
And then you need to check if the permission was granted, if not granted then you need to redirect the user to the Alarms & Reminders page
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val alarmManager = ContextCompat.getSystemService(context, AlarmManager::class.java)
if (alarmManager?.canScheduleExactAlarms() == false) {
Intent().also { intent ->
intent.action = Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM
context.startActivity(intent)
}
}
}
Google also suggests that you need to check any changes on this permission by registering a Broadcast Receiver and check the changes on ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED
Google states: "(when your app) requires precisely-timed actions". Your use case is "to schedule update weather data (…) send notification to user". While this might be user-facing, it doesn't seem to require to be precisely on a certain time. I would guess your app doesn't qualify.
The methods requiring the additional permission are currently: setExact(), setExactAndAllowWhileIdle() and setAlarmClock(). Repeating alarms will always be inexact. Seems like getting processing weather data and device sensors is something repetitive anyway.
From what you've mentioned, you're talking about user-facing features.
A hypothetical example of the opposite would be Facebook forcing synchronization of user data at some specific time. That would be bad because it's preferable not to force a schedule on those types of things as it doesn't matter whether it happens at a specific time or a minute later when system resources are not used by some other service.
Also, "should" means it's a recommendation. Facebook can do the above, but it would be a less optimal solution. It's best to leave control over those kinds of services to Android as it would likely do a better job at distributing resources and preventing lag. So in other words, you not listening to their recommendation won't get your app removed from the app store or something like that.
Also, the paragraph you quoted from the second link, has a link to examples of acceptable use cases, and it mentions alarm apps. This is likely why your question was downvoted.
effective solution
you need to add the permission to the manifest before <application
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.
I'm looking into porting some existing code to take Android M's new way of dealing with permissions into consideration. However the permission API needs to have an activity associated with it (for example the requestPermissions() method's first parameter is an activity).
So how should a service that needs to check if a permissions has been granted and request for permissions use this new API if the service doesn't have an activity?
Is it possible for the service to create a dummy invisible activity just for use with the permissions API? (if its possible I don't like the thought of doing that anyway though).
Or suppose its not a service but a model class that needs to perform a permissions check, in MVC a model shouldn't have any knowledge of the Vs and Cs and yet now either it has to in order to know which Activity to use with the permission API. Or potentially lots of code might have to migrate from model code into Activity code.
Any thoughts on how to migrate non activity based code that needs to check/prompt for permissions over to Android 6.0?
Update: I left out an important piece of information - this is code that is pre-installed (our company provides code that device manufacture's place in rom) and often may be run at device boot time and run in the background. Therefore the usual situation of a user being prompted for permission when they launch the app or later (and there therefore being an activity at that point) does not necessarily apply.
So how should a service that needs to check if a permissions has been granted and request for permissions use this new API if the service doesn't have an activity?
There is almost always an activity, except for pre-installed apps and plugins for other apps. Otherwise, your service is unlikely to ever run, as nothing will have used an explicit Intent to start up one of your app's components, so it will remain in the stopped state.
For the ~99.9% of Android apps that have an activity already, if the permissions are needed for the whole operation of the app, request them on first run. As Snild Dolkow notes, if the user later revokes the permission through Settings, you can detect that without an activity, then use other UI options (e.g., Notification, app widget) to let the user know that operation is suspended until they grant you the permissions again, which they would then do through your activity.
Is it possible for the service to create a dummy invisible activity just for use with the permissions API?
Presumably you can have a Theme.NoDisplay activity use requestPermissions(). However, from the user's standpoint, it will not make much sense, unless there's some alternative UI (app widget?) that they are interacting with. Popping up a permission dialog out of nowhere is unlikely to make you popular.
UPDATE 2019-06-15: Note that Android Q bans services popping up activities frmo the background. Please use a notification instead.
in MVC a model shouldn't have any knowledge of the Vs and Cs and yet now either it has to in order to know which Activity to use with the permission API
Do not touch the models until you have requested the permission, and gracefully fail if the permission is revoked. You already have to gracefully fail in other circumstances (out of disk space, no Internet connection, etc.), so a revoked permission should be handled in much the same way.
using this new 6.0 API seems like an recipe for bad design and tight coupling
You are welcome to your opinion. Based on what I have read, the Android engineers believe that asking the user for permissions is part of the user experience and is best handled at the UI layer as a result.
Again: the vast majority of Android apps will not have a problem with this, as they have a user interface. Apps that do not have a user interface and need dangerous permissions are in for some amount of rework.
this is code that is pre-installed (our company provides code that device manufacture's place in rom) and often may be run at device boot time
First, please understand that this is so far from normal that you can't even see normal from where you are due to the curvature of the Earth. :-) You can't really complain that Google did not optimize this particular scenario.
As I understand it, even system apps should be asking for runtime permissions. The Camera app did, for example, on the 6.0 preview. That being said, there's gotta be some database on the device somewhere that is tracking what has been granted, and presumably there is some way to pre-populate it. However, the user could still revoke it from Settings, presumably. But, the manufacturer could pull some stunts (e.g., messing with the Settings app) to possibly even preclude that scenario. I'd be looking in the same area as "how do I get it so my app cannot be force-stopped?" that device manufacturers can do.
Your alternatives would be to get rid of the dangerous permissions or to migrate your app off the SDK and into a standard Linux binary that would be run as part of the boot process and be put into a Linux user group that has access to the stuff that you need.
Ask for it when the user enables whatever feature your service provides. They'll be in one of your activities at the time. Yes, it means that your activities need knowledge of what permissions your services will require.
The service can always check for the permission by itself, though, since checkSelfPermission() is available in all Context instances. So you don't need an activity for that.
I guess an alternative would be to have your service post a notification saying "feature X requires you to approve more permissions". Actually, that may be a good idea regardless, in case the user goes into settings and revokes any permissions after the fact. That notification would then take the user to some activity with an "enable feature X" button/checkbox -- ask for the permission when that is selected.
You can send a notification. Look this library to manage the permissions: permission library
i saw some applications with a little dialog asking for permit the app to listen for notification. That dialog got 2 button: cancel, and go (that opens the security settings to allow apps for listen for notification). That dialog is persisten so i guess it have a sort of method to detect if the app is allowed or not. Anyone can point me to that API? Thanks
I know this is an old question, but here what I use now in my application:
String notificationListenerString = Settings.Secure.getString(this.getContentResolver(),"enabled_notification_listeners");
//Check notifications access permission
if (notificationListenerString == null || !notificationListenerString.contains(getPackageName()))
{
//The notification access has not acquired yet!
}else{
//Your application has access to the notifications
}
You can move the user to Notification Access Permission settings by open the activity:
startActivity(new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));
This is tested very well from Jelly Bean 4.3 to Marshmallow 6.0 and I use it in my applications.
Hi I don't think that there is a method to call to know if you have permission to Listen Notifications, but you can try the following:
Try to acquire the reference of your NotificationListenerService instance.
Now if you got a null pointer when you expected it to be not null then you should prompt a Dialog asking user to enable the Security setting.
add onClickListener in "Ok" button and now just startActivity(new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));
All applications on Android can send notifications, there is not even a Permission for it. Any dialog you see in UIs is something implemented by each developer (to be extra considerate).
Bottom line, there is no API for accessing if an app can send notifications (all can).
Otherwise, there are Application Permissions for a variety of other things, which would also be worth learning about.