I want to write own lite file browser.
File API does not work for external storage now.
The release also offers improvements to scoped storage, which makes it easier for developers to migrate to using this storage model.
I don't understand how use scoped storage for access to /sdcard.
If you're looking for a file picker experience, Storage Access Framework is your only option now. Below code let's you pick up multiple files. If you want directory level selection, you can use ACTION_OPEN_DOCUMENT_TREE
intent.
private fun openStorageAccess() {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
type = "*/*"
addCategory(Intent.CATEGORY_OPENABLE)
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
}
startActivityForResult(intent, openDirectoryAccessCode)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == openDirectoryAccessCode && resultCode == Activity.RESULT_OK) {
val fileUris = data?.clipData ?: data?.data
}
}
Additionally, you can request a special all files access to MediaStore.Files
from Google Play Console. More on Android 11 storage changes.
Edit:
If you want to implement a file browser like experience in Android 29+, here is a proposed idea that I personally haven't tried out but should work. It won't be an optimal experience but would closely resemble a file browser.
requestLegacyExternalStorage="true"
if API == 29).MANAGE_EXTERNAL_STORAGE
flag in ManifestACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION
intent.MediaStore.Files
along with RELATIVE_PATH
DCIM/Vacation/IMG_1234.jpg
.I recently wrote an Android file/folder chooser library in Java that targets API 29+ (e.g., the Android OS 10/11 changes). It is called the Android File Picker Light. The idea is to have a barebones file/directory selector that displays minimalistic information about the local file system without pulling in too much multimedia processing to do things like visually display media files and image thumbnails. Some code that I used to get at the initial poster's question of how to enumerate files on the local disk (or SD card) via traditional Unix-V style paths is seen here (for example, and elsewhere there). It still works well on Android OS 10 (API 29) active as of December, 2020.
The links provided above should get you started. The source to my library project is available freely under the GPL. There is also some Google-sanctioned official source code to document the implementation of a custom file storage provider on their GitHub repos. One thing to keep in mind is that the Android API is effectively trying to generalize the interface to a "file content" so that we have a common mechanism for online indexing (like a DropBox link) and the local file system. This is well intentioned enough until one sees how much more complicated it becomes to perform simple, routine filesystem operations from the local disk or integrated SD card. Eventually us avid developers may have to be led en mass to petition the Android official documentation writers for better pointers to handle these formerly common cases of file system access :).
With this point in mind, I want to iterate on a couple of distinguishing issues to the new scoped storage changes that others may run into writing their own custom code. I hope this saves developers some future stumbling around with what seem to be common issues (to me) not adequately addressed in some of the under documented parts of the Android developer docs about scoped storage. It is possible that as Android 11 starts to occupy more live devices in the wild these problems I had will get integrated into the office docs. For now, I suggest the following few reference points:
MatrixCursor
type column data by creating a subclass of DocumentsProvider
. This is all to say that the new changes will return legit System-V-Unix style traditional paths (like /storage/0/self/primary/Pictures/Screenshots
), but doesn't seem to like to honor them as a way to refer to these files explicitly outside of the special file provider inheritance scheme (sigh.). The only way I found to extract POSIX style permissions from a valid Java File
instance enumerated from a hardcoded path is referenced in my library code seen inline here. Your milage may vary.DocumentsProvider
subclass I had to create in my library is capable of returning handles to the Unix-type paths for Java files (for local file system cases), or otherwise to Uri
objects for abstract file type references that do not conform to this specification. In general, and so moving forward with the new API requirements, the subclassed DocumentsProvider
is responsible for servicing the actual file data (as a String
or Byte[]
array typically), and currently at the same time as when users can enumerate these files to select by their familiar path names. Needless to say, this complicates the usage pattern for developers that want the user to select the file by its name a long while before the file contents are ever read to process by the program.AndroidManifest.xml
options that can be used with current Android 10 devices to bypass the scoped storage requirements. Read about them in my compiled links listed here (library Markdown reference). These legacy behavior enablers include the android:requestLegacyExternalStorage
and android:preserveLegacyExternalStorage
application
tag options. Notice that this type of compatibility for pre-11 OS devices has the strange counterintuitive downside of requiring a new MinSdkVersion
setting in the local application build.gradle
file (with Android Studio).appCtx.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
may return a NULL
Java File
handler, but a hardcoded path like new File("/storage/self/primary/Documents")
can still be made to work if we configure the XML file path names correctly for use with the AndroidManifest
file, e.g.: <provider
android:name="com.maxieds.androidfilepickerlightlibrary.BasicFileProvider"
android:authorities="com.maxieds.androidfilepickerlightlibrary.FileChooserActivity"
android:exported="true"
android:enabled="true"
android:grantUriPermissions="true"
android:permission="android.permission.MANAGE_DOCUMENTS"
android:initOrder="100"
>
<intent-filter>
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
</intent-filter>
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider_paths_base" />
</provider>
I apologize for the long winded commentary I just gave. I hope this saves people some time in the future. -- M
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With