Remove RefreshScheduler

pull/2860/head
Alex Baker 1 month ago
parent f84a37a60a
commit d60472d1bc

@ -21,13 +21,11 @@ import org.tasks.jobs.WorkManager
import org.tasks.location.GeofenceApi import org.tasks.location.GeofenceApi
import org.tasks.notifications.NotificationManager import org.tasks.notifications.NotificationManager
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.scheduling.RefreshScheduler
import org.tasks.sync.SyncAdapters import org.tasks.sync.SyncAdapters
import javax.inject.Inject import javax.inject.Inject
class TaskDao @Inject constructor( class TaskDao @Inject constructor(
private val taskDao: TaskDao, private val taskDao: TaskDao,
private val refreshScheduler: RefreshScheduler,
private val localBroadcastManager: LocalBroadcastManager, private val localBroadcastManager: LocalBroadcastManager,
private val notificationManager: NotificationManager, private val notificationManager: NotificationManager,
private val geofenceApi: GeofenceApi, private val geofenceApi: GeofenceApi,
@ -134,7 +132,7 @@ class TaskDao @Inject constructor(
geofenceApi.update(task.id) geofenceApi.update(task.id)
} }
alarmService.scheduleAlarms(task) alarmService.scheduleAlarms(task)
refreshScheduler.scheduleRefresh(task) workManager.scheduleRefresh()
if (!task.isSuppressRefresh()) { if (!task.isSuppressRefresh()) {
localBroadcastManager.broadcastRefresh() localBroadcastManager.broadcastRefresh()
} }

@ -30,7 +30,6 @@ import org.tasks.opentasks.OpenTaskContentObserver
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.receivers.RefreshReceiver import org.tasks.receivers.RefreshReceiver
import org.tasks.scheduling.NotificationSchedulerIntentService import org.tasks.scheduling.NotificationSchedulerIntentService
import org.tasks.scheduling.RefreshScheduler
import org.tasks.themes.ThemeBase import org.tasks.themes.ThemeBase
import org.tasks.widget.AppWidgetManager import org.tasks.widget.AppWidgetManager
import timber.log.Timber import timber.log.Timber
@ -47,12 +46,11 @@ class Tasks : Application(), Configuration.Provider {
@Inject lateinit var localBroadcastManager: LocalBroadcastManager @Inject lateinit var localBroadcastManager: LocalBroadcastManager
@Inject lateinit var upgrader: Lazy<Upgrader> @Inject lateinit var upgrader: Lazy<Upgrader>
@Inject lateinit var workManager: Lazy<WorkManager> @Inject lateinit var workManager: Lazy<WorkManager>
@Inject lateinit var refreshScheduler: Lazy<RefreshScheduler>
@Inject lateinit var geofenceApi: Lazy<GeofenceApi> @Inject lateinit var geofenceApi: Lazy<GeofenceApi>
@Inject lateinit var appWidgetManager: Lazy<AppWidgetManager> @Inject lateinit var appWidgetManager: Lazy<AppWidgetManager>
@Inject lateinit var workerFactory: HiltWorkerFactory @Inject lateinit var workerFactory: HiltWorkerFactory
@Inject lateinit var contentObserver: Lazy<OpenTaskContentObserver> @Inject lateinit var contentObserver: Lazy<OpenTaskContentObserver>
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
buildSetup.setup() buildSetup.setup()
@ -95,15 +93,15 @@ class Tasks : Application(), Configuration.Provider {
private fun backgroundWork() = CoroutineScope(Dispatchers.Default).launch { private fun backgroundWork() = CoroutineScope(Dispatchers.Default).launch {
inventory.updateTasksAccount() inventory.updateTasksAccount()
NotificationSchedulerIntentService.enqueueWork(context) NotificationSchedulerIntentService.enqueueWork(context)
refreshScheduler.get().scheduleAll()
workManager.get().apply { workManager.get().apply {
updateBackgroundSync() updateBackgroundSync()
scheduleMidnightRefresh() scheduleMidnightRefresh()
scheduleBackup() scheduleBackup()
scheduleConfigRefresh() scheduleConfigRefresh()
OpenTaskContentObserver.registerObserver(context, contentObserver.get())
updatePurchases() updatePurchases()
scheduleRefresh()
} }
OpenTaskContentObserver.registerObserver(context, contentObserver.get())
geofenceApi.get().registerAll() geofenceApi.get().registerAll()
FileHelper.delete(context, preferences.cacheDirectory) FileHelper.delete(context, preferences.cacheDirectory)
appWidgetManager.get().reconfigureWidgets() appWidgetManager.get().reconfigureWidgets()

@ -25,11 +25,24 @@ import org.tasks.preferences.QueryPreferences
import org.tasks.time.DateTimeUtils.currentTimeMillis import org.tasks.time.DateTimeUtils.currentTimeMillis
import timber.log.Timber import timber.log.Timber
private const val MAX_TIME = 9999999999999
@Dao @Dao
abstract class TaskDao(private val database: Database) { abstract class TaskDao(private val database: Database) {
@Query("SELECT * FROM tasks WHERE completed = 0 AND deleted = 0 AND (hideUntil > :now OR dueDate > :now)") @Query("""
internal abstract suspend fun needsRefresh(now: Long = now()): List<Task> SELECT MIN(min_value)
FROM (
SELECT
MIN(
CASE WHEN dueDate > :now THEN dueDate ELSE $MAX_TIME END,
CASE WHEN hideUntil > :now THEN hideUntil ELSE $MAX_TIME END
) as min_value
FROM tasks
WHERE completed = 0 AND deleted = 0
)
""")
abstract suspend fun nextRefresh(now: Long = System.currentTimeMillis()): Long
@Query("SELECT * FROM tasks WHERE _id = :id LIMIT 1") @Query("SELECT * FROM tasks WHERE _id = :id LIMIT 1")
abstract suspend fun fetch(id: Long): Task? abstract suspend fun fetch(id: Long): Task?

@ -13,6 +13,7 @@ import org.tasks.R
import org.tasks.caldav.FileStorage import org.tasks.caldav.FileStorage
import org.tasks.data.CaldavDao import org.tasks.data.CaldavDao
import org.tasks.data.OpenTaskDao import org.tasks.data.OpenTaskDao
import org.tasks.data.TaskDao
import org.tasks.db.Migrations import org.tasks.db.Migrations
import org.tasks.jobs.WorkManager import org.tasks.jobs.WorkManager
import org.tasks.jobs.WorkManagerImpl import org.tasks.jobs.WorkManagerImpl
@ -51,6 +52,7 @@ internal class ProductionModule {
@ApplicationContext context: Context, @ApplicationContext context: Context,
preferences: Preferences, preferences: Preferences,
caldavDao: CaldavDao, caldavDao: CaldavDao,
openTaskDao: OpenTaskDao openTaskDao: OpenTaskDao,
): WorkManager = WorkManagerImpl(context, preferences, caldavDao, openTaskDao) taskDao: TaskDao,
): WorkManager = WorkManagerImpl(context, preferences, caldavDao, openTaskDao, taskDao)
} }

@ -7,20 +7,20 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import org.tasks.LocalBroadcastManager import org.tasks.LocalBroadcastManager
import org.tasks.analytics.Firebase import org.tasks.analytics.Firebase
import org.tasks.scheduling.RefreshScheduler
@HiltWorker @HiltWorker
class RefreshWork @AssistedInject constructor( class RefreshWork @AssistedInject constructor(
@Assisted context: Context, @Assisted context: Context,
@Assisted workerParams: WorkerParameters, @Assisted workerParams: WorkerParameters,
firebase: Firebase, firebase: Firebase,
private val refreshScheduler: RefreshScheduler, private val localBroadcastManager: LocalBroadcastManager,
private val localBroadcastManager: LocalBroadcastManager) : RepeatingWorker(context, workerParams, firebase) { private val workManager: WorkManager,
) : RepeatingWorker(context, workerParams, firebase) {
override suspend fun run(): Result { override suspend fun run(): Result {
localBroadcastManager.broadcastRefresh() localBroadcastManager.broadcastRefresh()
return Result.success() return Result.success()
} }
override suspend fun scheduleNext() = refreshScheduler.scheduleNext() override suspend fun scheduleNext() = workManager.scheduleRefresh()
} }

@ -20,7 +20,7 @@ interface WorkManager {
fun updateBackgroundSync() fun updateBackgroundSync()
fun scheduleRefresh(time: Long) suspend fun scheduleRefresh()
fun scheduleMidnightRefresh() fun scheduleMidnightRefresh()

@ -6,9 +6,18 @@ import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import androidx.work.* import androidx.work.Constraints
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.ExistingWorkPolicy.APPEND_OR_REPLACE import androidx.work.ExistingWorkPolicy.APPEND_OR_REPLACE
import androidx.work.ExistingWorkPolicy.REPLACE import androidx.work.ExistingWorkPolicy.REPLACE
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequest
import androidx.work.PeriodicWorkRequest
import androidx.work.WorkContinuation
import androidx.work.WorkInfo
import androidx.work.WorkRequest
import androidx.work.Worker
import androidx.work.workDataOf
import com.todoroo.andlib.utility.AndroidUtilities import com.todoroo.andlib.utility.AndroidUtilities
import com.todoroo.andlib.utility.AndroidUtilities.atLeastS import com.todoroo.andlib.utility.AndroidUtilities.atLeastS
import com.todoroo.andlib.utility.DateUtilities import com.todoroo.andlib.utility.DateUtilities
@ -17,11 +26,15 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.tasks.BuildConfig import org.tasks.BuildConfig
import org.tasks.R import org.tasks.R
import org.tasks.data.* import org.tasks.data.CaldavAccount
import org.tasks.data.CaldavAccount.Companion.TYPE_CALDAV import org.tasks.data.CaldavAccount.Companion.TYPE_CALDAV
import org.tasks.data.CaldavAccount.Companion.TYPE_ETEBASE import org.tasks.data.CaldavAccount.Companion.TYPE_ETEBASE
import org.tasks.data.CaldavAccount.Companion.TYPE_GOOGLE_TASKS import org.tasks.data.CaldavAccount.Companion.TYPE_GOOGLE_TASKS
import org.tasks.data.CaldavAccount.Companion.TYPE_TASKS import org.tasks.data.CaldavAccount.Companion.TYPE_TASKS
import org.tasks.data.CaldavDao
import org.tasks.data.OpenTaskDao
import org.tasks.data.Place
import org.tasks.data.TaskDao
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.jobs.DriveUploader.Companion.EXTRA_PURGE import org.tasks.jobs.DriveUploader.Companion.EXTRA_PURGE
@ -42,15 +55,16 @@ 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
import java.util.* import java.util.Random
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.math.max import kotlin.math.max
class WorkManagerImpl( class WorkManagerImpl(
private val context: Context, private val context: Context,
private val preferences: Preferences, private val preferences: Preferences,
private val caldavDao: CaldavDao, private val caldavDao: CaldavDao,
private val openTaskDao: OpenTaskDao private val openTaskDao: OpenTaskDao,
private val taskDao: TaskDao,
): WorkManager { ): WorkManager {
private val throttle = Throttle(200, 60000, "WORK") 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
@ -126,7 +140,8 @@ class WorkManagerImpl(
} }
} }
override fun scheduleRefresh(time: Long) = enqueueUnique(TAG_REFRESH, RefreshWork::class.java, time) override suspend fun scheduleRefresh() =
enqueueUnique(TAG_REFRESH, RefreshWork::class.java, taskDao.nextRefresh())
override fun scheduleMidnightRefresh() = override fun scheduleMidnightRefresh() =
enqueueUnique(TAG_MIDNIGHT_REFRESH, MidnightRefreshWork::class.java, midnight()) enqueueUnique(TAG_MIDNIGHT_REFRESH, MidnightRefreshWork::class.java, midnight())

@ -1,56 +0,0 @@
package org.tasks.scheduling
import com.todoroo.astrid.data.Task
import org.tasks.data.TaskDao
import org.tasks.jobs.WorkManager
import org.tasks.time.DateTimeUtils
import java.util.SortedSet
import java.util.TreeSet
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class RefreshScheduler @Inject internal constructor(
private val workManager: WorkManager,
private val taskDao: TaskDao,
) {
private val jobs: SortedSet<Long> = TreeSet()
suspend fun scheduleAll() {
for (task in taskDao.needsRefresh()) {
scheduleRefresh(task)
}
}
@Synchronized
fun scheduleRefresh(task: Task) {
if (task.hasDueDate()) {
scheduleRefresh(task.dueDate)
}
if (task.hasStartDate()) {
scheduleRefresh(task.hideUntil)
}
}
@Synchronized
fun scheduleNext() {
val lapsed = jobs.headSet(DateTimeUtils.currentTimeMillis() + 1).toList()
jobs.removeAll(lapsed)
if (!jobs.isEmpty()) {
workManager.scheduleRefresh(jobs.first())
}
}
private fun scheduleRefresh(timestamp: Long) {
val now = DateTimeUtils.currentTimeMillis()
if (now < timestamp) {
val upcoming = jobs.tailSet(now)
val reschedule = upcoming.isEmpty() || timestamp < upcoming.first()
jobs.add(timestamp)
if (reschedule) {
scheduleNext()
}
}
}
}
Loading…
Cancel
Save