|
|
@ -15,9 +15,9 @@ import org.tasks.R
|
|
|
|
import org.tasks.data.CaldavDao
|
|
|
|
import org.tasks.data.CaldavDao
|
|
|
|
import org.tasks.data.GoogleTaskListDao
|
|
|
|
import org.tasks.data.GoogleTaskListDao
|
|
|
|
import org.tasks.data.Place
|
|
|
|
import org.tasks.data.Place
|
|
|
|
import org.tasks.data.runBlocking
|
|
|
|
|
|
|
|
import org.tasks.date.DateTimeUtils.midnight
|
|
|
|
import org.tasks.date.DateTimeUtils.midnight
|
|
|
|
import org.tasks.date.DateTimeUtils.newDateTime
|
|
|
|
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.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
|
|
|
@ -26,6 +26,7 @@ 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
|
|
|
|
|
|
|
|
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
|
|
|
|
import timber.log.Timber
|
|
|
|
import timber.log.Timber
|
|
|
@ -38,32 +39,42 @@ class WorkManagerImpl constructor(
|
|
|
|
private val preferences: Preferences,
|
|
|
|
private val preferences: Preferences,
|
|
|
|
private val googleTaskListDao: GoogleTaskListDao,
|
|
|
|
private val googleTaskListDao: GoogleTaskListDao,
|
|
|
|
private val caldavDao: CaldavDao): WorkManager {
|
|
|
|
private val caldavDao: CaldavDao): WorkManager {
|
|
|
|
|
|
|
|
private val throttle = Throttle(200, 60000, "WORK")
|
|
|
|
private val alarmManager: AlarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
|
|
|
private val alarmManager: AlarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
|
|
|
private val workManager = androidx.work.WorkManager.getInstance(context)
|
|
|
|
private val workManager = androidx.work.WorkManager.getInstance(context)
|
|
|
|
|
|
|
|
|
|
|
|
override fun afterComplete(current: Task, original: Task?) {
|
|
|
|
private suspend fun enqueue(builder: WorkRequest.Builder<*, *>) {
|
|
|
|
workManager.enqueue(
|
|
|
|
throttle.run {
|
|
|
|
|
|
|
|
workManager.enqueue(builder.build())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private suspend fun enqueue(continuation: WorkContinuation) {
|
|
|
|
|
|
|
|
throttle.run {
|
|
|
|
|
|
|
|
continuation.enqueue()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
override suspend fun afterComplete(task: Task) {
|
|
|
|
|
|
|
|
enqueue(
|
|
|
|
OneTimeWorkRequest.Builder(AfterSaveWork::class.java)
|
|
|
|
OneTimeWorkRequest.Builder(AfterSaveWork::class.java)
|
|
|
|
.setInputData(Data.Builder()
|
|
|
|
.setInputData(Data.Builder()
|
|
|
|
.putLong(AfterSaveWork.EXTRA_ID, current.id)
|
|
|
|
.putLong(AfterSaveWork.EXTRA_ID, task.id)
|
|
|
|
.build())
|
|
|
|
.build()))
|
|
|
|
.build())
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override fun cleanup(ids: Iterable<Long>) {
|
|
|
|
override suspend fun cleanup(ids: Iterable<Long>) {
|
|
|
|
ids.chunked(MAX_CLEANUP_LENGTH) {
|
|
|
|
ids.eachChunk(MAX_CLEANUP_LENGTH) {
|
|
|
|
workManager.enqueue(
|
|
|
|
enqueue(
|
|
|
|
OneTimeWorkRequest.Builder(CleanupWork::class.java)
|
|
|
|
OneTimeWorkRequest.Builder(CleanupWork::class.java)
|
|
|
|
.setInputData(
|
|
|
|
.setInputData(
|
|
|
|
Data.Builder()
|
|
|
|
Data.Builder()
|
|
|
|
.putLongArray(CleanupWork.EXTRA_TASK_IDS, it.toLongArray())
|
|
|
|
.putLongArray(CleanupWork.EXTRA_TASK_IDS, it.toLongArray())
|
|
|
|
.build())
|
|
|
|
.build()))
|
|
|
|
.build())
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override fun sync(immediate: Boolean) {
|
|
|
|
override suspend fun sync(immediate: Boolean) {
|
|
|
|
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)) {
|
|
|
@ -78,24 +89,26 @@ class WorkManagerImpl constructor(
|
|
|
|
if (!immediate) {
|
|
|
|
if (!immediate) {
|
|
|
|
builder.setInitialDelay(1, TimeUnit.MINUTES)
|
|
|
|
builder.setInitialDelay(1, TimeUnit.MINUTES)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
val request = builder.build()
|
|
|
|
throttle.run {
|
|
|
|
workManager.beginUniqueWork(TAG_SYNC, ExistingWorkPolicy.REPLACE, request).enqueue()
|
|
|
|
workManager
|
|
|
|
|
|
|
|
.beginUniqueWork(TAG_SYNC, ExistingWorkPolicy.REPLACE, builder.build())
|
|
|
|
|
|
|
|
.enqueue()
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override fun reverseGeocode(place: Place) {
|
|
|
|
override suspend fun reverseGeocode(place: Place) {
|
|
|
|
if (BuildConfig.DEBUG && place.id == 0L) {
|
|
|
|
if (BuildConfig.DEBUG && place.id == 0L) {
|
|
|
|
throw RuntimeException("Missing id")
|
|
|
|
throw RuntimeException("Missing id")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
workManager.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)
|
|
|
|
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.MINUTES)
|
|
|
|
.setConstraints(
|
|
|
|
.setConstraints(
|
|
|
|
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())
|
|
|
|
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()))
|
|
|
|
.build())
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override fun updateBackgroundSync() = runBlocking {
|
|
|
|
override suspend fun updateBackgroundSync() {
|
|
|
|
updateBackgroundSync(null, null, null)
|
|
|
|
updateBackgroundSync(null, null, null)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -114,8 +127,9 @@ class WorkManagerImpl constructor(
|
|
|
|
scheduleBackgroundSync(backgroundEnabled && accountsPresent, onlyOnWifi)
|
|
|
|
scheduleBackgroundSync(backgroundEnabled && accountsPresent, onlyOnWifi)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private 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)
|
|
|
|
|
|
|
|
throttle.run {
|
|
|
|
if (enabled) {
|
|
|
|
if (enabled) {
|
|
|
|
workManager.enqueueUniquePeriodicWork(
|
|
|
|
workManager.enqueueUniquePeriodicWork(
|
|
|
|
TAG_BACKGROUND_SYNC,
|
|
|
|
TAG_BACKGROUND_SYNC,
|
|
|
@ -128,10 +142,11 @@ class WorkManagerImpl constructor(
|
|
|
|
workManager.cancelUniqueWork(TAG_BACKGROUND_SYNC)
|
|
|
|
workManager.cancelUniqueWork(TAG_BACKGROUND_SYNC)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override fun scheduleRefresh(time: Long) = enqueueUnique(TAG_REFRESH, RefreshWork::class.java, time)
|
|
|
|
override suspend fun scheduleRefresh(time: Long) = enqueueUnique(TAG_REFRESH, RefreshWork::class.java, time)
|
|
|
|
|
|
|
|
|
|
|
|
override fun scheduleMidnightRefresh() =
|
|
|
|
override suspend fun scheduleMidnightRefresh() =
|
|
|
|
enqueueUnique(TAG_MIDNIGHT_REFRESH, MidnightRefreshWork::class.java, midnight())
|
|
|
|
enqueueUnique(TAG_MIDNIGHT_REFRESH, MidnightRefreshWork::class.java, midnight())
|
|
|
|
|
|
|
|
|
|
|
|
override fun scheduleNotification(scheduledTime: Long) {
|
|
|
|
override fun scheduleNotification(scheduledTime: Long) {
|
|
|
@ -149,7 +164,7 @@ class WorkManagerImpl constructor(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override fun scheduleBackup() {
|
|
|
|
override suspend fun scheduleBackup() =
|
|
|
|
enqueueUnique(
|
|
|
|
enqueueUnique(
|
|
|
|
TAG_BACKUP,
|
|
|
|
TAG_BACKUP,
|
|
|
|
BackupWork::class.java,
|
|
|
|
BackupWork::class.java,
|
|
|
@ -157,9 +172,9 @@ class WorkManagerImpl constructor(
|
|
|
|
.plusDays(1)
|
|
|
|
.plusDays(1)
|
|
|
|
.millis
|
|
|
|
.millis
|
|
|
|
.coerceAtMost(midnight()))
|
|
|
|
.coerceAtMost(midnight()))
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
override fun scheduleConfigRefresh() {
|
|
|
|
override suspend fun scheduleConfigRefresh() {
|
|
|
|
|
|
|
|
throttle.run {
|
|
|
|
workManager.enqueueUniquePeriodicWork(
|
|
|
|
workManager.enqueueUniquePeriodicWork(
|
|
|
|
TAG_REMOTE_CONFIG,
|
|
|
|
TAG_REMOTE_CONFIG,
|
|
|
|
ExistingPeriodicWorkPolicy.KEEP,
|
|
|
|
ExistingPeriodicWorkPolicy.KEEP,
|
|
|
@ -170,8 +185,9 @@ class WorkManagerImpl constructor(
|
|
|
|
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())
|
|
|
|
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())
|
|
|
|
.build())
|
|
|
|
.build())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override fun scheduleDriveUpload(uri: Uri, purge: Boolean) {
|
|
|
|
override suspend fun scheduleDriveUpload(uri: Uri, purge: Boolean) {
|
|
|
|
if (!preferences.getBoolean(R.string.p_google_drive_backup, false)) {
|
|
|
|
if (!preferences.getBoolean(R.string.p_google_drive_backup, false)) {
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -181,7 +197,7 @@ class WorkManagerImpl constructor(
|
|
|
|
if (purge) {
|
|
|
|
if (purge) {
|
|
|
|
builder.setInitialDelay(Random().nextInt(3600).toLong(), TimeUnit.SECONDS)
|
|
|
|
builder.setInitialDelay(Random().nextInt(3600).toLong(), TimeUnit.SECONDS)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
workManager.enqueue(builder.build())
|
|
|
|
enqueue(builder)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private val networkConstraints: Constraints
|
|
|
|
private val networkConstraints: Constraints
|
|
|
@ -193,14 +209,15 @@ class WorkManagerImpl constructor(
|
|
|
|
.setRequiredNetworkType(if (unmeteredOnly) NetworkType.UNMETERED else NetworkType.CONNECTED)
|
|
|
|
.setRequiredNetworkType(if (unmeteredOnly) NetworkType.UNMETERED else NetworkType.CONNECTED)
|
|
|
|
.build()
|
|
|
|
.build()
|
|
|
|
|
|
|
|
|
|
|
|
private fun enqueueUnique(key: String, c: Class<out CoroutineWorker?>, time: Long) {
|
|
|
|
@SuppressLint("EnqueueWork")
|
|
|
|
|
|
|
|
private suspend fun enqueueUnique(key: String, c: Class<out CoroutineWorker?>, time: Long) {
|
|
|
|
val delay = time - DateUtilities.now()
|
|
|
|
val delay = time - DateUtilities.now()
|
|
|
|
val builder = OneTimeWorkRequest.Builder(c)
|
|
|
|
val builder = OneTimeWorkRequest.Builder(c)
|
|
|
|
if (delay > 0) {
|
|
|
|
if (delay > 0) {
|
|
|
|
builder.setInitialDelay(delay, TimeUnit.MILLISECONDS)
|
|
|
|
builder.setInitialDelay(delay, TimeUnit.MILLISECONDS)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Timber.d("$key: ${DateTimeUtils.printTimestamp(time)} (${DateTimeUtils.printDuration(delay)})")
|
|
|
|
Timber.d("$key: ${DateTimeUtils.printTimestamp(time)} (${DateTimeUtils.printDuration(delay)})")
|
|
|
|
workManager.beginUniqueWork(key, ExistingWorkPolicy.REPLACE, builder.build()).enqueue()
|
|
|
|
enqueue(workManager.beginUniqueWork(key, ExistingWorkPolicy.REPLACE, builder.build()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override fun cancelNotifications() {
|
|
|
|
override fun cancelNotifications() {
|
|
|
|