Last active
April 18, 2021 01:21
-
-
Save micer/ae5de2984dbbdb386dd262782cfdb39c to your computer and use it in GitHub Desktop.
Utility class to get real path from URI object - all API versions
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.content.ContentUris | |
import android.content.Context | |
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.support.v4.content.CursorLoader | |
import android.text.TextUtils | |
import com.github.ajalt.timberkt.e | |
object RealPathUtil { | |
fun getRealPath(context: Context, fileUri: Uri): String? { | |
val realPath: String? | |
if (Build.VERSION.SDK_INT < 11) { | |
// SDK < 11 | |
realPath = RealPathUtil.getRealPathFromUriBelowAPI11(context, fileUri) | |
} else if (Build.VERSION.SDK_INT < 19) { | |
// SDK >= 11 && SDK < 19 | |
realPath = RealPathUtil.getRealPathFromUriAPI11to18(context, fileUri) | |
} else { | |
// SDK > 19 (Android 4.4) and up | |
realPath = RealPathUtil.getRealPathFromUriAPI19(context, fileUri) | |
} | |
return realPath | |
} | |
private 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 column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA) | |
cursor.moveToFirst() | |
result = cursor.getString(column_index) | |
cursor.close() | |
} | |
return result | |
} | |
private fun getRealPathFromUriBelowAPI11(context: Context, contentUri: Uri): String { | |
val proj = arrayOf(MediaStore.Images.Media.DATA) | |
val cursor = context.contentResolver.query(contentUri, proj, null, null, null) | |
var column_index = 0 | |
var result = "" | |
if (cursor != null) { | |
column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA) | |
cursor.moveToFirst() | |
result = cursor.getString(column_index) | |
cursor.close() | |
return result | |
} | |
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 paulburke | |
*/ | |
private 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)) { | |
val path = StringBuilder() | |
path.append(Environment.getExternalStorageDirectory()) | |
path.append("/") | |
path.append(split[1]) | |
return path.toString() | |
} | |
// TODO handle non-primary volumes | |
} else if (isDownloadsDocument(uri)) { | |
val id = DocumentsContract.getDocumentId(uri) | |
if (!TextUtils.isEmpty(id)) { | |
if (id.startsWith("raw:")) { | |
return id.replaceFirst("raw:", ""); | |
} | |
return try { | |
val contentUri = ContentUris.withAppendedId( | |
Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id)) | |
getDataColumn(context, contentUri, null, null) | |
} catch (e: NumberFormatException) { | |
e(e) | |
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 | |
if ("image" == type) { | |
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI | |
} else if ("video" == type) { | |
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI | |
} else if ("audio" == type) { | |
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. | |
*/ | |
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 { | |
if (cursor != null) | |
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 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I create this library: https://github.com/onimur/handle-path-oz . Can be used with kotlin or java