Since Android introduced major changes in storage framework recently much of the documentation talks about permissions and scoped storage. But I couldn't find details on how to process Uri of a file, for it to be readable by other apps.
The intent action to view/read a file by other apps fail. I don't understand what's the problem here;
java.io.File
and java.nio.File
?The Android storage samples (FileManager) has this bug as well. It lists all the files in a directory successfully but can't open a selected image, or a document. I've reported this issue but no help so far.
Following snippet is from FileManager (storage-samples)
fun openFile(activity: AppCompatActivity, selectedItem: File) {
// Get URI and MIME type of file
val uri = Uri.fromFile(selectedItem).normalizeScheme()
val mime: String = getMimeType(uri.toString())
// Open file with user selected app
val intent = Intent()
intent.action = Intent.ACTION_VIEW
intent.data = uri
intent.type = mime
return activity.startActivity(intent)
}
After the hints from the comments, I found the answer in developer docs.
Caution: If you want to set both the URI and MIME type, don't call setData() and setType() because they each nullify the value of the other. Always use setDataAndType() to set both URI and MIME type.
The reason behind openFile
didn't throw FileUriExposedException
in android-storage-samples is that after setting intent.type
, the Uri gets nullified and when I changed it to setDataAndType()
I got the exception. The final snippet looks like
fun openFile(activity: AppCompatActivity, selectedItem: File) {
// Get URI and MIME type of file
val uri = FileProvider.getUriForFile(activity.applicationContext, AUTHORITY, selectedItem)
// val uri = Uri.fromFile(selectedItem).normalizeScheme()
val mime: String = getMimeType(uri.toString())
// Open file with user selected app
val intent = Intent()
intent.action = Intent.ACTION_VIEW
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
// intent.data = uri
// intent.type = mime
intent.setDataAndType(uri, mime)
return activity.startActivity(intent)
}
I think they forgot to update the samples over time, let me create a pull request to commit this change over there as well.