I was testing Pixel with 21, 23, 29, 30 API emulators and they would return two paths (first is external built-in sdcard and second is external removable sdcard) when using getExternalFilesDirs(null)
method:
/storage/emulated/0/Android/data/com.*.*/files
/storage/13F6-3510/Android/data/com.*.*/files
But then I tried to use Pixel with 26 API and I only got one path:
/storage/emulated/0/Android/data/com.*.*/files
Then I found another method to get all storages paths which returns something new to me, usually it would start with /storage/
but now it starts with /mnt/media_rw/
:
/storage/emulated/0
/mnt/media_rw/1D13-0D17
Method to get it using StorageManager
:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
val storageVolumes = storageManager.storageVolumes
if (!storageVolumes.isNullOrEmpty()) {
for (storageVolume in storageVolumes) {
val volumePath = getVolumePath(storageVolume) ?: continue
result.add(File(volumePath))
}
}
}
@RequiresApi(Build.VERSION_CODES.N)
private fun getVolumePath(storageVolume: StorageVolume): String? {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
return storageVolume.directory?.absolutePath
try {
val storageVolumeClazz = StorageVolume::class.java
val getPath = storageVolumeClazz.getMethod("getPath")
return getPath.invoke(storageVolume) as String
} catch (e: Exception) {
e.printStackTrace()
}
return null
}
You can see that this method even uses reflection for API < R (30)
So I got this path /mnt/media_rw/1D13-0D17
for Pixel 26 API. I don't understand why there is difference from other APIs.
But this path is not accessible yet, I can't read it. Then I tried to use some popular Files Browser/Explorer apps from Google Play and I found out that they request some permission to get access to such external removable storage:
I've never seen something like this before. How do they do it and why it even exists?
I have real devices with 21, 23, 29, 30 API and none of them need to use such method to access external removable storage, I can just use getExternalFilesDirs(null)
. The same works for Pixel emulators with the same API
So where does /mnt/media_rw/*
come from and how to request permission to access it from my app and why do I even need to grant this permission if for other APIs I don't need to do it?
I can't find any information about it at official Android documentation
So I got this path /mnt/media_rw/1D13-0D17 for Pixel 26 API. I don't understand why there is difference from other APIs. But this path is not accessible yet, I can't read it. Then I tried to use some popular Files Browser/Explorer apps from Google Play and I found out that they request some permission to get access to such external removable storage:
I found such paths unreadable and unlistable too.
But why other apps can? I think they cannot too using the File class. They will use Storage Access Framework.
For instance SDK 27 is Android O.
For Android N, O and P your app can create an access intent with:
volume.createAccessIntent()
Please try.