20

All of the sudden, I started getting the following exception from devices running android 4.3 and above

java.lang.SecurityException: Permission Denial: opening provider com.google.android.apps.photos.content.GooglePhotosImageProvider from ProcessRecord{454ca9d0 5914:com.propertymanager/u0a10231} (pid=5914, uid=10231) requires com.google.android.apps.photos.permission.GOOGLE_PHOTOS or com.google.android.apps.photos.permission.GOOGLE_PHOTOS
        at android.os.Parcel.readException(Parcel.java:1431)
        at android.os.Parcel.readException(Parcel.java:1385)
        at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:2896)
        at android.app.ActivityThread.acquireProvider(ActivityThread.java:4755)
        at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2480)
        at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1152)
        at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:759)
        at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:665)
        at android.content.ContentResolver.openInputStream(ContentResolver.java:500)
        at com.myapp.xxxx.determineCorrectScale(SourceFile:148)

My The code causing it is

    public static int determineCorrectScale(Context con, Uri imagUri) {
        int scale = 1;
        InputStream imageStream = null;

                imageStream = con.getContentResolver().openInputStream(imagUri);
.
.
.
    }

Any help??

EDIT: This is how I let the user pick a picture before calling the above method

Intent choosePictureIntent = new Intent(Intent.ACTION_PICK, Images.Media.INTERNAL_CONTENT_URI);
tartActivityForResult(choosePictureIntent, REQUEST_CHOOSE_IMAGE);

Here is the OnActivityResult:

protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);
    if (resultCode == RESULT_OK) {
        switch (requestCode) {
        case REQUEST_CHOOSE_IMAGE:

            Uri selectedImage = intent.getData();

            try {

                int scale = CommonFunc.determineCorrectScale(this, selectedImage);
Snake
  • 14,228
  • 27
  • 117
  • 250
  • There's no `com.google.android.apps.photos.permission.GOOGLE_PHOTOS` permission in the SDK - even API level 19 source does not list this permission. It's probably some internal permission used only by Google. – ChuongPham Jan 13 '14 at 02:40

2 Answers2

30

While adding the permission works for this particular content provider it won't work if your data is delivered by other content providers (on Android there's no guarantee you'll get the data by a specific content provider unless you explicitly access that content provider).

The "final" solution to this problem can be found here:

Getting access with temporary permissions

You can access data in a content provider, even if you don't have the proper access permissions, by sending an intent to an application that does have the permissions and receiving back a result intent containing "URI" permissions. These are permissions for a specific content URI that last until the activity that receives them is finished.

http://developer.android.com/guide/topics/providers/content-provider-basics.html

Since version 4.3 Android checks whether the receiving Activity is still running and if not throws the SecurityException. The determineCorrectScale is a static method so I assume it's at least sometimes called outside the Activity life cycle. To fix this once and for all you need to retrieve the data from the content provider while the Activity is running. I don't know the requirements for your app but if there's no heavy lifting involved (like copying images from the content provider) then just do it on the ui thread. If heavy lifting is needed then use an AsyncTask started by the Activity but then you have to make sure the Activity doesn't finish before the data has been retrieved (which might be tricky).

I didn't just add that answer because I think it's the correct one but because other developers might not be aware of this change introduced in 4.3/4.4 and might run into the same issue with other content providers.

Emanuel Moecklin
  • 28,488
  • 11
  • 69
  • 85
  • Thank you for the detailed answer. +1. My app requirement is that during my activity lifecycle, The user clicks a button to load a picture from his gallery, once the picture is chosen, I take the URI and call the determineCorrectScale so I can sample the picture and load it to image view (and copy the sampled one to local files for future quick loading). I use the following content provider only getContentResolver().openInputStream – Snake Jan 13 '14 at 18:01
  • Oh and the static method so I can call it from any where but so far I only call it from within activity – Snake Jan 13 '14 at 18:02
  • How do you let the user pick a picture form the gallery? I guess you start some activity using an Intent? Can you post that piece of code? I'm asking because in that case the returned URI is an arbitrary URI depending on what gallery app(s) the user has installed and thus the content provider is arbitrary too meaning adding that permission might fix the exception for that particular content provider but not for other content providers. – Emanuel Moecklin Jan 13 '14 at 18:24
  • Please check my Edit for the code I use to grab the image URI. What do you suggest? This could be the new accepted solution – Snake Jan 14 '14 at 11:15
  • Using your intent to retrieve an image means you could get an arbitrary content provider uri. With the accepted answer you will be able to fix the issue for this specific content provider but not in general. I tried to reproduce the issue but didn't manage to trigger the Google+ image provider and so I'm not confident that my answer would solve the issue either. If you know a way to trigger the Google+ content provider (that's the one with the com.google.android.apps.photos.permission.GOOGLE_PHOTOS permission), please let me know and I'll give it another shot. – Emanuel Moecklin Jan 16 '14 at 21:44
  • That was exactly the case in my situation. Thanks a lot! – Primoz990 Jun 05 '17 at 12:06
  • Anyone who wants to process the data on another activity and not the receiving activity should `addFlag` `Intent.FLAG_GRANT_READ_URI_PERMISSION` on the new activity. Note that the receiving activity should not be finished while reading the `Uri`s. Also beware of using `noHistory` flag ;) – idish Nov 09 '18 at 14:16
  • This doesn't work for ACTION_PICK. I have not found a way to persist the permission after the activity is finished when using ACTION_PICK – PhillyTheThrilly Oct 01 '19 at 16:04
24

you need to add this permission to your manifest:

<uses-permission android:name="com.google.android.apps.photos.permission.GOOGLE_PHOTOS"/>

hope this works for you. please give me a feedback

Coderji
  • 7,655
  • 5
  • 37
  • 51
  • 3
    Oh Ok , is that a new permission? I have never seen it before. I cant reproduce it a I dont have 4.3 device so I hope it fixes it :) – Snake Jan 13 '14 at 01:52
  • glad it worked with you. I used to have the same error, but when I was reading how Google+ was working, it turns that they are using this permission with there apps. it seems it is used to get the photos from your mobile even the one that has been stored online like in google+ but i am not sure yet! please share if you found anything.... and why did i get a down vote! – Coderji Jan 13 '14 at 02:26
  • 1
    Sorry for the down vote. The question isn't clear enough on whether only that particular content provider will ever be accessed or if other content providers might be used as well so there's really no telling if your answer is the correct one or not. Depending on Snake's feedback I will convert it to an up vote (or not). – Emanuel Moecklin Jan 13 '14 at 02:44
  • Its only that content provider that will be used – Snake Jan 13 '14 at 18:02
  • 2
    Thanks a lot! This permission seems to be required when the image is not yet downloaded. – Ayyappa Jun 04 '15 at 17:06