In my app, I want the user to be able to select any file they want (.mp4, .pdf, etc.), display the file name & extension within the app, and finally allow them to open the referenced file using the system dialog. I've already succeeded in opening the file picker dialog, getting the selected file's path and info, but I'm having trouble understanding how to go about using that file's path to trigger the OS dialog that will handle the file opening process. I've read up a bit on the SAF and the ACTION_OPEN_DOCUMENT
action, but I can't seem to understand if that's necessary or how to even go about it.
Here's my file retrieval process:
private fun openFilePicker() {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "*/*"
startActivityForResult(intent, PICKFILE_RESULT_CODE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
PICKFILE_RESULT_CODE -> if (resultCode == RESULT_OK) {
val filePath: String? = data?.data?.path
if (filePath != null) attachmentsAdapter.addFilePath(filePath) else Toast.makeText(
requireContext(),
"Something went wrong, please try again!",
Toast.LENGTH_SHORT
).show()
}
else -> super.onActivityResult(requestCode, resultCode, data)
}
}
I know that the SAF was introduced to improve the user's privacy and that apps can initially only access their own dirs (and some public ones I think), but do I really need to do something like creating my own dir, copying the referenced files there and then doing whatever I need to do to open them?
Update based on CommonsWare's answer:
As CommonsWare stated, the trick is to simply avoid using the path of the returned URI and instead use the URI itself. See their answer for the details.
Furthermore, since I'm only using the file's URI, getting its name and extension is a bit different. Here's how that can be done using a Cursor:
private fun getFileNameWithExtensionFromUri(currentFileUri: String): String? {
val returnCursor: Cursor? = context.contentResolver.query(Uri.parse(currentFileUri), null, null, null, null)
/*
* Get the column indexes of the data in the Cursor,
* move to the first row in the Cursor, get the data,
* and display it.
*/
val nameIndex = returnCursor?.getColumnIndex(OpenableColumns.DISPLAY_NAME)
returnCursor?.moveToFirst()
val fileName = returnCursor?.getString(nameIndex!!)
returnCursor?.close()
return fileName
}
Here's my file retrieval process
A Uri
is not a file. data?.data?.path
will not usually return a filesystem path.
I'm having trouble understanding how to go about using that file's path to trigger the OS dialog that will handle the file opening process
Android does not have an "OS dialog that will handle the file opening process", at least as I would use those terms.
If you want to try opening some app that can view the content, create an ACTION_VIEW
Intent
:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
PICKFILE_RESULT_CODE -> if (resultCode == RESULT_OK) {
data?.data?.let { uri ->
try {
startActivity(Intent(Intent.ACTION_VIEW, uri)).addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
} catch (e: Exception) {
Toast.makeText(
requireContext(),
"Something went wrong, please try again!",
Toast.LENGTH_SHORT
).show()
}
}
}
else -> super.onActivityResult(requestCode, resultCode, data)
}
}
The try
/catch
is important, as you are allowing the user to select any sort of content, and there may not be an app installed that offers support for viewing that particular type of content.