From 746beb84ed87a21b2dfbb802fce1029895e44ba8 Mon Sep 17 00:00:00 2001 From: cketti Date: Wed, 6 May 2020 13:44:25 +0200 Subject: [PATCH 1/8] Check if periodic mail sync is disabled in MailSyncWorker --- .../fsck/k9/controller/MessagingController.java | 6 +++--- .../main/java/com/fsck/k9/job/MailSyncWorker.kt | 17 +++++++++++++++-- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java index 620cf0cf9..9fb3989ab 100644 --- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java +++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java @@ -2264,7 +2264,7 @@ public class MessagingController { context.startActivity(chooserIntent); } - public void checkMailBlocking(Account account) { + public void performPeriodicMailSync(Account account) { final CountDownLatch latch = new CountDownLatch(1); checkMail(context, account, true, false, new SimpleMessagingListener() { @Override @@ -2273,11 +2273,11 @@ public class MessagingController { } }); - Timber.v("checkMailBlocking(%s) about to await latch release", account.getDescription()); + Timber.v("performPeriodicMailSync(%s) about to await latch release", account.getDescription()); try { latch.await(); - Timber.v("checkMailBlocking(%s) got latch release", account.getDescription()); + Timber.v("performPeriodicMailSync(%s) got latch release", account.getDescription()); } catch (Exception e) { Timber.e(e, "Interrupted while awaiting latch release"); } diff --git a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt index 5ad34721c..a376b389e 100644 --- a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt +++ b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt @@ -4,6 +4,7 @@ import android.content.ContentResolver import android.content.Context import androidx.work.Worker import androidx.work.WorkerParameters +import com.fsck.k9.Account import com.fsck.k9.K9 import com.fsck.k9.Preferences import com.fsck.k9.controller.MessagingController @@ -27,10 +28,19 @@ class MailSyncWorker( return Result.success() } - preferences.getAccount(accountUuid)?.let { account -> - messagingController.checkMailBlocking(account) + val account = preferences.getAccount(accountUuid) + if (account == null) { + Timber.e("Account %s not found. Can't perform mail sync.", accountUuid) + return Result.failure() } + if (account.isPeriodicMailSyncDisabled) { + Timber.d("Periodic mail sync has been disabled for this account. Skipping mail sync.") + return Result.success() + } + + messagingController.performPeriodicMailSync(account) + return Result.success() } @@ -42,6 +52,9 @@ class MailSyncWorker( } } + private val Account.isPeriodicMailSyncDisabled + get() = automaticCheckIntervalMinutes <= 0 + companion object { const val EXTRA_ACCOUNT_UUID = "accountUuid" } From fad2d91f72f36d1bfd941ae307e70d6428e28dde Mon Sep 17 00:00:00 2001 From: cketti Date: Wed, 6 May 2020 14:07:01 +0200 Subject: [PATCH 2/8] Fix check to not sync a folder if it was checked recently --- .../k9/controller/MessagingController.java | 87 ++++++++----------- 1 file changed, 36 insertions(+), 51 deletions(-) diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java index 9fb3989ab..47b697cf1 100644 --- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java +++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java @@ -2357,11 +2357,6 @@ public class MessagingController { Timber.i("Skipping synchronizing unavailable account %s", account.getDescription()); return; } - final long accountInterval = account.getAutomaticCheckIntervalMinutes() * 60 * 1000; - if (!ignoreLastCheckedTime && accountInterval <= 0) { - Timber.i("Skipping synchronizing account %s", account.getDescription()); - return; - } Timber.i("Synchronizing account %s", account.getDescription()); @@ -2403,7 +2398,7 @@ public class MessagingController { continue; } - synchronizeFolder(account, folder, ignoreLastCheckedTime, accountInterval, listener); + synchronizeFolder(account, folder, ignoreLastCheckedTime, listener); } } catch (MessagingException e) { Timber.e(e, "Unable to synchronize account %s", account.getName()); @@ -2425,57 +2420,47 @@ public class MessagingController { } + private void synchronizeFolder(Account account, LocalFolder folder, boolean ignoreLastCheckedTime, + MessagingListener listener) { + putBackground("sync" + folder.getServerId(), null, () -> { + synchronizeFolderInBackground(account, folder, ignoreLastCheckedTime, listener); + }); + } - private void synchronizeFolder( - final Account account, - final LocalFolder folder, - final boolean ignoreLastCheckedTime, - final long accountInterval, - final MessagingListener listener) { - + private void synchronizeFolderInBackground(Account account, LocalFolder folder, boolean ignoreLastCheckedTime, + MessagingListener listener) { Timber.v("Folder %s was last synced @ %tc", folder.getServerId(), folder.getLastChecked()); - if (!ignoreLastCheckedTime && folder.getLastChecked() > System.currentTimeMillis() - accountInterval) { - Timber.v("Not syncing folder %s, previously synced @ %tc which would be too recent for the account " + - "period", folder.getServerId(), folder.getLastChecked()); - return; + if (!ignoreLastCheckedTime) { + long lastCheckedTime = folder.getLastChecked(); + long now = System.currentTimeMillis(); + + if (lastCheckedTime > now) { + // The time this folder was last checked lies in the future. We better ignore this and sync now. + } else { + long syncInterval = account.getAutomaticCheckIntervalMinutes() * 60L * 1000L; + long nextSyncTime = lastCheckedTime + syncInterval; + if (nextSyncTime > now) { + Timber.v("Not syncing folder %s, previously synced @ %tc which would be too recent for the " + + "account sync interval", folder.getServerId(), lastCheckedTime); + return; + } + } } - putBackground("sync" + folder.getServerId(), null, new Runnable() { - @Override - public void run() { - LocalFolder tLocalFolder = null; - try { - // In case multiple Commands get enqueued, don't run more than - // once - final LocalStore localStore = localStoreProvider.getInstance(account); - tLocalFolder = localStore.getFolder(folder.getServerId()); - tLocalFolder.open(); - - if (!ignoreLastCheckedTime && tLocalFolder.getLastChecked() > - (System.currentTimeMillis() - accountInterval)) { - Timber.v("Not running Command for folder %s, previously synced @ %tc which would " + - "be too recent for the account period", - folder.getServerId(), folder.getLastChecked()); - return; - } - showFetchingMailNotificationIfNecessary(account, folder); - try { - synchronizeMailboxSynchronous(account, folder.getDatabaseId(), listener); - } finally { - clearFetchingMailNotificationIfNecessary(account); - } - } catch (Exception e) { - Timber.e(e, "Exception while processing folder %s:%s", - account.getDescription(), folder.getServerId()); - } finally { - closeFolder(tLocalFolder); - } - } - } - ); - + try { + showFetchingMailNotificationIfNecessary(account, folder); + try { + synchronizeMailboxSynchronous(account, folder.getDatabaseId(), listener); + long now = System.currentTimeMillis(); + folder.setLastChecked(now); + } finally { + clearFetchingMailNotificationIfNecessary(account); + } + } catch (Exception e) { + Timber.e(e, "Exception while processing folder %s:%s", account.getDescription(), folder.getServerId()); + } } private void showFetchingMailNotificationIfNecessary(Account account, LocalFolder folder) { From c30911cbf6bc53f25aefccc42e42f54c51fa36bb Mon Sep 17 00:00:00 2001 From: cketti Date: Wed, 6 May 2020 14:12:19 +0200 Subject: [PATCH 3/8] Check last sync time when performing periodic syncs --- .../main/java/com/fsck/k9/controller/MessagingController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java index 47b697cf1..2f3f87963 100644 --- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java +++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java @@ -2266,7 +2266,7 @@ public class MessagingController { public void performPeriodicMailSync(Account account) { final CountDownLatch latch = new CountDownLatch(1); - checkMail(context, account, true, false, new SimpleMessagingListener() { + checkMail(context, account, false, false, new SimpleMessagingListener() { @Override public void checkMailFinished(Context context, Account account) { latch.countDown(); From 35aac53e10c68ecae26ca80ac1d0442d5916a43e Mon Sep 17 00:00:00 2001 From: cketti Date: Wed, 6 May 2020 15:04:02 +0200 Subject: [PATCH 4/8] Disable mail sync job when 'background sync' is set to 'never' --- .../src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt index b1c10a070..ad98fdae1 100644 --- a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt +++ b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt @@ -7,12 +7,15 @@ import androidx.work.PeriodicWorkRequestBuilder import androidx.work.WorkManager import androidx.work.workDataOf import com.fsck.k9.Account +import com.fsck.k9.K9 import java.util.concurrent.TimeUnit import timber.log.Timber class MailSyncWorkerManager(private val workManager: WorkManager) { fun scheduleMailSync(account: Account) { + if (isNeverSyncInBackground()) return + getSyncIntervalInMinutesIfEnabled(account)?.let { syncInterval -> Timber.v("Scheduling mail sync worker for %s", account.description) @@ -34,6 +37,8 @@ class MailSyncWorkerManager(private val workManager: WorkManager) { } } + private fun isNeverSyncInBackground() = K9.backgroundOps == K9.BACKGROUND_OPS.NEVER + private fun getSyncIntervalInMinutesIfEnabled(account: Account): Long? { val intervalMinutes = account.automaticCheckIntervalMinutes if (intervalMinutes <= Account.INTERVAL_MINUTES_NEVER) { From 1e21f94e1c6fc5d387c516a5b0cd33eae46be464 Mon Sep 17 00:00:00 2001 From: cketti Date: Wed, 6 May 2020 15:37:02 +0200 Subject: [PATCH 5/8] Only reschedule sync job for the account whose settings were changed --- .../main/java/com/fsck/k9/job/K9JobManager.kt | 16 +++++++++++----- .../com/fsck/k9/job/MailSyncWorkerManager.kt | 6 ++++++ .../settings/account/AccountSettingsDataStore.kt | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/app/core/src/main/java/com/fsck/k9/job/K9JobManager.kt b/app/core/src/main/java/com/fsck/k9/job/K9JobManager.kt index b1de21507..68545cc3c 100644 --- a/app/core/src/main/java/com/fsck/k9/job/K9JobManager.kt +++ b/app/core/src/main/java/com/fsck/k9/job/K9JobManager.kt @@ -1,6 +1,7 @@ package com.fsck.k9.job import androidx.work.WorkManager +import com.fsck.k9.Account import com.fsck.k9.Preferences import timber.log.Timber @@ -14,7 +15,16 @@ class K9JobManager( scheduleMailSync() } - fun scheduleMailSync() { + fun scheduleMailSync(account: Account) { + mailSyncWorkerManager.cancelMailSync(account) + mailSyncWorkerManager.scheduleMailSync(account) + } + + fun schedulePusherRefresh() { + // Push is temporarily disabled. See GH-4253 + } + + private fun scheduleMailSync() { cancelAllMailSyncJobs() preferences.availableAccounts?.forEach { account -> @@ -22,10 +32,6 @@ class K9JobManager( } } - fun schedulePusherRefresh() { - // Push is temporarily disabled. See GH-4253 - } - private fun cancelAllMailSyncJobs() { Timber.v("canceling mail sync job") workManager.cancelAllWorkByTag(MailSyncWorkerManager.MAIL_SYNC_TAG) diff --git a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt index ad98fdae1..fc63da973 100644 --- a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt +++ b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt @@ -13,6 +13,12 @@ import timber.log.Timber class MailSyncWorkerManager(private val workManager: WorkManager) { + fun cancelMailSync(account: Account) { + Timber.v("Canceling mail sync worker for %s", account.description) + val uniqueWorkName = createUniqueWorkName(account.uuid) + workManager.cancelUniqueWork(uniqueWorkName) + } + fun scheduleMailSync(account: Account) { if (isNeverSyncInBackground()) return diff --git a/app/ui/src/main/java/com/fsck/k9/ui/settings/account/AccountSettingsDataStore.kt b/app/ui/src/main/java/com/fsck/k9/ui/settings/account/AccountSettingsDataStore.kt index 79a41f987..ed1d23b98 100644 --- a/app/ui/src/main/java/com/fsck/k9/ui/settings/account/AccountSettingsDataStore.kt +++ b/app/ui/src/main/java/com/fsck/k9/ui/settings/account/AccountSettingsDataStore.kt @@ -215,7 +215,7 @@ class AccountSettingsDataStore( } private fun reschedulePoll() { - jobManager.scheduleMailSync() + jobManager.scheduleMailSync(account) } private fun restartPushers() { From a224291532c818f47003df8e71da35f8c2b75a25 Mon Sep 17 00:00:00 2001 From: cketti Date: Wed, 6 May 2020 16:34:22 +0200 Subject: [PATCH 6/8] Save last sync time --- app/core/src/main/java/com/fsck/k9/Account.java | 9 +++++++++ .../com/fsck/k9/AccountPreferenceSerializer.kt | 4 ++++ .../fsck/k9/controller/MessagingController.java | 15 +++++++++++++++ .../java/com/fsck/k9/helper/MutableBoolean.kt | 3 +++ 4 files changed, 31 insertions(+) create mode 100644 app/core/src/main/java/com/fsck/k9/helper/MutableBoolean.kt diff --git a/app/core/src/main/java/com/fsck/k9/Account.java b/app/core/src/main/java/com/fsck/k9/Account.java index fa92209d9..97b94fa38 100644 --- a/app/core/src/main/java/com/fsck/k9/Account.java +++ b/app/core/src/main/java/com/fsck/k9/Account.java @@ -189,6 +189,7 @@ public class Account implements BaseAccount { private boolean remoteSearchFullText; private int remoteSearchNumResults; private boolean uploadSentMessages; + private long lastSyncTime; private boolean changedVisibleLimits = false; @@ -1125,6 +1126,14 @@ public class Account implements BaseAccount { remoteSearchFullText = val; } + public synchronized long getLastSyncTime() { + return lastSyncTime; + } + + public synchronized void setLastSyncTime(long lastSyncTime) { + this.lastSyncTime = lastSyncTime; + } + boolean isChangedVisibleLimits() { return changedVisibleLimits; } diff --git a/app/core/src/main/java/com/fsck/k9/AccountPreferenceSerializer.kt b/app/core/src/main/java/com/fsck/k9/AccountPreferenceSerializer.kt index a73619312..456215688 100644 --- a/app/core/src/main/java/com/fsck/k9/AccountPreferenceSerializer.kt +++ b/app/core/src/main/java/com/fsck/k9/AccountPreferenceSerializer.kt @@ -162,6 +162,7 @@ class AccountPreferenceSerializer( isMarkMessageAsReadOnView = storage.getBoolean("$accountUuid.markMessageAsReadOnView", true) isMarkMessageAsReadOnDelete = storage.getBoolean("$accountUuid.markMessageAsReadOnDelete", true) isAlwaysShowCcBcc = storage.getBoolean("$accountUuid.alwaysShowCcBcc", false) + lastSyncTime = storage.getLong("$accountUuid.lastSyncTime", 0L) // Use email address as account description if necessary if (description == null) { @@ -321,6 +322,7 @@ class AccountPreferenceSerializer( editor.putString("$accountUuid.ringtone", notificationSetting.ringtone) editor.putBoolean("$accountUuid.led", notificationSetting.isLedEnabled) editor.putInt("$accountUuid.ledColor", notificationSetting.ledColor) + editor.putLong("$accountUuid.lastSyncTime", lastSyncTime) for (type in NetworkType.values()) { val useCompression = compressionMap[type] @@ -443,6 +445,7 @@ class AccountPreferenceSerializer( editor.remove("$accountUuid.archiveFolderId") editor.remove("$accountUuid.spamFolderId") editor.remove("$accountUuid.autoExpandFolderId") + editor.remove("$accountUuid.lastSyncTime") for (type in NetworkType.values()) { editor.remove("$accountUuid.useCompression." + type.name) @@ -581,6 +584,7 @@ class AccountPreferenceSerializer( isMarkMessageAsReadOnView = true isMarkMessageAsReadOnDelete = true isAlwaysShowCcBcc = false + lastSyncTime = 0L setArchiveFolderId(null, SpecialFolderSelection.AUTOMATIC) setDraftsFolderId(null, SpecialFolderSelection.AUTOMATIC) diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java index 2f3f87963..b6f26db06 100644 --- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java +++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java @@ -56,6 +56,7 @@ import com.fsck.k9.controller.MessagingControllerCommands.PendingMoveOrCopy; import com.fsck.k9.controller.MessagingControllerCommands.PendingSetFlag; import com.fsck.k9.controller.ProgressBodyFactory.ProgressListener; import com.fsck.k9.helper.Contacts; +import com.fsck.k9.helper.MutableBoolean; import com.fsck.k9.mail.Address; import com.fsck.k9.mail.AuthenticationFailedException; import com.fsck.k9.mail.CertificateValidationException; @@ -2266,11 +2267,17 @@ public class MessagingController { public void performPeriodicMailSync(Account account) { final CountDownLatch latch = new CountDownLatch(1); + MutableBoolean syncError = new MutableBoolean(false); checkMail(context, account, false, false, new SimpleMessagingListener() { @Override public void checkMailFinished(Context context, Account account) { latch.countDown(); } + + @Override + public void synchronizeMailboxFailed(Account account, long folderId, String message) { + syncError.setValue(true); + } }); Timber.v("performPeriodicMailSync(%s) about to await latch release", account.getDescription()); @@ -2281,6 +2288,14 @@ public class MessagingController { } catch (Exception e) { Timber.e(e, "Interrupted while awaiting latch release"); } + + boolean success = !syncError.getValue(); + if (success) { + long now = System.currentTimeMillis(); + Timber.v("Account %s successfully synced @ %tc", account, now); + account.setLastSyncTime(now); + Preferences.getPreferences(context).saveAccount(account); + } } /** diff --git a/app/core/src/main/java/com/fsck/k9/helper/MutableBoolean.kt b/app/core/src/main/java/com/fsck/k9/helper/MutableBoolean.kt new file mode 100644 index 000000000..e0d35179f --- /dev/null +++ b/app/core/src/main/java/com/fsck/k9/helper/MutableBoolean.kt @@ -0,0 +1,3 @@ +package com.fsck.k9.helper + +class MutableBoolean(var value: Boolean) From 76f1d37bc1f8b3bc67a467221d3ac15f625b7a1b Mon Sep 17 00:00:00 2001 From: cketti Date: Wed, 6 May 2020 17:03:24 +0200 Subject: [PATCH 7/8] Use last sync time to calculate initial delay for periodic syncs --- .../main/java/com/fsck/k9/job/KoinModule.kt | 3 +- .../com/fsck/k9/job/MailSyncWorkerManager.kt | 46 +++++++++++++------ 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/app/core/src/main/java/com/fsck/k9/job/KoinModule.kt b/app/core/src/main/java/com/fsck/k9/job/KoinModule.kt index cc7dcc7b2..4bf3a7002 100644 --- a/app/core/src/main/java/com/fsck/k9/job/KoinModule.kt +++ b/app/core/src/main/java/com/fsck/k9/job/KoinModule.kt @@ -1,6 +1,7 @@ package com.fsck.k9.job import androidx.work.WorkerFactory +import com.fsck.k9.Clock import org.koin.dsl.module val jobModule = module { @@ -8,5 +9,5 @@ val jobModule = module { single { K9WorkerFactory(get(), get()) } single { get().getWorkManager() } single { K9JobManager(get(), get(), get()) } - factory { MailSyncWorkerManager(get()) } + factory { MailSyncWorkerManager(get(), Clock.INSTANCE) } } diff --git a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt index fc63da973..23efcbae5 100644 --- a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt +++ b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt @@ -7,11 +7,12 @@ import androidx.work.PeriodicWorkRequestBuilder import androidx.work.WorkManager import androidx.work.workDataOf import com.fsck.k9.Account +import com.fsck.k9.Clock import com.fsck.k9.K9 -import java.util.concurrent.TimeUnit +import java.time.Duration import timber.log.Timber -class MailSyncWorkerManager(private val workManager: WorkManager) { +class MailSyncWorkerManager(private val workManager: WorkManager, val clock: Clock) { fun cancelMailSync(account: Account) { Timber.v("Canceling mail sync worker for %s", account.description) @@ -22,21 +23,29 @@ class MailSyncWorkerManager(private val workManager: WorkManager) { fun scheduleMailSync(account: Account) { if (isNeverSyncInBackground()) return - getSyncIntervalInMinutesIfEnabled(account)?.let { syncInterval -> + getSyncIntervalIfEnabled(account)?.let { syncInterval -> Timber.v("Scheduling mail sync worker for %s", account.description) + Timber.v(" sync interval: %d minutes", syncInterval.toMinutes()) val constraints = Constraints.Builder() - .setRequiredNetworkType(NetworkType.CONNECTED) - .setRequiresStorageNotLow(true) - .build() + .setRequiredNetworkType(NetworkType.CONNECTED) + .setRequiresStorageNotLow(true) + .build() + + val lastSyncTime = account.lastSyncTime + Timber.v(" last sync time: %tc", lastSyncTime) + + val initialDelay = calculateInitialDelay(lastSyncTime, syncInterval) + Timber.v(" initial delay: %d minutes", initialDelay.toMinutes()) val data = workDataOf(MailSyncWorker.EXTRA_ACCOUNT_UUID to account.uuid) - val mailSyncRequest = PeriodicWorkRequestBuilder(syncInterval, TimeUnit.MINUTES) - .setConstraints(constraints) - .setInputData(data) - .addTag(MAIL_SYNC_TAG) - .build() + val mailSyncRequest = PeriodicWorkRequestBuilder(syncInterval) + .setInitialDelay(initialDelay) + .setConstraints(constraints) + .setInputData(data) + .addTag(MAIL_SYNC_TAG) + .build() val uniqueWorkName = createUniqueWorkName(account.uuid) workManager.enqueueUniquePeriodicWork(uniqueWorkName, ExistingPeriodicWorkPolicy.REPLACE, mailSyncRequest) @@ -45,13 +54,24 @@ class MailSyncWorkerManager(private val workManager: WorkManager) { private fun isNeverSyncInBackground() = K9.backgroundOps == K9.BACKGROUND_OPS.NEVER - private fun getSyncIntervalInMinutesIfEnabled(account: Account): Long? { + private fun getSyncIntervalIfEnabled(account: Account): Duration? { val intervalMinutes = account.automaticCheckIntervalMinutes if (intervalMinutes <= Account.INTERVAL_MINUTES_NEVER) { return null } - return intervalMinutes.toLong() + return Duration.ofMinutes(intervalMinutes.toLong()) + } + + private fun calculateInitialDelay(lastSyncTime: Long, syncInterval: Duration): Duration { + val now = clock.time + val nextSyncTime = lastSyncTime + syncInterval.toMillis() + + return if (lastSyncTime > now || nextSyncTime <= now) { + Duration.ZERO + } else { + Duration.ofMillis(nextSyncTime - now) + } } private fun createUniqueWorkName(accountUuid: String): String { From 03d057a7858476821c1446f62c064d4089b494ff Mon Sep 17 00:00:00 2001 From: cketti Date: Wed, 6 May 2020 17:09:16 +0200 Subject: [PATCH 8/8] Retry failed periodic syncs with exponential backoff --- .../main/java/com/fsck/k9/controller/MessagingController.java | 4 +++- app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt | 4 ++-- .../src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java index b6f26db06..bae37949f 100644 --- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java +++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java @@ -2265,7 +2265,7 @@ public class MessagingController { context.startActivity(chooserIntent); } - public void performPeriodicMailSync(Account account) { + public boolean performPeriodicMailSync(Account account) { final CountDownLatch latch = new CountDownLatch(1); MutableBoolean syncError = new MutableBoolean(false); checkMail(context, account, false, false, new SimpleMessagingListener() { @@ -2296,6 +2296,8 @@ public class MessagingController { account.setLastSyncTime(now); Preferences.getPreferences(context).saveAccount(account); } + + return success; } /** diff --git a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt index a376b389e..bb1237c10 100644 --- a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt +++ b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt @@ -39,9 +39,9 @@ class MailSyncWorker( return Result.success() } - messagingController.performPeriodicMailSync(account) + val success = messagingController.performPeriodicMailSync(account) - return Result.success() + return if (success) Result.success() else Result.retry() } private fun isBackgroundSyncDisabled(): Boolean { diff --git a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt index 23efcbae5..3db9b9d66 100644 --- a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt +++ b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt @@ -1,5 +1,6 @@ package com.fsck.k9.job +import androidx.work.BackoffPolicy import androidx.work.Constraints import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.NetworkType @@ -42,6 +43,7 @@ class MailSyncWorkerManager(private val workManager: WorkManager, val clock: Clo val mailSyncRequest = PeriodicWorkRequestBuilder(syncInterval) .setInitialDelay(initialDelay) + .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, INITIAL_BACKOFF_DELAY) .setConstraints(constraints) .setInputData(data) .addTag(MAIL_SYNC_TAG) @@ -80,5 +82,6 @@ class MailSyncWorkerManager(private val workManager: WorkManager, val clock: Clo companion object { const val MAIL_SYNC_TAG = "MailSync" + private val INITIAL_BACKOFF_DELAY = Duration.ofMinutes(5) } }