#283 fixed restoring to missing Download subdir

This commit is contained in:
Thibault Deckers 2022-09-28 21:08:34 +02:00
parent 25ae1a6c1e
commit 38b9f84af0
4 changed files with 67 additions and 47 deletions

View file

@ -15,6 +15,10 @@ All notable changes to this project will be documented in this file.
- Slideshow: option for no transition - Slideshow: option for no transition
- Widget: tap action setting - Widget: tap action setting
### Fixed
- restoring to missing Download subdir
## <a id="v1.7.0"></a>[v1.7.0] - 2022-09-19 ## <a id="v1.7.0"></a>[v1.7.0] - 2022-09-19
### Added ### Added

View file

@ -7,7 +7,6 @@ import android.content.*
import android.media.MediaScannerConnection import android.media.MediaScannerConnection
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Environment
import android.provider.MediaStore import android.provider.MediaStore
import android.util.Log import android.util.Log
import com.commonsware.cwac.document.DocumentFileCompat import com.commonsware.cwac.document.DocumentFileCompat
@ -391,10 +390,15 @@ class MediaStoreImageProvider : ImageProvider() {
effectiveTargetDir = targetDir effectiveTargetDir = targetDir
targetDirDocFile = StorageUtils.createDirectoryDocIfAbsent(activity, targetDir) targetDirDocFile = StorageUtils.createDirectoryDocIfAbsent(activity, targetDir)
if (!File(targetDir).exists()) { if (!File(targetDir).exists()) {
val downloadDirPath = StorageUtils.getDownloadDirPath(activity, targetDir)
val isDownloadSubdir = downloadDirPath != null && targetDir.startsWith(downloadDirPath)
// download subdirectories can be created later by Media Store insertion
if (!isDownloadSubdir) {
callback.onFailure(Exception("failed to create directory at path=$targetDir")) callback.onFailure(Exception("failed to create directory at path=$targetDir"))
return return
} }
} }
}
for (entry in entries) { for (entry in entries) {
val mimeType = entry.mimeType val mimeType = entry.mimeType
@ -535,10 +539,17 @@ class MediaStoreImageProvider : ImageProvider() {
targetNameWithoutExtension: String, targetNameWithoutExtension: String,
write: (OutputStream) -> Unit, write: (OutputStream) -> Unit,
): String { ): String {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && isDownloadDir(activity, targetDir)) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val downloadDirPath = StorageUtils.getDownloadDirPath(activity, targetDir)
val isDownloadSubdir = downloadDirPath != null && targetDir.startsWith(downloadDirPath)
if (isDownloadSubdir) {
val volumePath = StorageUtils.getVolumePath(activity, targetDir)
val relativePath = targetDir.substring(volumePath?.length ?: 0)
val targetFileName = "$targetNameWithoutExtension${extensionFor(mimeType)}" val targetFileName = "$targetNameWithoutExtension${extensionFor(mimeType)}"
val values = ContentValues().apply { val values = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, targetFileName) put(MediaStore.MediaColumns.DISPLAY_NAME, targetFileName)
put(MediaStore.MediaColumns.RELATIVE_PATH, relativePath)
put(MediaStore.MediaColumns.IS_PENDING, 1) put(MediaStore.MediaColumns.IS_PENDING, 1)
} }
val resolver = activity.contentResolver val resolver = activity.contentResolver
@ -551,8 +562,10 @@ class MediaStoreImageProvider : ImageProvider() {
resolver.update(uri, values, null, null) resolver.update(uri, values, null, null)
} ?: throw Exception("MediaStore failed for some reason") } ?: throw Exception("MediaStore failed for some reason")
File(targetDir, targetFileName).path return File(targetDir, targetFileName).path
} else { }
}
targetDirDocFile ?: throw Exception("failed to get tree doc for directory at path=$targetDir") targetDirDocFile ?: throw Exception("failed to get tree doc for directory at path=$targetDir")
// the file created from a `TreeDocumentFile` is also a `TreeDocumentFile` // the file created from a `TreeDocumentFile` is also a `TreeDocumentFile`
@ -576,13 +589,7 @@ class MediaStoreImageProvider : ImageProvider() {
// - a file with the same name already exists, some implementations give a suffix like ` (1)`, some *do not* // - a file with the same name already exists, some implementations give a suffix like ` (1)`, some *do not*
// - the original extension does not match the extension added by the underlying provider // - the original extension does not match the extension added by the underlying provider
val fileName = targetDocFile.name val fileName = targetDocFile.name
targetDir + fileName return targetDir + fileName
}
}
private fun isDownloadDir(context: Context, dirPath: String): Boolean {
val relativeDir = removeTrailingSeparator(PathSegments(context, dirPath).relativeDir ?: "")
return relativeDir == Environment.DIRECTORY_DOWNLOADS
} }
override suspend fun renameMultiple( override suspend fun renameMultiple(

View file

@ -105,7 +105,11 @@ object PermissionManager {
val primaryDir = dirSegments.firstOrNull() val primaryDir = dirSegments.firstOrNull()
if (getRestrictedPrimaryDirectories().contains(primaryDir) && dirSegments.size > 1) { if (getRestrictedPrimaryDirectories().contains(primaryDir) && dirSegments.size > 1) {
// request secondary directory (if any) for restricted primary directory // request secondary directory (if any) for restricted primary directory
dirSet.add(dirSegments.take(2).joinToString(File.separator)) val dir = dirSegments.take(2).joinToString(File.separator)
// only register directories that exist on storage, so they can be selected for access grant
if (File(volumePath, dir).exists()) {
dirSet.add(dir)
}
} else { } else {
primaryDir?.let { dirSet.add(it) } primaryDir?.let { dirSet.add(it) }
} }

View file

@ -9,6 +9,7 @@ import android.content.pm.PackageManager
import android.media.MediaMetadataRetriever import android.media.MediaMetadataRetriever
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Environment
import android.os.storage.StorageManager import android.os.storage.StorageManager
import android.provider.DocumentsContract import android.provider.DocumentsContract
import android.provider.MediaStore import android.provider.MediaStore
@ -93,6 +94,10 @@ object StorageUtils {
return getVolumePaths(context).firstOrNull { anyPath.startsWith(it) } return getVolumePaths(context).firstOrNull { anyPath.startsWith(it) }
} }
fun getDownloadDirPath(context: Context, anyPath: String): String? {
return getVolumePath(context, anyPath)?.let { volumePath -> ensureTrailingSeparator(File(volumePath, Environment.DIRECTORY_DOWNLOADS).path) }
}
private fun getPathStepIterator(context: Context, anyPath: String, root: String?): Iterator<String?>? { private fun getPathStepIterator(context: Context, anyPath: String, root: String?): Iterator<String?>? {
val rootLength = (root ?: getVolumePath(context, anyPath))?.length ?: return null val rootLength = (root ?: getVolumePath(context, anyPath))?.length ?: return null