From 4af306abef49281c20cf1e65c674afb0cd797d4d Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 22 Sep 2026 09:53:21 +0200 Subject: [PATCH 1/4] fix(auto-upload): rescan periodic worker Signed-off-by: alperozturk96 --- .../nextcloud/client/jobs/BackgroundJobManager.kt | 1 + .../client/jobs/BackgroundJobManagerImpl.kt | 3 +++ .../jobs/autoUpload/AutoUploadRescanWorker.kt | 5 ++--- .../com/owncloud/android/utils/FilesSyncHelper.kt | 13 +++++++++++++ 4 files changed, 19 insertions(+), 3 deletions(-) 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 030359d57e31..2ee6dd3efca8 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -145,6 +145,7 @@ interface BackgroundJobManager { fun startAlbumFilesUploadJob(user: User, uploadIds: LongArray, albumName: String) fun getFileUploads(user: User): LiveData> fun cancelFilesUploadJob(user: User) + fun isAutoUploadScheduled(syncedFolderID: Long): Boolean fun isStartFileUploadJobScheduled(accountName: String): Boolean fun isAutoUploadIgnoringPowerSavingScheduled(syncedFolderID: Long): Boolean fun schedulePeriodicAutoUpload() 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 12b6ffc52ced..f039e00542b4 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -490,6 +490,9 @@ internal class BackgroundJobManagerImpl( workManager.enqueueUniqueWork(JOB_CONTENT_OBSERVER, ExistingWorkPolicy.REPLACE, request) } + override fun isAutoUploadScheduled(syncedFolderID: Long): Boolean = + workManager.isWorkScheduled(autoUploadWorkName(syncedFolderID)) + private fun autoUploadWorkName(syncedFolderID: Long): String = JOB_IMMEDIATE_FILES_SYNC + "_" + syncedFolderID private fun autoUploadIgnorePowerSavingTag(syncedFolderID: Long): String = diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadRescanWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadRescanWorker.kt index a512a6102ae2..8389c797be03 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadRescanWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadRescanWorker.kt @@ -29,10 +29,9 @@ class AutoUploadRescanWorker( } override suspend fun doWork(): Result = withContext(Dispatchers.IO) { - val requestedFolders = FilesSyncHelper.startAutoUploadForEnabledSyncedFolders( + val requestedFolders = FilesSyncHelper.startAutoUploadForEnabledSyncedFoldersIfNotActive( syncedFolderProvider, - backgroundJobManager, - false + backgroundJobManager ) Log_OC.d(TAG, "requested auto upload for $requestedFolders folder(s)") diff --git a/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.kt b/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.kt index 673040d0b65b..da410ec9de63 100644 --- a/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.kt +++ b/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.kt @@ -41,6 +41,19 @@ object FilesSyncHelper { ) } + fun startAutoUploadForEnabledSyncedFoldersIfNotActive( + provider: SyncedFolderProvider, + manager: BackgroundJobManager + ) { + val folders = provider.syncedFolders.filter { it.isEnabled } + if (folders.isEmpty()) return + + val notScheduledFolders = folders.filter { !manager.isAutoUploadScheduled(it.id) } + if (notScheduledFolders.isEmpty()) return + + notScheduledFolders.forEach { manager.startAutoUpload(it) } + } + @JvmStatic fun startAutoUploadForEnabledSyncedFolders( provider: SyncedFolderProvider, From e87c312a95eee1175ccd8525746b143368f0c5ca Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 22 Sep 2026 10:37:59 +0200 Subject: [PATCH 2/4] cancel per folder first Signed-off-by: alperozturk96 --- .../nextcloud/client/jobs/BackgroundJobManager.kt | 1 + .../client/jobs/BackgroundJobManagerImpl.kt | 15 ++++++++++++--- .../jobs/autoUpload/AutoUploadRescanWorker.kt | 2 ++ .../com/owncloud/android/utils/FilesSyncHelper.kt | 13 +++++++------ 4 files changed, 22 insertions(+), 9 deletions(-) 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 2ee6dd3efca8..e69b3e0aaf16 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -149,6 +149,7 @@ interface BackgroundJobManager { fun isStartFileUploadJobScheduled(accountName: String): Boolean fun isAutoUploadIgnoringPowerSavingScheduled(syncedFolderID: Long): Boolean fun schedulePeriodicAutoUpload() + fun cancelLegacyPerFolderPeriodicAutoUpload() fun cancelFilesDownloadJob(accountName: String, fileId: Long) @Suppress("LongParameterList") 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 f039e00542b4..c49d8374c1f5 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -490,17 +490,26 @@ internal class BackgroundJobManagerImpl( workManager.enqueueUniqueWork(JOB_CONTENT_OBSERVER, ExistingWorkPolicy.REPLACE, request) } - override fun isAutoUploadScheduled(syncedFolderID: Long): Boolean = - workManager.isWorkScheduled(autoUploadWorkName(syncedFolderID)) - private fun autoUploadWorkName(syncedFolderID: Long): String = JOB_IMMEDIATE_FILES_SYNC + "_" + syncedFolderID + override fun isAutoUploadScheduled(syncedFolderID: Long): Boolean = + workManager.getWorkInfosForUniqueWork(autoUploadWorkName(syncedFolderID)) + .get() + .any { !it.state.isFinished } + private fun autoUploadIgnorePowerSavingTag(syncedFolderID: Long): String = autoUploadWorkName(syncedFolderID) + "_" + TAG_SUFFIX_IGNORE_POWER_SAVING override fun isAutoUploadIgnoringPowerSavingScheduled(syncedFolderID: Long): Boolean = workManager.isWorkScheduled(autoUploadIgnorePowerSavingTag(syncedFolderID)) + override fun cancelLegacyPerFolderPeriodicAutoUpload() { + workManager.getWorkInfosByTag(formatClassTag(AutoUploadWorker::class)) + .get() + .filter { !it.state.isFinished && it.periodicityInfo != null } + .forEach { workManager.cancelWorkById(it.id).result.get() } + } + override fun schedulePeriodicAutoUpload() { val request = periodicRequestBuilder( jobClass = AutoUploadRescanWorker::class, diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadRescanWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadRescanWorker.kt index 8389c797be03..71d34c3b0ba6 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadRescanWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadRescanWorker.kt @@ -29,6 +29,8 @@ class AutoUploadRescanWorker( } override suspend fun doWork(): Result = withContext(Dispatchers.IO) { + backgroundJobManager.cancelLegacyPerFolderPeriodicAutoUpload() + val requestedFolders = FilesSyncHelper.startAutoUploadForEnabledSyncedFoldersIfNotActive( syncedFolderProvider, backgroundJobManager diff --git a/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.kt b/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.kt index da410ec9de63..de00fd8401db 100644 --- a/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.kt +++ b/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.kt @@ -44,14 +44,15 @@ object FilesSyncHelper { fun startAutoUploadForEnabledSyncedFoldersIfNotActive( provider: SyncedFolderProvider, manager: BackgroundJobManager - ) { - val folders = provider.syncedFolders.filter { it.isEnabled } - if (folders.isEmpty()) return + ): Int { + val startedFolders = provider.syncedFolders + .filter { it.isEnabled } + .filterNot { manager.isAutoUploadScheduled(it.id) } + .onEach { manager.startAutoUpload(it) } - val notScheduledFolders = folders.filter { !manager.isAutoUploadScheduled(it.id) } - if (notScheduledFolders.isEmpty()) return + Log_OC.d(TAG, "start auto upload for ${startedFolders.size} not already active folder(s)") - notScheduledFolders.forEach { manager.startAutoUpload(it) } + return startedFolders.size } @JvmStatic From 882f59c4b9633df538f6154c3ae74cb6c31d2296 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 22 Sep 2026 10:47:41 +0200 Subject: [PATCH 3/4] retry if already auto upload runs Signed-off-by: alperozturk96 --- .../client/jobs/BackgroundJobManager.kt | 2 +- .../client/jobs/BackgroundJobManagerImpl.kt | 16 ++++++++++------ .../jobs/autoUpload/AutoUploadRescanWorker.kt | 4 +++- 3 files changed, 14 insertions(+), 8 deletions(-) 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 e69b3e0aaf16..b0b2e4a17d0e 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -149,7 +149,7 @@ interface BackgroundJobManager { fun isStartFileUploadJobScheduled(accountName: String): Boolean fun isAutoUploadIgnoringPowerSavingScheduled(syncedFolderID: Long): Boolean fun schedulePeriodicAutoUpload() - fun cancelLegacyPerFolderPeriodicAutoUpload() + fun isAnyAutoUploadScheduled(): Boolean fun cancelFilesDownloadJob(accountName: String, fileId: Long) @Suppress("LongParameterList") 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 c49d8374c1f5..2f326e98e870 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -503,11 +503,9 @@ internal class BackgroundJobManagerImpl( override fun isAutoUploadIgnoringPowerSavingScheduled(syncedFolderID: Long): Boolean = workManager.isWorkScheduled(autoUploadIgnorePowerSavingTag(syncedFolderID)) - override fun cancelLegacyPerFolderPeriodicAutoUpload() { - workManager.getWorkInfosByTag(formatClassTag(AutoUploadWorker::class)) - .get() - .filter { !it.state.isFinished && it.periodicityInfo != null } - .forEach { workManager.cancelWorkById(it.id).result.get() } + override fun isAnyAutoUploadScheduled(): Boolean { + return workManager.getWorkInfosByTag(formatClassTag(AutoUploadWorker::class)) + .get().any { !it.state.isFinished } } override fun schedulePeriodicAutoUpload() { @@ -515,7 +513,13 @@ internal class BackgroundJobManagerImpl( jobClass = AutoUploadRescanWorker::class, jobName = JOB_PERIODIC_FILES_SYNC, constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build() - ).build() + ) + .setBackoffCriteria( + BackoffPolicy.LINEAR, + DEFAULT_PERIODIC_JOB_INTERVAL_MINUTES, + TimeUnit.MINUTES + ) + .build() workManager.enqueueUniquePeriodicWork(JOB_PERIODIC_FILES_SYNC, ExistingPeriodicWorkPolicy.KEEP, request) } diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadRescanWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadRescanWorker.kt index 71d34c3b0ba6..9f34aced642d 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadRescanWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadRescanWorker.kt @@ -29,7 +29,9 @@ class AutoUploadRescanWorker( } override suspend fun doWork(): Result = withContext(Dispatchers.IO) { - backgroundJobManager.cancelLegacyPerFolderPeriodicAutoUpload() + if (backgroundJobManager.isAnyAutoUploadScheduled()) { + return@withContext Result.retry() + } val requestedFolders = FilesSyncHelper.startAutoUploadForEnabledSyncedFoldersIfNotActive( syncedFolderProvider, From a6363864a3cca4d3ba5cd43601729f16289b51d4 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 22 Sep 2026 10:59:51 +0200 Subject: [PATCH 4/4] cancel enqueued ones so that we can re-start. Some workers may stuck thus we need to have clean start. Signed-off-by: alperozturk96 --- .../client/jobs/BackgroundJobManager.kt | 2 +- .../client/jobs/BackgroundJobManagerImpl.kt | 16 ++++++---------- .../jobs/autoUpload/AutoUploadRescanWorker.kt | 6 +++--- 3 files changed, 10 insertions(+), 14 deletions(-) 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 b0b2e4a17d0e..eca99280e462 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -149,7 +149,7 @@ interface BackgroundJobManager { fun isStartFileUploadJobScheduled(accountName: String): Boolean fun isAutoUploadIgnoringPowerSavingScheduled(syncedFolderID: Long): Boolean fun schedulePeriodicAutoUpload() - fun isAnyAutoUploadScheduled(): Boolean + fun cancelEnqueuedAutoUploads() fun cancelFilesDownloadJob(accountName: String, fileId: Long) @Suppress("LongParameterList") 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 2f326e98e870..8058bcc435d3 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -503,9 +503,11 @@ internal class BackgroundJobManagerImpl( override fun isAutoUploadIgnoringPowerSavingScheduled(syncedFolderID: Long): Boolean = workManager.isWorkScheduled(autoUploadIgnorePowerSavingTag(syncedFolderID)) - override fun isAnyAutoUploadScheduled(): Boolean { - return workManager.getWorkInfosByTag(formatClassTag(AutoUploadWorker::class)) - .get().any { !it.state.isFinished } + override fun cancelEnqueuedAutoUploads() { + workManager.getWorkInfosByTag(formatClassTag(AutoUploadWorker::class)) + .get() + .filter { it.state == WorkInfo.State.ENQUEUED && it.periodicityInfo != null } + .forEach { workManager.cancelWorkById(it.id) } } override fun schedulePeriodicAutoUpload() { @@ -513,13 +515,7 @@ internal class BackgroundJobManagerImpl( jobClass = AutoUploadRescanWorker::class, jobName = JOB_PERIODIC_FILES_SYNC, constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build() - ) - .setBackoffCriteria( - BackoffPolicy.LINEAR, - DEFAULT_PERIODIC_JOB_INTERVAL_MINUTES, - TimeUnit.MINUTES - ) - .build() + ).build() workManager.enqueueUniquePeriodicWork(JOB_PERIODIC_FILES_SYNC, ExistingPeriodicWorkPolicy.KEEP, request) } diff --git a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadRescanWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadRescanWorker.kt index 9f34aced642d..4ac19f358735 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadRescanWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/autoUpload/AutoUploadRescanWorker.kt @@ -29,9 +29,9 @@ class AutoUploadRescanWorker( } override suspend fun doWork(): Result = withContext(Dispatchers.IO) { - if (backgroundJobManager.isAnyAutoUploadScheduled()) { - return@withContext Result.retry() - } + // cancel enqueued ones so that we can re-start. Some workers may stuck + // thus we need to have clean start. + backgroundJobManager.cancelEnqueuedAutoUploads() val requestedFolders = FilesSyncHelper.startAutoUploadForEnabledSyncedFoldersIfNotActive( syncedFolderProvider,