opening an external "file explorer" app: how to get absolute path from a uri pointing to a folder

592 Views Asked by At

In my app, the user can choose where the created files (text files) are created. This part is working fine. But now, I want to open an external "file explorer" app, pointing directly to the chosen folder. The "file explorer " apps I know accept an absolute path as input (like /storage/emulated/0/Documents/test_folder)

When the user chooses a folder (with Intent.ACTION_OPEN_DOCUMENT_TREE), I get a content uri (like content://com.android.externalstorage.documents/tree/home%3Atest_folder)

Another example with an external sd card:

  • uri: content://com.android.externalstorage.documents/tree/3877-DB74%3ADocuments%2Ftest_folder
  • expected path: /storage/3877-DB74/Documents/test_folder

The uri points to a folder, not a file, so I can't use something like openInputStream

I have tried :

File f = new File(uri.getPath());
String path = f.getAbsolutePath();

but it gives: /tree/home:test_folder or /tree/3877-DB74:Documents/test_folder if on sd card

How can I get the real absolute path?

The code I use to call a file explorer:

Intent intent = new Intent(Intent.ACTION_VIEW);
String path = getExternalFilesDir(null).getAbsolutePath();
intent.setDataAndType(Uri.parse(path), "resource/folder");
if (intent.resolveActivityInfo(getPackageManager(), 0) != null)
{
    startActivity(intent);
}
3

There are 3 best solutions below

0
Laurent D. On BEST ANSWER

I finally wrote my own method to get the absolute path for a folder from a Uri. It is surely not fully generic, but it meets my need.

if it can help someone, here is my code:

Note: VOLUME_MAP is a map containing all mounted external volumes

    /**************************************************************************/
    public static String getRealPathFromContentUri(final Uri uri)
    {
        if (!isExternalStorageDocument(uri))
        {
            return null;
        }

        List<String> segs = uri.getPathSegments();
        if (!"tree".equalsIgnoreCase(segs.get(0)))
        {
            return null;
        }

        String path = uri.getLastPathSegment();
        final String[] split = path.split(":");
        final String volumeId = split[0];
        String userPath = "";
        if (split.length > 1)
        {
            userPath = "/" + split[1];
        }
        if ("primary".equalsIgnoreCase(volumeId))
        {
            return Environment.getExternalStorageDirectory().getAbsolutePath() + userPath;
        }

        if ("home".equalsIgnoreCase(volumeId))
        {
            return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath() + userPath;
        }

        // look for real volumeId
        final String volumeName = VOLUME_MAP.get(volumeId);
        if (volumeName == null)
        {
            return null;
        }
        path = "/storage";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
        {
            path = Environment.getStorageDirectory().getAbsolutePath();
        }
        return path  + "/" + volumeId + userPath;
    }

Thanks to all contributors on this topic.

1
jayesh gurudayalani On

so basically you want to get file path from uri

you give try with this code

https://gist.github.com/pratikbutani/eb56f6f9f7013e31d8bfea9effbd4251

0
Laurent D. On

I have tried the suggested code (see above).

Unfortunately, I got an exception:

     Caused by: java.lang.UnsupportedOperationException: Unsupported Uri content://com.android.externalstorage.documents/tree/home%3Atest_folder
        at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:167)
        at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
        at android.content.ContentProviderProxy.query(ContentProviderNative.java:418)
        at android.content.ContentResolver.query(ContentResolver.java:760)
        at android.content.ContentResolver.query(ContentResolver.java:710)
        at android.content.ContentResolver.query(ContentResolver.java:668)
        at ....UriUtils.getDataColumn(UriUtils.java:278)

Here is a copy of the code:

private static String getDataColumn(Context context, Uri uri)
{
    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = { column };

    try {
        cursor = context.getContentResolver().query(uri, projection, 
                                                    null, null, null);
        if (cursor != null && cursor.moveToFirst()) {
            final int index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}