Skip to content

Instantly share code, notes, and snippets.

@MeNiks
Last active July 10, 2024 08:57
Show Gist options
  • Save MeNiks/947b471b762f3b26178ef165a7f5558a to your computer and use it in GitHub Desktop.
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.
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
}
}
// 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)
@Bajranghudda
Copy link

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
                    }

@onimur
Copy link

onimur commented Jun 25, 2020

I created a library to facilitate the handling of Intent (Uri) received. It can be found here.

@Victortorresf
Copy link

Victortorresf commented Jan 5, 2021

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