diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index d1731b12ff..d78fb75004 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -173,4 +173,5 @@ interface BackgroundJobManager { fun scheduleInternal2WaySync(intervalMinutes: Long) fun cancelAllFilesDownloadJobs() fun syncFolder(files: List) + fun cancelSyncFolder() } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 24badc052b..e6fa062e7f 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -715,6 +715,7 @@ internal class BackgroundJobManagerImpl( workManager.enqueueUniquePeriodicWork(JOB_INTERNAL_TWO_WAY_SYNC, ExistingPeriodicWorkPolicy.UPDATE, request) } + // TODO: Add tag for chosen folder override fun syncFolder(files: List) { val filePaths = files.map { it.decryptedRemotePath } @@ -729,4 +730,9 @@ internal class BackgroundJobManagerImpl( workManager.enqueueUniqueWork(JOB_SYNC_FOLDER, ExistingWorkPolicy.REPLACE, request) } + + // TODO: Add cancellation for chosen folder + override fun cancelSyncFolder() { + TODO("Not yet implemented") + } } diff --git a/app/src/main/java/com/nextcloud/client/jobs/sync/SyncWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/sync/SyncWorker.kt index 15873f619a..53143c0867 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/sync/SyncWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/sync/SyncWorker.kt @@ -14,13 +14,15 @@ import androidx.work.CoroutineWorker import androidx.work.WorkerParameters import com.nextcloud.client.account.User import com.owncloud.android.datamodel.FileDataStorageManager +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.OwnCloudClientManagerFactory import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.ui.helpers.FileOperationsHelper import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay import kotlinx.coroutines.withContext +import java.util.Collections class SyncWorker( private val user: User, @@ -37,7 +39,7 @@ class SyncWorker( const val FILE_DOWNLOAD_COMPLETION_BROADCAST = "FILE_DOWNLOAD_COMPLETION_BROADCAST" const val FILE_PATH = "FILE_PATH" - private var downloadingFilePaths = ArrayList() + private var downloadingFilePaths = mutableListOf() /** * It is used to add the sync icon next to the file in the folder. @@ -49,45 +51,37 @@ class SyncWorker( private val notificationManager = SyncWorkerNotificationManager(context) - @Suppress("DEPRECATION", "MagicNumber") + @Suppress("TooGenericExceptionCaught") override suspend fun doWork(): Result { + Log_OC.d(TAG, "SyncWorker started") + withContext(Dispatchers.Main) { notificationManager.showStartNotification() } return withContext(Dispatchers.IO) { - Log_OC.d(TAG, "SyncWorker started") - val filePaths = inputData.getStringArray(FILE_PATHS) - - if (filePaths.isNullOrEmpty()) { - return@withContext Result.success() - } - - val fileDataStorageManager = FileDataStorageManager(user, context.contentResolver) - - // Add the topParentPath to mark the sync icon on the selected folder. - val topParentPath = getTopParentPath(fileDataStorageManager, filePaths.first()) - downloadingFilePaths = ArrayList(filePaths.toList()).apply { - add(topParentPath) - } - - val account = user.toOwnCloudAccount() - val client = OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(account, context) - - var result = true - filePaths.forEachIndexed { index, path -> - if (isStopped) { - notificationManager.dismiss() - return@withContext Result.failure() + try { + val filePaths = inputData.getStringArray(FILE_PATHS) + if (filePaths.isNullOrEmpty()) { + return@withContext Result.success() } - fileDataStorageManager.getFileByDecryptedRemotePath(path)?.let { file -> - val fileSizeInByte = file.fileLength - val availableDiskSpace = FileOperationsHelper.getAvailableSpaceOnDevice() + val storageManager = FileDataStorageManager(user, context.contentResolver) - // TODO check - if (availableDiskSpace < fileSizeInByte) { - notificationManager.showNotAvailableDiskSpace() + val topParentPath = prepareDownloadingFilePathsAndGetTopParentPath(storageManager, filePaths) + + val client = getClient() + + var result = true + filePaths.forEachIndexed { index, path -> + if (isStopped) { + notificationManager.dismiss() + return@withContext Result.failure() + } + + val file = storageManager.getFileByDecryptedRemotePath(path) ?: return@forEachIndexed + + if (!checkDiskSize(file)) { return@withContext Result.failure() } @@ -95,39 +89,82 @@ class SyncWorker( notificationManager.showProgressNotification(file.fileName, index, filePaths.size) } - delay(1000) - - val operation = DownloadFileOperation(user, file, context).execute(client) - Log_OC.d(TAG, "Syncing file: " + file.decryptedRemotePath) - - if (operation.isSuccess) { - sendFileDownloadCompletionBroadcast(path) - downloadingFilePaths.remove(path) - } else { + val syncFileResult = syncFile(file, path, client) + if (!syncFileResult) { result = false } } - } - withContext(Dispatchers.Main) { - notificationManager.showCompletionMessage(result) - } + withContext(Dispatchers.Main) { + notificationManager.showCompletionMessage(result) + } - if (result) { - downloadingFilePaths.remove(topParentPath) - sendSyncWorkerCompletionBroadcast() - Log_OC.d(TAG, "SyncWorker completed") - Result.success() - } else { - Log_OC.d(TAG, "SyncWorker failed") + if (result) { + downloadingFilePaths.remove(topParentPath) + sendSyncWorkerCompletionBroadcast() + Log_OC.d(TAG, "SyncWorker completed") + Result.success() + } else { + Log_OC.d(TAG, "SyncWorker failed") + Result.failure() + } + } catch (e: Exception) { + Log_OC.d(TAG, "SyncWorker failed reason: $e") Result.failure() } } } - private fun getTopParentPath(fileDataStorageManager: FileDataStorageManager, firstFilePath: String): String { - val firstFile = fileDataStorageManager.getFileByDecryptedRemotePath(firstFilePath) - val topParentFile = fileDataStorageManager.getTopParent(firstFile) + @Suppress("DEPRECATION") + private fun getClient(): OwnCloudClient { + val account = user.toOwnCloudAccount() + return OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(account, context) + } + + /** + * Add the topParentPath to mark the sync icon on the selected folder. + */ + private fun prepareDownloadingFilePathsAndGetTopParentPath( + storageManager: FileDataStorageManager, + filePaths: Array + ): String { + val topParentPath = getTopParentPath(storageManager, filePaths.first()) + downloadingFilePaths = Collections.synchronizedList(ArrayList(filePaths.toList())).apply { + add(topParentPath) + } + + return topParentPath + } + + private suspend fun checkDiskSize(file: OCFile): Boolean { + val fileSizeInByte = file.fileLength + val availableDiskSpace = FileOperationsHelper.getAvailableSpaceOnDevice() + + return if (availableDiskSpace < fileSizeInByte) { + notificationManager.showNotAvailableDiskSpace() + false + } else { + true + } + } + + @Suppress("DEPRECATION") + private fun syncFile(file: OCFile, path: String, client: OwnCloudClient): Boolean { + val operation = DownloadFileOperation(user, file, context).execute(client) + Log_OC.d(TAG, "Syncing file: " + file.decryptedRemotePath) + + return if (operation.isSuccess) { + sendFileDownloadCompletionBroadcast(path) + downloadingFilePaths.remove(path) + true + } else { + false + } + } + + private fun getTopParentPath(storageManager: FileDataStorageManager, firstFilePath: String): String { + val firstFile = storageManager.getFileByDecryptedRemotePath(firstFilePath) + val topParentFile = storageManager.getTopParent(firstFile) return topParentFile.decryptedRemotePath } diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 6b765c2afd..ec1c09285f 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -975,6 +975,10 @@ public class FileOperationsHelper { } } + if (file.isFolder()) { + // TODO: Call cancellation function + } + if (FileDownloadHelper.Companion.instance().isDownloading(currentUser, file)) { List files = fileActivity.getStorageManager().getAllFilesRecursivelyInsideFolder(file); FileDownloadHelper.Companion.instance().cancelPendingOrCurrentDownloads(currentUser, files);