As part of my app, users can select images from their device and I store the URLs to these in my database. Then, elsewhere in the app, I need to display those images.
I am getting the image URI through Intent.ACTION_PICK
:
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
imagePickerAction = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
if (uri != null) {
val uriString = uri.toString()
saveToDatabase(uriString)
}
}
This results in a URI string like content://com.android.providers.media.documents/document/image%3A1000000038
.
I am able to show the image using ImageView.setImageURI
at this point.
But later on, when I fetch the URI from the database and try to use setImageURI
again, I get this error:
java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{cdd4e32 10499:com.skamz.shadercam/u0a160} (pid=10499, uid=10160) requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs
I have also tried following the docs here https://developer.android.com/training/data-storage/shared/documents-files#open:
private fun getBitmapFromUri(uri: Uri): Bitmap {
val parcelFileDescriptor: ParcelFileDescriptor? =
contentResolver.openFileDescriptor(uri, "r")
if (parcelFileDescriptor == null) {
return bitmapFromUri(contentResolver, Uri.parse(TextureOverlayShaderData.defaultImageUrl))
}
val fileDescriptor: FileDescriptor = parcelFileDescriptor.fileDescriptor
val image: Bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor)
parcelFileDescriptor.close()
return image
}
This returns a bitmap, which I then pass into ImageView.bitmapFromUri
. Unfortunately, this produces the same error, this time coming from contentResolver.openFileDescriptor(uri, "r")
when I fetch the URI from the database
That's not an option with ACTION_PICK
. You cannot reliably persist a Uri
that you received from ACTION_PICK
and use it again later. Your access rights to the content are short-lived.
If you switch to ACTION_OPEN_DOCUMENT
and use takePersistableUriPermissions()
on a ContentResolver
when you get the Uri
in onActivityResult()
, you can safely persist that Uri
. You might still run into problems using it later — for example, the user could delete the image that the Uri
points to — but you will not encounter the access problem that you are seeing here.