Ivan Morgillo
Ivan Morgillo

Reputation: 3844

SecurityException: Calling uid does not have permission to access picker uri

I'm using

fun Context.persistUriAccess(uri: Uri) {
    grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
    contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
}

to access images from the gallery after the user picked them using PickVisualMedia().

Everything works until I uninstall and reinstall the app 🤦

After that, I can't access the images anymore:

SecurityException: Calling uid ( 10575 ) does not have permission to access picker uri: content://media/picker/0/com.android.providers.media.photopicker/media/1000012483

I tried to go "All in! Let's ask for the whole thing!"

    private fun accessGallery() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
            requestPermissions.launch(arrayOf(READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_VISUAL_USER_SELECTED))
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            requestPermissions.launch(arrayOf(READ_MEDIA_IMAGES, READ_MEDIA_VIDEO))
        } else {
            requestPermissions.launch(arrayOf(READ_EXTERNAL_STORAGE))
        }
    }

as stated here: https://developer.android.com/about/versions/14/changes/partial-photo-video-access, but I still get the SecurityException and no image on screen.

How am I supposed to do this? I would rather not make copies of the images and ship them to my BE only to download them every time I want to show them 😬

Upvotes: 2

Views: 1383

Answers (1)

CommonsWare
CommonsWare

Reputation: 1007474

How am I supposed to do this?

To some extent, the answer is: hope the user does not uninstall and reinstall the app. If you are anticipating that this will happen a lot, that seems like a problem to try to solve.

The Uri values are useless except for this app installation. Once the app is uninstalled, any permissions associated with those Uri values go "poof".

Storing such Uri values is fine for a "link" sort of operation, where you are in position to deal with broken links for any reason. For example, the user could delete the image; my assumption is that your app will similarly break for that scenario, if you try to use a Uri that points to the now-deleted image. Once you figure out what sort of UX you want to have for this scenario, you can decide if it could be extended for the uninstall/reinstall scenario.

If you determine that you cannot cope with the deleted-image case, then you have more of an "import" operation, where you need to make your own copy of the content and work with that copy that you control. And, if you want to extend that approach to handle uninstall/reinstall, you will need to "make copies of the images and ship them to my BE".

only to download them every time I want to show them

So, cache them:

  • When the user imports an image into your app, copy it to your cache and arrange to upload it to your BE
  • If you have a reference to an image that is not cached locally (uninstall/reinstall, cache eviction policy, "clear data" in Settings, etc.), download it from the BE into the cache

In the ideal case, the user never downloads the image, as they just use the cached copy.

Upvotes: 0

Related Questions