Fix storage getting full while moving multiple items to the recycle bin at once

This commit is contained in:
Mino260806 2022-09-04 23:41:21 +01:00
parent 07fb21a775
commit 9f152ea01d
6 changed files with 66 additions and 15 deletions

View File

@ -656,9 +656,10 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
val pathsToDelete = ArrayList<String>()
itemsToDelete.mapTo(pathsToDelete) { it.path }
movePathsInRecycleBin(pathsToDelete) {
if (it) {
deleteFilteredFileDirItems(itemsToDelete, folders)
movePathsInRecycleBin(pathsToDelete) { wasSuccess, range ->
if (wasSuccess) {
val itemsInRange = itemsToDelete.subList(range.first, range.second)
deleteFilteredFileDirItems(ArrayList(itemsInRange), ArrayList())
} else {
toast(R.string.unknown_error_occurred)
}

View File

@ -887,9 +887,10 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
val movingItems = resources.getQuantityString(R.plurals.moving_items_into_bin, filtered.size, filtered.size)
toast(movingItems)
movePathsInRecycleBin(filtered.map { it.path } as ArrayList<String>) {
if (it) {
deleteFilteredFiles(filtered)
movePathsInRecycleBin(filtered.map { it.path } as ArrayList<String>) { wasSuccess, range ->
if (wasSuccess) {
val itemsInRange = filtered.subList(range.first, range.second)
deleteFilteredFiles(ArrayList(itemsInRange))
} else {
toast(R.string.unknown_error_occurred)
}

View File

@ -267,9 +267,10 @@ class SearchActivity : SimpleActivity(), MediaOperationsListener {
val movingItems = resources.getQuantityString(R.plurals.moving_items_into_bin, filtered.size, filtered.size)
toast(movingItems)
movePathsInRecycleBin(filtered.map { it.path } as ArrayList<String>) {
if (it) {
deleteFilteredFiles(filtered)
movePathsInRecycleBin(filtered.map { it.path } as ArrayList<String>) { wasSuccess, range ->
if (wasSuccess) {
val itemsInRange = filtered.subList(range.first, range.second)
deleteFilteredFiles(ArrayList(itemsInRange))
} else {
toast(R.string.unknown_error_occurred)
}

View File

@ -1161,8 +1161,8 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
onPageSelected(0)
}
movePathsInRecycleBin(arrayListOf(path)) {
if (it) {
movePathsInRecycleBin(arrayListOf(path)) { wasSuccess, _ ->
if (wasSuccess) {
tryDeleteFileDirItem(fileDirItem, false, false) {
mIgnoredPaths.remove(fileDirItem.path)
if (media.isEmpty()) {

View File

@ -44,6 +44,7 @@ import com.squareup.picasso.Picasso
import java.io.*
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.ArrayList
fun Activity.sharePath(path: String) {
sharePathIntent(path, BuildConfig.APPLICATION_ID)
@ -313,18 +314,45 @@ fun BaseSimpleActivity.tryDeleteFileDirItem(
}
}
fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList<String>, callback: ((wasSuccess: Boolean) -> Unit)?) {
fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList<String>, callback: ((wasSuccess: Boolean, movedRange: Pair<Int, Int>) -> Unit)?) {
ensureBackgroundThread {
var pathsCnt = paths.size
val OTGPath = config.OTGPath
for (source in paths) {
var availableSize = getAvailableInternalMemorySize().toLong()
// If available size is more than 200MB, keep a safe distance from
// exceeding the remaining size
if (availableSize > 1024 * 1024 * 200)
availableSize -= 1024 * 1024 * 50
var totalCopiedSize = 0L
var lastDeletedIndex = -1
val ensureSizeIsAvailable = { index: Int, size: Long ->
// Try to delete already moved files if space if not sufficient
if (size <= availableSize && totalCopiedSize > 0 && totalCopiedSize + size > availableSize) {
// Return true in wasSuccess for now, callback will be called
// at the end of the function with the correct parameter
callback?.invoke(true, Pair(lastDeletedIndex + 1, index + 1))
availableSize = getAvailableInternalMemorySize()
totalCopiedSize = 0L
lastDeletedIndex = index
}
size <= availableSize
}
for ((index, source) in paths.withIndex()) {
if (OTGPath.isNotEmpty() && source.startsWith(OTGPath)) {
var inputStream: InputStream? = null
var out: OutputStream? = null
try {
val destination = "$recycleBinPath/$source"
val fileDocument = getSomeDocumentFile(source)
val originalSize = fileDocument?.getItemSize(true)!!
if (!ensureSizeIsAvailable(index, originalSize))
continue
inputStream = applicationContext.contentResolver.openInputStream(fileDocument?.uri!!)
out = getFileOutputStreamSync(destination, source.getMimeType())
@ -339,9 +367,11 @@ fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList<String>, callback:
out?.flush()
if (fileDocument.getItemSize(true) == copiedSize && getDoesFilePathExist(destination)) {
if (originalSize == copiedSize && getDoesFilePathExist(destination)) {
mediaDB.updateDeleted("$RECYCLE_BIN$source", System.currentTimeMillis(), source)
pathsCnt--
totalCopiedSize += copiedSize
}
} catch (e: Exception) {
showErrorToast(e)
@ -352,6 +382,10 @@ fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList<String>, callback:
}
} else {
val file = File(source)
val originalSize = file.length()
if (!ensureSizeIsAvailable(index, originalSize))
continue
val internalFile = File(recycleBinPath, source)
val lastModified = file.lastModified()
try {
@ -362,6 +396,8 @@ fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList<String>, callback:
if (config.keepLastModified && lastModified != 0L) {
internalFile.setLastModified(lastModified)
}
totalCopiedSize += originalSize
}
} catch (e: Exception) {
showErrorToast(e)
@ -369,7 +405,7 @@ fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList<String>, callback:
}
}
}
callback?.invoke(pathsCnt == 0)
callback?.invoke(pathsCnt == 0, Pair(lastDeletedIndex + 1, paths.size))
}
}

View File

@ -8,7 +8,9 @@ import android.database.Cursor
import android.graphics.Bitmap
import android.graphics.drawable.PictureDrawable
import android.media.AudioManager
import android.os.Environment
import android.os.Process
import android.os.StatFs
import android.provider.MediaStore.Files
import android.provider.MediaStore.Images
import android.widget.ImageView
@ -43,6 +45,7 @@ import java.nio.ByteBuffer
import java.nio.channels.FileChannel
import kotlin.collections.set
val Context.audioManager get() = getSystemService(Context.AUDIO_SERVICE) as AudioManager
fun Context.getHumanizedFilename(path: String): String {
@ -1103,3 +1106,12 @@ fun Context.getFileDateTaken(path: String): Long {
return 0L
}
// https://stackoverflow.com/questions/8133417/android-get-free-size-of-internal-external-memory
fun Context.getAvailableInternalMemorySize(): Long {
val path: File = filesDir
val stat = StatFs(path.path)
val blockSize = stat.blockSizeLong
val availableBlocks = stat.availableBlocksLong
return availableBlocks * blockSize
}