Android 5.0 DocumentFile from tree URI

Well, I searched and searched, and I didn't have the exact answer, or I missed it. I want my users to select a directory:

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, READ_REQUEST_CODE);

In my activity I want to fix the actual path, which seems impossible.

protected void onActivityResult(int requestCode, int resultCode, Intent intent){
    super.onActivityResult(requestCode, resultCode, intent);
    if (resultCode == RESULT_OK) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M){
            //Marshmallow 

        } else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP){
            //Set directory as default in preferences
            Uri treeUri = intent.getData();
            //grant write permissions
            getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            //File myFile = new File(uri.getPath()); 
            DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);

I selected the folder:

Device storage/test/

I tried all of the following ways to get the exact path name, but to no avail.

File myFile = new File (uri.getPath());
//returns: /tree/1AF6-3708:test

treeUri.getPath();
//returns: /tree/1AF6-3708:test/

pickedDir.getName()
//returns: test

pickedDir.getParentFile()
//returns: null

Basically, I need to turn /tree/1AF6-3708:into /storage/emulated/0/or everything that each device causes a storage location in it. All other available options return /tree/1AF6-37u08:.

There are two reasons why I want to do this.

1) , . , , , , , . , , :

Device storage/Android/data/com.app.name/

2) 5.0 / , , -, . / , .

, , Mediastore, . - -, . . .

+4
3

( SD-)

Uri treeUri = data.getData();
String path = FileUtil.getFullPathFromTreeUri(treeUri,this); 

FileUtil -

public final class FileUtil {
    static String TAG="TAG";
    private static final String PRIMARY_VOLUME_NAME = "primary";

    @Nullable
    public static String getFullPathFromTreeUri(@Nullable final Uri treeUri, Context con) {
        if (treeUri == null) return null;
        String volumePath = getVolumePath(getVolumeIdFromTreeUri(treeUri),con);
        if (volumePath == null) return File.separator;
        if (volumePath.endsWith(File.separator))
            volumePath = volumePath.substring(0, volumePath.length() - 1);

        String documentPath = getDocumentPathFromTreeUri(treeUri);
        if (documentPath.endsWith(File.separator))
            documentPath = documentPath.substring(0, documentPath.length() - 1);

        if (documentPath.length() > 0) {
            if (documentPath.startsWith(File.separator))
                return volumePath + documentPath;
            else
                return volumePath + File.separator + documentPath;
        }
        else return volumePath;
    }


    @SuppressLint("ObsoleteSdkInt")
    private static String getVolumePath(final String volumeId, Context context) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return null;
        try {
            StorageManager mStorageManager =
                    (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
            Class<?> storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
            Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");
            Method getUuid = storageVolumeClazz.getMethod("getUuid");
            Method getPath = storageVolumeClazz.getMethod("getPath");
            Method isPrimary = storageVolumeClazz.getMethod("isPrimary");
            Object result = getVolumeList.invoke(mStorageManager);

            final int length = Array.getLength(result);
            for (int i = 0; i < length; i++) {
                Object storageVolumeElement = Array.get(result, i);
                String uuid = (String) getUuid.invoke(storageVolumeElement);
                Boolean primary = (Boolean) isPrimary.invoke(storageVolumeElement);

                // primary volume?
                if (primary && PRIMARY_VOLUME_NAME.equals(volumeId))
                    return (String) getPath.invoke(storageVolumeElement);

                // other volumes?
                if (uuid != null && uuid.equals(volumeId))
                    return (String) getPath.invoke(storageVolumeElement);
            }
            // not found.
            return null;
        } catch (Exception ex) {
            return null;
        }
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private static String getVolumeIdFromTreeUri(final Uri treeUri) {
        final String docId = DocumentsContract.getTreeDocumentId(treeUri);
        final String[] split = docId.split(":");
        if (split.length > 0) return split[0];
        else return null;
    }


    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private static String getDocumentPathFromTreeUri(final Uri treeUri) {
        final String docId = DocumentsContract.getTreeDocumentId(treeUri);
        final String[] split = docId.split(":");
        if ((split.length >= 2) && (split[1] != null)) return split[1];
        else return File.separator;
    }
}
+13

, .

, , , . , , , .

, , , , .

API- , , /, Framework , . , ACTION_OPEN_DOCUMENT_TREE.

5.0 /

, . .

+3

SAF UI . , , . ,

    DocumentFile saveDir = null;
    saveDir = DocumentFile.fromFile(Environment.getExternalStorageDirectory());
    String uriString = saveDir.getUri().toString();

    List<UriPermission> perms = getContentResolver().getPersistedUriPermissions();
    for (UriPermission p : perms) {
        if (p.getUri().toString().equals(uriString) && p.isWritePermission()) {
            canWrite = true;
            break;
        }
    }
    // Permitted to create a direct child of parent directory
    DocumentFile newDir = null;
    if (canWrite) {
         newDir = saveDir.createDirectory("MyFolder");
    }

    if (newDir != null && newDir.exists()) {
        return newDir;
    }

. MyFolder/MySubFolder, .

You can check if this directory has write permission, as far as I can see on 3 devices, it returns true if it was created using DocumentFileinstead of a class File. This is an easy way to create and grant write permission for Android> = 5.0 without usingACTION_OPEN_DOCUMENT_TREE

0
source

Source: https://habr.com/ru/post/1625350/


All Articles