Search code examples
androidandroid-intentandroid-permissionsandroid-storage

how to open files using intent action with latest Android storage framework?


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;

  1. Does it have to do with difference between java.io.File and java.nio.File?
  2. The Uri has missing permissions or the Uri is not well formatted.

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)
}

Solution

  • 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.