mirror of https://github.com/tasks/tasks
Use android-job for most scheduling
parent
b485b139c5
commit
c02164ad7a
@ -0,0 +1,139 @@
|
|||||||
|
package com.todoroo.astrid.reminders;
|
||||||
|
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.InOrder;
|
||||||
|
import org.tasks.Freeze;
|
||||||
|
import org.tasks.Snippet;
|
||||||
|
import org.tasks.jobs.JobManager;
|
||||||
|
import org.tasks.jobs.Reminder;
|
||||||
|
import org.tasks.makers.TaskMaker;
|
||||||
|
import org.tasks.preferences.Preferences;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static com.natpryce.makeiteasy.MakeItEasy.with;
|
||||||
|
import static com.todoroo.astrid.reminders.ReminderService.TYPE_DUE;
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
import static junit.framework.Assert.assertEquals;
|
||||||
|
import static org.mockito.AdditionalAnswers.returnsFirstArg;
|
||||||
|
import static org.mockito.Matchers.anyLong;
|
||||||
|
import static org.mockito.Mockito.inOrder;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.tasks.makers.TaskMaker.newTask;
|
||||||
|
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class ReminderAlarmSchedulerTest {
|
||||||
|
|
||||||
|
private static final long ONE_MINUTE = TimeUnit.MINUTES.toMillis(1);
|
||||||
|
|
||||||
|
private JobManager jobManager;
|
||||||
|
private ReminderAlarmScheduler scheduler;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
jobManager = mock(JobManager.class);
|
||||||
|
Preferences preferences = mock(Preferences.class);
|
||||||
|
when(preferences.adjustForQuietHours(anyLong())).then(returnsFirstArg());
|
||||||
|
scheduler = new ReminderAlarmScheduler(jobManager, preferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() {
|
||||||
|
verifyNoMoreInteractions(jobManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void scheduleFirstReminder() {
|
||||||
|
long now = currentTimeMillis();
|
||||||
|
|
||||||
|
scheduler.createAlarm(newTask(with(TaskMaker.ID, 1L)), now, 0);
|
||||||
|
|
||||||
|
verify(jobManager).scheduleReminder(now, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void dontScheduleLaterReminder() {
|
||||||
|
long now = currentTimeMillis();
|
||||||
|
|
||||||
|
scheduler.createAlarm(newTask(with(TaskMaker.ID, 1L)), now, 0);
|
||||||
|
scheduler.createAlarm(newTask(with(TaskMaker.ID, 1L)), now + ONE_MINUTE, 0);
|
||||||
|
|
||||||
|
verify(jobManager).scheduleReminder(now, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rescheduleNewerReminder() {
|
||||||
|
long now = currentTimeMillis();
|
||||||
|
|
||||||
|
scheduler.createAlarm(newTask(with(TaskMaker.ID, 1L)), now, 0);
|
||||||
|
scheduler.createAlarm(newTask(with(TaskMaker.ID, 2L)), now - ONE_MINUTE, 0);
|
||||||
|
|
||||||
|
InOrder order = inOrder(jobManager);
|
||||||
|
order.verify(jobManager).scheduleReminder(now, true);
|
||||||
|
order.verify(jobManager).scheduleReminder(now - ONE_MINUTE, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void removeLastReminderCancelsJob() {
|
||||||
|
long now = currentTimeMillis();
|
||||||
|
scheduler.createAlarm(newTask(with(TaskMaker.ID, 1L)), now, 0);
|
||||||
|
|
||||||
|
scheduler.createAlarm(newTask(with(TaskMaker.ID, 1L)), 0, 0);
|
||||||
|
|
||||||
|
InOrder order = inOrder(jobManager);
|
||||||
|
order.verify(jobManager).scheduleReminder(now, true);
|
||||||
|
order.verify(jobManager).cancelReminders();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void removePastRemindersReturnsPastReminder() {
|
||||||
|
long now = currentTimeMillis();
|
||||||
|
|
||||||
|
Freeze.freezeAt(now).thawAfter(new Snippet() {{
|
||||||
|
scheduler.createAlarm(newTask(with(TaskMaker.ID, 1L)), now, TYPE_DUE);
|
||||||
|
|
||||||
|
List<Reminder> reminders = scheduler.removePastReminders();
|
||||||
|
|
||||||
|
verify(jobManager).scheduleReminder(now, true);
|
||||||
|
|
||||||
|
assertEquals(singletonList(new Reminder(1, now, TYPE_DUE)), reminders);
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void dontRescheduleForSecondJobAtSameTime() {
|
||||||
|
long now = currentTimeMillis();
|
||||||
|
|
||||||
|
scheduler.createAlarm(newTask(with(TaskMaker.ID, 1L)), now, TYPE_DUE);
|
||||||
|
scheduler.createAlarm(newTask(with(TaskMaker.ID, 2L)), now, TYPE_DUE);
|
||||||
|
|
||||||
|
verify(jobManager).scheduleReminder(now, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void removePastRemindersReturnsPastRemindersAtSameTime() {
|
||||||
|
long now = currentTimeMillis();
|
||||||
|
|
||||||
|
Freeze.freezeAt(now).thawAfter(new Snippet() {{
|
||||||
|
scheduler.createAlarm(newTask(with(TaskMaker.ID, 1L)), now, TYPE_DUE);
|
||||||
|
scheduler.createAlarm(newTask(with(TaskMaker.ID, 2L)), now, TYPE_DUE);
|
||||||
|
|
||||||
|
List<Reminder> reminders = scheduler.removePastReminders();
|
||||||
|
|
||||||
|
verify(jobManager).scheduleReminder(now, true);
|
||||||
|
|
||||||
|
assertEquals(asList(new Reminder(1, now, TYPE_DUE), new Reminder(2, now, TYPE_DUE)), reminders);
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
package org.tasks.jobs;
|
||||||
|
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.tasks.Freeze;
|
||||||
|
import org.tasks.Snippet;
|
||||||
|
import org.tasks.preferences.Preferences;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static com.todoroo.astrid.reminders.ReminderService.TYPE_DUE;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
import static junit.framework.Assert.assertEquals;
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
import static org.mockito.AdditionalAnswers.returnsFirstArg;
|
||||||
|
import static org.mockito.Matchers.anyLong;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class JobQueueTest {
|
||||||
|
|
||||||
|
private static final long ONE_MINUTE = TimeUnit.MINUTES.toMillis(1);
|
||||||
|
|
||||||
|
private JobQueue<Reminder> queue;
|
||||||
|
private Preferences preferences;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
preferences = mock(Preferences.class);
|
||||||
|
when(preferences.adjustForQuietHours(anyLong())).then(returnsFirstArg());
|
||||||
|
queue = new JobQueue<>(preferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void twoJobsAtSameTime() {
|
||||||
|
queue.add(new Reminder(1, 1, 0));
|
||||||
|
queue.add(new Reminder(2, 1, 0));
|
||||||
|
|
||||||
|
assertEquals(2, queue.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rescheduleForFirstJob() {
|
||||||
|
assertTrue(queue.add(new Reminder(1, 1, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void dontRescheduleForLaterJobs() {
|
||||||
|
queue.add(new Reminder(1, 1, 0));
|
||||||
|
|
||||||
|
assertFalse(queue.add(new Reminder(2, 2, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rescheduleForNewerJob() {
|
||||||
|
queue.add(new Reminder(1, 2, 0));
|
||||||
|
|
||||||
|
assertTrue(queue.add(new Reminder(1, 1, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rescheduleWhenCancelingOnlyJob() {
|
||||||
|
queue.add(new Reminder(1, 2, 0));
|
||||||
|
|
||||||
|
assertTrue(queue.cancel(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rescheduleWhenCancelingFirstJob() {
|
||||||
|
queue.add(new Reminder(1, 1, 0));
|
||||||
|
queue.add(new Reminder(2, 2, 0));
|
||||||
|
|
||||||
|
assertTrue(queue.cancel(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void dontRescheduleWhenCancelingLaterJob() {
|
||||||
|
queue.add(new Reminder(1, 1, 0));
|
||||||
|
queue.add(new Reminder(2, 2, 0));
|
||||||
|
|
||||||
|
assertFalse(queue.cancel(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nextScheduledTimeIsZeroWhenQueueIsEmpty() {
|
||||||
|
when(preferences.adjustForQuietHours(anyLong())).thenReturn(1234L);
|
||||||
|
|
||||||
|
assertEquals(0, queue.nextScheduledTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void adjustNextScheduledTimeForQuietHours() {
|
||||||
|
when(preferences.adjustForQuietHours(anyLong())).thenReturn(1234L);
|
||||||
|
queue.add(new Reminder(1, 1, 1));
|
||||||
|
|
||||||
|
assertEquals(1234, queue.nextScheduledTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void overdueJobsAreReturned() {
|
||||||
|
long now = currentTimeMillis();
|
||||||
|
|
||||||
|
queue.add(new Reminder(1, now, TYPE_DUE));
|
||||||
|
queue.add(new Reminder(2, now + ONE_MINUTE, TYPE_DUE));
|
||||||
|
|
||||||
|
Freeze.freezeAt(now).thawAfter(new Snippet() {{
|
||||||
|
assertEquals(
|
||||||
|
singletonList(new Reminder(1, now, TYPE_DUE)),
|
||||||
|
queue.removeOverdueJobs());
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void overdueJobsAreRemoved() {
|
||||||
|
long now = currentTimeMillis();
|
||||||
|
|
||||||
|
queue.add(new Reminder(1, now, TYPE_DUE));
|
||||||
|
queue.add(new Reminder(2, now + ONE_MINUTE, TYPE_DUE));
|
||||||
|
|
||||||
|
Freeze.freezeAt(now).thawAfter(new Snippet() {{
|
||||||
|
queue.removeOverdueJobs();
|
||||||
|
}});
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
singletonList(new Reminder(2, now + ONE_MINUTE, TYPE_DUE)),
|
||||||
|
queue.getJobs());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.todoroo.astrid.reminders;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.data.Task;
|
||||||
|
|
||||||
|
public interface AlarmScheduler {
|
||||||
|
void createAlarm(Task task, long time, int type);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
package com.todoroo.astrid.reminders;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.data.Task;
|
||||||
|
|
||||||
|
import org.tasks.injection.ApplicationScope;
|
||||||
|
import org.tasks.jobs.JobManager;
|
||||||
|
import org.tasks.jobs.JobQueue;
|
||||||
|
import org.tasks.jobs.Reminder;
|
||||||
|
import org.tasks.preferences.Preferences;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static com.todoroo.astrid.reminders.ReminderService.NO_ALARM;
|
||||||
|
|
||||||
|
@ApplicationScope
|
||||||
|
public class ReminderAlarmScheduler implements AlarmScheduler {
|
||||||
|
|
||||||
|
private final JobQueue<Reminder> jobs;
|
||||||
|
private final JobManager jobManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public ReminderAlarmScheduler(JobManager jobManager, Preferences preferences) {
|
||||||
|
this.jobManager = jobManager;
|
||||||
|
jobs = new JobQueue<>(preferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an alarm for the given task at the given type
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void createAlarm(Task task, long time, int type) {
|
||||||
|
long taskId = task.getId();
|
||||||
|
if(taskId == Task.NO_ID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time == 0 || time == NO_ALARM) {
|
||||||
|
if (jobs.cancel(taskId)) {
|
||||||
|
scheduleNext(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Reminder reminder = new Reminder(taskId, time, type);
|
||||||
|
if (jobs.add(reminder)) {
|
||||||
|
scheduleNext(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
jobs.clear();
|
||||||
|
jobManager.cancelReminders();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void scheduleNextJob() {
|
||||||
|
scheduleNext(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleNext(boolean cancelCurrent) {
|
||||||
|
if (jobs.isEmpty()) {
|
||||||
|
if (cancelCurrent) {
|
||||||
|
jobManager.cancelReminders();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
jobManager.scheduleReminder(jobs.nextScheduledTime(), cancelCurrent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Reminder> removePastReminders() {
|
||||||
|
return jobs.removeOverdueJobs();
|
||||||
|
}
|
||||||
|
}
|
@ -1,25 +1,22 @@
|
|||||||
package org.tasks.injection;
|
package org.tasks.injection;
|
||||||
|
|
||||||
import org.tasks.location.GeofenceTransitionsIntentService;
|
import org.tasks.location.GeofenceTransitionsIntentService;
|
||||||
import org.tasks.scheduling.BackupIntentService;
|
|
||||||
import org.tasks.scheduling.CalendarNotificationIntentService;
|
import org.tasks.scheduling.CalendarNotificationIntentService;
|
||||||
import org.tasks.scheduling.GeofenceSchedulingIntentService;
|
import org.tasks.scheduling.GeofenceSchedulingIntentService;
|
||||||
import org.tasks.scheduling.RefreshSchedulerIntentService;
|
import org.tasks.scheduling.NotificationSchedulerIntentService;
|
||||||
import org.tasks.scheduling.ReminderSchedulerIntentService;
|
import org.tasks.scheduling.SchedulerIntentService;
|
||||||
|
|
||||||
import dagger.Subcomponent;
|
import dagger.Subcomponent;
|
||||||
|
|
||||||
@Subcomponent(modules = IntentServiceModule.class)
|
@Subcomponent(modules = IntentServiceModule.class)
|
||||||
public interface IntentServiceComponent {
|
public interface IntentServiceComponent {
|
||||||
void inject(ReminderSchedulerIntentService reminderSchedulerIntentService);
|
void inject(SchedulerIntentService schedulerIntentService);
|
||||||
|
|
||||||
void inject(RefreshSchedulerIntentService refreshSchedulerIntentService);
|
|
||||||
|
|
||||||
void inject(GeofenceSchedulingIntentService geofenceSchedulingIntentService);
|
void inject(GeofenceSchedulingIntentService geofenceSchedulingIntentService);
|
||||||
|
|
||||||
void inject(CalendarNotificationIntentService calendarNotificationIntentService);
|
void inject(CalendarNotificationIntentService calendarNotificationIntentService);
|
||||||
|
|
||||||
void inject(BackupIntentService backupIntentService);
|
|
||||||
|
|
||||||
void inject(GeofenceTransitionsIntentService geofenceTransitionsIntentService);
|
void inject(GeofenceTransitionsIntentService geofenceTransitionsIntentService);
|
||||||
|
|
||||||
|
void inject(NotificationSchedulerIntentService notificationSchedulerIntentService);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
package org.tasks.jobs;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.alarms.AlarmFields;
|
||||||
|
import com.todoroo.astrid.data.Metadata;
|
||||||
|
|
||||||
|
public class Alarm implements JobQueueEntry {
|
||||||
|
private final long alarmId;
|
||||||
|
private final long taskId;
|
||||||
|
private final long time;
|
||||||
|
|
||||||
|
public Alarm(Metadata metadata) {
|
||||||
|
this(metadata.getId(), metadata.getTask(), metadata.getValue(AlarmFields.TIME));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Alarm(long alarmId, long taskId, Long time) {
|
||||||
|
this.alarmId = alarmId;
|
||||||
|
this.taskId = taskId;
|
||||||
|
this.time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getId() {
|
||||||
|
return alarmId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTaskId() {
|
||||||
|
return taskId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTime() {
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
Alarm alarm = (Alarm) o;
|
||||||
|
|
||||||
|
return alarmId == alarm.alarmId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return (int) (alarmId ^ (alarmId >>> 32));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Alarm{" +
|
||||||
|
"alarmId=" + alarmId +
|
||||||
|
", taskId=" + taskId +
|
||||||
|
", time=" + time +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
package org.tasks.jobs;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.evernote.android.job.Job;
|
||||||
|
import com.todoroo.astrid.alarms.AlarmService;
|
||||||
|
import com.todoroo.astrid.dao.TaskDao;
|
||||||
|
import com.todoroo.astrid.data.Task;
|
||||||
|
import com.todoroo.astrid.reminders.ReminderService;
|
||||||
|
|
||||||
|
import org.tasks.Notifier;
|
||||||
|
import org.tasks.preferences.Preferences;
|
||||||
|
|
||||||
|
public class AlarmJob extends Job {
|
||||||
|
|
||||||
|
public static final String TAG = "job_alarm";
|
||||||
|
|
||||||
|
private final Preferences preferences;
|
||||||
|
private final AlarmService alarmService;
|
||||||
|
private final Notifier notifier;
|
||||||
|
private final TaskDao taskDao;
|
||||||
|
|
||||||
|
public AlarmJob(Preferences preferences, AlarmService alarmService, Notifier notifier, TaskDao taskDao) {
|
||||||
|
this.preferences = preferences;
|
||||||
|
this.alarmService = alarmService;
|
||||||
|
this.notifier = notifier;
|
||||||
|
this.taskDao = taskDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
protected Result onRunJob(Params params) {
|
||||||
|
try {
|
||||||
|
if (!preferences.isCurrentlyQuietHours()) {
|
||||||
|
for (Alarm alarm : alarmService.removePastDueAlarms()) {
|
||||||
|
Task task = taskDao.fetch(alarm.getTaskId(), Task.REMINDER_LAST);
|
||||||
|
if (task != null && task.getReminderLast() < alarm.getTime()) {
|
||||||
|
notifier.triggerTaskNotification(alarm.getTaskId(), ReminderService.TYPE_ALARM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Result.SUCCESS;
|
||||||
|
} finally {
|
||||||
|
alarmService.scheduleNextJob();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package org.tasks.jobs;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import com.evernote.android.job.Job;
|
||||||
|
import com.todoroo.astrid.alarms.AlarmService;
|
||||||
|
import com.todoroo.astrid.backup.TasksXmlExporter;
|
||||||
|
import com.todoroo.astrid.dao.TaskDao;
|
||||||
|
import com.todoroo.astrid.reminders.ReminderAlarmScheduler;
|
||||||
|
|
||||||
|
import org.tasks.Broadcaster;
|
||||||
|
import org.tasks.Notifier;
|
||||||
|
import org.tasks.injection.ApplicationScope;
|
||||||
|
import org.tasks.injection.ForApplication;
|
||||||
|
import org.tasks.preferences.Preferences;
|
||||||
|
import org.tasks.scheduling.RefreshScheduler;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
@ApplicationScope
|
||||||
|
public class JobCreator implements com.evernote.android.job.JobCreator {
|
||||||
|
|
||||||
|
private final Context context;
|
||||||
|
private final Notifier notifier;
|
||||||
|
private final JobManager jobManager;
|
||||||
|
private final Broadcaster broadcaster;
|
||||||
|
private final TasksXmlExporter tasksXmlExporter;
|
||||||
|
private final Preferences preferences;
|
||||||
|
private final RefreshScheduler refreshScheduler;
|
||||||
|
private final AlarmService alarmService;
|
||||||
|
private final TaskDao taskDao;
|
||||||
|
private final ReminderAlarmScheduler reminderAlarmScheduler;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public JobCreator(@ForApplication Context context, Notifier notifier, JobManager jobManager,
|
||||||
|
Broadcaster broadcaster, TasksXmlExporter tasksXmlExporter,
|
||||||
|
Preferences preferences, RefreshScheduler refreshScheduler,
|
||||||
|
AlarmService alarmService, TaskDao taskDao, ReminderAlarmScheduler reminderAlarmScheduler) {
|
||||||
|
this.context = context;
|
||||||
|
this.notifier = notifier;
|
||||||
|
this.jobManager = jobManager;
|
||||||
|
this.broadcaster = broadcaster;
|
||||||
|
this.tasksXmlExporter = tasksXmlExporter;
|
||||||
|
this.preferences = preferences;
|
||||||
|
this.refreshScheduler = refreshScheduler;
|
||||||
|
this.alarmService = alarmService;
|
||||||
|
this.taskDao = taskDao;
|
||||||
|
this.reminderAlarmScheduler = reminderAlarmScheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Job create(String tag) {
|
||||||
|
switch (tag) {
|
||||||
|
case ReminderJob.TAG:
|
||||||
|
return new ReminderJob(preferences, reminderAlarmScheduler, notifier);
|
||||||
|
case AlarmJob.TAG:
|
||||||
|
return new AlarmJob(preferences, alarmService, notifier, taskDao);
|
||||||
|
case RefreshJob.TAG:
|
||||||
|
return new RefreshJob(refreshScheduler, broadcaster);
|
||||||
|
case MidnightRefreshJob.TAG:
|
||||||
|
return new MidnightRefreshJob(broadcaster, jobManager);
|
||||||
|
case BackupJob.TAG:
|
||||||
|
return new BackupJob(context, jobManager, tasksXmlExporter, preferences);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package org.tasks.jobs;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import com.evernote.android.job.JobCreator;
|
||||||
|
import com.evernote.android.job.JobRequest;
|
||||||
|
|
||||||
|
import org.tasks.injection.ApplicationScope;
|
||||||
|
import org.tasks.injection.ForApplication;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
|
||||||
|
import static org.tasks.time.DateTimeUtils.nextMidnight;
|
||||||
|
|
||||||
|
@ApplicationScope
|
||||||
|
public class JobManager {
|
||||||
|
|
||||||
|
private final com.evernote.android.job.JobManager jobManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public JobManager(@ForApplication Context context) {
|
||||||
|
jobManager = com.evernote.android.job.JobManager.create(context);
|
||||||
|
jobManager.cancelAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addJobCreator(JobCreator jobCreator) {
|
||||||
|
jobManager.addJobCreator(jobCreator);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void scheduleAlarm(long time, boolean cancelCurrent) {
|
||||||
|
new JobRequest.Builder(AlarmJob.TAG)
|
||||||
|
.setExact(Math.max(time - currentTimeMillis(), 5000))
|
||||||
|
.setUpdateCurrent(cancelCurrent)
|
||||||
|
.build()
|
||||||
|
.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void scheduleReminder(long time, boolean cancelCurrent) {
|
||||||
|
new JobRequest.Builder(ReminderJob.TAG)
|
||||||
|
.setExact(Math.max(time - currentTimeMillis(), 5000))
|
||||||
|
.setUpdateCurrent(cancelCurrent)
|
||||||
|
.build()
|
||||||
|
.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void scheduleRefresh(long time, boolean cancelExisting) {
|
||||||
|
new JobRequest.Builder(RefreshJob.TAG)
|
||||||
|
.setExact(Math.max(time - currentTimeMillis(), 5000))
|
||||||
|
.setUpdateCurrent(cancelExisting)
|
||||||
|
.build()
|
||||||
|
.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void scheduleMidnightRefresh(boolean cancelExisting) {
|
||||||
|
scheduleMidnightJob(MidnightRefreshJob.TAG, cancelExisting);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void scheduleMidnightBackup(boolean cancelExisting) {
|
||||||
|
scheduleMidnightJob(BackupJob.TAG, cancelExisting);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleMidnightJob(String tag, boolean cancelExisting) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
new JobRequest.Builder(tag)
|
||||||
|
.setExact(nextMidnight(now) - now)
|
||||||
|
.setUpdateCurrent(cancelExisting)
|
||||||
|
.build()
|
||||||
|
.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancelAlarms() {
|
||||||
|
jobManager.cancelAllForTag(AlarmJob.TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancelRefreshes() {
|
||||||
|
jobManager.cancelAllForTag(RefreshJob.TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancelReminders() {
|
||||||
|
jobManager.cancelAllForTag(ReminderJob.TAG);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
package org.tasks.jobs;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.Ordering;
|
||||||
|
import com.google.common.collect.TreeMultimap;
|
||||||
|
import com.google.common.primitives.Longs;
|
||||||
|
|
||||||
|
import org.tasks.preferences.Preferences;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
|
||||||
|
import static com.google.common.collect.Iterables.filter;
|
||||||
|
import static com.google.common.collect.Lists.newArrayList;
|
||||||
|
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
|
||||||
|
|
||||||
|
public class JobQueue<T extends JobQueueEntry> {
|
||||||
|
private final TreeMultimap<Long, T> jobs = TreeMultimap.create(Ordering.natural(), (l, r) -> Longs.compare(l.getId(), r.getId()));
|
||||||
|
private final Preferences preferences;
|
||||||
|
|
||||||
|
public JobQueue(Preferences preferences) {
|
||||||
|
this.preferences = preferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean add(T entry) {
|
||||||
|
boolean result = jobs.isEmpty() || entry.getTime() < firstTime();
|
||||||
|
jobs.put(entry.getTime(), entry);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return jobs.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
jobs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean cancel(long id) {
|
||||||
|
boolean reschedule = false;
|
||||||
|
long firstTime = firstTime();
|
||||||
|
List<T> existing = newArrayList(filter(jobs.values(), r -> r.getId() == id));
|
||||||
|
for (T entry : existing) {
|
||||||
|
reschedule |= entry.getTime() == firstTime;
|
||||||
|
jobs.remove(entry.getTime(), entry);
|
||||||
|
}
|
||||||
|
return reschedule;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<T> getJobs() {
|
||||||
|
return ImmutableList.copyOf(jobs.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<T> removeOverdueJobs() {
|
||||||
|
List<T> result = newArrayList();
|
||||||
|
SortedSet<Long> lapsed = jobs.keySet().headSet(currentTimeMillis() + 1);
|
||||||
|
for (Long key : lapsed) {
|
||||||
|
result.addAll(jobs.removeAll(key));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return jobs.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private long firstTime() {
|
||||||
|
return jobs.isEmpty() ? 0 : jobs.asMap().firstKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long nextScheduledTime() {
|
||||||
|
long next = firstTime();
|
||||||
|
return next > 0 ? preferences.adjustForQuietHours(next) : 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package org.tasks.jobs;
|
||||||
|
|
||||||
|
public interface JobQueueEntry {
|
||||||
|
long getId();
|
||||||
|
|
||||||
|
long getTime();
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package org.tasks.jobs;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.evernote.android.job.Job;
|
||||||
|
|
||||||
|
import org.tasks.Broadcaster;
|
||||||
|
|
||||||
|
public class MidnightRefreshJob extends Job {
|
||||||
|
|
||||||
|
public static final String TAG = "job_midnight_refresh";
|
||||||
|
|
||||||
|
private final Broadcaster broadcaster;
|
||||||
|
private final JobManager jobManager;
|
||||||
|
|
||||||
|
public MidnightRefreshJob(Broadcaster broadcaster, JobManager jobManager) {
|
||||||
|
this.broadcaster = broadcaster;
|
||||||
|
this.jobManager = jobManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
protected Result onRunJob(Params params) {
|
||||||
|
try {
|
||||||
|
broadcaster.refresh();
|
||||||
|
return Result.SUCCESS;
|
||||||
|
} finally {
|
||||||
|
jobManager.scheduleMidnightRefresh(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package org.tasks.jobs;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.evernote.android.job.Job;
|
||||||
|
|
||||||
|
import org.tasks.Broadcaster;
|
||||||
|
import org.tasks.scheduling.RefreshScheduler;
|
||||||
|
|
||||||
|
public class RefreshJob extends Job {
|
||||||
|
|
||||||
|
public static final String TAG = "job_refresh";
|
||||||
|
|
||||||
|
private final RefreshScheduler refreshScheduler;
|
||||||
|
private final Broadcaster broadcaster;
|
||||||
|
|
||||||
|
public RefreshJob(RefreshScheduler refreshScheduler, Broadcaster broadcaster) {
|
||||||
|
this.refreshScheduler = refreshScheduler;
|
||||||
|
this.broadcaster = broadcaster;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
protected Result onRunJob(Params params) {
|
||||||
|
try {
|
||||||
|
broadcaster.refresh();
|
||||||
|
return Result.SUCCESS;
|
||||||
|
} finally {
|
||||||
|
refreshScheduler.scheduleNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package org.tasks.jobs;
|
||||||
|
|
||||||
|
public class Reminder implements JobQueueEntry {
|
||||||
|
private final long taskId;
|
||||||
|
private final long time;
|
||||||
|
private final int type;
|
||||||
|
|
||||||
|
public Reminder(long taskId, long time, int type) {
|
||||||
|
this.taskId = taskId;
|
||||||
|
this.time = time;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getId() {
|
||||||
|
return taskId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTime() {
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
Reminder reminder = (Reminder) o;
|
||||||
|
|
||||||
|
if (taskId != reminder.taskId) return false;
|
||||||
|
if (time != reminder.time) return false;
|
||||||
|
return type == reminder.type;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = (int) (taskId ^ (taskId >>> 32));
|
||||||
|
result = 31 * result + (int) (time ^ (time >>> 32));
|
||||||
|
result = 31 * result + type;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Reminder{" +
|
||||||
|
"taskId=" + taskId +
|
||||||
|
", time=" + time +
|
||||||
|
", type=" + type +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package org.tasks.jobs;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.evernote.android.job.Job;
|
||||||
|
import com.todoroo.astrid.reminders.ReminderAlarmScheduler;
|
||||||
|
|
||||||
|
import org.tasks.Notifier;
|
||||||
|
import org.tasks.preferences.Preferences;
|
||||||
|
|
||||||
|
public class ReminderJob extends Job {
|
||||||
|
|
||||||
|
public static final String TAG = "job_reminder";
|
||||||
|
|
||||||
|
private final Preferences preferences;
|
||||||
|
private final ReminderAlarmScheduler reminderAlarmScheduler;
|
||||||
|
private final Notifier notifier;
|
||||||
|
|
||||||
|
public ReminderJob(Preferences preferences, ReminderAlarmScheduler reminderAlarmScheduler, Notifier notifier) {
|
||||||
|
this.preferences = preferences;
|
||||||
|
this.reminderAlarmScheduler = reminderAlarmScheduler;
|
||||||
|
this.notifier = notifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
protected Result onRunJob(Params params) {
|
||||||
|
try {
|
||||||
|
if (!preferences.isCurrentlyQuietHours()) {
|
||||||
|
for (Reminder reminder : reminderAlarmScheduler.removePastReminders()) {
|
||||||
|
notifier.triggerTaskNotification(reminder.getId(), reminder.getType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Result.SUCCESS;
|
||||||
|
} finally {
|
||||||
|
reminderAlarmScheduler.scheduleNextJob();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,31 +0,0 @@
|
|||||||
package org.tasks.receivers;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
|
|
||||||
import org.tasks.Broadcaster;
|
|
||||||
import org.tasks.injection.BroadcastComponent;
|
|
||||||
import org.tasks.injection.InjectingBroadcastReceiver;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
public class RefreshReceiver extends InjectingBroadcastReceiver {
|
|
||||||
|
|
||||||
@Inject Broadcaster broadcaster;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
super.onReceive(context, intent);
|
|
||||||
|
|
||||||
Timber.d("onReceive(context, %s)", intent);
|
|
||||||
|
|
||||||
broadcaster.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void inject(BroadcastComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
package org.tasks.receivers;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
|
|
||||||
import org.tasks.Notifier;
|
|
||||||
import org.tasks.injection.BroadcastComponent;
|
|
||||||
import org.tasks.injection.InjectingBroadcastReceiver;
|
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
public class TaskNotificationReceiver extends InjectingBroadcastReceiver {
|
|
||||||
|
|
||||||
private static final ExecutorService executorService = Executors.newSingleThreadExecutor();
|
|
||||||
|
|
||||||
public static final String ID_KEY = "id"; //$NON-NLS-1$
|
|
||||||
public static final String EXTRAS_TYPE = "type"; //$NON-NLS-1$
|
|
||||||
|
|
||||||
@Inject Notifier notifier;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, final Intent intent) {
|
|
||||||
super.onReceive(context, intent);
|
|
||||||
|
|
||||||
executorService.execute(() -> notifier.triggerTaskNotification(
|
|
||||||
intent.getLongExtra(ID_KEY, 0),
|
|
||||||
intent.getIntExtra(EXTRAS_TYPE, (byte) 0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void inject(BroadcastComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
package org.tasks.scheduling;
|
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
|
|
||||||
import org.tasks.injection.InjectingIntentService;
|
|
||||||
import org.tasks.preferences.Preferences;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
|
||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
|
||||||
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
|
|
||||||
import static org.tasks.time.DateTimeUtils.nextMidnight;
|
|
||||||
import static org.tasks.time.DateTimeUtils.printTimestamp;
|
|
||||||
|
|
||||||
public abstract class MidnightIntentService extends InjectingIntentService {
|
|
||||||
|
|
||||||
private static final long PADDING = SECONDS.toMillis(1);
|
|
||||||
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
MidnightIntentService(String name) {
|
|
||||||
super(name);
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onHandleIntent(Intent intent) {
|
|
||||||
super.onHandleIntent(intent);
|
|
||||||
|
|
||||||
Context context = getApplicationContext();
|
|
||||||
Preferences preferences = new Preferences(context);
|
|
||||||
AlarmManager alarmManager = new AlarmManager(context, preferences);
|
|
||||||
|
|
||||||
String lastRunPreference = getLastRunPreference();
|
|
||||||
long lastRun = lastRunPreference == null ? 0 : preferences.getLong(lastRunPreference, 0);
|
|
||||||
long nextRun = nextMidnight(lastRun);
|
|
||||||
long now = currentTimeMillis();
|
|
||||||
|
|
||||||
if (nextRun <= now) {
|
|
||||||
nextRun = nextMidnight(now);
|
|
||||||
Timber.d("%s running now [nextRun=%s]", name, printTimestamp(nextRun));
|
|
||||||
if (!isNullOrEmpty(getLastRunPreference())) {
|
|
||||||
preferences.setLong(getLastRunPreference(), now);
|
|
||||||
}
|
|
||||||
run();
|
|
||||||
} else {
|
|
||||||
Timber.d("%s will run at %s [lastRun=%s]", name, printTimestamp(nextRun), printTimestamp(lastRun));
|
|
||||||
}
|
|
||||||
|
|
||||||
PendingIntent pendingIntent = PendingIntent.getService(this, 0, new Intent(this, this.getClass()), PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
alarmManager.noWakeup(nextRun + PADDING, pendingIntent);
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract void run();
|
|
||||||
|
|
||||||
String getLastRunPreference() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
package org.tasks.scheduling;
|
|
||||||
|
|
||||||
import com.todoroo.andlib.sql.Criterion;
|
|
||||||
import com.todoroo.astrid.dao.TaskDao;
|
|
||||||
import com.todoroo.astrid.data.Task;
|
|
||||||
|
|
||||||
import org.tasks.Broadcaster;
|
|
||||||
import org.tasks.injection.IntentServiceComponent;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
|
|
||||||
import static org.tasks.time.DateTimeUtils.nextMidnight;
|
|
||||||
|
|
||||||
public class RefreshSchedulerIntentService extends MidnightIntentService {
|
|
||||||
|
|
||||||
@Inject Broadcaster broadcaster;
|
|
||||||
@Inject RefreshScheduler refreshScheduler;
|
|
||||||
@Inject TaskDao taskDao;
|
|
||||||
|
|
||||||
public RefreshSchedulerIntentService() {
|
|
||||||
super(RefreshSchedulerIntentService.class.getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void run() {
|
|
||||||
scheduleApplicationRefreshes();
|
|
||||||
broadcaster.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void scheduleApplicationRefreshes() {
|
|
||||||
long now = currentTimeMillis();
|
|
||||||
long midnight = nextMidnight(now);
|
|
||||||
Criterion criterion = Criterion.or(
|
|
||||||
Criterion.and(Task.HIDE_UNTIL.gt(now), Task.HIDE_UNTIL.lt(midnight)),
|
|
||||||
Criterion.and(Task.DUE_DATE.gt(now), Task.DUE_DATE.lt(midnight)));
|
|
||||||
taskDao.selectActive(criterion, refreshScheduler::scheduleRefresh);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void inject(IntentServiceComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,49 @@
|
|||||||
|
package org.tasks.scheduling;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import com.todoroo.andlib.sql.Criterion;
|
||||||
|
import com.todoroo.astrid.dao.TaskDao;
|
||||||
|
import com.todoroo.astrid.data.Task;
|
||||||
|
|
||||||
|
import org.tasks.injection.InjectingIntentService;
|
||||||
|
import org.tasks.injection.IntentServiceComponent;
|
||||||
|
import org.tasks.jobs.JobManager;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
import static java.lang.System.currentTimeMillis;
|
||||||
|
|
||||||
|
public class SchedulerIntentService extends InjectingIntentService {
|
||||||
|
|
||||||
|
@Inject TaskDao taskDao;
|
||||||
|
@Inject JobManager jobManager;
|
||||||
|
@Inject RefreshScheduler refreshScheduler;
|
||||||
|
|
||||||
|
public SchedulerIntentService() {
|
||||||
|
super(SchedulerIntentService.class.getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onHandleIntent(Intent intent) {
|
||||||
|
super.onHandleIntent(intent);
|
||||||
|
|
||||||
|
Timber.d("onHandleIntent(%s)", intent);
|
||||||
|
|
||||||
|
jobManager.scheduleMidnightBackup(true);
|
||||||
|
jobManager.scheduleMidnightRefresh(true);
|
||||||
|
|
||||||
|
refreshScheduler.clear();
|
||||||
|
long now = currentTimeMillis();
|
||||||
|
taskDao.selectActive(
|
||||||
|
Criterion.or(Task.HIDE_UNTIL.gt(now), Task.DUE_DATE.gt(now)),
|
||||||
|
refreshScheduler::scheduleRefresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void inject(IntentServiceComponent component) {
|
||||||
|
component.inject(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<full-backup-content>
|
||||||
|
<exclude domain="sharedpref" path="evernote_jobs.xml" />
|
||||||
|
<exclude domain="database" path="evernote_jobs.db" />
|
||||||
|
</full-backup-content>
|
Loading…
Reference in New Issue