25

After a lot of findings about how to write(and rename) a file in SD Card (android 5 and above), I think the new SAF provided by android will be required to take permission from user to write SD card file.

I have seen in this File Manger Application ES File Explorer that initially it takes read and write permission the following way as shown in pictures.

enter image description here

Picture 2

After selecting sd card, the write permission is granted.

So in the same way I tried to use SAF, but failed in renaming a file. My code:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    rename = (Button) findViewById(R.id.rename);

    startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), 42);
}

@Override
public void onActivityResult(int requestCode,int resultCode,Intent resultData) {
    if (resultCode != RESULT_OK)
        return;
    Uri treeUri = resultData.getData();
    DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
    grantUriPermission(getPackageName(), treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}

public void renameclick(View v) {
    File ff = new File("/storage/sdcard1/try1.jpg");
    try {
        ff.createNewFile();
    } catch (Exception e) {
        Log.d("error", "creating");
        e.printStackTrace();
    }
}

Still after running the code I get EAacces permission denied.

jox
  • 2,218
  • 22
  • 32
Ankesh kumar Jaisansaria
  • 1,563
  • 4
  • 26
  • 44

1 Answers1

31

Letting the user choose the "SD card" or even the "Internal storage" SAF root give your application access to the corresponding storage, but only through the SAF API, not directly via the filesystem. For example you code could be translated into something like :

public void writeFile(DocumentFile pickedDir) {
    try {
        DocumentFile file = pickedDir.createFile("image/jpeg", "try2.jpg");
        OutputStream out = getContentResolver().openOutputStream(file.getUri());
        try {

            // write the image content

        } finally {
            out.close();
        }

    } catch (IOException e) {
        throw new RuntimeException("Something went wrong : " + e.getMessage(), e);
    }
}

In recent version of Android, accessing data outside your application using java.io.File is almost completely deprecated.

bwt
  • 17,292
  • 1
  • 42
  • 60
  • 1
    But then whenever i need to create or rename a file, SAF picker will open – Ankesh kumar Jaisansaria Apr 26 '16 at 13:22
  • 4
    Once you have the tree URI, you can do anything you want with the files and directories it includes. You don't need to ask the user each time if 1) You use `takePersistableUriPermission()` and 2) You store the URI somewhere, so that you can retrieve it on application startup – bwt Apr 26 '16 at 13:24
  • How could we have access to subdirectories of pickedDir while `createFile` only gets `MimeType` and name as the arguments. How could we convert `java.io.file` kind path to a `DocumentFile`? – Eftekhari Jul 26 '16 at 16:15
  • 3
    @Eftekhari you can do something like that: `DocumentFile pickedTree = DocumentFile.fromFile(App.getContext(), uriTree); for (DocumentFile file : pickedTree.listFiles()) { if (file.isDirectory()) file.createFile(mimeType, fileName); }` – Ruslan Berozov Sep 21 '16 at 14:18
  • How to write to a file which is present in some sub directory in SD Card. – Rahulrr2602 Jul 20 '17 at 12:04