Android "storing" and "reusing" obtained URIs

Viewed 595

My app collects media through an ACTION_PICK Intent to get android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI

type of content. When I retrieve the URI of the content I want, It works great and I can view it with:

val intent = Intent(Intent.ACTION_VIEW, myURI)
intent.setDataAndType(myURI,contentResolver.getType(myURI))
intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION)
startActivity(intent)

I store the Uri with Uri.toString method, and as soon as I close the activity and open it again, I get the following error:

java.lang.SecurityException: UID 10315 does not have permission to content://com.miui.gallery.open/raw/%2Fstorage%2Femulated%2F0%2FDCIM%2FCamera%2FVID_20200814_214253.mp4 [user 0]

and further down also:

Caused by: android.os.RemoteException: Remote stack trace:
    at com.android.server.uri.UriGrantsManagerService.checkGrantUriPermission(UriGrantsManagerService.java:1192)
    at com.android.server.uri.UriGrantsManagerService.checkGrantUriPermissionFromIntent(UriGrantsManagerService.java:579)
    at com.android.server.uri.UriGrantsManagerService.grantUriPermissionFromIntent(UriGrantsManagerService.java:618)
    at com.android.server.uri.UriGrantsManagerService$LocalService.grantUriPermissionFromIntent(UriGrantsManagerService.java:1392)

Ideally I would get the file path of the media and generate the URI from file through a fileProvider, but I haven't found a way of getting an absolute path from ContentURIs.

Read through https://commonsware.com/blog/2016/08/10/uri-access-lifetime-shorter-than-you-might-think.html which explains better what is happening, so how can I reuse or store a file I retrieved through its URI? Can I retrieve a file path instead of a URI in some way?

1 Answers

I store the Uri with Uri.toString method

That is not going to work. Your rights to the content obtained from ACTION_PICK are very short-lived. (note: this link is to a newer version of my blog post that you linked to in the question)

Ideally I would get the file path of the media

That also is not going to work. There is no requirement for ACTION_PICK or similar actions to return anything that relates to the filesystem, let alone to some file that you could access directly. In your specific case, the MediaStore has greater access than you do, so things that you find in the MediaStore may not be accessible, even if you query for the semi-deprecated DATA column to try to find a path. Plus, the implementation of ACTION_PICK that the user chooses may not return a MediaStore Uri anyway.

If you need to be able to select a piece of content, persist its Uri, and use that Uri to work with the content later, you need to:

  • Use ACTION_OPEN_DOCUMENT instead of ACTION_PICK

  • Call takePersistableUriPermissions() on a ContentResolver, passing in the Uri that you get

Now, you have long-term access to the content... assuming that the user does not do something dramatic like delete it.

Related