Separate sync work for each service

pull/1061/head
Alex Baker 4 years ago
parent 15637e784e
commit 7078dfa2bf

@ -58,7 +58,7 @@ class TaskDao @Inject constructor(
suspend fun touch(ids: List<Long>) { suspend fun touch(ids: List<Long>) {
ids.eachChunk { taskDao.touch(ids) } ids.eachChunk { taskDao.touch(ids) }
workManager.sync(false) syncAdapters.sync()
} }
suspend fun setParent(parent: Long, tasks: List<Long>) = taskDao.setParent(parent, tasks) suspend fun setParent(parent: Long, tasks: List<Long>) = taskDao.setParent(parent, tasks)

@ -9,6 +9,7 @@ import org.tasks.db.QueryUtils
import org.tasks.db.SuspendDbUtils.chunkedMap import org.tasks.db.SuspendDbUtils.chunkedMap
import org.tasks.jobs.WorkManager import org.tasks.jobs.WorkManager
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.sync.SyncAdapters
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
@ -18,7 +19,8 @@ class TaskDeleter @Inject constructor(
private val taskDao: TaskDao, private val taskDao: TaskDao,
private val localBroadcastManager: LocalBroadcastManager, private val localBroadcastManager: LocalBroadcastManager,
private val googleTaskDao: GoogleTaskDao, 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)) suspend fun markDeleted(item: Task) = markDeleted(persistentListOf(item.id))
@ -28,7 +30,7 @@ class TaskDeleter @Inject constructor(
ids.addAll(taskIds.chunkedMap(taskDao::getChildren)) ids.addAll(taskIds.chunkedMap(taskDao::getChildren))
deletionDao.markDeleted(ids) deletionDao.markDeleted(ids)
workManager.cleanup(ids) workManager.cleanup(ids)
workManager.sync(false) syncAdapters.sync()
localBroadcastManager.broadcastRefresh() localBroadcastManager.broadcastRefresh()
return ids.chunkedMap(taskDao::fetch) return ids.chunkedMap(taskDao::fetch)
} }

