Search code examples
androidkotlinurimediastoreandroid-fileprovider

Get PDF from MediaStore after receiving "content://" Uri in onActivityResult?


I start an ACTION_GET_CONTENT intent in order to pick a PDF:

override fun routeToFilePicker() {
    val intent = Intent()
    intent.type = MediaType.PDF.toString()
    intent.action = Intent.ACTION_GET_CONTENT
    activity.startActivityForResult(
        Intent.createChooser(intent, "Select PDF"),
        REQUEST_CODE_PDF_PICKER
    )
}

Then on onActivityResult I try to create a PDF from the Uri (content//:path):

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE_PDF_PICKER ) {
        data?.data?.let { pdfUri: Uri ->
            val pdfFile: File = pdfUri.toFile() <-- chrash
            ...
        }
    }
}

pdfUri.toFile() causes a fatal Exception:

java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1003, result=-1, data=Intent { dat=content://com.android.providers.downloads.documents/document/3569 flg=0x1 }} to activity {my.package.name.activity}: java.lang.IllegalArgumentException: Uri lacks 'file' scheme: content://com.android.providers.downloads.documents/document/3569

Caused by: java.lang.IllegalArgumentException: Uri lacks 'file' scheme: content://com.android.providers.downloads.documents/document/3569

I need a File in order to convert the pages into Images.
How can I get the PDF as a File from the Uri returned by MediaStore?


Solution

  • This is how I'm getting pdf as file :

    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
                                type = "application/pdf"
                                addCategory(Intent.CATEGORY_OPENABLE)
                                flags = flags or Intent.FLAG_GRANT_READ_URI_PERMISSION
                            }
                            startActivityForResult(intent, 111)
    

    Inside your OnActivityResult(requestCode:Int,resultCode:Int,data:Intent?)

    if (resultCode == Activity.RESULT_OK) {
                when (requestCode) {
    //                101 -> {
    //                    data?.data?.also { uri ->
    //                        Log.i(TAG, "Uri: $uri")
    //                        baseAdapter?.add(ImageArray(null, null, uri.toString()))
    //                    }
    //                }
                    111 -> {
                        data?.data?.also { documentUri ->
                            baseActivity.contentResolver?.takePersistableUriPermission(
                                    documentUri,
                                    Intent.FLAG_GRANT_READ_URI_PERMISSION
                            )
                            val file = DocumentUtils.getFile(baseActivity,documentUri)//use pdf as file 
                        }
                    }
                }
    
            }
    

    Singleton class to covert Uri to file:

    object DocumentUtils {
        fun getFile(mContext: BaseActivity?, documentUri: Uri): File {
            val inputStream = mContext?.contentResolver?.openInputStream(documentUri)
            var file =  File("")
            inputStream.use { input ->
                file =
                    File(mContext?.cacheDir, System.currentTimeMillis().toString()+".pdf")
                FileOutputStream(file).use { output ->
                    val buffer =
                        ByteArray(4 * 1024) // or other buffer size
                    var read: Int = -1
                    while (input?.read(buffer).also {
                            if (it != null) {
                                read = it
                            }
                        } != -1) {
                        output.write(buffer, 0, read)
                    }
                    output.flush()
                }
            }
            return file
        }
    } 
    

    P.S: Do not forget to ask permission at runtime

    Manifest.permission.WRITE_EXTERNAL_STORAGE
    Manifest.permission.READ_EXTERNAL_STORAGE