I'm looking forward to build a File Explorer app but I'm shocked with what I found on I do need full read/write permission and access to everything.
So as they state here:
Declare the MANAGE_EXTERNAL_STORAGE permission in the manifest.
Use the ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION intent action to direct users to a system settings page where they can enable the following option for your app
To determine whether your app has been granted the MANAGE_EXTERNAL_STORAGE permission, call Environment.isExternalStorageManager().
Now I can access to the root folder "/storage/emulated/0/" via Environment.getExternalStoragePublicDirectory(path)
and then file.listFiles()
But when I want to access to Downloads folder I can't, I've looked at SAF but I'd have to use like ACTIONS and I just want to explore through folders, then I looked at MediaStore but there's not a clear example of how I could use it here since I'm trying to get the files but cursor.moveToNext()
or cursor.moveToFirst()
returns false
Here's the code I've used
val projectionDownloads = arrayOf(
MediaStore.Downloads._ID,
MediaStore.Downloads.DISPLAY_NAME,
)
val selectionDownloads = ""
val selectionArgsDownloads = emptyArray<String>()
val sortOrderDownloads = "${MediaStore.Downloads.DISPLAY_NAME} ASC"
context.applicationContext.contentResolver.query(
MediaStore.Downloads.EXTERNAL_CONTENT_URI,
projectionDownloads,
selectionDownloads,
selectionArgsDownloads,
sortOrderDownloads
)?.use { cursor ->
Log.i("SeeMedia", "we got cursor! $cursor")
val idColumn = cursor.getColumnIndex(MediaStore.Images.ImageColumns._ID)
val nameColumn = cursor.getColumnIndex(MediaStore.Files.FileColumns.DISPLAY_NAME)
while (cursor.moveToNext()) { //Here return false
Log.i("SeeMedia", "Move to next!")
val id = cursor.getLong(idColumn)
val name = cursor.getString(nameColumn)
Log.i("SeeMedia", "ID = $id AND NAME= $name")
}
}
My app contains the 2 permissions:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
There are 3 questions that I'm wondering after this:
Question 1: Do I need other permissions for the purpose of reading files?
Question 2: What am I missing on this MediaStore query? Why it doesn't provide me the files of download?
Question 3: What if I want to query on other unknown files/directories, for example a folder inside Downloads which there is another folder and so on? "Downloads/Folder1/Folder2" I guess I should use MediaStore.Files, right? So how is the URI for accessing those files?
EDIT 1: SDK 29 = Android 10
SDK 30 = Android 11
What I want is to query are just files, no image, no audio just files whatever it comes, so for example the path "/" which is root will return a list of Directories: -Ringtones -Music -DCIM -Download -Documents
That's good it works with the Environment.getExternalStorageDirectory and the permission MANAGE_EXTERNAL_STORAGE.
But then I want to access to one of those directories and it's empty, for example "DCIM" (which I know it contains some pictures) and <= 28 it retrieves me the pictures with:
But in >= 29 it returns an empty, how could I get access to those files with the classic methods or MediaStore?
If I'm wrong in something just tell me because right now my head is filled with a lot of mixed stuff since I've watched a lot of videos and documentation and questions and I'm just trying to understand some critical points.
Here's a simple code that I finally could query the root "/" with MediaStore in case you want to see it, but don't know how to query other paths and retrieve me their files:
val projection = arrayOf(
MediaStore.Files.FileColumns.DISPLAY_NAME
)
context.applicationContext.contentResolver.query(
MediaStore.Files.getContentUri("external"),
projection,
null,
null,
null
)?.use { cursor ->
Log.i("SeeMedia", "we got cursor! $cursor")
val nameColumn =
cursor.getColumnIndex(MediaStore.Files.FileColumns.DISPLAY_NAME)
while(cursor.moveToNext()){
Log.i("SeeMedia", "Move to next!")
val name = cursor.getString(nameColumn)
Log.i("SeeMedia", "Name = $name")
}
}
Answering some of your questions:
Do I need other permissions for the purpose of reading files?
No, as it's stated here, you've got all the possible file-related permissions.
What am I missing on this MediaStore query? Why it doesn't provide me the files of download?
Download is a kind of special case. Here at the very bottom of the section it says
In particular, if your app wants to access a file within the MediaStore.Downloads collection that your app didn't create, you must use the Storage Access Framework.
And even using SAF you will not be able to access all files in Download directory. So you can access a single file picked by user, but you cannot list the content of the directory.
Generally, as it's stated here, having the MANAGE_EXTERNAL_STORAGE
permission granted, you can access all non-restricted files using both MediaStore
and file paths. Both ways should give the same result.