@ -146,7 +146,7 @@ class CaldavAccount : Parcelable {
} }
companion object { companion object {
private const val TYPE_CALDAV = 0 const val TYPE_CALDAV = 0
const val TYPE_ETESYNC = 1 const val TYPE_ETESYNC = 1
const val TYPE_LOCAL = 2 const val TYPE_LOCAL = 2

@ -33,6 +33,9 @@ abstract class CaldavDao {
@Query("SELECT COUNT(*) FROM caldav_accounts WHERE cda_account_type != 2") @Query("SELECT COUNT(*) FROM caldav_accounts WHERE cda_account_type != 2")
abstract suspend fun accountCount(): Int abstract suspend fun accountCount(): Int
@Query("SELECT * FROM caldav_accounts WHERE cda_account_type = :type")
abstract suspend fun getAccounts(type: Int): List<CaldavAccount>
@Query("SELECT * FROM caldav_accounts ORDER BY cda_account_type, UPPER(cda_name)") @Query("SELECT * FROM caldav_accounts ORDER BY cda_account_type, UPPER(cda_name)")
abstract suspend fun getAccounts(): List<CaldavAccount> abstract suspend fun getAccounts(): List<CaldavAccount>
@ -127,6 +130,16 @@ abstract class CaldavDao {
@Query("SELECT * FROM caldav_tasks WHERE cd_task = :taskId") @Query("SELECT * FROM caldav_tasks WHERE cd_task = :taskId")
abstract suspend fun getTasks(taskId: Long): List<CaldavTask> abstract suspend fun getTasks(taskId: Long): List<CaldavTask>
@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") @Query("SELECT * FROM caldav_tasks WHERE cd_task in (:taskIds) AND cd_deleted = 0")
abstract suspend fun getTasks(taskIds: List<Long>): List<CaldavTask> abstract suspend fun getTasks(taskIds: List<Long>): List<CaldavTask>

@ -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<Deferred<Unit>> = coroutineScope {
caldavDao.getAccounts(TYPE_CALDAV)
.map {
async(Dispatchers.IO) {
caldavSynchronizer.sync(it)
}
}
}
}

@ -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<Deferred<Unit>> = coroutineScope {
caldavDao.getAccounts(TYPE_ETESYNC)
.map {
async(Dispatchers.IO) {
eteSynchronizer.sync(it)
}
}
}
}

@ -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<Deferred<Unit>> = coroutineScope {
googleTaskListDao
.getAccounts()
.mapIndexed { i, account ->
async(Dispatchers.IO) {
googleTaskSynchronizer.sync(account, i)
}
}
}
}

@ -1,80 +1,47 @@
package org.tasks.jobs package org.tasks.jobs
import android.content.Context import android.content.Context
import androidx.hilt.Assisted
import androidx.hilt.work.WorkerInject
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import kotlinx.coroutines.*
import org.tasks.LocalBroadcastManager import org.tasks.LocalBroadcastManager
import org.tasks.analytics.Firebase 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.injection.BaseWorker
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.sync.SyncAdapters
class SyncWork @WorkerInject constructor( abstract class SyncWork constructor(
@Assisted context: Context, context: Context,
@Assisted workerParams: WorkerParameters, workerParams: WorkerParameters,
firebase: Firebase, firebase: Firebase,
private val caldavSynchronizer: CaldavSynchronizer,
private val eteSynchronizer: EteSynchronizer,
private val googleTaskSynchronizer: GoogleTaskSynchronizer,
private val localBroadcastManager: LocalBroadcastManager, private val localBroadcastManager: LocalBroadcastManager,
private val preferences: Preferences, private val preferences: Preferences) : BaseWorker(context, workerParams, firebase) {
private val caldavDao: CaldavDao,
private val googleTaskListDao: GoogleTaskListDao,
private val syncAdapters: SyncAdapters) : BaseWorker(context, workerParams, firebase) {
override suspend fun run(): Result { final override suspend fun run(): Result {
if (!syncAdapters.isSyncEnabled()) { if (!enabled()) {
return Result.success() return Result.failure()
} }
synchronized(LOCK) { synchronized(LOCK) {
if (preferences.isSyncOngoing) { if (preferences.getBoolean(syncStatus, false)) {
return Result.retry() return Result.retry()
} }
preferences.setBoolean(syncStatus, true)
} }
preferences.isSyncOngoing = true
localBroadcastManager.broadcastRefresh() localBroadcastManager.broadcastRefresh()
try { try {
caldavJobs().plus(googleTaskJobs()).awaitAll() doSync()
} catch (e: Exception) { } catch (e: Exception) {
firebase.reportException(e) firebase.reportException(e)
} finally { } finally {
preferences.isSyncOngoing = false preferences.setBoolean(syncStatus, false)
localBroadcastManager.broadcastRefresh() localBroadcastManager.broadcastRefresh()
} }
return Result.success() return Result.success()
} }
private suspend fun caldavJobs(): List<Deferred<Unit>> = coroutineScope { protected abstract val syncStatus: Int
caldavDao.getAccounts()
.filterNot { it.accountType == TYPE_LOCAL }
.map {
async(Dispatchers.IO) {
if (it.isCaldavAccount) {
caldavSynchronizer.sync(it)
} else if (it.isEteSyncAccount) {
eteSynchronizer.sync(it)
}
}
}
}
private suspend fun googleTaskJobs(): List<Deferred<Unit>> = coroutineScope { protected abstract suspend fun enabled(): Boolean
googleTaskListDao
.getAccounts() protected abstract suspend fun doSync()
.mapIndexed { i, account ->
async(Dispatchers.IO) {
googleTaskSynchronizer.sync(account, i)
}
}
}
companion object { companion object {
private val LOCK = Any() private val LOCK = Any()

@ -11,7 +11,11 @@ interface WorkManager {
suspend fun cleanup(ids: Iterable<Long>) suspend fun cleanup(ids: Iterable<Long>)
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) suspend fun reverseGeocode(place: Place)
@ -42,8 +46,12 @@ interface WorkManager {
const val TAG_BACKUP = "tag_backup" const val TAG_BACKUP = "tag_backup"
const val TAG_REFRESH = "tag_refresh" const val TAG_REFRESH = "tag_refresh"
const val TAG_MIDNIGHT_REFRESH = "tag_midnight_refresh" const val TAG_MIDNIGHT_REFRESH = "tag_midnight_refresh"
const val TAG_SYNC = "tag_sync" const val TAG_SYNC_GOOGLE_TASKS = "tag_sync_google_tasks"
const val TAG_BACKGROUND_SYNC = "tag_background_sync" 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" const val TAG_REMOTE_CONFIG = "tag_remote_config"
} }
} }

@ -20,12 +20,16 @@ import org.tasks.date.DateTimeUtils.newDateTime
import org.tasks.db.SuspendDbUtils.eachChunk import org.tasks.db.SuspendDbUtils.eachChunk
import org.tasks.jobs.WorkManager.Companion.MAX_CLEANUP_LENGTH 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.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_BACKUP
import org.tasks.jobs.WorkManager.Companion.TAG_MIDNIGHT_REFRESH import org.tasks.jobs.WorkManager.Companion.TAG_MIDNIGHT_REFRESH
import org.tasks.jobs.WorkManager.Companion.TAG_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_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.notifications.Throttle
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.time.DateTimeUtils 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<out SyncWork>) {
val constraints = Constraints.Builder() val constraints = Constraints.Builder()
.setRequiredNetworkType( .setRequiredNetworkType(
if (!immediate && preferences.getBoolean(R.string.p_background_sync_unmetered_only, false)) { if (!immediate && preferences.getBoolean(R.string.p_background_sync_unmetered_only, false)) {
@ -83,15 +96,13 @@ class WorkManagerImpl constructor(
NetworkType.CONNECTED NetworkType.CONNECTED
}) })
.build() .build()
val builder = OneTimeWorkRequest.Builder(SyncWork::class.java) val builder = OneTimeWorkRequest.Builder(c).setConstraints(constraints)
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.MINUTES)
.setConstraints(constraints)
if (!immediate) { if (!immediate) {
builder.setInitialDelay(1, TimeUnit.MINUTES) builder.setInitialDelay(1, TimeUnit.MINUTES)
} }
throttle.run { throttle.run {
workManager workManager
.beginUniqueWork(TAG_SYNC, ExistingWorkPolicy.REPLACE, builder.build()) .beginUniqueWork(tag, ExistingWorkPolicy.REPLACE, builder.build())
.enqueue() .enqueue()
} }
} }
@ -103,7 +114,6 @@ class WorkManagerImpl constructor(
enqueue( enqueue(
OneTimeWorkRequest.Builder(ReverseGeocodeWork::class.java) OneTimeWorkRequest.Builder(ReverseGeocodeWork::class.java)
.setInputData(Data.Builder().putLong(ReverseGeocodeWork.PLACE_ID, place.id).build()) .setInputData(Data.Builder().putLong(ReverseGeocodeWork.PLACE_ID, place.id).build())
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.MINUTES)
.setConstraints( .setConstraints(
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())) Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()))
} }
@ -129,17 +139,22 @@ class WorkManagerImpl constructor(
private suspend fun scheduleBackgroundSync(enabled: Boolean, onlyOnUnmetered: Boolean) { private suspend fun scheduleBackgroundSync(enabled: Boolean, onlyOnUnmetered: Boolean) {
Timber.d("background sync enabled: %s, onlyOnUnmetered: %s", enabled, onlyOnUnmetered) 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<out SyncWork>) {
throttle.run { throttle.run {
if (enabled) { if (enabled) {
workManager.enqueueUniquePeriodicWork( workManager.enqueueUniquePeriodicWork(
TAG_BACKGROUND_SYNC, tag,
ExistingPeriodicWorkPolicy.KEEP, ExistingPeriodicWorkPolicy.KEEP,
PeriodicWorkRequest.Builder(SyncWork::class.java, 1, TimeUnit.HOURS) PeriodicWorkRequest.Builder(c, 1, TimeUnit.HOURS)
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.MINUTES)
.setConstraints(getNetworkConstraints(onlyOnUnmetered)) .setConstraints(getNetworkConstraints(onlyOnUnmetered))
.build()) .build())
} else { } else {
workManager.cancelUniqueWork(TAG_BACKGROUND_SYNC) workManager.cancelUniqueWork(tag)
} }
} }
} }
@ -180,7 +195,6 @@ class WorkManagerImpl constructor(
ExistingPeriodicWorkPolicy.KEEP, ExistingPeriodicWorkPolicy.KEEP,
PeriodicWorkRequest.Builder( PeriodicWorkRequest.Builder(
RemoteConfigWork::class.java, REMOTE_CONFIG_INTERVAL_HOURS, TimeUnit.HOURS) RemoteConfigWork::class.java, REMOTE_CONFIG_INTERVAL_HOURS, TimeUnit.HOURS)
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.MINUTES)
.setConstraints( .setConstraints(
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()) Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())
.build()) .build())

