From 7078dfa2bf68e0e4f8dcb682c8552eef6d559a3d Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Thu, 30 Jul 2020 12:29:20 -0500 Subject: [PATCH] Separate sync work for each service --- .../java/com/todoroo/astrid/dao/TaskDao.kt | 2 +- .../com/todoroo/astrid/service/TaskDeleter.kt | 6 +- .../main/java/org/tasks/data/CaldavAccount.kt | 2 +- app/src/main/java/org/tasks/data/CaldavDao.kt | 13 ++++ .../java/org/tasks/jobs/SyncCaldavWork.kt | 42 ++++++++++++ .../java/org/tasks/jobs/SyncEteSyncWork.kt | 42 ++++++++++++ .../org/tasks/jobs/SyncGoogleTasksWork.kt | 42 ++++++++++++ app/src/main/java/org/tasks/jobs/SyncWork.kt | 65 +++++-------------- .../main/java/org/tasks/jobs/WorkManager.kt | 14 +++- .../java/org/tasks/jobs/WorkManagerImpl.kt | 40 ++++++++---- .../java/org/tasks/preferences/Preferences.kt | 8 ++- .../preferences/fragments/Synchronization.kt | 6 +- .../main/java/org/tasks/sync/SyncAdapters.kt | 54 ++++++++++----- app/src/main/res/values/keys.xml | 4 +- 14 files changed, 248 insertions(+), 92 deletions(-) create mode 100644 app/src/main/java/org/tasks/jobs/SyncCaldavWork.kt create mode 100644 app/src/main/java/org/tasks/jobs/SyncEteSyncWork.kt create mode 100644 app/src/main/java/org/tasks/jobs/SyncGoogleTasksWork.kt diff --git a/app/src/main/java/com/todoroo/astrid/dao/TaskDao.kt b/app/src/main/java/com/todoroo/astrid/dao/TaskDao.kt index ee751b69b..ac25e20d9 100644 --- a/app/src/main/java/com/todoroo/astrid/dao/TaskDao.kt +++ b/app/src/main/java/com/todoroo/astrid/dao/TaskDao.kt @@ -58,7 +58,7 @@ class TaskDao @Inject constructor( suspend fun touch(ids: List) { ids.eachChunk { taskDao.touch(ids) } - workManager.sync(false) + syncAdapters.sync() } suspend fun setParent(parent: Long, tasks: List) = taskDao.setParent(parent, tasks) diff --git a/app/src/main/java/com/todoroo/astrid/service/TaskDeleter.kt b/app/src/main/java/com/todoroo/astrid/service/TaskDeleter.kt index 8cd62d769..4bccf9915 100644 --- a/app/src/main/java/com/todoroo/astrid/service/TaskDeleter.kt +++ b/app/src/main/java/com/todoroo/astrid/service/TaskDeleter.kt @@ -9,6 +9,7 @@ import org.tasks.db.QueryUtils import org.tasks.db.SuspendDbUtils.chunkedMap import org.tasks.jobs.WorkManager import org.tasks.preferences.Preferences +import org.tasks.sync.SyncAdapters import java.util.* import javax.inject.Inject @@ -18,7 +19,8 @@ class TaskDeleter @Inject constructor( private val taskDao: TaskDao, private val localBroadcastManager: LocalBroadcastManager, private val googleTaskDao: GoogleTaskDao, - private val preferences: Preferences) { + private val preferences: Preferences, + private val syncAdapters: SyncAdapters) { suspend fun markDeleted(item: Task) = markDeleted(persistentListOf(item.id)) @@ -28,7 +30,7 @@ class TaskDeleter @Inject constructor( ids.addAll(taskIds.chunkedMap(taskDao::getChildren)) deletionDao.markDeleted(ids) workManager.cleanup(ids) - workManager.sync(false) + syncAdapters.sync() localBroadcastManager.broadcastRefresh() return ids.chunkedMap(taskDao::fetch) } diff --git a/app/src/main/java/org/tasks/data/CaldavAccount.kt b/app/src/main/java/org/tasks/data/CaldavAccount.kt index 32c935d31..89238b411 100644 --- a/app/src/main/java/org/tasks/data/CaldavAccount.kt +++ b/app/src/main/java/org/tasks/data/CaldavAccount.kt @@ -146,7 +146,7 @@ class CaldavAccount : Parcelable { } companion object { - private const val TYPE_CALDAV = 0 + const val TYPE_CALDAV = 0 const val TYPE_ETESYNC = 1 const val TYPE_LOCAL = 2 diff --git a/app/src/main/java/org/tasks/data/CaldavDao.kt b/app/src/main/java/org/tasks/data/CaldavDao.kt index c29eab22f..d83f44a00 100644 --- a/app/src/main/java/org/tasks/data/CaldavDao.kt +++ b/app/src/main/java/org/tasks/data/CaldavDao.kt @@ -33,6 +33,9 @@ abstract class CaldavDao { @Query("SELECT COUNT(*) FROM caldav_accounts WHERE cda_account_type != 2") abstract suspend fun accountCount(): Int + @Query("SELECT * FROM caldav_accounts WHERE cda_account_type = :type") + abstract suspend fun getAccounts(type: Int): List + @Query("SELECT * FROM caldav_accounts ORDER BY cda_account_type, UPPER(cda_name)") abstract suspend fun getAccounts(): List @@ -127,6 +130,16 @@ abstract class CaldavDao { @Query("SELECT * FROM caldav_tasks WHERE cd_task = :taskId") abstract suspend fun getTasks(taskId: Long): List + @Query(""" +SELECT EXISTS(SELECT 1 + FROM caldav_tasks + INNER JOIN caldav_lists ON cdl_uuid = cd_calendar + INNER JOIN caldav_accounts ON cda_uuid = cdl_account + WHERE cd_task = :id + AND cda_account_type = :type) +""") + abstract suspend fun isAccountType(id: Long, type: Int): Boolean + @Query("SELECT * FROM caldav_tasks WHERE cd_task in (:taskIds) AND cd_deleted = 0") abstract suspend fun getTasks(taskIds: List): List diff --git a/app/src/main/java/org/tasks/jobs/SyncCaldavWork.kt b/app/src/main/java/org/tasks/jobs/SyncCaldavWork.kt new file mode 100644 index 000000000..47759acfa --- /dev/null +++ b/app/src/main/java/org/tasks/jobs/SyncCaldavWork.kt @@ -0,0 +1,42 @@ +package org.tasks.jobs + +import android.content.Context +import androidx.hilt.Assisted +import androidx.hilt.work.WorkerInject +import androidx.work.WorkerParameters +import kotlinx.coroutines.* +import org.tasks.LocalBroadcastManager +import org.tasks.R +import org.tasks.analytics.Firebase +import org.tasks.caldav.CaldavSynchronizer +import org.tasks.data.CaldavAccount.Companion.TYPE_CALDAV +import org.tasks.data.CaldavDao +import org.tasks.preferences.Preferences + +class SyncCaldavWork @WorkerInject constructor( + @Assisted context: Context, + @Assisted workerParams: WorkerParameters, + firebase: Firebase, + localBroadcastManager: LocalBroadcastManager, + preferences: Preferences, + private val caldavDao: CaldavDao, + private val caldavSynchronizer: CaldavSynchronizer +) : SyncWork(context, workerParams, firebase, localBroadcastManager, preferences) { + + override suspend fun enabled() = caldavDao.getAccounts(TYPE_CALDAV).isNotEmpty() + + override val syncStatus = R.string.p_sync_ongoing_caldav + + override suspend fun doSync() { + caldavJobs().awaitAll() + } + + private suspend fun caldavJobs(): List> = coroutineScope { + caldavDao.getAccounts(TYPE_CALDAV) + .map { + async(Dispatchers.IO) { + caldavSynchronizer.sync(it) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/tasks/jobs/SyncEteSyncWork.kt b/app/src/main/java/org/tasks/jobs/SyncEteSyncWork.kt new file mode 100644 index 000000000..afcb69b87 --- /dev/null +++ b/app/src/main/java/org/tasks/jobs/SyncEteSyncWork.kt @@ -0,0 +1,42 @@ +package org.tasks.jobs + +import android.content.Context +import androidx.hilt.Assisted +import androidx.hilt.work.WorkerInject +import androidx.work.WorkerParameters +import kotlinx.coroutines.* +import org.tasks.LocalBroadcastManager +import org.tasks.R +import org.tasks.analytics.Firebase +import org.tasks.data.CaldavAccount.Companion.TYPE_ETESYNC +import org.tasks.data.CaldavDao +import org.tasks.etesync.EteSynchronizer +import org.tasks.preferences.Preferences + +class SyncEteSyncWork @WorkerInject constructor( + @Assisted context: Context, + @Assisted workerParams: WorkerParameters, + firebase: Firebase, + localBroadcastManager: LocalBroadcastManager, + preferences: Preferences, + private val caldavDao: CaldavDao, + private val eteSynchronizer: EteSynchronizer +) : SyncWork(context, workerParams, firebase, localBroadcastManager, preferences) { + + override suspend fun enabled() = caldavDao.getAccounts(TYPE_ETESYNC).isNotEmpty() + + override val syncStatus = R.string.p_sync_ongoing_etesync + + override suspend fun doSync() { + etesyncJobs().awaitAll() + } + + private suspend fun etesyncJobs(): List> = coroutineScope { + caldavDao.getAccounts(TYPE_ETESYNC) + .map { + async(Dispatchers.IO) { + eteSynchronizer.sync(it) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/tasks/jobs/SyncGoogleTasksWork.kt b/app/src/main/java/org/tasks/jobs/SyncGoogleTasksWork.kt new file mode 100644 index 000000000..d8cb82d98 --- /dev/null +++ b/app/src/main/java/org/tasks/jobs/SyncGoogleTasksWork.kt @@ -0,0 +1,42 @@ +package org.tasks.jobs + +import android.content.Context +import androidx.hilt.Assisted +import androidx.hilt.work.WorkerInject +import androidx.work.WorkerParameters +import kotlinx.coroutines.* +import org.tasks.LocalBroadcastManager +import org.tasks.R +import org.tasks.analytics.Firebase +import org.tasks.data.GoogleTaskListDao +import org.tasks.gtasks.GoogleTaskSynchronizer +import org.tasks.preferences.Preferences + +class SyncGoogleTasksWork @WorkerInject constructor( + @Assisted context: Context, + @Assisted workerParams: WorkerParameters, + firebase: Firebase, + localBroadcastManager: LocalBroadcastManager, + preferences: Preferences, + private val googleTaskListDao: GoogleTaskListDao, + private val googleTaskSynchronizer: GoogleTaskSynchronizer +) : SyncWork(context, workerParams, firebase, localBroadcastManager, preferences) { + + override suspend fun enabled() = googleTaskListDao.getAccounts().isNotEmpty() + + override val syncStatus = R.string.p_sync_ongoing_google_tasks + + override suspend fun doSync() { + googleTaskJobs().awaitAll() + } + + private suspend fun googleTaskJobs(): List> = coroutineScope { + googleTaskListDao + .getAccounts() + .mapIndexed { i, account -> + async(Dispatchers.IO) { + googleTaskSynchronizer.sync(account, i) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/tasks/jobs/SyncWork.kt b/app/src/main/java/org/tasks/jobs/SyncWork.kt index 62bcc7abf..c4c5af5e7 100644 --- a/app/src/main/java/org/tasks/jobs/SyncWork.kt +++ b/app/src/main/java/org/tasks/jobs/SyncWork.kt @@ -1,80 +1,47 @@ package org.tasks.jobs import android.content.Context -import androidx.hilt.Assisted -import androidx.hilt.work.WorkerInject import androidx.work.WorkerParameters -import kotlinx.coroutines.* import org.tasks.LocalBroadcastManager import org.tasks.analytics.Firebase -import org.tasks.caldav.CaldavSynchronizer -import org.tasks.data.CaldavAccount.Companion.TYPE_LOCAL -import org.tasks.data.CaldavDao -import org.tasks.data.GoogleTaskListDao -import org.tasks.etesync.EteSynchronizer -import org.tasks.gtasks.GoogleTaskSynchronizer import org.tasks.injection.BaseWorker import org.tasks.preferences.Preferences -import org.tasks.sync.SyncAdapters -class SyncWork @WorkerInject constructor( - @Assisted context: Context, - @Assisted workerParams: WorkerParameters, +abstract class SyncWork constructor( + context: Context, + workerParams: WorkerParameters, firebase: Firebase, - private val caldavSynchronizer: CaldavSynchronizer, - private val eteSynchronizer: EteSynchronizer, - private val googleTaskSynchronizer: GoogleTaskSynchronizer, private val localBroadcastManager: LocalBroadcastManager, - private val preferences: Preferences, - private val caldavDao: CaldavDao, - private val googleTaskListDao: GoogleTaskListDao, - private val syncAdapters: SyncAdapters) : BaseWorker(context, workerParams, firebase) { + private val preferences: Preferences) : BaseWorker(context, workerParams, firebase) { - override suspend fun run(): Result { - if (!syncAdapters.isSyncEnabled()) { - return Result.success() + final override suspend fun run(): Result { + if (!enabled()) { + return Result.failure() } + synchronized(LOCK) { - if (preferences.isSyncOngoing) { + if (preferences.getBoolean(syncStatus, false)) { return Result.retry() } + preferences.setBoolean(syncStatus, true) } - preferences.isSyncOngoing = true localBroadcastManager.broadcastRefresh() try { - caldavJobs().plus(googleTaskJobs()).awaitAll() + doSync() } catch (e: Exception) { firebase.reportException(e) } finally { - preferences.isSyncOngoing = false + preferences.setBoolean(syncStatus, false) localBroadcastManager.broadcastRefresh() } return Result.success() } - private suspend fun caldavJobs(): List> = coroutineScope { - caldavDao.getAccounts() - .filterNot { it.accountType == TYPE_LOCAL } - .map { - async(Dispatchers.IO) { - if (it.isCaldavAccount) { - caldavSynchronizer.sync(it) - } else if (it.isEteSyncAccount) { - eteSynchronizer.sync(it) - } - } - } - } + protected abstract val syncStatus: Int - private suspend fun googleTaskJobs(): List> = coroutineScope { - googleTaskListDao - .getAccounts() - .mapIndexed { i, account -> - async(Dispatchers.IO) { - googleTaskSynchronizer.sync(account, i) - } - } - } + protected abstract suspend fun enabled(): Boolean + + protected abstract suspend fun doSync() companion object { private val LOCK = Any() diff --git a/app/src/main/java/org/tasks/jobs/WorkManager.kt b/app/src/main/java/org/tasks/jobs/WorkManager.kt index adc91ba93..a61847a6f 100644 --- a/app/src/main/java/org/tasks/jobs/WorkManager.kt +++ b/app/src/main/java/org/tasks/jobs/WorkManager.kt @@ -11,7 +11,11 @@ interface WorkManager { suspend fun cleanup(ids: Iterable) - suspend fun sync(immediate: Boolean) + suspend fun googleTaskSync(immediate: Boolean) + + suspend fun caldavSync(immediate: Boolean) + + suspend fun eteSync(immediate: Boolean) suspend fun reverseGeocode(place: Place) @@ -42,8 +46,12 @@ interface WorkManager { const val TAG_BACKUP = "tag_backup" const val TAG_REFRESH = "tag_refresh" const val TAG_MIDNIGHT_REFRESH = "tag_midnight_refresh" - const val TAG_SYNC = "tag_sync" - const val TAG_BACKGROUND_SYNC = "tag_background_sync" + const val TAG_SYNC_GOOGLE_TASKS = "tag_sync_google_tasks" + const val TAG_SYNC_CALDAV = "tag_sync_caldav" + const val TAG_SYNC_ETESYNC = "tag_sync_etesync" + const val TAG_BACKGROUND_SYNC_GOOGLE_TASKS = "tag_background_sync_google_tasks" + const val TAG_BACKGROUND_SYNC_CALDAV = "tag_background_sync_caldav" + const val TAG_BACKGROUND_SYNC_ETESYNC = "tag_background_sync_etesync" const val TAG_REMOTE_CONFIG = "tag_remote_config" } } \ No newline at end of file diff --git a/app/src/main/java/org/tasks/jobs/WorkManagerImpl.kt b/app/src/main/java/org/tasks/jobs/WorkManagerImpl.kt index 22b55b92d..fc0da1332 100644 --- a/app/src/main/java/org/tasks/jobs/WorkManagerImpl.kt +++ b/app/src/main/java/org/tasks/jobs/WorkManagerImpl.kt @@ -20,12 +20,16 @@ import org.tasks.date.DateTimeUtils.newDateTime import org.tasks.db.SuspendDbUtils.eachChunk import org.tasks.jobs.WorkManager.Companion.MAX_CLEANUP_LENGTH import org.tasks.jobs.WorkManager.Companion.REMOTE_CONFIG_INTERVAL_HOURS -import org.tasks.jobs.WorkManager.Companion.TAG_BACKGROUND_SYNC +import org.tasks.jobs.WorkManager.Companion.TAG_BACKGROUND_SYNC_CALDAV +import org.tasks.jobs.WorkManager.Companion.TAG_BACKGROUND_SYNC_ETESYNC +import org.tasks.jobs.WorkManager.Companion.TAG_BACKGROUND_SYNC_GOOGLE_TASKS import org.tasks.jobs.WorkManager.Companion.TAG_BACKUP import org.tasks.jobs.WorkManager.Companion.TAG_MIDNIGHT_REFRESH import org.tasks.jobs.WorkManager.Companion.TAG_REFRESH import org.tasks.jobs.WorkManager.Companion.TAG_REMOTE_CONFIG -import org.tasks.jobs.WorkManager.Companion.TAG_SYNC +import org.tasks.jobs.WorkManager.Companion.TAG_SYNC_CALDAV +import org.tasks.jobs.WorkManager.Companion.TAG_SYNC_ETESYNC +import org.tasks.jobs.WorkManager.Companion.TAG_SYNC_GOOGLE_TASKS import org.tasks.notifications.Throttle import org.tasks.preferences.Preferences import org.tasks.time.DateTimeUtils @@ -74,7 +78,16 @@ class WorkManagerImpl constructor( } } - override suspend fun sync(immediate: Boolean) { + override suspend fun googleTaskSync(immediate: Boolean) = + sync(immediate, TAG_SYNC_GOOGLE_TASKS, SyncGoogleTasksWork::class.java) + + override suspend fun caldavSync(immediate: Boolean) = + sync(immediate, TAG_SYNC_CALDAV, SyncCaldavWork::class.java) + + override suspend fun eteSync(immediate: Boolean) = + sync(immediate, TAG_SYNC_ETESYNC, SyncEteSyncWork::class.java) + + private suspend fun sync(immediate: Boolean, tag: String, c: Class) { val constraints = Constraints.Builder() .setRequiredNetworkType( if (!immediate && preferences.getBoolean(R.string.p_background_sync_unmetered_only, false)) { @@ -83,15 +96,13 @@ class WorkManagerImpl constructor( NetworkType.CONNECTED }) .build() - val builder = OneTimeWorkRequest.Builder(SyncWork::class.java) - .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.MINUTES) - .setConstraints(constraints) + val builder = OneTimeWorkRequest.Builder(c).setConstraints(constraints) if (!immediate) { builder.setInitialDelay(1, TimeUnit.MINUTES) } throttle.run { workManager - .beginUniqueWork(TAG_SYNC, ExistingWorkPolicy.REPLACE, builder.build()) + .beginUniqueWork(tag, ExistingWorkPolicy.REPLACE, builder.build()) .enqueue() } } @@ -103,7 +114,6 @@ class WorkManagerImpl constructor( enqueue( OneTimeWorkRequest.Builder(ReverseGeocodeWork::class.java) .setInputData(Data.Builder().putLong(ReverseGeocodeWork.PLACE_ID, place.id).build()) - .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.MINUTES) .setConstraints( Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())) } @@ -129,17 +139,22 @@ class WorkManagerImpl constructor( private suspend fun scheduleBackgroundSync(enabled: Boolean, onlyOnUnmetered: Boolean) { Timber.d("background sync enabled: %s, onlyOnUnmetered: %s", enabled, onlyOnUnmetered) + scheduleBackgroundSync(enabled, onlyOnUnmetered, TAG_BACKGROUND_SYNC_GOOGLE_TASKS, SyncGoogleTasksWork::class.java) + scheduleBackgroundSync(enabled, onlyOnUnmetered, TAG_BACKGROUND_SYNC_CALDAV, SyncCaldavWork::class.java) + scheduleBackgroundSync(enabled, onlyOnUnmetered, TAG_BACKGROUND_SYNC_ETESYNC, SyncEteSyncWork::class.java) + } + + private suspend fun scheduleBackgroundSync(enabled: Boolean, onlyOnUnmetered: Boolean, tag: String, c: Class) { throttle.run { if (enabled) { workManager.enqueueUniquePeriodicWork( - TAG_BACKGROUND_SYNC, + tag, ExistingPeriodicWorkPolicy.KEEP, - PeriodicWorkRequest.Builder(SyncWork::class.java, 1, TimeUnit.HOURS) - .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.MINUTES) + PeriodicWorkRequest.Builder(c, 1, TimeUnit.HOURS) .setConstraints(getNetworkConstraints(onlyOnUnmetered)) .build()) } else { - workManager.cancelUniqueWork(TAG_BACKGROUND_SYNC) + workManager.cancelUniqueWork(tag) } } } @@ -180,7 +195,6 @@ class WorkManagerImpl constructor( ExistingPeriodicWorkPolicy.KEEP, PeriodicWorkRequest.Builder( RemoteConfigWork::class.java, REMOTE_CONFIG_INTERVAL_HOURS, TimeUnit.HOURS) - .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.MINUTES) .setConstraints( Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()) .build()) diff --git a/app/src/main/java/org/tasks/preferences/Preferences.kt b/app/src/main/java/org/tasks/preferences/Preferences.kt index bea648ee1..fb634db4d 100644 --- a/app/src/main/java/org/tasks/preferences/Preferences.kt +++ b/app/src/main/java/org/tasks/preferences/Preferences.kt @@ -411,9 +411,9 @@ class Preferences @JvmOverloads constructor(private val context: Context, name: } var isSyncOngoing: Boolean - get() = getBoolean(R.string.p_sync_ongoing, false) + get() = syncFlags.any { getBoolean(it, false) } set(value) { - setBoolean(R.string.p_sync_ongoing, value) + syncFlags.forEach { setBoolean(it, value) } } fun useGooglePlaces(): Boolean { @@ -491,5 +491,9 @@ class Preferences @JvmOverloads constructor(private val context: Context, name: private fun getSharedPreferencesName(context: Context): String { return context.packageName + "_preferences" } + private val syncFlags = listOf( + R.string.p_sync_ongoing_google_tasks, + R.string.p_sync_ongoing_caldav, + R.string.p_sync_ongoing_etesync) } } \ No newline at end of file diff --git a/app/src/main/java/org/tasks/preferences/fragments/Synchronization.kt b/app/src/main/java/org/tasks/preferences/fragments/Synchronization.kt index 6819b4b81..00e5fc69d 100644 --- a/app/src/main/java/org/tasks/preferences/fragments/Synchronization.kt +++ b/app/src/main/java/org/tasks/preferences/fragments/Synchronization.kt @@ -28,6 +28,7 @@ import org.tasks.injection.InjectingPreferenceFragment import org.tasks.jobs.WorkManager import org.tasks.preferences.Preferences import org.tasks.sync.AddAccountDialog +import org.tasks.sync.SyncAdapters import org.tasks.ui.Toaster import javax.inject.Inject @@ -43,6 +44,7 @@ class Synchronization : InjectingPreferenceFragment() { @Inject lateinit var caldavDao: CaldavDao @Inject lateinit var googleTaskListDao: GoogleTaskListDao @Inject lateinit var taskDeleter: TaskDeleter + @Inject lateinit var syncAdapters: SyncAdapters override fun getPreferenceXml() = R.xml.preferences_synchronization @@ -95,14 +97,14 @@ class Synchronization : InjectingPreferenceFragment() { if (requestCode == REQUEST_CALDAV_SETTINGS) { if (resultCode == Activity.RESULT_OK) { lifecycleScope.launch(NonCancellable) { - workManager.sync(true) + syncAdapters.sync(true) workManager.updateBackgroundSync() } } } else if (requestCode == REQUEST_GOOGLE_TASKS) { if (resultCode == Activity.RESULT_OK) { lifecycleScope.launch(NonCancellable) { - workManager.sync(true) + syncAdapters.sync(true) workManager.updateBackgroundSync() } } else if (data != null) { diff --git a/app/src/main/java/org/tasks/sync/SyncAdapters.kt b/app/src/main/java/org/tasks/sync/SyncAdapters.kt index b80e44527..cb7abc28e 100644 --- a/app/src/main/java/org/tasks/sync/SyncAdapters.kt +++ b/app/src/main/java/org/tasks/sync/SyncAdapters.kt @@ -4,7 +4,10 @@ import com.todoroo.astrid.data.SyncFlags import com.todoroo.astrid.data.Task import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.withContext +import org.tasks.data.CaldavAccount.Companion.TYPE_CALDAV +import org.tasks.data.CaldavAccount.Companion.TYPE_ETESYNC import org.tasks.data.CaldavDao +import org.tasks.data.GoogleTaskDao import org.tasks.data.GoogleTaskListDao import org.tasks.jobs.WorkManager import javax.inject.Inject @@ -12,19 +15,24 @@ import javax.inject.Inject class SyncAdapters @Inject constructor( private val workManager: WorkManager, private val caldavDao: CaldavDao, + private val googleTaskDao: GoogleTaskDao, private val googleTaskListDao: GoogleTaskListDao) { suspend fun sync(task: Task, original: Task?) { - val suppress = task.checkTransitory(SyncFlags.SUPPRESS_SYNC) - val forceCaldav = task.checkTransitory(SyncFlags.FORCE_CALDAV_SYNC) - val pushGtasks = !suppress - && !task.googleTaskUpToDate(original) - && isGoogleTaskSyncEnabled() - val pushCaldav = !suppress - && (forceCaldav || !task.caldavUpToDate(original)) - && isCaldavSyncEnabled() - if (pushGtasks || pushCaldav) { - sync() + if (task.checkTransitory(SyncFlags.SUPPRESS_SYNC)) { + return + } + if (!task.googleTaskUpToDate(original) + && googleTaskDao.getAllByTaskId(task.id).isNotEmpty()) { + workManager.googleTaskSync(false) + } + if (task.checkTransitory(SyncFlags.FORCE_CALDAV_SYNC) || !task.caldavUpToDate(original)) { + if (caldavDao.isAccountType(task.id, TYPE_CALDAV)) { + workManager.caldavSync(false) + } + if (caldavDao.isAccountType(task.id, TYPE_ETESYNC)) { + workManager.eteSync(false) + } } } @@ -33,17 +41,27 @@ class SyncAdapters @Inject constructor( } suspend fun sync(immediate: Boolean): Boolean = withContext(NonCancellable) { - if (isSyncEnabled()) { - workManager.sync(immediate) - true - } else { - false + val googleTasks = isGoogleTaskSyncEnabled() + if (googleTasks) { + workManager.googleTaskSync(immediate) + } + + val caldav = isCaldavSyncEnabled() + if (caldav) { + workManager.caldavSync(immediate) } + + val eteSync = isEteSyncEnabled() + if (eteSync) { + workManager.eteSync(immediate) + } + + return@withContext googleTasks || caldav || eteSync } - suspend fun isSyncEnabled(): Boolean = isGoogleTaskSyncEnabled() || isCaldavSyncEnabled() + suspend fun isGoogleTaskSyncEnabled() = googleTaskListDao.getAccounts().isNotEmpty() - suspend fun isGoogleTaskSyncEnabled(): Boolean = googleTaskListDao.getAccounts().isNotEmpty() + suspend fun isCaldavSyncEnabled() = caldavDao.getAccounts(TYPE_CALDAV).isNotEmpty() - suspend fun isCaldavSyncEnabled(): Boolean = caldavDao.accountCount() > 0 + suspend fun isEteSyncEnabled() = caldavDao.getAccounts(TYPE_ETESYNC).isNotEmpty() } \ No newline at end of file diff --git a/app/src/main/res/values/keys.xml b/app/src/main/res/values/keys.xml index 8e8860b15..78e29ebf0 100644 --- a/app/src/main/res/values/keys.xml +++ b/app/src/main/res/values/keys.xml @@ -333,7 +333,9 @@ debug_crash_main_queries warned_play_services background_sync_unmetered_only - sync_ongoing + sync_ongoing_google_tasks + sync_ongoing_caldav + sync_ongoing_etesync last_backup show_description show_full_description