Get file path from URI
A simpler version of the accepted answer that will detect the API level and use the correct method :
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String getFilePath(Context context, Uri uri)
{
int currentApiVersion;
try
{
currentApiVersion = android.os.Build.VERSION.SDK_INT;
}
catch(NumberFormatException e)
{
//API 3 will crash if SDK_INT is called
currentApiVersion = 3;
}
if (currentApiVersion >= Build.VERSION_CODES.KITKAT)
{
String filePath = "";
String wholeID = DocumentsContract.getDocumentId(uri);
// Split at colon, use second item in the array
String id = wholeID.split(":")[1];
String[] column = {MediaStore.Images.Media.DATA};
// where id is equal to
String sel = MediaStore.Images.Media._ID + "=?";
Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, new String[]{id}, null);
int columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst())
{
filePath = cursor.getString(columnIndex);
}
cursor.close();
return filePath;
}
else if (currentApiVersion <= Build.VERSION_CODES.HONEYCOMB_MR2 && currentApiVersion >= Build.VERSION_CODES.HONEYCOMB)
{
String[] proj = {MediaStore.Images.Media.DATA};
String result = null;
CursorLoader cursorLoader = new CursorLoader(
context,
uri, proj, null, null, null);
Cursor cursor = cursorLoader.loadInBackground();
if (cursor != null)
{
int column_index =
cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
result = cursor.getString(column_index);
}
return result;
}
else
{
String[] proj = {MediaStore.Images.Media.DATA};
Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null);
int column_index
= cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
}
Here's my solution, using all tricks I've found so far, which I use on my own app too (here) :
FileUtilEx.kt
fun Closeable?.closeSilently() {
if (this != null) try {
this.close()
} catch (e: Exception) {
}
}
object FileUtilEx {
fun getFilePathFromUri(context: Context, uri: Uri, includeUriMappingTechnique: Boolean = true, tryToGetWritePermission: Boolean = false): ClosableFileHolder? {
var file: File
uri.path?.let {
file = File(it)
if (file.exists() && file.canRead()) {
// Log.d("AppLog", "got real file")
return ClosableFileHolder(file)
}
}
if (uri.scheme == "file") {
try {
val jUri = java.net.URI(uri.scheme, uri.schemeSpecificPart, uri.fragment)
file = File(jUri)
if (file.exists() && file.canRead()) {
// Log.d("AppLog", "got real file")
return ClosableFileHolder(file)
}
} catch (e: Exception) {
}
try {
val uriStr = uri.toString()
val decodePath = URLDecoder.decode(uriStr, "UTF-8")
file = File(decodePath)
if (file.exists() && file.canRead()) {
// Log.d("AppLog", "got real file")
return ClosableFileHolder(file)
}
} catch (e: UnsupportedEncodingException) {
}
}
val authority = uri.authority
if (uri.scheme == "content") {
//handles "Files" app, and many others
getRealPathFromUri(context, uri)?.let {
file = File(it)
if (file.exists() && file.canRead()) {
// Log.d("AppLog", "got real file")
return ClosableFileHolder(file)
}
}
}
if (includeUriMappingTechnique) {
val fileUsingUriMappingTechnique = getFileUsingUriMappingTechnique(context, uri, tryToGetWritePermission)
if (fileUsingUriMappingTechnique != null)
return fileUsingUriMappingTechnique
}
getFilePathFromDocumentUri(context, uri)?.let { filePath ->
file = File(filePath)
if (file.exists() && file.canRead())
return ClosableFileHolder(file)
}
return null
}
private fun getRealPathFromUri(context: Context, contentUri: Uri): String? {
try {
context.contentResolver.query(contentUri, arrayOf(MediaStore.Images.Media.DATA), null, null, null)?.use { cursor ->
val columnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA)
if (columnIndex < 0 || cursor.count <= 0)
return null
cursor.moveToFirst()
return cursor.getString(columnIndex)
}
} catch (e: Exception) {
e.printStackTrace()
}
return null
}
fun getFileUsingUriMappingTechnique(context: Context, androidUri: Uri, tryToGetWritePermission: Boolean = false): ClosableFileHolder? {
var parcelFileDescriptor: ParcelFileDescriptor? = null
for (i in 0..1)
try {
parcelFileDescriptor = context.contentResolver.openFileDescriptor(androidUri, if (tryToGetWritePermission && i == 0) "w" else "r")
if (parcelFileDescriptor != null) {
val fd: Int = parcelFileDescriptor.fd
val linkFileName = "/proc/self/fd/$fd"
if (VERSION.SDK_INT >= VERSION_CODES.O) {
val realFilePath = Files.readSymbolicLink(Paths.get(linkFileName))
val file = realFilePath.toFile()
if (file.exists() && file.canRead()) {
parcelFileDescriptor.closeSilently()
return ClosableFileHolder(file)
}
}
val file = File(linkFileName)
if (file.exists() && file.canRead())
return ClosableFileHolder(file, parcelFileDescriptor)
parcelFileDescriptor.closeSilently()
}
} catch (e: Exception) {
parcelFileDescriptor.closeSilently()
parcelFileDescriptor = null
}
return null
}
private fun getFilePathFromDocumentUri(context: Context, uri: Uri): String? {
// https://stackoverflow.com/questions/5657411/android-getting-a-file-uri-from-a-content-uri
// DocumentProvider
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT && DocumentFile.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if ("com.android.externalstorage.documents" == uri.authority) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]
// This is for checking Main Memory
return if ("primary".equals(type, ignoreCase = true)) {
if (split.size > 1) {
Environment.getExternalStorageDirectory().absolutePath + "/" + split[1] + "/"
} else {
Environment.getExternalStorageDirectory().absolutePath + "/"
}
// This is for checking SD Card
} else {
"storage" + "/" + docId.replace(":", "/")
}
}
}
return null
}
}
ClosableFileHolder.kt
class ClosableFileHolder(val file: File, private val parcelFileDescriptor: ParcelFileDescriptor? = null) : Closeable {
fun isUsingUriMappingTechnique(): Boolean = parcelFileDescriptor != null
override fun close() {
parcelFileDescriptor.closeSilently()
}
protected fun finalize() {
parcelFileDescriptor.closeSilently()
}
}
Usage:
FileUtilEx.getFilePathFromUri(context, uri, false)?.use {
val file = it.file
...
}
The tryToGetWritePermission
parameter is in case you want to access the file, but it's in fact not available normally (like in SAF), so it's offered you in a different place. This is useful in case you want to access the file but don't care where it really exists.
Solution:
public class RealPathUtil {
@SuppressLint("NewApi")
public static String getRealPathFromURI_API19(Context context, Uri uri){
String filePath = "";
String wholeID = DocumentsContract.getDocumentId(uri);
// Split at colon, use second item in the array
String id = wholeID.split(":")[1];
String[] column = { MediaStore.Images.Media.DATA };
// where id is equal to
String sel = MediaStore.Images.Media._ID + "=?";
Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, new String[]{ id }, null);
int columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);
}
cursor.close();
return filePath;
}
@SuppressLint("NewApi")
public static String getRealPathFromURI_API11to18(Context context, Uri contentUri) {
String[] proj = { MediaStore.Images.Media.DATA };
String result = null;
CursorLoader cursorLoader = new CursorLoader(
context,
contentUri, proj, null, null, null);
Cursor cursor = cursorLoader.loadInBackground();
if(cursor != null){
int column_index =
cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
result = cursor.getString(column_index);
}
return result;
}
public static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri){
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index
= cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
}
http://hmkcode.com/android-display-selected-image-and-its-real-path/