Last active
July 10, 2024 08:57
-
-
Save MeNiks/947b471b762f3b26178ef165a7f5558a to your computer and use it in GitHub Desktop.
Kotlin code to get real path / sd card path from intent data while browsing file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.annotation.SuppressLint | |
import android.content.ContentUris | |
import android.content.Context | |
import android.content.CursorLoader | |
import android.database.Cursor | |
import android.net.Uri | |
import android.os.Build | |
import android.os.Environment | |
import android.provider.DocumentsContract | |
import android.provider.MediaStore | |
import android.text.TextUtils | |
object RealPathUtil { | |
fun getRealPath(context: Context, fileUri: Uri): String? { | |
// SDK >= 11 && SDK < 19 | |
return if (Build.VERSION.SDK_INT < 19) { | |
getRealPathFromURIAPI11to18(context, fileUri) | |
} else { | |
getRealPathFromURIAPI19(context, fileUri) | |
}// SDK > 19 (Android 4.4) and up | |
} | |
@SuppressLint("NewApi") | |
fun getRealPathFromURIAPI11to18(context: Context, contentUri: Uri): String? { | |
val proj = arrayOf(MediaStore.Images.Media.DATA) | |
var result: String? = null | |
val cursorLoader = CursorLoader(context, contentUri, proj, null, null, null) | |
val cursor = cursorLoader.loadInBackground() | |
if (cursor != null) { | |
val columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA) | |
cursor.moveToFirst() | |
result = cursor.getString(columnIndex) | |
cursor.close() | |
} | |
return result | |
} | |
/** | |
* Get a file path from a Uri. This will get the the path for Storage Access | |
* Framework Documents, as well as the _data field for the MediaStore and | |
* other file-based ContentProviders. | |
* | |
* @param context The context. | |
* @param uri The Uri to query. | |
* @author Niks | |
*/ | |
@SuppressLint("NewApi") | |
fun getRealPathFromURIAPI19(context: Context, uri: Uri): String? { | |
val isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT | |
// DocumentProvider | |
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { | |
// ExternalStorageProvider | |
if (isExternalStorageDocument(uri)) { | |
val docId = DocumentsContract.getDocumentId(uri) | |
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() | |
val type = split[0] | |
if ("primary".equals(type, ignoreCase = true)) { | |
return Environment.getExternalStorageDirectory().toString() + "/" + split[1] | |
} | |
} else if (isDownloadsDocument(uri)) { | |
var cursor: Cursor? = null | |
try { | |
cursor = context.contentResolver.query(uri, arrayOf(MediaStore.MediaColumns.DISPLAY_NAME), null, null, null) | |
cursor!!.moveToNext() | |
val fileName = cursor.getString(0) | |
val path = Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName | |
if (!TextUtils.isEmpty(path)) { | |
return path | |
} | |
} finally { | |
cursor?.close() | |
} | |
val id = DocumentsContract.getDocumentId(uri) | |
if (id.startsWith("raw:")) { | |
return id.replaceFirst("raw:".toRegex(), "") | |
} | |
val contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads"), java.lang.Long.valueOf(id)) | |
return getDataColumn(context, contentUri, null, null) | |
} else if (isMediaDocument(uri)) { | |
val docId = DocumentsContract.getDocumentId(uri) | |
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() | |
val type = split[0] | |
var contentUri: Uri? = null | |
when (type) { | |
"image" -> contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI | |
"video" -> contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI | |
"audio" -> contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI | |
} | |
val selection = "_id=?" | |
val selectionArgs = arrayOf(split[1]) | |
return getDataColumn(context, contentUri, selection, selectionArgs) | |
}// MediaProvider | |
// DownloadsProvider | |
} else if ("content".equals(uri.scheme!!, ignoreCase = true)) { | |
// Return the remote address | |
return if (isGooglePhotosUri(uri)) uri.lastPathSegment else getDataColumn(context, uri, null, null) | |
} else if ("file".equals(uri.scheme!!, ignoreCase = true)) { | |
return uri.path | |
}// File | |
// MediaStore (and general) | |
return null | |
} | |
/** | |
* Get the value of the data column for this Uri. This is useful for | |
* MediaStore Uris, and other file-based ContentProviders. | |
* | |
* @param context The context. | |
* @param uri The Uri to query. | |
* @param selection (Optional) Filter used in the query. | |
* @param selectionArgs (Optional) Selection arguments used in the query. | |
* @return The value of the _data column, which is typically a file path. | |
* @author Niks | |
*/ | |
private fun getDataColumn(context: Context, uri: Uri?, selection: String?, | |
selectionArgs: Array<String>?): String? { | |
var cursor: Cursor? = null | |
val column = "_data" | |
val projection = arrayOf(column) | |
try { | |
cursor = context.contentResolver.query(uri!!, projection, selection, selectionArgs, null) | |
if (cursor != null && cursor.moveToFirst()) { | |
val index = cursor.getColumnIndexOrThrow(column) | |
return cursor.getString(index) | |
} | |
} finally { | |
cursor?.close() | |
} | |
return null | |
} | |
/** | |
* @param uri The Uri to check. | |
* @return Whether the Uri authority is ExternalStorageProvider. | |
*/ | |
private 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. | |
*/ | |
private 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. | |
*/ | |
private fun isMediaDocument(uri: Uri): Boolean { | |
return "com.android.providers.media.documents" == uri.authority | |
} | |
/** | |
* @param uri The Uri to check. | |
* @return Whether the Uri authority is Google Photos. | |
*/ | |
private fun isGooglePhotosUri(uri: Uri): Boolean { | |
return "com.google.android.apps.photos.content" == uri.authority | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Extension on intent | |
fun Intent?.getFilePath(context: Context): String { | |
return this?.data?.let { data -> RealPathUtil.getRealPath(context, data) ?: "" } ?: "" | |
} | |
fun Uri?.getFilePath(context: Context): String { | |
return this?.let { uri -> RealPathUtil.getRealPath(context, uri) ?: "" } ?: "" | |
} | |
fun ClipData.Item?.getFilePath(context: Context): String { | |
return this?.uri?.getFilePath(context) ?: "" | |
} | |
// Usage | |
val selectedPath = intent.getFilePath(context) |
Works for me too. Thanks!
What's context? How do I get it?
thanx works for me in android 8 i love you :3
What's context? How do I get it?
you pass the application context
This is not working if we are selecting a file from the download folder and if that file is downloaded from google drive. I am getting the path from the below code if the file does not exist.
cursor = context.contentResolver.query(uri, arrayOf(MediaStore.MediaColumns.DISPLAY_NAME), null, null, null)
cursor!!.moveToNext()
val fileName = cursor.getString(0)
val path = Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName
if (!TextUtils.isEmpty(path)) {
return path
}
I created a library to facilitate the handling of Intent (Uri) received. It can be found here.
thanks for the code,
if i want to retrieve an audio file and use it on a media player how can i pass the audio to mediaPlayer.create?
Below is the code i have where i create and initiate the player
`
private fun controlSound(id: Uri){
fab_play.setOnClickListener{
if (mp == null){
mp = MediaPlayer.create(this, id)
Log.d("MediaPlayer", "ID: ${mp!!.audioSessionId}")
initialiseSeekBar()
}
mp?.start()
Log.d("MediaPlayer", "Duration: ${mp!!.duration/1000} seconds")
}`
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
this doesnt work when opening a file from google chrome downloads on api > 19 with a uri of something like this content://com.android.chrome.FileProvider/downloads/<some_file_name>