diff --git a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt index 7e5daabf4e37..465fd032f8af 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt @@ -14,9 +14,13 @@ import com.nextcloud.client.account.User import com.nextcloud.utils.extensions.getNonEncryptedSubfolders import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.operations.RefreshFolderOperation +import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.withContext @Suppress("DEPRECATION") @@ -107,7 +111,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri val operation = RefreshFolderOperation(folder, storageManager, user, context) return@withContext try { - val result = operation.execute(user, context) + val result = operation.executeCancellable() if (result.isSuccess) { Log_OC.d(TAG, "Successfully fetched metadata for: ${folder.remotePath}") true @@ -115,9 +119,21 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri Log_OC.e(TAG, "Failed to fetch metadata for: ${folder.remotePath}") false } + } catch (e: CancellationException) { + throw e } catch (e: Exception) { Log_OC.e(TAG, "Exception refreshing folder ${folder.remotePath}: ${e.message}", e) false } } + + private suspend fun RefreshFolderOperation.executeCancellable(): RemoteOperationResult<*> = coroutineScope { + val execution = async { execute(user, context) } + try { + execution.await() + } catch (e: CancellationException) { + cancel() + throw e + } + } } diff --git a/app/src/main/java/com/nextcloud/utils/extensions/OCFileExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/OCFileExtensions.kt index 371e7da30e82..3a0326a4964f 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/OCFileExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/OCFileExtensions.kt @@ -53,9 +53,7 @@ fun OCFile.isTempFile(): Boolean { return storagePath?.startsWith(appTempPath) == true } -fun OCFile?.isPNG(): Boolean { - return this != null && "image/png".equals(mimeType, ignoreCase = true) -} +fun OCFile?.isPNG(): Boolean = this != null && "image/png".equals(mimeType, ignoreCase = true) fun OCFile?.getDepth(): OCFileDepth? { if (this == null) { diff --git a/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java index 497cc1d51571..8f9f6937d3c3 100644 --- a/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java @@ -18,10 +18,10 @@ import com.nextcloud.common.NextcloudClient; import com.nextcloud.utils.ResultParser; import com.nextcloud.utils.e2ee.E2EVersionHelper; -import com.nextcloud.utils.share.UnifiedShareSharees; import com.nextcloud.utils.extensions.FileDataStorageManagerExtensionsKt; import com.nextcloud.utils.extensions.OCFileExtensionsKt; import com.nextcloud.utils.extensions.StringExtensionsKt; +import com.nextcloud.utils.share.UnifiedShareSharees; import com.owncloud.android.datamodel.ArbitraryDataProvider; import com.owncloud.android.datamodel.ArbitraryDataProviderImpl; import com.owncloud.android.datamodel.FileDataStorageManager; @@ -34,6 +34,7 @@ import com.owncloud.android.lib.common.OwnCloudClientFactory; import com.owncloud.android.lib.common.UserInfo; import com.owncloud.android.lib.common.accounts.AccountUtils; +import com.owncloud.android.lib.common.operations.OperationCancelledException; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; @@ -57,6 +58,7 @@ import java.util.List; import java.util.Map; import java.util.Vector; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import androidx.annotation.NonNull; @@ -123,6 +125,8 @@ public class RefreshFolderOperation extends RemoteOperation { */ private final AtomicInteger mFailsInKeptInSyncFound = new AtomicInteger(); + private final AtomicBoolean cancellationRequested = new AtomicBoolean(false); + /** * Map of remote and local paths to files that where locally stored in a location out of the ownCloud folder and * couldn't be copied automatically into it @@ -343,6 +347,10 @@ protected RemoteOperationResult run(OwnCloudClient client) { return result; } + public void cancel() { + cancellationRequested.set(true); + } + private void updateOCVersion(OwnCloudClient client) { UpdateOCVersionOperation update = new UpdateOCVersionOperation(user, mContext); RemoteOperationResult result = update.execute(client); @@ -489,6 +497,11 @@ private RemoteOperationResult fetchAndSyncRemoteFolder(OwnCloudClient client) { if (result.isSuccess()) { synchronizeData(result.getData()); + + if (cancellationRequested.get()) { + return new RemoteOperationResult<>(new OperationCancelledException()); + } + if (mConflictsFound.get() > 0 || mFailsInKeptInSyncFound.get() > 0) { result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT); // should be a different result code, but will do the job @@ -658,6 +671,11 @@ private void synchronizeData(List folderAndFiles) { UnifiedShareSharees.fillBlocking(user, updatedFiles); + if (cancellationRequested.get()) { + Log_OC.d(TAG, "Refresh of " + mLocalFolder.getRemotePath() + " cancelled, local data is not updated"); + return; + } + FileDataStorageManagerExtensionsKt.saveFolder(fileDataStorageManager, remoteFolder, updatedFiles,