Android 11 Action_open_document_tree: Set Initial Uri To The Documents Folder
using the Scoped Storage model in Android 11 I want to give the user the ability to choose a folder, starting in the documents folder: val intent = Intent(Intent.ACTION_O
Solution 1:
We will manupilate INITIAL_URI
obtained from StorageManager..getPrimaryStorageVolume().createOpenDocumentTreeIntent()
.
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q)
{
StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
Intent intent = sm.getPrimaryStorageVolume().createOpenDocumentTreeIntent();
//String startDir = "Android";
//String startDir = "Download"; // Not choosable on an Android 11 device
//String startDir = "DCIM";
//String startDir = "DCIM/Camera"; // replace "/", "%2F"
//String startDir = "DCIM%2FCamera";
String startDir = "Documents";
Uri uri = intent.getParcelableExtra("android.provider.extra.INITIAL_URI");
String scheme = uri.toString();
Log.d(TAG, "INITIAL_URI scheme: " + scheme);
scheme = scheme.replace("/root/", "/document/");
scheme += "%3A" + startDir;
uri = Uri.parse(scheme);
intent.putExtra("android.provider.extra.INITIAL_URI", uri);
Log.d(TAG, "uri: " + uri.toString());
((Activity) context).startActivityForResult(intent, REQUEST_ACTION_OPEN_DOCUMENT_TREE);
return;
}
Solution 2:
how can I generate a proper URI of the phone's documents folder?
Tested on :
- Xiaomi M2102J20SI
- Emulator Pixel 4 XL API 30
Function askPermission()
opens the target directory.
@RequiresApi(Build.VERSION_CODES.Q)privatefunaskPermission() {
val storageManager = application.getSystemService(Context.STORAGE_SERVICE) as StorageManager
val intent = storageManager.primaryStorageVolume.createOpenDocumentTreeIntent()
val targetDirectory = "WhatsApp%2FMedia%2F.Statuses"// add your directory to be selected by the uservar uri = intent.getParcelableExtra<Uri>("android.provider.extra.INITIAL_URI") as Uri
var scheme = uri.toString()
scheme = scheme.replace("/root/", "/document/")
scheme += "%3A$targetDirectory"
uri = Uri.parse(scheme)
intent.putExtra("android.provider.extra.INITIAL_URI", uri)
startActivityForResult(intent, REQUEST_CODE)
}
Uri of the file will be returned in onActivityResult()
overridefunonActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK && requestCode == REQUEST_CODE) {
if (data != null) {
data.data?.let { treeUri ->
// treeUri is the Uri of the file// if life long access is required the takePersistableUriPermission() is used
contentResolver.takePersistableUriPermission(
treeUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
readSDK30(treeUri)
}
}
}
}
Function readSDK30()
is used to read files & folders from Uri
privatefunreadSDK30(treeUri: Uri) {
val tree = DocumentFile.fromTreeUri(this, treeUri)!!
thread {
val uriList = arrayListOf<Uri>()
listFiles(tree).forEach { uri ->
// Collect all the Uri from here
}
}
}
Function listFiles()
returns all the files & folders in the given Uri
funlistFiles(folder: DocumentFile): List<Uri> {
returnif (folder.isDirectory) {
folder.listFiles().mapNotNull { file ->
if (file.name != null) file.uri elsenull
}
} else {
emptyList()
}
}
Solution 3:
All the credit goes to blackapps answer! https://stackoverflow.com/a/67554693/2036264
Here is the same code in Kotlin language:
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
val sm = getSystemService(Context.STORAGE_SERVICE) as StorageManager
intent = sm.primaryStorageVolume.createOpenDocumentTreeIntent()
//String startDir = "Android";//String startDir = "Download"; // Not choosable on an Android 11 device//String startDir = "DCIM";//String startDir = "DCIM/Camera"; // replace "/", "%2F"//String startDir = "DCIM%2FCamera";val startDir = "Documents"var uriroot = intent.getParcelableExtra<Uri>("android.provider.extra.INITIAL_URI") // get system root urivar scheme = uriroot.toString()
Log.d("Debug", "INITIAL_URI scheme: $scheme")
scheme = scheme.replace("/root/", "/document/")
scheme += "%3A$startDir"//change uri to Documents folder
uriroot = Uri.parse(scheme)
intent.putExtra("android.provider.extra.INITIAL_URI", uriroot) // give changed uri to Intent
Log.d("Debug", "uri: $uriroot")
startActivityForResult(intent, OPEN_DIRECTORY_REQUEST_CODE);
}
As some commentors mentioned, this code might break and not work in the future, which is true. However, considering Android's past, they will change the storage API anyways every other year.
Post a Comment for "Android 11 Action_open_document_tree: Set Initial Uri To The Documents Folder"