'How to gain access to a specific folder and write a file into it using Scoped Storage
My app has a feature that exports GPS data in txt format into a shared folder (now accessed with getExternalStorageDirectory
), and I have to switch it to Scoped Storage (API 30).
(As information, the app is the open source GPS Logger for Android.)
In the future I would let the users choose the folder to be used for the exportation, using:
public void openDirectory(Uri uriToLoad) {
// Choose a directory using the system's file picker.
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, your-request-code);
}
public void onActivityResult(int requestCode, int resultCode,
Intent resultData) {
if (requestCode == your-request-code && resultCode == Activity.RESULT_OK) {
// The result data contains a URI for the directory that the user selected.
Uri uri = null;
if (resultData != null) {
uri = resultData.getData();
// Perform operations on the document using its URI.
}
}
}
This way my app will gain access to the selected folder.
How can I create a text file into that folder and write data using a BufferedWriter
?
I know that maybe I can use something like:
...
Uri fileUri = // Something related to the previous uri, but I cannot find the solution
OutputStream outputStream = getContentResolver().openOutputStream(fileUri, "rw");
txtBW = new BufferedWriter(new OutputStreamWriter(outputStream));
...
but I found nothing that works.
Solution 1:[1]
DocumentFile
is Google's somewhat clunky solution for navigating through document trees. The recipe for what you want should be:
- Take the
Uri
that you got for your tree and wrap it in aDocumentFile
usingDocumentFile.fromTreeUri()
- Call
createFile()
on thatDocumentFile
, supplying a filename or other display name, which will give you aDocumentFile
representing that document - Call
getUri()
on the document'sDocumentFile
to get aUri
representing the document - Use
openOutputStream()
on aContentResolver
to write your desired content to thatUri
Note that if you need long-term access to this tree, be sure to call takePersistableUriPermission()
on a ContentResolver
, passing in the Uri
for the document tree. That should give you access to the tree and all documents inside of it.
Solution 2:[2]
1-You can create a target path like this (I'm targetting the "Android/media" folder)
private const val ROOT_FOLDER = "primary:"
private const val ANDROID_MEDIA = "${ROOT_FOLDER}Android/media"
private const val EXTERNAL_STORAGE_PROVIDER_AUTHORITY = "com.android.externalstorage.documents"
2- Create URI and intent object
val storageManager = getSystemService(Context.STORAGE_SERVICE) as StorageManager
val uri =DocumentsContract.buildDocumentUri(EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
ANDROID_MEDIA)
val intent = storageManager.primaryStorageVolume.createOpenDocumentTreeIntent()
.putExtra(DocumentsContract.EXTRA_INITIAL_URI,uri)
3- Register activity for results
for example
private val openDocumentTreeLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_OK) {
val data: Uri = it.data?.data!!
contentResolver.takePersistableUriPermission(
data,
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)}
finally launch the Activity for results
openDocumentTreeLauncher.launch(intent)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | CommonsWare |
Solution 2 | Rufan Khokhar |