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 a4f825ad2492..1b8eb1d08014 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -163,4 +163,5 @@ interface BackgroundJobManager { fun cancelAllJobs() fun schedulePeriodicHealthStatus() fun startHealthStatus() + fun bothFilesSyncJobsRunning(): Boolean } 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 c2117074987b..7a28404ad748 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -28,6 +28,7 @@ import com.nextcloud.client.documentscan.GeneratePdfFromImagesWork import com.nextcloud.client.jobs.download.FileDownloadWorker import com.nextcloud.client.jobs.upload.FileUploadWorker import com.nextcloud.client.preferences.AppPreferences +import com.nextcloud.utils.extensions.isWorkRunning import com.nextcloud.utils.extensions.isWorkScheduled import com.owncloud.android.datamodel.OCFile import com.owncloud.android.operations.DownloadType @@ -403,6 +404,11 @@ internal class BackgroundJobManagerImpl( workManager.cancelJob(JOB_PERIODIC_CALENDAR_BACKUP, user) } + override fun bothFilesSyncJobsRunning(): Boolean { + return workManager.isWorkRunning(JOB_PERIODIC_FILES_SYNC) && + workManager.isWorkRunning(JOB_IMMEDIATE_FILES_SYNC) + } + override fun schedulePeriodicFilesSyncJob() { val request = periodicRequestBuilder( jobClass = FilesSyncWork::class, diff --git a/app/src/main/java/com/nextcloud/client/jobs/FilesSyncWork.kt b/app/src/main/java/com/nextcloud/client/jobs/FilesSyncWork.kt index 88990164c5d7..52a2ac224593 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/FilesSyncWork.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/FilesSyncWork.kt @@ -91,18 +91,50 @@ class FilesSyncWork( setForegroundAsync(foregroundInfo) } + private fun canExitEarly(changedFiles: Array?): Boolean { + var canExitEarly = false + // If we are in power save mode better to postpone scan and upload + val overridePowerSaving = inputData.getBoolean(OVERRIDE_POWER_SAVING, false) + if ((powerManagementService.isPowerSavingEnabled && !overridePowerSaving)) { + canExitEarly = true + } + + // or sync worker already running and no changed files to be processed + val alreadyRunning = backgroundJobManager.bothFilesSyncJobsRunning() + if (alreadyRunning && changedFiles.isNullOrEmpty()) { + Log_OC.d(TAG, "File-sync kill worker since another instance of the worker seems to be running already!") + canExitEarly = true + } + + if (!syncedFolderProvider.syncedFolders.any { it.isEnabled }) { + Log_OC.d(TAG, "File-sync kill worker since no sync folder is enabled!") + canExitEarly = true + } + + if (syncedFolderProvider.syncedFolders.all { it.isChargingOnly } && + !powerManagementService.battery.isCharging && + !powerManagementService.battery.isFull + ) { + Log_OC.d(TAG, "File-sync kill worker since phone is not charging!") + canExitEarly = true + } + + return canExitEarly + } + @Suppress("MagicNumber") override fun doWork(): Result { backgroundJobManager.logStartOfWorker(BackgroundJobManagerImpl.formatClassTag(this::class)) Log_OC.d(TAG, "File-sync worker started") - val overridePowerSaving = inputData.getBoolean(OVERRIDE_POWER_SAVING, false) - // If we are in power save mode, better to postpone upload - if (powerManagementService.isPowerSavingEnabled && !overridePowerSaving) { + val changedFiles = inputData.getStringArray(CHANGED_FILES) + + if (canExitEarly(changedFiles)) { val result = Result.success() backgroundJobManager.logEndOfWorker(BackgroundJobManagerImpl.formatClassTag(this::class), result) return result } + val resources = context.resources val lightVersion = resources.getBoolean(R.bool.syncedFolder_light) FilesSyncHelper.restartJobsIfNeeded( @@ -113,7 +145,6 @@ class FilesSyncWork( ) // Get changed files from ContentObserverWork (only images and videos) or by scanning filesystem - val changedFiles = inputData.getStringArray(CHANGED_FILES) Log_OC.d(TAG, "File-sync worker changed files from observer: " + changedFiles.contentToString()) collectChangedFiles(changedFiles) Log_OC.d(TAG, "File-sync worker finished checking files.") @@ -157,7 +188,7 @@ class FilesSyncWork( // Check every file in every synced folder for changes and update // filesystemDataProvider database (potentially needs a long time so use foreground worker) updateForegroundWorker(5, true) - FilesSyncHelper.insertAllDBEntries(syncedFolderProvider) + FilesSyncHelper.insertAllDBEntries(syncedFolderProvider, powerManagementService) updateForegroundWorker(50, true) } } diff --git a/app/src/main/java/com/nextcloud/utils/extensions/WorkManagerExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/WorkManagerExtensions.kt index cbd059801677..6e285cc2dab5 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/WorkManagerExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/WorkManagerExtensions.kt @@ -13,23 +13,24 @@ import com.google.common.util.concurrent.ListenableFuture import com.owncloud.android.lib.common.utils.Log_OC import java.util.concurrent.ExecutionException -fun WorkManager.isWorkScheduled(tag: String): Boolean { - val statuses: ListenableFuture> = this.getWorkInfosByTag(tag) - var running = false +private const val TAG = "WorkManager" + +fun WorkManager.isWorkRunning(tag: String): Boolean = checkWork(tag, listOf(WorkInfo.State.RUNNING)) + +fun WorkManager.isWorkScheduled(tag: String): Boolean = + checkWork(tag, listOf(WorkInfo.State.RUNNING, WorkInfo.State.ENQUEUED)) + +private fun WorkManager.checkWork(tag: String, stateConditions: List): Boolean { + val statuses: ListenableFuture> = getWorkInfosByTag(tag) var workInfoList: List = emptyList() try { workInfoList = statuses.get() } catch (e: ExecutionException) { - Log_OC.d("Worker", "ExecutionException in isWorkScheduled: $e") + Log_OC.d(TAG, "ExecutionException in checkWork: $e") } catch (e: InterruptedException) { - Log_OC.d("Worker", "InterruptedException in isWorkScheduled: $e") - } - - for (workInfo in workInfoList) { - val state = workInfo.state - running = running || (state == WorkInfo.State.RUNNING || state == WorkInfo.State.ENQUEUED) + Log_OC.d(TAG, "InterruptedException in checkWork: $e") } - return running + return workInfoList.any { workInfo -> stateConditions.contains(workInfo.state) } } diff --git a/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java b/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java index 5f31b88a10b8..941771b11873 100644 --- a/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java +++ b/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java @@ -145,9 +145,15 @@ private static void insertAllDBEntriesForSyncedFolder(SyncedFolder syncedFolder) } } - public static void insertAllDBEntries(SyncedFolderProvider syncedFolderProvider) { + public static void insertAllDBEntries(SyncedFolderProvider syncedFolderProvider, + PowerManagementService powerManagementService) { for (SyncedFolder syncedFolder : syncedFolderProvider.getSyncedFolders()) { - if (syncedFolder.isEnabled()) { + if (syncedFolder.isEnabled() && + !(syncedFolder.isChargingOnly() && + !powerManagementService.getBattery().isCharging() && + !powerManagementService.getBattery().isFull() + ) + ) { insertAllDBEntriesForSyncedFolder(syncedFolder); } }