#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.Build
import android.os.StatFs import android.os.StatFs
import android.util.Log
import java.io.BufferedReader import java.io.BufferedReader
import java.io.File import java.io.File
import java.io.FileReader import java.io.FileReader
import java.io.FileWriter import java.io.FileWriter
import java.io.IOException
const val LOCATION_EXTENSION = "storageLocationMarker"
data class StorageDevice( data class StorageDevice(
val file: File, val file: File,
val isInternal: Boolean 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 private set
val name: String val name: String
@ -62,32 +70,19 @@ data class StorageDevice(
it.blockSize.toLong() * it.blockCount.toLong() 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. // Create unique file to identify duplicate devices.
private fun createLocationCode() { private fun createLocationCode() {
if (!getLocationCodeFromFolder(file)) { if (!getLocationCodeFromFolder(file)) {
val locationCode = File(file.path, ".storageLocationMarker") File(file.path, ".$LOCATION_EXTENSION").let { locationCode ->
try {
locationCode.createNewFile() locationCode.createNewFile()
val fw = FileWriter(locationCode) FileWriter(locationCode).use { it.write(file.path) }
fw.write(file.path)
fw.close()
} catch (e: IOException) {
Log.d("android-storage-devices", "Unable to create marker file, duplicates may be listed")
} }
} }
} }
// Check if there is already a device code in our path // Check if there is already a device code in our path
private fun getLocationCodeFromFolder(folder: File): Boolean { private fun getLocationCodeFromFolder(folder: File): Boolean {
val locationCode = File(folder.path, ".storageLocationMarker") val locationCode = File(folder.path, ".$LOCATION_EXTENSION")
if (locationCode.exists()) { if (locationCode.exists()) {
try { try {
BufferedReader(FileReader(locationCode)).use { br -> BufferedReader(FileReader(locationCode)).use { br ->
@ -102,11 +97,11 @@ data class StorageDevice(
return true return true
} }
} }
val parentFile = folder.parentFile val parent = folder.parentFile
if (parentFile == null) { if (parent == null) {
isDuplicate = false isDuplicate = false
return 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.File
import java.io.FileFilter import java.io.FileFilter
import java.io.RandomAccessFile import java.io.RandomAccessFile
import java.nio.channels.FileLock
import java.util.ArrayList import java.util.ArrayList
object StorageDeviceUtils { object StorageDeviceUtils {
@JvmStatic @JvmStatic
fun getStorageDevices(context: Context, writable: Boolean): List<StorageDevice> { fun getStorageDevices(context: Context, writable: Boolean): List<StorageDevice> {
val storageDevices = ArrayList<StorageDevice>() val storageDevices = ArrayList<StorageDevice>().apply {
add(environmentDevices(writable))
storageDevices.add(environmentDevices(Environment.getExternalStorageDirectory().path, writable)) addAll(externalMountPointDevices())
storageDevices.addAll(externalMountPointDevices()) addAll(externalFilesDirsDevices(context, writable))
storageDevices.addAll(externalFilesDirsDevices(context, writable)) }
return validate(storageDevices, writable)
return validate(storageDevices, writable).also(::deleteStorageMarkers)
} }
private fun externalFilesDirsDevices( private fun externalFilesDirsDevices(
@ -48,44 +46,47 @@ object StorageDeviceUtils {
.filterNotNull() .filterNotNull()
.map { dir -> StorageDevice(generalisePath(dir.path, writable), false) } .map { dir -> StorageDevice(generalisePath(dir.path, writable), false) }
private fun externalMountPointDevices(): Collection<StorageDevice> { private fun externalMountPointDevices(): Collection<StorageDevice> =
val storageDevices = ArrayList<StorageDevice>() ExternalPaths.possiblePaths.fold(mutableListOf(), { acc, path ->
for (path in ExternalPaths.possiblePaths) { acc.apply {
if (path.endsWith("*")) { if (path.endsWith("*")) {
val root = File(path.substringBeforeLast("*")) addAll(devicesBeneath(File(path.substringBeforeLast("*"))))
root.listFiles(FileFilter(File::isDirectory))
?.mapTo(storageDevices) { dir -> StorageDevice(dir, false) }
} else { } else {
storageDevices.add(StorageDevice(path, false)) 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( private fun environmentDevices(
environmentPath: String,
writable: Boolean writable: Boolean
) = ) =
// This is our internal storage directory StorageDevice(
if (Environment.isExternalStorageEmulated()) generalisePath(Environment.getExternalStorageDirectory().path, writable),
StorageDevice(generalisePath(environmentPath, writable), true) Environment.isExternalStorageEmulated()
// This is an external storage directory )
else StorageDevice(generalisePath(environmentPath, writable), false)
// Remove app specific path from directories so that we can search them from the top // Remove app specific path from directories so that we can search them from the top
private fun generalisePath(path: String, writable: Boolean) = private fun generalisePath(path: String, writable: Boolean) =
if (writable) path if (writable) path
else path.substringBeforeLast("/Android/data/") else path.substringBefore("/Android/data/")
// Amazingly file.canWrite() does not always return the correct value // 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 { try {
RandomAccessFile(it, "rw").use { randomAccessFile -> RandomAccessFile(it, "rw").use { randomAccessFile ->
randomAccessFile.channel.use { channel -> randomAccessFile.channel.use { channel ->
channel.lock().also(FileLock::release) channel.lock().use { fileLock ->
fileLock.release()
true true
} }
} }
}
} catch (ignore: Exception) {
false false
} finally { } finally {
File(it).delete() File(it).delete()
@ -95,13 +96,13 @@ object StorageDeviceUtils {
private fun validate( private fun validate(
storageDevices: ArrayList<StorageDevice>, storageDevices: ArrayList<StorageDevice>,
writable: Boolean writable: Boolean
): List<StorageDevice> { ) = storageDevices.asSequence().distinct()
return storageDevices.asSequence().distinct()
.filter { it.file.exists() } .filter { it.file.exists() }
.filter { it.file.isDirectory } .filter { it.file.isDirectory }
.filter { (!writable || canWrite(it.file)) } .filter { canWrite(it.file) || !writable }
.filterNot(StorageDevice::isDuplicate).toList() .filterNot(StorageDevice::isDuplicate)
} .toList()
.also(StorageDeviceUtils::deleteStorageMarkers)
private fun deleteStorageMarkers(validatedDevices: List<StorageDevice>) { private fun deleteStorageMarkers(validatedDevices: List<StorageDevice>) {
validatedDevices.forEach { recursiveDeleteStorageMarkers(it.file) } validatedDevices.forEach { recursiveDeleteStorageMarkers(it.file) }
@ -109,10 +110,9 @@ object StorageDeviceUtils {
private fun recursiveDeleteStorageMarkers(file: File) { private fun recursiveDeleteStorageMarkers(file: File) {
file.listFiles().forEach { file.listFiles().forEach {
if (it.isDirectory) { when {
recursiveDeleteStorageMarkers(it) it.isDirectory -> recursiveDeleteStorageMarkers(it)
} else if (it.extension == "storageMarker") { it.extension == LOCATION_EXTENSION -> it.delete()
it.delete()
} }
} }
} }