From 7e8658bb833ddafb38a76b887e2cda6508bfb181 Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Tue, 15 Oct 2024 11:51:19 +0530 Subject: [PATCH 1/4] Fixed: Application crashing due to `Input dispatching timed out` when deleting the ZIM files. * Moved the file deleting logic on IO thread, and refactored our code according to this change. --- .../library/CopyMoveFileHandler.kt | 4 +- .../fileselectView/effects/DeleteFiles.kt | 32 +++++--- .../kiwixmobile/core/dao/DownloadRoomDao.kt | 7 +- .../core/extensions/FileExtensions.kt | 6 +- .../kiwixmobile/core/utils/files/FileUtils.kt | 79 ++++++++++--------- 5 files changed, 76 insertions(+), 52 deletions(-) diff --git a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/CopyMoveFileHandler.kt b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/CopyMoveFileHandler.kt index 7ea71da622..9cb21f4acc 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/CopyMoveFileHandler.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/CopyMoveFileHandler.kt @@ -301,7 +301,9 @@ class CopyMoveFileHandler @Inject constructor( } fileCopyMoveCallback?.onError(userFriendlyMessage).also { // Clean up the destination file if an error occurs - destinationFile.deleteFile() + CoroutineScope(Dispatchers.IO).launch { + destinationFile.deleteFile() + } } } diff --git a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/fileselectView/effects/DeleteFiles.kt b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/fileselectView/effects/DeleteFiles.kt index 576aad09ec..954a3f4802 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/fileselectView/effects/DeleteFiles.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/fileselectView/effects/DeleteFiles.kt @@ -19,8 +19,12 @@ package org.kiwix.kiwixmobile.zimManager.fileselectView.effects import androidx.appcompat.app.AppCompatActivity -import org.kiwix.kiwixmobile.core.R +import androidx.lifecycle.lifecycleScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.kiwix.kiwixmobile.cachedComponent +import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.base.BaseActivity import org.kiwix.kiwixmobile.core.base.SideEffect import org.kiwix.kiwixmobile.core.dao.NewBookDao @@ -30,6 +34,7 @@ import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer import org.kiwix.kiwixmobile.core.utils.dialog.DialogShower import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog.DeleteZims import org.kiwix.kiwixmobile.core.utils.files.FileUtils +import org.kiwix.kiwixmobile.core.utils.files.Log import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk import javax.inject.Inject @@ -46,19 +51,25 @@ data class DeleteFiles(private val booksOnDiskListItems: List) : val name = booksOnDiskListItems.joinToString(separator = "\n") { it.book.title } dialogShower.show(DeleteZims(name), { - activity.toast( - if (booksOnDiskListItems.deleteAll()) { - R.string.delete_zims_toast - } else { - R.string.delete_zim_failed + activity.lifecycleScope.launch { + val deleteResult = withContext(Dispatchers.IO) { + booksOnDiskListItems.deleteAll() } - ) + activity.toast( + if (deleteResult) { + R.string.delete_zims_toast + } else { + R.string.delete_zim_failed + } + ) + } }) } - private fun List.deleteAll(): Boolean { + private suspend fun List.deleteAll(): Boolean { return fold(true) { acc, book -> acc && deleteSpecificZimFile(book).also { + Log.i("kiwix", "Deleting file: ${book.zimReaderSource.file?.path}, success: $it") if (it && book.zimReaderSource == zimReaderContainer.zimReaderSource) { zimReaderContainer.setZimReaderSource(null) } @@ -66,16 +77,19 @@ data class DeleteFiles(private val booksOnDiskListItems: List) : } } - private fun deleteSpecificZimFile(book: BookOnDisk): Boolean { + private suspend fun deleteSpecificZimFile(book: BookOnDisk): Boolean { val file = book.zimReaderSource.file file?.let { + Log.i("kiwix", "Attempting to delete file: ${it.path}") @Suppress("UnreachableCode") FileUtils.deleteZimFile(it.path) } if (file?.isFileExist() == true) { + Log.e("kiwix", "File deletion failed: ${file.path}") return false } newBookDao.delete(book.databaseId) + Log.i("kiwix", "Book entry deleted: ${book.databaseId}") return true } } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/DownloadRoomDao.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/DownloadRoomDao.kt index f90d8ea868..21883f54d0 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/DownloadRoomDao.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/DownloadRoomDao.kt @@ -25,6 +25,9 @@ import androidx.room.Query import androidx.room.Update import io.reactivex.Flowable import io.reactivex.Single +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import org.kiwix.kiwixmobile.core.dao.entities.DownloadRoomEntity import org.kiwix.kiwixmobile.core.downloader.DownloadRequester import org.kiwix.kiwixmobile.core.downloader.downloadManager.Status @@ -95,7 +98,9 @@ abstract class DownloadRoomDao { fun delete(downloadId: Long) { // remove the previous file from storage since we have cancelled the download. getEntityForDownloadId(downloadId)?.file?.let { - File(it).deleteFile() + CoroutineScope(Dispatchers.IO).launch { + File(it).deleteFile() + } } deleteDownloadByDownloadId(downloadId) } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/FileExtensions.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/FileExtensions.kt index 7a2061cdd7..a405c4a305 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/FileExtensions.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/FileExtensions.kt @@ -47,8 +47,4 @@ fun File.canReadFile(): Boolean = runBlocking { } } -fun File.deleteFile(): Boolean = runBlocking { - withContext(Dispatchers.IO) { - delete() - } -} +suspend fun File.deleteFile(): Boolean = withContext(Dispatchers.IO) { delete() } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/utils/files/FileUtils.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/utils/files/FileUtils.kt index 2fd010492b..a54ec93513 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/utils/files/FileUtils.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/utils/files/FileUtils.kt @@ -34,6 +34,8 @@ import androidx.documentfile.provider.DocumentFile import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import org.kiwix.kiwixmobile.core.CoreApp import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.downloader.ChunkUtils @@ -51,6 +53,8 @@ import java.io.IOException object FileUtils { + private val fileOperationMutex = Mutex() + @JvmStatic fun getFileCacheDir(context: Context): File? = if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState()) { @@ -68,49 +72,52 @@ object FileUtils { } @JvmStatic - @Synchronized - fun deleteZimFile(path: String) { - var path = path - if (path.substring(path.length - ChunkUtils.PART.length) == ChunkUtils.PART) { - path = path.substring(0, path.length - ChunkUtils.PART.length) - } - Log.i("kiwix", "Deleting file: $path") - val file = File(path) - if (file.path.substring(file.path.length - 3) != "zim") { - var alphabetFirst = 'a' - fileloop@ while (alphabetFirst <= 'z') { - var alphabetSecond = 'a' - while (alphabetSecond <= 'z') { - val chunkPath = path.substring(0, path.length - 2) + alphabetFirst + alphabetSecond - val fileChunk = File(chunkPath) - if (fileChunk.isFileExist()) { - fileChunk.deleteFile() - } else if (!deleteZimFileParts(chunkPath)) { - break@fileloop + suspend fun deleteZimFile(path: String) { + fileOperationMutex.withLock { + var path = path + if (path.substring(path.length - ChunkUtils.PART.length) == ChunkUtils.PART) { + path = path.substring(0, path.length - ChunkUtils.PART.length) + } + Log.i("kiwix", "Deleting file: $path") + val file = File(path) + if (file.path.substring(file.path.length - 3) != "zim") { + var alphabetFirst = 'a' + fileloop@ while (alphabetFirst <= 'z') { + var alphabetSecond = 'a' + while (alphabetSecond <= 'z') { + val chunkPath = path.substring(0, path.length - 2) + alphabetFirst + alphabetSecond + val fileChunk = File(chunkPath) + if (fileChunk.isFileExist()) { + fileChunk.deleteFile() + } else if (!deleteZimFileParts(chunkPath)) { + break@fileloop + } + alphabetSecond++ } - alphabetSecond++ + alphabetFirst++ } - alphabetFirst++ + } else { + file.deleteFile() + deleteZimFileParts(path) } - } else { - file.deleteFile() - deleteZimFileParts(path) } } - @Synchronized - private fun deleteZimFileParts(path: String): Boolean { - val file = File(path + ChunkUtils.PART) - if (file.isFileExist()) { - file.deleteFile() - return true - } - val singlePart = File("$path.part") - if (singlePart.isFileExist()) { - singlePart.deleteFile() - return true + @Suppress("ReturnCount") + private suspend fun deleteZimFileParts(path: String): Boolean { + fileOperationMutex.withLock { + val file = File(path + ChunkUtils.PART) + if (file.isFileExist()) { + file.deleteFile() + return@deleteZimFileParts true + } + val singlePart = File("$path.part") + if (singlePart.isFileExist()) { + singlePart.deleteFile() + return@deleteZimFileParts true + } + return@deleteZimFileParts false } - return false } @JvmStatic From 676056a89fb7d36f222fda97c2a409b772018811 Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Tue, 15 Oct 2024 14:18:14 +0530 Subject: [PATCH 2/4] Fixed the compilation error in CopyMoveFileHandlerTest. --- .../kiwixmobile/localLibrary/CopyMoveFileHandlerTest.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/androidTest/java/org/kiwix/kiwixmobile/localLibrary/CopyMoveFileHandlerTest.kt b/app/src/androidTest/java/org/kiwix/kiwixmobile/localLibrary/CopyMoveFileHandlerTest.kt index cca64ea5ed..a1f8d3068a 100644 --- a/app/src/androidTest/java/org/kiwix/kiwixmobile/localLibrary/CopyMoveFileHandlerTest.kt +++ b/app/src/androidTest/java/org/kiwix/kiwixmobile/localLibrary/CopyMoveFileHandlerTest.kt @@ -24,12 +24,14 @@ import androidx.core.content.ContextCompat import androidx.core.content.edit import androidx.documentfile.provider.DocumentFile import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.NavHostFragment import androidx.preference.PreferenceManager import androidx.test.core.app.ActivityScenario import androidx.test.internal.runner.junit4.statement.UiThreadStatement import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice +import kotlinx.coroutines.launch import org.junit.After import org.junit.Assert import org.junit.Before @@ -265,8 +267,10 @@ class CopyMoveFileHandlerTest : BaseActivityTest() { } private fun deleteBothPreviousFiles() { - selectedFile.deleteFile() - destinationFile.deleteFile() + kiwixMainActivity.lifecycleScope.launch { + selectedFile.deleteFile() + destinationFile.deleteFile() + } } private fun deleteAllFilesInDirectory(directory: File) { From a839b8d40cfac5c7bac4546651e27e850a21e6b0 Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Tue, 15 Oct 2024 15:17:13 +0530 Subject: [PATCH 3/4] Improved the deleting logic of files. * Removed the unused code from FileUtils class. --- .../library/CopyMoveFileHandler.kt | 2 +- .../zimManager/AppProgressListenerProvider.kt | 4 +- .../fileselectView/effects/DeleteFiles.kt | 5 -- .../kiwixmobile/core/utils/files/FileUtils.kt | 71 +++---------------- 4 files changed, 13 insertions(+), 69 deletions(-) diff --git a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/CopyMoveFileHandler.kt b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/CopyMoveFileHandler.kt index 9cb21f4acc..d068e67204 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/CopyMoveFileHandler.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/CopyMoveFileHandler.kt @@ -301,7 +301,7 @@ class CopyMoveFileHandler @Inject constructor( } fileCopyMoveCallback?.onError(userFriendlyMessage).also { // Clean up the destination file if an error occurs - CoroutineScope(Dispatchers.IO).launch { + lifecycleScope?.launch { destinationFile.deleteFile() } } diff --git a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/AppProgressListenerProvider.kt b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/AppProgressListenerProvider.kt index 19dfb56531..7636099641 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/AppProgressListenerProvider.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/AppProgressListenerProvider.kt @@ -33,12 +33,12 @@ class AppProgressListenerProvider( if (contentLength == DEFAULT_INT_VALUE.toLong()) { ZERO } else { - (bytesRead * HUNDERED / contentLength).toInt() * 3 + (bytesRead * 3 * HUNDERED / contentLength).coerceAtMost(HUNDERED.toLong()) } zimManageViewModel.downloadProgress.postValue( zimManageViewModel.context.getString( R.string.downloading_library, - zimManageViewModel.context.getString(R.string.percentage, progress) + zimManageViewModel.context.getString(R.string.percentage, progress.toInt()) ) ) } diff --git a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/fileselectView/effects/DeleteFiles.kt b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/fileselectView/effects/DeleteFiles.kt index 954a3f4802..274403fc3f 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/fileselectView/effects/DeleteFiles.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/fileselectView/effects/DeleteFiles.kt @@ -34,7 +34,6 @@ import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer import org.kiwix.kiwixmobile.core.utils.dialog.DialogShower import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog.DeleteZims import org.kiwix.kiwixmobile.core.utils.files.FileUtils -import org.kiwix.kiwixmobile.core.utils.files.Log import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk import javax.inject.Inject @@ -69,7 +68,6 @@ data class DeleteFiles(private val booksOnDiskListItems: List) : private suspend fun List.deleteAll(): Boolean { return fold(true) { acc, book -> acc && deleteSpecificZimFile(book).also { - Log.i("kiwix", "Deleting file: ${book.zimReaderSource.file?.path}, success: $it") if (it && book.zimReaderSource == zimReaderContainer.zimReaderSource) { zimReaderContainer.setZimReaderSource(null) } @@ -80,16 +78,13 @@ data class DeleteFiles(private val booksOnDiskListItems: List) : private suspend fun deleteSpecificZimFile(book: BookOnDisk): Boolean { val file = book.zimReaderSource.file file?.let { - Log.i("kiwix", "Attempting to delete file: ${it.path}") @Suppress("UnreachableCode") FileUtils.deleteZimFile(it.path) } if (file?.isFileExist() == true) { - Log.e("kiwix", "File deletion failed: ${file.path}") return false } newBookDao.delete(book.databaseId) - Log.i("kiwix", "Book entry deleted: ${book.databaseId}") return true } } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/utils/files/FileUtils.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/utils/files/FileUtils.kt index a54ec93513..977e965359 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/utils/files/FileUtils.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/utils/files/FileUtils.kt @@ -18,19 +18,15 @@ package org.kiwix.kiwixmobile.core.utils.files import android.annotation.SuppressLint -import android.app.Activity import android.content.ContentUris import android.content.Context -import android.content.Intent import android.content.res.AssetFileDescriptor import android.net.Uri import android.os.Build import android.os.Environment import android.provider.DocumentsContract import android.webkit.URLUtil -import android.widget.Toast import androidx.core.content.ContextCompat -import androidx.documentfile.provider.DocumentFile import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -42,7 +38,6 @@ import org.kiwix.kiwixmobile.core.downloader.ChunkUtils import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book import org.kiwix.kiwixmobile.core.extensions.deleteFile import org.kiwix.kiwixmobile.core.extensions.isFileExist -import org.kiwix.kiwixmobile.core.extensions.toast import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil import java.io.BufferedReader @@ -78,7 +73,6 @@ object FileUtils { if (path.substring(path.length - ChunkUtils.PART.length) == ChunkUtils.PART) { path = path.substring(0, path.length - ChunkUtils.PART.length) } - Log.i("kiwix", "Deleting file: $path") val file = File(path) if (file.path.substring(file.path.length - 3) != "zim") { var alphabetFirst = 'a' @@ -105,19 +99,17 @@ object FileUtils { @Suppress("ReturnCount") private suspend fun deleteZimFileParts(path: String): Boolean { - fileOperationMutex.withLock { - val file = File(path + ChunkUtils.PART) - if (file.isFileExist()) { - file.deleteFile() - return@deleteZimFileParts true - } - val singlePart = File("$path.part") - if (singlePart.isFileExist()) { - singlePart.deleteFile() - return@deleteZimFileParts true - } - return@deleteZimFileParts false + val file = File(path + ChunkUtils.PART) + if (file.isFileExist()) { + file.deleteFile() + return true } + val singlePart = File("$path.part") + if (singlePart.isFileExist()) { + singlePart.deleteFile() + return true + } + return false } @JvmStatic @@ -364,49 +356,6 @@ object FileUtils { .firstOrNull { it.path.contains(storageName) } ?.path?.substringBefore(context.getString(R.string.android_directory_seperator)) - @SuppressLint("WrongConstant") - @JvmStatic - fun getPathFromUri(activity: Activity, data: Intent): String? { - val uri: Uri? = data.data - val takeFlags: Int = data.flags and ( - Intent.FLAG_GRANT_READ_URI_PERMISSION - or Intent.FLAG_GRANT_WRITE_URI_PERMISSION - ) - uri?.let { - activity.grantUriPermission( - activity.packageName, it, - Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION - ) - activity.contentResolver.takePersistableUriPermission(it, takeFlags) - - val dFile = DocumentFile.fromTreeUri(activity, it) - if (dFile != null) { - dFile.uri.path?.let { file -> - val originalPath = file.substring( - file.lastIndexOf(":") + 1 - ) - val path = "${activity.getExternalFilesDirs("")[1]}" - return@getPathFromUri path.substringBefore( - activity.getString(R.string.android_directory_seperator) - ) - .plus(File.separator).plus(originalPath) - } - } - activity.toast( - activity.resources - .getString(R.string.system_unable_to_grant_permission_message), - Toast.LENGTH_SHORT - ) - } ?: run { - activity.toast( - activity.resources - .getString(R.string.system_unable_to_grant_permission_message), - Toast.LENGTH_SHORT - ) - } - return null - } - /* * This method returns a file name guess from the url using URLUtils.guessFileName() method of android.webkit. which is using Uri.decode method to extract the filename From 79a61e330d69ef5912fd5c8c854e7ced7db14e3d Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Tue, 15 Oct 2024 15:38:26 +0530 Subject: [PATCH 4/4] Fixed CopyMoveFileHandlerTest failing. --- .../localLibrary/CopyMoveFileHandlerTest.kt | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/app/src/androidTest/java/org/kiwix/kiwixmobile/localLibrary/CopyMoveFileHandlerTest.kt b/app/src/androidTest/java/org/kiwix/kiwixmobile/localLibrary/CopyMoveFileHandlerTest.kt index a1f8d3068a..a388daa1c1 100644 --- a/app/src/androidTest/java/org/kiwix/kiwixmobile/localLibrary/CopyMoveFileHandlerTest.kt +++ b/app/src/androidTest/java/org/kiwix/kiwixmobile/localLibrary/CopyMoveFileHandlerTest.kt @@ -31,7 +31,9 @@ import androidx.test.core.app.ActivityScenario import androidx.test.internal.runner.junit4.statement.UiThreadStatement import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.junit.After import org.junit.Assert import org.junit.Before @@ -253,24 +255,26 @@ class CopyMoveFileHandlerTest : BaseActivityTest() { destinationFile.name, "testCopyMove_1.zim" ) - deleteBothPreviousFiles() + kiwixMainActivity.lifecycleScope.launch { + withContext(Dispatchers.IO) { + deleteBothPreviousFiles() + } - // test when there is no zim file available in the storage it should return the same fileName - selectedFile = File(parentFile, selectedFileName) - copyMoveFileHandler.setSelectedFileAndUri(null, DocumentFile.fromFile(selectedFile)) - destinationFile = copyMoveFileHandler.getDestinationFile() - Assert.assertEquals( - destinationFile.name, - selectedFile.name - ) - deleteBothPreviousFiles() + // test when there is no zim file available in the storage it should return the same fileName + selectedFile = File(parentFile, selectedFileName) + copyMoveFileHandler.setSelectedFileAndUri(null, DocumentFile.fromFile(selectedFile)) + destinationFile = copyMoveFileHandler.getDestinationFile() + Assert.assertEquals( + destinationFile.name, + selectedFile.name + ) + deleteBothPreviousFiles() + } } - private fun deleteBothPreviousFiles() { - kiwixMainActivity.lifecycleScope.launch { - selectedFile.deleteFile() - destinationFile.deleteFile() - } + private suspend fun deleteBothPreviousFiles() { + selectedFile.deleteFile() + destinationFile.deleteFile() } private fun deleteAllFilesInDirectory(directory: File) {