To get right to the point I'm having an issue where I am selecting a file using the Intent.createChooser
and I've used an assortment of different way to get the absolute path to the file and they all result in content://downloads/public_downloads/1006
.
Using this path in an emulator works perfectly fine and produces the expected results, but as soon as I build the app on my device (Galaxy S9) I get an error that the file does not exist.
I have requested permissions for Manifest.permission.READ_EXTERNAL_STORAGE
and Manifest.permission.WRITE_EXTERNAL_STORAGE
and verified that the permissions are enabled in the app.
After searching for a few hours I'm running out of ideas to try and would be happy if someone could guide me in the right way.
The method I'm currently using for getting the absolute path is
private fun getAbsoluteFilePath(uri: Uri): String {
val id = DocumentsContract.getDocumentId(uri)
val contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/my_downloads"), id.toLong())
val projection = arrayOf(MediaStore.Images.Media.DATA)
val cursor = contentResolver.query(contentUri, projection, null, null, null)
val columnIndex = cursor!!.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
cursor.moveToFirst()
return cursor.getString(columnIndex)
}
but I've also tried
object PathUtil {
/*
* Gets the file path of the given Uri.
*/
@SuppressLint("NewApi")
@Throws(URISyntaxException::class)
fun getPath(context: Context, uri: Uri): String? {
var uri = uri
val needToCheckUri = Build.VERSION.SDK_INT >= 19
var selection: String? = null
var selectionArgs: Array<String>? = null
// Uri is different in versions after KITKAT (Android 4.4), we need to
// deal with different Uris.
if (needToCheckUri && DocumentsContract.isDocumentUri(context.applicationContext, uri)) {
if (isExternalStorageDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
return Environment.getExternalStorageDirectory().toString() + "/" + split[1]
}
if (isDownloadsDocument(uri)) {
val id = DocumentsContract.getDocumentId(uri)
uri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))
} else if (isMediaDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]
if ("image" == type) {
uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
} else if ("video" == type) {
uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
} else if ("audio" == type) {
uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
}
selection = "_id=?"
selectionArgs = arrayOf(split[1])
}
}
if ("content".equals(uri.scheme, ignoreCase = true)) {
val projection = arrayOf(MediaStore.Images.Media.DATA)
var cursor: Cursor? = null
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
val columnIndex = cursor!!.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
if (cursor!!.moveToFirst()) {
return cursor!!.getString(columnIndex)
}
} else if ("file".equals(uri.scheme, ignoreCase = true)) {
return uri.path
}
return null
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
fun isExternalStorageDocument(uri: Uri): Boolean {
return "com.android.externalstorage.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
fun isDownloadsDocument(uri: Uri): Boolean {
return "com.android.providers.downloads.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
fun isMediaDocument(uri: Uri): Boolean {
return "com.android.providers.media.documents" == uri.authority
}
}
which yields the same result, my code is more or less this:
fun doSomething() {
val intent = Intent().apply {
action = Intent.ACTION_GET_CONTENT
type = "*/*"
addCategory(Intent.CATEGORY_OPENABLE)
}
val chooser = Intent.createChooser(intent, "Select")
startActivityForResult(chooser, 1)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
ZipFile(getAbsoluteFilePath(data.data))
}
Oh, and please don't close this as a duplicate - I've found lots of similar issues but no solution has worked for me yet, not sure what I'm missing but I bet it's something stupid