Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storage Access Framework, takePersistableUriPermission

In my application user is able to select the downloads directory. If he selects external removable SD card (not an emulated sd card!, but a memory, which is a real physicel microSD card for example), starting from Android 4.4 I am only able to write to it using SAF (Storage Access Framework).

I've figured out how to create and write a single file using SAF:

public void newFile() {
    Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);

    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("text/plain");
    intent.putExtra(Intent.EXTRA_TITLE, "newfile.txt");

    startActivityForResult(intent, CREATE_REQUEST_CODE);
}

public void saveFile() {
    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("text/plain");

    startActivityForResult(intent, SAVE_REQUEST_CODE);
}

And here is my onActivityResult, where I actually write to file:

public void onActivityResult(int requestCode, int resultCode,
                             Intent resultData) {
    Uri currentUri = null;

    if (resultCode == Activity.RESULT_OK) {
        if (requestCode == CREATE_REQUEST_CODE) {
            if (resultData != null) {
                Log.d(TAG, "CREATE_REQUEST_CODE resultData = " + resultData);
            }
        } else if (requestCode == SAVE_REQUEST_CODE) {

            if (resultData != null) {
                currentUri = resultData.getData();
                getContentResolver().takePersistableUriPermission(currentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
                        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                writeFileContent(currentUri);
                Log.d(TAG, "SAVE_REQUEST_CODE currentUri = " + currentUri);
            }
        }
    }
}

And also writeFileContent:

private void writeFileContent(Uri uri) {
    try {
        ParcelFileDescriptor pfd =
                this.getContentResolver().
                        openFileDescriptor(uri, "w");

        FileOutputStream fileOutputStream =
                new FileOutputStream(pfd.getFileDescriptor());

        String textContent = "some text";

        fileOutputStream.write(textContent.getBytes());

        fileOutputStream.close();
        pfd.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

And finally my question:

How do I create other files, and write them after I called getContentResolver().takePersistableUriPermission without a prompt to select a directory in future?

If I'm right, then getContentResolver().takePersistableUriPermission shoudl allow me to do tha

like image 754
Vladyslav Matviienko Avatar asked Sep 16 '25 08:09

Vladyslav Matviienko


1 Answers

Thanks to @earthw0rmjim answer, and googling, I figgured out a complete solution:

public void saveFile() {
    List<UriPermission> permissions = getContentResolver().getPersistedUriPermissions();
    if (permissions != null && permissions.size() > 0) {
        DocumentFile pickedDir = DocumentFile.fromTreeUri(this, permissions.get(0).getUri());
        DocumentFile file = pickedDir.createFile("text/plain", "try2.txt");
        writeFileContent(file.getUri());
    } else {
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("text/plain");

        startActivityForResult(intent, SAVE_REQUEST_CODE);
    }
}

So firstly, if we don't have PersistedUriPermissions, it will request such permissions. This way here is how onActivityResult looks like

public void onActivityResult(int requestCode, int resultCode,
                             Intent resultData) {
    Uri currentUri = null;

    if (resultCode == Activity.RESULT_OK) {
        if (requestCode == SELECT_DIR_REQUEST_CODE) {
            if (resultData != null) {
                Uri treeUri=resultData.getData();
                Log.d(TAG, "SELECT_DIR_REQUEST_CODE resultData = " + resultData);
                getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
                        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
                DocumentFile file = pickedDir.createFile("text/plain", "try2.txt");
                writeFileContent(file.getUri());
            }
        }
    }
}

And the writeFileContent looks same as in the question

private void writeFileContent(Uri uri) {
    try {
        ParcelFileDescriptor pfd =
                this.getContentResolver().
                        openFileDescriptor(uri, "w");

        FileOutputStream fileOutputStream =
                new FileOutputStream(pfd.getFileDescriptor());

        String textContent = "some text";

        fileOutputStream.write(textContent.getBytes());

        fileOutputStream.close();
        pfd.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
like image 155
Vladyslav Matviienko Avatar answered Sep 19 '25 14:09

Vladyslav Matviienko