#1333 cleanup and extension correction

This commit is contained in:
Sean Mac Gillicuddy 2019-08-15 13:48:31 +01:00
parent 8ae692cfbe
commit a2bd77e98e
2 changed files with 58 additions and 63 deletions

View File

@ -21,19 +21,27 @@ package eu.mhutti1.utils.storage
import android.os.Build
import android.os.StatFs
import android.util.Log
import java.io.BufferedReader
import java.io.File
import java.io.FileReader
import java.io.FileWriter
import java.io.IOException
const val LOCATION_EXTENSION = "storageLocationMarker"
data class StorageDevice(
val file: File,
val isInternal: Boolean
) {
var isDuplicate = true
constructor(path: String, internal: Boolean) : this(File(path), internal)
init {
if (file.exists()) {
createLocationCode()
}
}
var isDuplicate = false
private set
val name: String
@ -62,32 +70,19 @@ data class StorageDevice(
it.blockSize.toLong() * it.blockCount.toLong()
}
constructor(path: String, internal: Boolean) : this(File(path), internal)
init {
if (file.exists()) {
createLocationCode()
}
}
// Create unique file to identify duplicate devices.
private fun createLocationCode() {
if (!getLocationCodeFromFolder(file)) {
val locationCode = File(file.path, ".storageLocationMarker")
try {
File(file.path, ".$LOCATION_EXTENSION").let { locationCode ->
locationCode.createNewFile()
val fw = FileWriter(locationCode)
fw.write(file.path)
fw.close()
} catch (e: IOException) {
Log.d("android-storage-devices", "Unable to create marker file, duplicates may be listed")
FileWriter(locationCode).use { it.write(file.path) }
}
}
}
// Check if there is already a device code in our path
private fun getLocationCodeFromFolder(folder: File): Boolean {
val locationCode = File(folder.path, ".storageLocationMarker")
val locationCode = File(folder.path, ".$LOCATION_EXTENSION")
if (locationCode.exists()) {
try {
BufferedReader(FileReader(locationCode)).use { br ->
@ -102,11 +97,11 @@ data class StorageDevice(
return true
}
}
val parentFile = folder.parentFile
if (parentFile == null) {
val parent = folder.parentFile
if (parent == null) {
isDuplicate = false
return false
}
return getLocationCodeFromFolder(parentFile)
return getLocationCodeFromFolder(parent)
}
}

View File

@ -25,20 +25,18 @@ import androidx.core.content.ContextCompat
import java.io.File
import java.io.FileFilter
import java.io.RandomAccessFile
import java.nio.channels.FileLock
import java.util.ArrayList
object StorageDeviceUtils {
@JvmStatic
fun getStorageDevices(context: Context, writable: Boolean): List<StorageDevice> {
val storageDevices = ArrayList<StorageDevice>()
storageDevices.add(environmentDevices(Environment.getExternalStorageDirectory().path, writable))
storageDevices.addAll(externalMountPointDevices())
storageDevices.addAll(externalFilesDirsDevices(context, writable))
return validate(storageDevices, writable).also(::deleteStorageMarkers)
val storageDevices = ArrayList<StorageDevice>().apply {
add(environmentDevices(writable))
addAll(externalMountPointDevices())
addAll(externalFilesDirsDevices(context, writable))
}
return validate(storageDevices, writable)
}
private fun externalFilesDirsDevices(
@ -48,44 +46,47 @@ object StorageDeviceUtils {
.filterNotNull()
.map { dir -> StorageDevice(generalisePath(dir.path, writable), false) }
private fun externalMountPointDevices(): Collection<StorageDevice> {
val storageDevices = ArrayList<StorageDevice>()
for (path in ExternalPaths.possiblePaths) {
if (path.endsWith("*")) {
val root = File(path.substringBeforeLast("*"))
root.listFiles(FileFilter(File::isDirectory))
?.mapTo(storageDevices) { dir -> StorageDevice(dir, false) }
} else {
storageDevices.add(StorageDevice(path, false))
private fun externalMountPointDevices(): Collection<StorageDevice> =
ExternalPaths.possiblePaths.fold(mutableListOf(), { acc, path ->
acc.apply {
if (path.endsWith("*")) {
addAll(devicesBeneath(File(path.substringBeforeLast("*"))))
} else {
add(StorageDevice(path, false))
}
}
}
return storageDevices
}
})
private fun devicesBeneath(directory: File) =
directory.listFiles(FileFilter(File::isDirectory))
?.map { dir -> StorageDevice(dir, false) }
.orEmpty()
private fun environmentDevices(
environmentPath: String,
writable: Boolean
) =
// This is our internal storage directory
if (Environment.isExternalStorageEmulated())
StorageDevice(generalisePath(environmentPath, writable), true)
// This is an external storage directory
else StorageDevice(generalisePath(environmentPath, writable), false)
StorageDevice(
generalisePath(Environment.getExternalStorageDirectory().path, writable),
Environment.isExternalStorageEmulated()
)
// Remove app specific path from directories so that we can search them from the top
private fun generalisePath(path: String, writable: Boolean) =
if (writable) path
else path.substringBeforeLast("/Android/data/")
else path.substringBefore("/Android/data/")
// Amazingly file.canWrite() does not always return the correct value
private fun canWrite(file: File) = "$file/test.txt".let {
private fun canWrite(file: File): Boolean = "$file/test.txt".let {
try {
RandomAccessFile(it, "rw").use { randomAccessFile ->
randomAccessFile.channel.use { channel ->
channel.lock().also(FileLock::release)
true
channel.lock().use { fileLock ->
fileLock.release()
true
}
}
}
} catch (ignore: Exception) {
false
} finally {
File(it).delete()
@ -95,13 +96,13 @@ object StorageDeviceUtils {
private fun validate(
storageDevices: ArrayList<StorageDevice>,
writable: Boolean
): List<StorageDevice> {
return storageDevices.asSequence().distinct()
.filter { it.file.exists() }
.filter { it.file.isDirectory }
.filter { (!writable || canWrite(it.file)) }
.filterNot(StorageDevice::isDuplicate).toList()
}
) = storageDevices.asSequence().distinct()
.filter { it.file.exists() }
.filter { it.file.isDirectory }
.filter { canWrite(it.file) || !writable }
.filterNot(StorageDevice::isDuplicate)
.toList()
.also(StorageDeviceUtils::deleteStorageMarkers)
private fun deleteStorageMarkers(validatedDevices: List<StorageDevice>) {
validatedDevices.forEach { recursiveDeleteStorageMarkers(it.file) }
@ -109,10 +110,9 @@ object StorageDeviceUtils {
private fun recursiveDeleteStorageMarkers(file: File) {
file.listFiles().forEach {
if (it.isDirectory) {
recursiveDeleteStorageMarkers(it)
} else if (it.extension == "storageMarker") {
it.delete()
when {
it.isDirectory -> recursiveDeleteStorageMarkers(it)
it.extension == LOCATION_EXTENSION -> it.delete()
}
}
}