How to save files with File API to a user-selected location in Android 11?

Viewed 6445

I am very confused with Scoped Storage and Storage Access Framework (SAF) and all restrictions.. I need to use File API, not Uri, so:
Android API level <= 29 (Android 10) save to /storage/emulated/0 works (with requestLegacyExternalStorage).
Android API level = 30 (Android 11) save to /storage/emulated/0 does not work (IOException: Operation not permitted).

Environment.getExternalStorageDirectory() is deprecated. OK, so getExternalFilesDirs() In Android 11:

ctx.getExternalFilesDirs(): /storage/emulated/0/Android/data/<package name>/files //External storage in internal memory
ctx.getExternalFilesDirs(): /storage/16F4-3A1C/Android/data/<package name>/files //SDcard

works, because it's app's storage. But users want to have app's folder in root of external storage /storage/emulated/0/MySpecificFolder or sdcard /storage/16F4-3A1C/MySpecificFolder. I am working with File API which should be functional again (unlike Android10).

How can I write to user specific directory, for example to /storage/emulated/0/MySpecificFolder?

I tried to use:

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

which open File manager. User creates new directory (because root can't use): /storage/emulated/0/MySpecificFolder. Next I am trying create a new file via:

File nomedia = new File("/storage/emulated/0/MySpecificFolder", ".nomedia");
if (!nomedia.exists()) {
    nomedia.createNewFile();
}

but it's not working IOException: Operation not permitted. There is probably problem with write permission.

This line works:

DocumentFile newFile = pickedDir.createFile("text/plain", "My Novel");

which works with Uri. Why is it not possible to use File API? When I call createFile() which uses Uri, that's working, but when I call createNewFile() which uses File API, that's not working. So user can select own directory, but only when app working with Uri?

How to get path (for later use with File API) from SAF, not only Uri.

// Get Uri from Storage Access Framework.
Uri treeUri = data.getData();
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
Log.i(TAG, "Tree uri: "+treeUri.getPath());  //returns /tree/primary:My
Log.i(TAG, "Picked dir: "+pickedDir.getUri().getPath()); //returns /tree/primary:My/document/primary:My

I need use File API, because app. creates video+photo+data files which need to be together.

Question: Is it possible for user to choose own path + create folder (via SAF probably) and return File (file descriptor) of new created folder by user to app?

1 Answers

On Android 11 every app can just write to the public directories on external storage using the old File classes.

Dont let the user choose a location as then for further actions you need yo use SAF.

If you want to let the user choose between Documents, Download, Alarms, DCIM, Pictures and so on use a small list with an Alert Builder.

Related