4

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?

sgtpotatoe
  • 340
  • 6
  • 17

1 Answers1

5

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.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 1
    Not going to lie, I was crossing my fingers that CommonsWare, author of the article that described best my situation, would reply, and here it is! - This definitely works, users will have to adapt to using the documentProvider to select media but it seems to be the only working way – sgtpotatoe Aug 18 '20 at 23:52
  • and also when calling `takePersistableUriPermissions()` make sure you're setting the appropriate flags as you explained [here](https://stackoverflow.com/a/46917241/2445763) – lasec0203 Aug 19 '21 at 03:10
  • There is another method using DocumentsContract to get the display name of the files, and then querying the MediaStore for that display name. I have tested it for Android 4, 9, and 11 and have not ran into issues yet. – John Glen Aug 13 '22 at 20:52
  • @JohnGlen: I would imagine that you would start getting problems once you have more than one file with the same display name. This also is not a general replacement for `ACTION_OPEN_DOCUMENT`, though it might hold up for media content. – CommonsWare Aug 13 '22 at 20:59