108

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?

Tony Wickham
  • 4,706
  • 3
  • 29
  • 35

5 Answers5

51

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.

schnatterer
  • 7,525
  • 7
  • 61
  • 80
Ali Naddaf
  • 16,951
  • 2
  • 21
  • 28
  • This is the solution that [Benjamin Poiesz](https://plus.google.com/111703124687948696691/posts) proposed. You can listen this [podcast](http://androidbackstage.blogspot.jp/2015/08/episode-33-permission-mission.html) from 23:40 – xiaomi Sep 25 '15 at 06:26
  • You can also call requestPermission() inside fragment. – Misagh Emamverdi Oct 27 '15 at 07:06
  • 4
    What is the solution for the case of a running background service checking periodically for location updates and I just turn off location permission in the settings. Since there is no activity, this causes my service to crash when i reopen the app – stud91 Nov 06 '15 at 10:30
  • 1
    @stud91 At the very least, catch security exceptions or query permissions every time you request location updates. This will prevent your app from crashing (though you won't get any locations if the permission has been revoked). Even better: check for permission, and if it is missing, display a notification that takes the user to an Activity which is just a placeholder for the permissions dialog. – user149408 Jul 09 '16 at 13:41
  • 9
    Here's how I solved it: https://github.com/mvglasow/satstat/blob/master/src/com/vonglasow/michael/satstat/utils/PermissionHelper.java It can be called from any `Context` which also implements `OnRequestPermissionsResultCallback`. Functionality is similar to standard `requestPermission()`. – user149408 Jul 09 '16 at 13:44
  • Where is the Benjamin Poiesz solution? – KansaiRobot Apr 01 '17 at 12:51
15

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.

Derek Fung
  • 8,171
  • 1
  • 25
  • 28
7

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
      }
  }
Heisenberg
  • 1,500
  • 3
  • 18
  • 35
  • 2
    I've tried async version in a Service and it didn't work. onComplete has never being called – Leo DroidCoder Sep 01 '16 at 12:27
  • Good idea, but it's not available in repository – naXa stands with Ukraine Oct 02 '16 at 20:44
  • 2
    This package worked for me, thanks for the suggestion. I would note, though, that I did not try the async version. Also, for those who are having problems using `PermissionEverywhere`, make sure that you declare the helper activity in your manifest AND make sure that when you declare it, it's tied to the correct package (if you're using `PermissionEverywhere` as a separate package). It took me a long time to realize that I wasn't actually specifying the `PermissionEverywhere` package in the manifest. – user3570982 Dec 28 '16 at 04:09
  • I ran `PermissionEverywhere`'s demo app and it didn't work. – User May 14 '19 at 05:05
  • Can't get it working and github issues are unanswered years later. Think this has been abandoned. – topher217 Aug 19 '21 at 03:53
5

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

Nishkarsh
  • 274
  • 4
  • 16
-2

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

Farrux Bahodirov
  • 358
  • 4
  • 12