Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix recycle bin filling up storage when deleting multiple items #2600

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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())

Expand All @@ -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)
Expand All @@ -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 {
Expand All @@ -362,14 +396,16 @@ fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList<String>, callback:
if (config.keepLastModified && lastModified != 0L) {
internalFile.setLastModified(lastModified)
}

totalCopiedSize += originalSize
}
} catch (e: Exception) {
showErrorToast(e)
return@ensureBackgroundThread
}
}
}
callback?.invoke(pathsCnt == 0)
callback?.invoke(pathsCnt == 0, Pair(lastDeletedIndex + 1, paths.size))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}