48

I'm unable to create directory in android 10. It's working on devices till android Oreo.

I tried two ways for creating folders.

Using File.mkdir():

   File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pastebin");
                    if (!f.isFile()) {
                        if (!(f.isDirectory())) {
                               success =  f.mkdir();
                        }

Here, the variable success is always false which means the directory isn't created.

Using Files.createDirectory():

   File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pastebin");
                    if (!f.isFile()) {
                        if (!(f.isDirectory())) {
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                                try {
                                    Files.createDirectory(Paths.get(f.getAbsolutePath()));
                                } catch (IOException e) {
                                    e.printStackTrace();
                                    Toast.makeText(getApplicationContext(), R.string.unable_to_download, Toast.LENGTH_LONG).show();
                                }
                            } else {
                                f.mkdir();
                            }
                        }

which causes this exception:

pzy64.pastebinpro W/System.err: java.nio.file.AccessDeniedException: /storage/emulated/0/Pastebin
pzy64.pastebinpro W/System.err:     at sun.nio.fs.UnixFileSystemProvider.createDirectory(UnixFileSystemProvider.java:391)
pzy64.pastebinpro W/System.err:     at java.nio.file.Files.createDirectory(Files.java:674)

I've implemented the run-time permissions and

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

are all set.

pz64_
  • 2,212
  • 2
  • 20
  • 43

7 Answers7

133

As was first disclosed back in March 2019, you no longer have access by default to arbitrary locations on external storage or removable storage on Android 10+. This includes Environment.getExternalStorageDirectory() and other methods on Environment (e.g., getExternalStoragePublicDirectory().

For Android 10 and 11, you can add android:requestLegacyExternalStorage="true" to your <application> element in the manifest. This opts you into the legacy storage model, and your existing external storage code will work.

Otherwise, your choices are:

  • Use methods on Context, such as getExternalFilesDir(), to get at directories on external storage into which your app can write. You do not need any permissions to use those directories on Android 4.4+. However, the data that you store there gets removed when your app is uninstalled.

  • Use the Storage Access Framework, such as ACTION_OPEN_DOCUMENT and ACTION_CREATE_DOCUMENT.

  • If your content is media, you can use MediaStore to place the media in standard media locations.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 1
    are you saying that there is no way to create my own directory on Android Q? – Xihuny Oct 24 '19 at 21:30
  • 2
    @Xihuny: You are welcome to create subdirectories of `getExternalFilesDir()` and similar locations supplied by `Context`. You cannot create subdirectories off of the roots of external or removable storage directly, using filesystem APIs. – CommonsWare Oct 24 '19 at 22:54
  • 3
    I don't want to do that because the files will be removed when user uninstall the app. – Xihuny Oct 25 '19 at 09:17
  • 2
    @Xihuny: Then use the Storage Access Framework and allow the user to choose where on the user's device you put the user's content. – CommonsWare Oct 25 '19 at 10:51
  • 1
    I tried, but I was not able to create my own directory. Is there a way to create my own custom named directory using SAF? – Xihuny Oct 25 '19 at 14:30
  • 3
    @Xihuny: You can use `ACTION_OPEN_DOCUMENT_TREE` to allow the user to choose a document tree. From there, use `DocumentFile.fromTreeUri()` to get a `DocumentFile` for that document tree. You can then create children (documents and trees) in that tree, with whatever names you want. Whether it is a "directory" depends on what the user chooses as the base document tree -- there is no requirement that they choose something on the filesystem. – CommonsWare Oct 25 '19 at 14:55
  • 1
    So, the user has to select a directory and ```Allow Access``` to that directory before the app can create any other directory inside? – Xihuny Oct 25 '19 at 18:42
  • 1
    @Xihuny: Correct. – CommonsWare Oct 25 '19 at 18:42
  • 1
    Is there any way to open ```Intent``` to specific directory? For example, I want to open the ```Intent``` in Pictures folder. – Xihuny Oct 25 '19 at 18:59
  • 1
    @Xihuny: "Is there any way to open Intent to specific directory?" -- if you mean `ACTION_OPEN_DOCUMENT_TREE`, you can use `EXTRA_INITIAL_URI`, but that has to be a `Uri` that you previously received from SAF. – CommonsWare Oct 25 '19 at 19:26
  • I updated my device to Android 10 and noticed this issue now. Till Pie, it is able to create a folder in root sdcard(/sdcard/0/ or Internal Shred Storage) where the user download stuffs thru my app which need not to be deleted when the app is uninstalled. I'll try to fix this this, if i am able to do this, i'll write an answer ;) – chankruze Dec 24 '19 at 14:32
  • @chankruze are you able to solve this issue if yes then please do share. Thanks in advance. – Chitrang Mar 04 '20 at 18:34
  • @Xihuny In Android 11 we cannot get access to Downloads folder using `ACTION_OPEN_DOCUMENT_TREE` and I want to put all my files in a directory like Downloads/MyDirectory. What should I do? Is letting my user create MyDirectory himself the only option? – Md Azharuddin Oct 13 '20 at 07:35
  • Great Explanation! Worked for me.. just by adding a line inside tag of Android manifest file.. android:requestLegacyExternalStorage="true". I am creating folder with code lines.. String path = Environment.getExternalStorageDirectory().toString() + File.separator + "Test Folder"; File file = new File(path); if (!file.exists()) file.mkdirs(); – Moeed Ahmed Apr 15 '21 at 18:50
20

For Android 10, you can add

android:requestLegacyExternalStorage="true"

to your element in the manifest. This opts you into the legacy storage model, and your existing external storage code will work. This fix will not work on Android R and higher though, so this is only a short-term fix.

pz64_
  • 2,212
  • 2
  • 20
  • 43
Sujit Jamdade
  • 211
  • 2
  • 4
11

There are more restrictions in Android API 30

you can only write in your app-specific files

 File dir_ = new File(context.getFilesDir(), "YOUR_DIR");
 dir_.mkdirs();

or in the external storage of your app Android/data

File dir_ = new File(myContext.getExternalFilesDir("FolderName"),"YOUR_DIR");

UPDATE

this answer provided another solution https://stackoverflow.com/a/65744517/8195076

UPDATE

another way is to grant this permission in manifest

<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

like this answer https://stackoverflow.com/a/66968986/8195076

Wowo Ot
  • 1,362
  • 13
  • 21
5

This works for me and I think it's functional on Android 10>

ContentResolver resolver = getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/Folder Example");
String path = String.valueOf(resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues));
File folder = new File(path);
boolean isCreada = folder.exists();
if(!isCreada) {
    folder.mkdirs();
}
Teocci
  • 7,189
  • 1
  • 50
  • 48
