Search code examples
androidandroid-contentproviderandroid-bitmap

How can I load Images from the Gallery by URIs stored in the db without permission denial


I'm currently creating my own gallery app. I use a custom object which holds all required information for a gallery including urls of the images from the local android gallery.

public class GalleryDTO {
   private Long id;
   private String name;
   private List<Uri> photos = new ArrayList<>();

I store this gallery object in a sql lite db.

I have an activity to view this gallery objects. In this activity I load the gallery I want do display - this works.

But when try to load the images:

   GalleryDTO galleryDTO=vrGalleryApp.getGalleryService().loadGalleryById(displayedGalleryId);

    if(galleryDTO.getPhotos()!=null&&!galleryDTO.getPhotos().isEmpty()){
        for(int i=0;i<galleryDTO.getPhotos().size();i++){
            Uri imageUrl = galleryDTO.getPhotos().get(i);
            try {
                Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(),  imageUrl);

Then the following exception is thrown :

java.lang.SecurityException: Permission Denial: opening provider com.google.android.apps.photos.contentprovider.MediaContentProvider from ProcessRecord{3585e48d 8727:at....vrgallery.vrgallery/u0a137} (pid=8727, uid=10137) that is not exported from uid 10071

even I declared the required rights in the manifest:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

This exception does not occur for galleries which where just saved before viewing them. But when I close my app (e.g. with the task manager) and reopen it then the exception is thrown for these new galleries too.

What do I am wrong?


Solution

  • I store this gallery object in a sql lite db.

    That is not going to work in many cases.

    Think of a Uri as being akin to a user-authenticated URL in a Web app. The URL may be useful now, but as soon as the user's session times out, the URL becomes useless. The same thing holds true here: by default, a Uri may only be useful until your process terminates.

    Then the following exception is thrown :

    That is because your rights to that Uri expired, probably because your process was terminated.

    Also, bear in mind that the Uri may become invalid for other reasons, such as:

    • The user deleted the content

    • The user moved the content, and the Uri would now be different

    • The app that gave you the Uri is only keeping a local cache of content, and it eventually evicts this content out of that cache, requiring it to be downloaded again

    What do I am wrong?

    You are assuming that a Uri lives forever.

    You can try takePersistableUriPermission(). This will require a minSdkVersion of 19 (Android 4.4+), may not work on many Uri values (because the provider is not offering persistable permissions), and it will not solve all of the problems (e.g., user deleted the content).

    Or, you can make your own local copy of the content as soon as you get a Uri, rather than relying upon Uri values from other apps.