M. Maximovich
M. Maximovich

Reputation: 209

Can't create a directory using DocumentFile.createDirectory() on Android 7

I have granted permission to write external and removable storages. But I still can't write everywhere on the sd card on Android 7.

Intent intent = storageVolume.createAccessIntent(null);
startActivityForResult(intent, 989);

;

RxPermissions.getInstance(getActivity())
                .request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                .subscribe(granted -> {
                    if (!granted) return;
                    showAlternativeDirectoryChooser();//success
                }, throwable -> {
                });

Here is the code of folder creation:

DocumentFile documentFile = DocumentFile.fromFile(dir);
DocumentFile test = documentFile.createDirectory("test_folder");

test == null

Upvotes: 3

Views: 2136

Answers (2)

nnyerges
nnyerges

Reputation: 593

You cannot use :

DocumentFile documentFile = DocumentFile.fromFile(dir);

Becouse its not a SAF valid Uri.

If you dont want to use ACTION_OPEN_DOCUMENT_TREE or ACTION_OPEN_DOCUMENT to get an Uri, you can convert FILE to Uri (SAF) using the following method valid from API19(Android4.4-Kitkat) to API28(Android8-Oreo). The returned Uri's are the same that return the dialog and its valid for API 28 security restrictions (SAF permissions), if you want to access external removable storage outside your application...

    /**
 * Ing.N.Nyerges 2019 V2.0
 *
 * Storage Access Framework(SAF) Uri's creator from File (java.IO),
 * for removable external storages
 *
 * @param context Application Context
 * @param file File path + file name
 * @return Uri[]:
 *   uri[0] = SAF TREE Uri
 *   uri[1] = SAF DOCUMENT Uri
 */
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static Uri[] getSafUris (Context context, File file) {

    Uri[] uri = new Uri[2];
    String scheme = "content";
    String authority = "com.android.externalstorage.documents";

    // Separate each element of the File path
    // File format: "/storage/XXXX-XXXX/sub-folder1/sub-folder2..../filename"
    // (XXXX-XXXX is external removable number
    String[] ele = file.getPath().split(File.separator);
    //  ele[0] = not used (empty)
    //  ele[1] = not used (storage name)
    //  ele[2] = storage number
    //  ele[3 to (n-1)] = folders
    //  ele[n] = file name

    // Construct folders strings using SAF format
    StringBuilder folders = new StringBuilder();
    if (ele.length > 4) {
        folders.append(ele[3]);
        for (int i = 4; i < ele.length - 1; ++i) folders.append("%2F").append(ele[i]);
    }

    String common = ele[2] + "%3A" + folders.toString();

    // Construct TREE Uri
    Uri.Builder builder = new Uri.Builder();
    builder.scheme(scheme);
    builder.authority(authority);
    builder.encodedPath("/tree/" + common);
    uri[0] = builder.build();

    // Construct DOCUMENT Uri
    builder = new Uri.Builder();
    builder.scheme(scheme);
    builder.authority(authority);
    if (ele.length > 4) common = common + "%2F";
    builder.encodedPath("/document/" + common + file.getName());
    uri[1] = builder.build();

    return uri;
}

Then you can call the permissions using something like this:

    context.grantUriPermission(context.getPackageName(), uri, Intent
            .FLAG_GRANT_READ_URI_PERMISSION | Intent
            .FLAG_GRANT_WRITE_URI_PERMISSION);
    context.getContentResolver().takePersistableUriPermission(uri, Intent
            .FLAG_GRANT_READ_URI_PERMISSION | Intent
            .FLAG_GRANT_WRITE_URI_PERMISSION);

Upvotes: 1

j__m
j__m

Reputation: 9645

Android delivers the Uri you need to use in onActivityResult. That Uri is not necessarily related, at all, to the path you're trying to access. You cannot guess it. You have to actually use the Uri you're given.

If you call DocumentFile.fromFile or Uri.parse, then you are wrong.

Upvotes: 0

Related Questions