JP711
  • 533
  • 6
  • 15
  • You are querying a `File`, so you will have to add `android:requestLegacyExternalStorage="true"` when targeting Android 10>. In that case, you might as well keep using `getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)`. – HB. May 09 '20 at 10:15
  • 1
    getExternalStoragePublicDirectory is Deprecated in API level 29 – JP711 May 09 '20 at 15:44
  • 1
    Yes, and? As the documentation states `When an app targets Build.VERSION_CODES.Q, the path returned from this method is no longer directly accessible`, so if you have `android:requestLegacyExternalStorage="true"` in your manifest, you can still use it. – HB. May 09 '20 at 15:52
  • "Yes, and?" and, as the documentation states `Apps can continue to access content stored on shared/external storage by migrating to alternatives such as Context#getExternalFilesDir(String), MediaStore, or Intent#ACTION_OPEN_DOCUMENT` I am new to this but then my question would be, is my proposal wrong or why the negative vote? I don't know very well how this works, is it better then to continue with `getExternalStoragePublicDirectory`? – JP711 May 09 '20 at 16:17
  • 2
    Firstly, it wasn't me who downvoted. To answer your question, you are querying a file, which is not allowed on Android 10>, unless you request legacy storage. To do it correctly, you should get the `Uri`, like this `Uri mUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);` then use that `Uri` directly instead of passing it to a `File` object. – HB. May 09 '20 at 16:37
  • 1
    An apology, this is just how I create the Uri `resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);` As I said I am new programming for android but it seems to me that if it is necessary to passing to File to create the folder, sorry bad english – JP711 May 09 '20 at 16:56
  • 4
    You do not have to create a folder. When you write to the `Uri` the folder gets created automatically. – HB. May 09 '20 at 17:12
  • @HB. But what if we only want to create the folder? – cmak Oct 20 '22 at 17:40
5

You can use public directory to save files in Android 11 like this:

dir = new File(Environment.getExternalStoragePublicDirectory(DIRECTORY_DOCUMENTS).getPath()
    + "/foldername");

if (!dir.exists()) {
     dir.mkdir();
     Toast.makeText(getApplicationContext(), "not exist", Toast.LENGTH_SHORT).show();
}
Gass
  • 7,536
  • 3
  • 37
  • 41
Hesam Kh
  • 111
  • 2
  • 1
  • This is working in Android 12 but not in Android 9 and 10 devices. getExternalStoragePublicDirectory(DIRECTORY_DOCUMENTS) is not available in those so replaced that with Context.getExternalFilesDir(DIRECTORY_DOCUMENTS) but no folder was created. Documents folder is not seen in Android 9 and 10 – tbfp Apr 06 '22 at 12:45
  • Environment.getExternalStoragePublicDirectory is deprecated on new versions, use `MediaStore` queries and `Environment.DIRECTORY_DOCUMENTS` (or the directory you require) instead – cmak Oct 20 '22 at 19:32
4

Since Q beta 4 it's possible to opt-out of that feature by:

targeting api 28 (or lower) using requestLegacyExternalStorage manifest attribute:

<manifest ... >
  <!-- This attribute is "false" by default on apps targeting Android Q. -->
  <application android:requestLegacyExternalStorage="true" ... >
    ...
  </application>
</manifest>
IntelliJ Amiya
  • 74,896
  • 15
  • 165
  • 198
Amit_android
  • 498
  • 2
  • 5
  • 20
0

only use

android:requestLegacyExternalStorage="true"

in manifests

David Buck
  • 3,752
  • 35
  • 31
  • 35
  • 2
    this is only for android version < android 11. Not applicable for android version greater then 10. – user6159419 Oct 19 '20 at 12:33
  • @user6159419 Yes and on Android 11>, `File` path access is once again allowed. So, `android:requestLegacyExternalStorage="true"` is to ensure it works on Android 10. – HB. Jan 10 '21 at 09:10