Skip to content

Instantly share code, notes, and snippets.

@yrezgui
Created November 19, 2020 17:45
Show Gist options
  • Save yrezgui/79488ca2b810e9fcd5f5ece1f43840eb to your computer and use it in GitHub Desktop.
Save yrezgui/79488ca2b810e9fcd5f5ece1f43840eb to your computer and use it in GitHub Desktop.
Storage utilities for Android
package com.yrezgui.videoplayer
import android.annotation.SuppressLint
import android.content.Context
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import android.os.Environment
import android.os.storage.StorageManager
import android.os.storage.StorageVolume
import androidx.annotation.RequiresApi
import java.io.File
enum class VolumeType {
EMULATED, REMOVABLE, MIXED
}
data class VolumeResource(
val type: VolumeType,
val path: String
)
@RequiresApi(api = VERSION_CODES.KITKAT)
private fun getVolumesApi19(): List<VolumeResource> {
val path = Environment.getExternalStorageDirectory()
val isRemovable = Environment.isExternalStorageRemovable()
val isEmulated = Environment.isExternalStorageEmulated()
val volumeType = when {
isEmulated && isRemovable -> VolumeType.MIXED
isEmulated && !isRemovable -> VolumeType.EMULATED
else -> VolumeType.REMOVABLE
}
return listOf(VolumeResource(type = volumeType, path = path.toString()))
}
@RequiresApi(api = VERSION_CODES.LOLLIPOP)
fun getVolumesApi21(context: Context): List<VolumeResource> {
// e.g. /storage/emulated/0/Android/media/com.yrezgui.videoplayer
// e.g. /storage/sdcard/Android/media/com.yrezgui.videoplayer
val volumeRootFolders = context.externalMediaDirs.map {
it.parentFile?.parentFile?.parentFile
}
return volumeRootFolders.filterNotNull().map { folder ->
val folderState = Environment.getStorageState(folder)
val isEmulated = Environment.isExternalStorageEmulated(folder)
val isRemovable = Environment.isExternalStorageRemovable(folder)
val volumeType = when {
isEmulated && isRemovable -> VolumeType.MIXED
isEmulated && !isRemovable -> VolumeType.EMULATED
else -> VolumeType.REMOVABLE
}
VolumeResource(type = volumeType, path = folder.toString())
}
}
@RequiresApi(api = VERSION_CODES.R)
private fun getVolumesApi30(context: Context): List<VolumeResource> {
val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
return storageManager.storageVolumes.map {
val volumeType = when {
it.isEmulated && it.isRemovable -> VolumeType.MIXED
it.isEmulated && !it.isRemovable -> VolumeType.EMULATED
else -> VolumeType.REMOVABLE
}
VolumeResource(type = volumeType, path = it.directory!!.toString())
}
}
fun getVolumes(context: Context): List<VolumeResource> {
return when {
VERSION.SDK_INT >= VERSION_CODES.R -> getVolumesApi30(context)
VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP -> getVolumesApi21(context)
else -> getVolumesApi19()
}
}
fun getFiles(folder: File): List<File> {
val files = folder.listFiles()?.asSequence() ?: emptySequence<File>()
return files
.filter(::removeHiddenFiles)
.filter(::removeNonVideoFiles)
.sortedByDescending { it.isDirectory }
.toList()
}
private fun removeHiddenFiles(file: File): Boolean {
return !file.isHidden || file.name.first() != '.'
}
val VIDEO_EXTENSIONS = arrayOf("mpg", "mpeg", "mp4", "asf", "wma", "wmv", "avi", "3gpp", "3gpp2")
private fun removeNonVideoFiles(file: File): Boolean {
return file.isDirectory || (file.isFile && VIDEO_EXTENSIONS.contains(file.extension))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment