android-filestorage-access-frameworkandroid-storage

Is there a way to save a text file to a public directory without any user interaction targeting Android API 30?


File fFoo = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "foo.txt");
BufferedWriter bos = new BufferedWriter(new FileWriter(fFoo));

The above code throws:

java.io.FileNotFoundException: /storage/emulated/0/Download/foo.txt: open failed: EACCES (Permission denied)

In build.gradle:

compileSdkVersion 31
targetSdkVersion 30

Could anyone offer a tip?


Solution

  • For API 29+ you could use MediaStore API, here is an example:

    ContentResolver contentResolver = context.getContentResolver();
    
    ContentValues values = new ContentValues();
    values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
    values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
    values.put(MediaStore.MediaColumns.IS_PENDING, 1);
    
    Uri mediaUri = contentResolver.insert(
            MediaStore.Downloads.EXTERNAL_CONTENT_URI,
            values);
    
    try (OutputStream out = contentResolver.openOutputStream(mediaUri)){
        // Write your data here
        out.write(data);
    }
    
    values = new ContentValues();
    values.put(MediaStore.MediaColumns.IS_PENDING, 0);
    
    contentResolver.update(mediaUri, values, null, null);
    

    To place a file into a subfolder, we should add one more line before calling insert()

    values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS + "/subfolder");
    

    More info: https://developer.android.com/training/data-storage/shared/media#add-item