From 4eb6306efb6cdfae4e34f170c8b9d4e135b04d51 Mon Sep 17 00:00:00 2001 From: Anggrayudi H Date: Wed, 16 Jun 2021 22:15:40 +0700 Subject: [PATCH] fromPublicFolder(DOWNLOADS) causes infinity recursion --- gradle.properties | 2 +- .../storage/file/DocumentFileCompat.kt | 34 ++++++--------- .../storage/file/DocumentFileExt.kt | 41 ++++++++++++++----- .../com/anggrayudi/storage/file/FileExt.kt | 5 ++- 4 files changed, 47 insertions(+), 35 deletions(-) diff --git a/gradle.properties b/gradle.properties index fe64551..99fb7a9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,4 +19,4 @@ android.useAndroidX=true android.enableJetifier=true # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official -STORAGE_VERSION=0.8.1-SNAPSHOT \ No newline at end of file +STORAGE_VERSION=0.8.1 \ No newline at end of file diff --git a/storage/src/main/java/com/anggrayudi/storage/file/DocumentFileCompat.kt b/storage/src/main/java/com/anggrayudi/storage/file/DocumentFileCompat.kt index a0f9408..ae033be 100644 --- a/storage/src/main/java/com/anggrayudi/storage/file/DocumentFileCompat.kt +++ b/storage/src/main/java/com/anggrayudi/storage/file/DocumentFileCompat.kt @@ -125,12 +125,12 @@ object DocumentFileCompat { } else { val file = exploreFile(context, storageId, basePath, documentType, considerRawFile) if (file == null && basePath.startsWith(Environment.DIRECTORY_DOWNLOADS) && storageId == PRIMARY) { - fromPublicFolder(context, PublicDirectory.DOWNLOADS, basePath.substringAfter('/', ""), considerRawFile = considerRawFile) - ?.takeIf { - documentType == DocumentFileType.ANY - || documentType == DocumentFileType.FILE && it.isFile - || documentType == DocumentFileType.FOLDER && it.isDirectory - } + val downloads = context.fromTreeUri(Uri.parse(DOWNLOADS_TREE_URI))?.takeIf { it.canRead() } ?: return null + downloads.child(context, basePath.substringAfter('/', ""))?.takeIf { + documentType == DocumentFileType.ANY + || documentType == DocumentFileType.FILE && it.isFile + || documentType == DocumentFileType.FOLDER && it.isDirectory + } } else { file } @@ -210,7 +210,9 @@ object DocumentFileCompat { if (subFile.isNotEmpty()) { rawFile = File("$rawFile/$subFile".trimEnd('/')) } - if (considerRawFile && rawFile.canRead() && (requiresWriteAccess && rawFile.isWritable(context) || !requiresWriteAccess)) { + if (rawFile.canRead() && (considerRawFile || rawFile.isExternalStorageManager(context)) + && (requiresWriteAccess && rawFile.isWritable(context) || !requiresWriteAccess) + ) { return DocumentFile.fromFile(rawFile) } @@ -227,17 +229,9 @@ object DocumentFileCompat { but unfortunately cannot create file in the directory. So creating directory with this authority is useless. Hence, convert it to writable URI with DocumentFile.toWritableDownloadsDocumentFile() */ - var downloadFolder = context.fromTreeUri(Uri.parse(DOWNLOADS_TREE_URI)) + val downloadFolder = context.fromTreeUri(Uri.parse(DOWNLOADS_TREE_URI)) if (downloadFolder?.canRead() == true) { - getDirectorySequence(subFile).forEach { - val directory = downloadFolder?.findFile(it) ?: return null - if (directory.canRead()) { - downloadFolder = directory - } else { - return null - } - } - downloadFolder + downloadFolder.child(context, subFile, requiresWriteAccess) } else { fromFullPath(context, rawFile.absolutePath, considerRawFile = false) } @@ -662,11 +656,7 @@ object DocumentFileCompat { } } val file = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { - var current = getRootDocumentFile(context, storageId, considerRawFile) ?: return null - getDirectorySequence(basePath).forEach { - current = current.findFile(it) ?: return null - } - current + getRootDocumentFile(context, storageId, considerRawFile)?.child(context, basePath) ?: return null } else { val directorySequence = getDirectorySequence(basePath).toMutableList() val parentTree = ArrayList(directorySequence.size) diff --git a/storage/src/main/java/com/anggrayudi/storage/file/DocumentFileExt.kt b/storage/src/main/java/com/anggrayudi/storage/file/DocumentFileExt.kt index 6e68109..13040ac 100644 --- a/storage/src/main/java/com/anggrayudi/storage/file/DocumentFileExt.kt +++ b/storage/src/main/java/com/anggrayudi/storage/file/DocumentFileExt.kt @@ -266,6 +266,33 @@ fun DocumentFile.toTreeDocumentFile(context: Context): DocumentFile? { fun DocumentFile.toMediaFile(context: Context) = if (isTreeDocumentFile) null else MediaFile(context, uri) +/** + * @param path single file name or file path. Empty string returns to itself. + */ +fun DocumentFile.child(context: Context, path: String, requiresWriteAccess: Boolean = false): DocumentFile? { + return when { + path.isEmpty() -> this + isDirectory -> { + val file = if (isRawFile) { + DocumentFile.fromFile(File(uri.path!!, path)) + } else { + var currentDirectory = this + DocumentFileCompat.getDirectorySequence(path).forEach { + val directory = currentDirectory.findFile(it) ?: return null + if (directory.canRead()) { + currentDirectory = directory + } else { + return null + } + } + currentDirectory + } + file.takeIf { it.canRead() && (requiresWriteAccess && it.isWritable(context) || !requiresWriteAccess) } + } + else -> null + } +} + /** * @return File path without storage ID. Returns empty `String` if: * * It is the root path @@ -633,18 +660,10 @@ fun DocumentFile.toWritableDownloadsDocumentFile(context: Context): DocumentFile // content://com.android.providers.downloads.documents/tree/downloads/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2FIKO5 // raw:/storage/emulated/0/Download/IKO5 Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && (path.startsWith("/tree/downloads/document/raw:") || path.startsWith("/document/raw:")) -> { - var currentDirectory = DocumentFileCompat.fromPublicFolder(context, PublicDirectory.DOWNLOADS, considerRawFile = false) - ?: return null + val downloads = DocumentFileCompat.fromPublicFolder(context, PublicDirectory.DOWNLOADS, considerRawFile = false) ?: return null val fullPath = path.substringAfterLast("/document/raw:") - DocumentFileCompat.getDirectorySequence(fullPath.substringAfter("/${Environment.DIRECTORY_DOWNLOADS}")).forEach { - val directory = currentDirectory.findFile(it) ?: return null - if (directory.canRead()) { - currentDirectory = directory - } else { - return null - } - } - currentDirectory.takeIf { it.isWritable(context) } + val subFile = fullPath.substringAfter("/${Environment.DIRECTORY_DOWNLOADS}", "") + downloads.child(context, subFile, true) } // msd for directories and msf for files diff --git a/storage/src/main/java/com/anggrayudi/storage/file/FileExt.kt b/storage/src/main/java/com/anggrayudi/storage/file/FileExt.kt index 9f763bd..0505d3f 100644 --- a/storage/src/main/java/com/anggrayudi/storage/file/FileExt.kt +++ b/storage/src/main/java/com/anggrayudi/storage/file/FileExt.kt @@ -45,7 +45,10 @@ fun File.getStorageType(context: Context) = when { else -> StorageType.UNKNOWN } -fun File.child(name: String) = File(this, name) +/** + * @param path single file name or file path + */ +fun File.child(path: String) = File(this, path) /** * @see [Context.getDataDir]