@ -411,9 +411,9 @@ class Preferences @JvmOverloads constructor(private val context: Context, name:
} }
var isSyncOngoing: Boolean var isSyncOngoing: Boolean
get() = getBoolean(R.string.p_sync_ongoing, false) get() = syncFlags.any { getBoolean(it, false) }
set(value) { set(value) {
setBoolean(R.string.p_sync_ongoing, value) syncFlags.forEach { setBoolean(it, value) }
} }
fun useGooglePlaces(): Boolean { fun useGooglePlaces(): Boolean {
@ -491,5 +491,9 @@ class Preferences @JvmOverloads constructor(private val context: Context, name:
private fun getSharedPreferencesName(context: Context): String { private fun getSharedPreferencesName(context: Context): String {
return context.packageName + "_preferences" 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)
} }
} }

@ -28,6 +28,7 @@ import org.tasks.injection.InjectingPreferenceFragment
import org.tasks.jobs.WorkManager import org.tasks.jobs.WorkManager
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.sync.AddAccountDialog import org.tasks.sync.AddAccountDialog
import org.tasks.sync.SyncAdapters
import org.tasks.ui.Toaster import org.tasks.ui.Toaster
import javax.inject.Inject import javax.inject.Inject
@ -43,6 +44,7 @@ class Synchronization : InjectingPreferenceFragment() {
@Inject lateinit var caldavDao: CaldavDao @Inject lateinit var caldavDao: CaldavDao
@Inject lateinit var googleTaskListDao: GoogleTaskListDao @Inject lateinit var googleTaskListDao: GoogleTaskListDao
@Inject lateinit var taskDeleter: TaskDeleter @Inject lateinit var taskDeleter: TaskDeleter
@Inject lateinit var syncAdapters: SyncAdapters
override fun getPreferenceXml() = R.xml.preferences_synchronization override fun getPreferenceXml() = R.xml.preferences_synchronization
@ -95,14 +97,14 @@ class Synchronization : InjectingPreferenceFragment() {
if (requestCode == REQUEST_CALDAV_SETTINGS) { if (requestCode == REQUEST_CALDAV_SETTINGS) {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
lifecycleScope.launch(NonCancellable) { lifecycleScope.launch(NonCancellable) {
workManager.sync(true) syncAdapters.sync(true)
workManager.updateBackgroundSync() workManager.updateBackgroundSync()
} }
} }
} else if (requestCode == REQUEST_GOOGLE_TASKS) { } else if (requestCode == REQUEST_GOOGLE_TASKS) {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
lifecycleScope.launch(NonCancellable) { lifecycleScope.launch(NonCancellable) {
workManager.sync(true) syncAdapters.sync(true)
workManager.updateBackgroundSync() workManager.updateBackgroundSync()
} }
} else if (data != null) { } else if (data != null) {

@ -4,7 +4,10 @@ import com.todoroo.astrid.data.SyncFlags
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.withContext 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.CaldavDao
import org.tasks.data.GoogleTaskDao
import org.tasks.data.GoogleTaskListDao import org.tasks.data.GoogleTaskListDao
import org.tasks.jobs.WorkManager import org.tasks.jobs.WorkManager
import javax.inject.Inject import javax.inject.Inject
@ -12,19 +15,24 @@ import javax.inject.Inject
class SyncAdapters @Inject constructor( class SyncAdapters @Inject constructor(
private val workManager: WorkManager, private val workManager: WorkManager,
private val caldavDao: CaldavDao, private val caldavDao: CaldavDao,
private val googleTaskDao: GoogleTaskDao,
private val googleTaskListDao: GoogleTaskListDao) { private val googleTaskListDao: GoogleTaskListDao) {
suspend fun sync(task: Task, original: Task?) { suspend fun sync(task: Task, original: Task?) {
val suppress = task.checkTransitory(SyncFlags.SUPPRESS_SYNC) if (task.checkTransitory(SyncFlags.SUPPRESS_SYNC)) {
val forceCaldav = task.checkTransitory(SyncFlags.FORCE_CALDAV_SYNC) return
val pushGtasks = !suppress }
&& !task.googleTaskUpToDate(original) if (!task.googleTaskUpToDate(original)
&& isGoogleTaskSyncEnabled() && googleTaskDao.getAllByTaskId(task.id).isNotEmpty()) {
val pushCaldav = !suppress workManager.googleTaskSync(false)
&& (forceCaldav || !task.caldavUpToDate(original)) }
&& isCaldavSyncEnabled() if (task.checkTransitory(SyncFlags.FORCE_CALDAV_SYNC) || !task.caldavUpToDate(original)) {
if (pushGtasks || pushCaldav) { if (caldavDao.isAccountType(task.id, TYPE_CALDAV)) {
sync() 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) { suspend fun sync(immediate: Boolean): Boolean = withContext(NonCancellable) {
if (isSyncEnabled()) { val googleTasks = isGoogleTaskSyncEnabled()
workManager.sync(immediate) if (googleTasks) {
true workManager.googleTaskSync(immediate)
} else {
false
} }
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()
} }

@ -333,7 +333,9 @@
<string name="p_crash_main_queries">debug_crash_main_queries</string> <string name="p_crash_main_queries">debug_crash_main_queries</string>
<string name="warned_play_services">warned_play_services</string> <string name="warned_play_services">warned_play_services</string>
<string name="p_background_sync_unmetered_only">background_sync_unmetered_only</string> <string name="p_background_sync_unmetered_only">background_sync_unmetered_only</string>
<string name="p_sync_ongoing">sync_ongoing</string> <string name="p_sync_ongoing_google_tasks">sync_ongoing_google_tasks</string>
<string name="p_sync_ongoing_caldav">sync_ongoing_caldav</string>
<string name="p_sync_ongoing_etesync">sync_ongoing_etesync</string>
<string name="p_last_backup">last_backup</string> <string name="p_last_backup">last_backup</string>
<string name="p_show_description">show_description</string> <string name="p_show_description">show_description</string>
<string name="p_show_full_description">show_full_description</string> <string name="p_show_full_description">show_full_description</string>

Loading…
Cancel
Save