From d60472d1bc484d5c155e027a78b7108ffa77deab Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Sun, 28 Apr 2024 03:15:15 -0500 Subject: [PATCH] Remove RefreshScheduler --- .../java/com/todoroo/astrid/dao/TaskDao.kt | 4 +- app/src/main/java/org/tasks/Tasks.kt | 8 +-- app/src/main/java/org/tasks/data/TaskDao.kt | 17 +++++- .../org/tasks/injection/ProductionModule.kt | 6 +- .../main/java/org/tasks/jobs/RefreshWork.kt | 14 ++--- .../main/java/org/tasks/jobs/WorkManager.kt | 2 +- .../java/org/tasks/jobs/WorkManagerImpl.kt | 31 +++++++--- .../org/tasks/scheduling/RefreshScheduler.kt | 56 ------------------- 8 files changed, 54 insertions(+), 84 deletions(-) delete mode 100644 app/src/main/java/org/tasks/scheduling/RefreshScheduler.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 67a1e43cd..fdeb6fa80 100644 --- a/app/src/main/java/com/todoroo/astrid/dao/TaskDao.kt +++ b/app/src/main/java/com/todoroo/astrid/dao/TaskDao.kt @@ -21,13 +21,11 @@ import org.tasks.jobs.WorkManager import org.tasks.location.GeofenceApi import org.tasks.notifications.NotificationManager import org.tasks.preferences.Preferences -import org.tasks.scheduling.RefreshScheduler import org.tasks.sync.SyncAdapters import javax.inject.Inject class TaskDao @Inject constructor( private val taskDao: TaskDao, - private val refreshScheduler: RefreshScheduler, private val localBroadcastManager: LocalBroadcastManager, private val notificationManager: NotificationManager, private val geofenceApi: GeofenceApi, @@ -134,7 +132,7 @@ class TaskDao @Inject constructor( geofenceApi.update(task.id) } alarmService.scheduleAlarms(task) - refreshScheduler.scheduleRefresh(task) + workManager.scheduleRefresh() if (!task.isSuppressRefresh()) { localBroadcastManager.broadcastRefresh() } diff --git a/app/src/main/java/org/tasks/Tasks.kt b/app/src/main/java/org/tasks/Tasks.kt index 17973dd90..70b7f6f1c 100644 --- a/app/src/main/java/org/tasks/Tasks.kt +++ b/app/src/main/java/org/tasks/Tasks.kt @@ -30,7 +30,6 @@ import org.tasks.opentasks.OpenTaskContentObserver import org.tasks.preferences.Preferences import org.tasks.receivers.RefreshReceiver import org.tasks.scheduling.NotificationSchedulerIntentService -import org.tasks.scheduling.RefreshScheduler import org.tasks.themes.ThemeBase import org.tasks.widget.AppWidgetManager import timber.log.Timber @@ -47,12 +46,11 @@ class Tasks : Application(), Configuration.Provider { @Inject lateinit var localBroadcastManager: LocalBroadcastManager @Inject lateinit var upgrader: Lazy @Inject lateinit var workManager: Lazy - @Inject lateinit var refreshScheduler: Lazy @Inject lateinit var geofenceApi: Lazy @Inject lateinit var appWidgetManager: Lazy @Inject lateinit var workerFactory: HiltWorkerFactory @Inject lateinit var contentObserver: Lazy - + override fun onCreate() { super.onCreate() buildSetup.setup() @@ -95,15 +93,15 @@ class Tasks : Application(), Configuration.Provider { private fun backgroundWork() = CoroutineScope(Dispatchers.Default).launch { inventory.updateTasksAccount() NotificationSchedulerIntentService.enqueueWork(context) - refreshScheduler.get().scheduleAll() workManager.get().apply { updateBackgroundSync() scheduleMidnightRefresh() scheduleBackup() scheduleConfigRefresh() - OpenTaskContentObserver.registerObserver(context, contentObserver.get()) updatePurchases() + scheduleRefresh() } + OpenTaskContentObserver.registerObserver(context, contentObserver.get()) geofenceApi.get().registerAll() FileHelper.delete(context, preferences.cacheDirectory) appWidgetManager.get().reconfigureWidgets() diff --git a/app/src/main/java/org/tasks/data/TaskDao.kt b/app/src/main/java/org/tasks/data/TaskDao.kt index aac76a7f3..a19d479b6 100644 --- a/app/src/main/java/org/tasks/data/TaskDao.kt +++ b/app/src/main/java/org/tasks/data/TaskDao.kt @@ -25,11 +25,24 @@ import org.tasks.preferences.QueryPreferences import org.tasks.time.DateTimeUtils.currentTimeMillis import timber.log.Timber +private const val MAX_TIME = 9999999999999 + @Dao abstract class TaskDao(private val database: Database) { - @Query("SELECT * FROM tasks WHERE completed = 0 AND deleted = 0 AND (hideUntil > :now OR dueDate > :now)") - internal abstract suspend fun needsRefresh(now: Long = now()): List + @Query(""" +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") abstract suspend fun fetch(id: Long): Task? diff --git a/app/src/main/java/org/tasks/injection/ProductionModule.kt b/app/src/main/java/org/tasks/injection/ProductionModule.kt index 88c12c70d..b28b93847 100644 --- a/app/src/main/java/org/tasks/injection/ProductionModule.kt +++ b/app/src/main/java/org/tasks/injection/ProductionModule.kt @@ -13,6 +13,7 @@ import org.tasks.R import org.tasks.caldav.FileStorage import org.tasks.data.CaldavDao import org.tasks.data.OpenTaskDao +import org.tasks.data.TaskDao import org.tasks.db.Migrations import org.tasks.jobs.WorkManager import org.tasks.jobs.WorkManagerImpl @@ -51,6 +52,7 @@ internal class ProductionModule { @ApplicationContext context: Context, preferences: Preferences, caldavDao: CaldavDao, - openTaskDao: OpenTaskDao - ): WorkManager = WorkManagerImpl(context, preferences, caldavDao, openTaskDao) + openTaskDao: OpenTaskDao, + taskDao: TaskDao, + ): WorkManager = WorkManagerImpl(context, preferences, caldavDao, openTaskDao, taskDao) } \ No newline at end of file diff --git a/app/src/main/java/org/tasks/jobs/RefreshWork.kt b/app/src/main/java/org/tasks/jobs/RefreshWork.kt index 4c31a45b0..05682560b 100644 --- a/app/src/main/java/org/tasks/jobs/RefreshWork.kt +++ b/app/src/main/java/org/tasks/jobs/RefreshWork.kt @@ -7,20 +7,20 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedInject import org.tasks.LocalBroadcastManager import org.tasks.analytics.Firebase -import org.tasks.scheduling.RefreshScheduler @HiltWorker class RefreshWork @AssistedInject constructor( - @Assisted context: Context, - @Assisted workerParams: WorkerParameters, - firebase: Firebase, - private val refreshScheduler: RefreshScheduler, - private val localBroadcastManager: LocalBroadcastManager) : RepeatingWorker(context, workerParams, firebase) { + @Assisted context: Context, + @Assisted workerParams: WorkerParameters, + firebase: Firebase, + private val localBroadcastManager: LocalBroadcastManager, + private val workManager: WorkManager, +) : RepeatingWorker(context, workerParams, firebase) { override suspend fun run(): Result { localBroadcastManager.broadcastRefresh() return Result.success() } - override suspend fun scheduleNext() = refreshScheduler.scheduleNext() + override suspend fun scheduleNext() = workManager.scheduleRefresh() } \ No newline at end of file diff --git a/app/src/main/java/org/tasks/jobs/WorkManager.kt b/app/src/main/java/org/tasks/jobs/WorkManager.kt index 5eb00d4a6..c6e1bf2c0 100644 --- a/app/src/main/java/org/tasks/jobs/WorkManager.kt +++ b/app/src/main/java/org/tasks/jobs/WorkManager.kt @@ -20,7 +20,7 @@ interface WorkManager { fun updateBackgroundSync() - fun scheduleRefresh(time: Long) + suspend fun scheduleRefresh() fun scheduleMidnightRefresh() diff --git a/app/src/main/java/org/tasks/jobs/WorkManagerImpl.kt b/app/src/main/java/org/tasks/jobs/WorkManagerImpl.kt index e919cd16d..9491e1f2a 100644 --- a/app/src/main/java/org/tasks/jobs/WorkManagerImpl.kt +++ b/app/src/main/java/org/tasks/jobs/WorkManagerImpl.kt @@ -6,9 +6,18 @@ import android.app.PendingIntent import android.content.Context import android.content.Intent 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.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.atLeastS import com.todoroo.andlib.utility.DateUtilities @@ -17,11 +26,15 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.tasks.BuildConfig 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_ETEBASE import org.tasks.data.CaldavAccount.Companion.TYPE_GOOGLE_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.newDateTime 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.time.DateTimeUtils import timber.log.Timber -import java.util.* +import java.util.Random import java.util.concurrent.TimeUnit import kotlin.math.max class WorkManagerImpl( - private val context: Context, - private val preferences: Preferences, - private val caldavDao: CaldavDao, - private val openTaskDao: OpenTaskDao + private val context: Context, + private val preferences: Preferences, + private val caldavDao: CaldavDao, + private val openTaskDao: OpenTaskDao, + private val taskDao: TaskDao, ): WorkManager { private val throttle = Throttle(200, 60000, "WORK") 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() = enqueueUnique(TAG_MIDNIGHT_REFRESH, MidnightRefreshWork::class.java, midnight()) diff --git a/app/src/main/java/org/tasks/scheduling/RefreshScheduler.kt b/app/src/main/java/org/tasks/scheduling/RefreshScheduler.kt deleted file mode 100644 index 8c28802ec..000000000 --- a/app/src/main/java/org/tasks/scheduling/RefreshScheduler.kt +++ /dev/null @@ -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 = 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() - } - } - } -} \ No newline at end of file