diff --git a/astrid/plugin-src/com/todoroo/astrid/reminders/ReminderService.java b/astrid/plugin-src/com/todoroo/astrid/reminders/ReminderService.java index a925c41aa..e897214de 100644 --- a/astrid/plugin-src/com/todoroo/astrid/reminders/ReminderService.java +++ b/astrid/plugin-src/com/todoroo/astrid/reminders/ReminderService.java @@ -72,6 +72,8 @@ public final class ReminderService { private AlarmScheduler scheduler = new ReminderAlarmScheduler(); + private long now = -1; // For tracking when reminders might be scheduled all at once + private ReminderService() { DependencyInjectionService.getInstance().inject(this); setPreferenceDefaults(); @@ -121,6 +123,7 @@ public final class ReminderService { TodorooCursor cursor = getTasksWithReminders(PROPERTIES); try { Task task = new Task(); + now = DateUtilities.now(); // Before mass scheduling, initialize now variable for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { task.readFromCursor(cursor); scheduleAlarm(task, false); @@ -129,9 +132,15 @@ public final class ReminderService { // suppress } finally { cursor.close(); + now = -1; // Signal done with now variable } } + private long getNowValue() { + // If we're in the midst of mass scheduling, use the prestored now var + return (now == -1 ? DateUtilities.now() : now); + } + private static final long NO_ALARM = Long.MAX_VALUE; /** @@ -189,9 +198,18 @@ public final class ReminderService { // notifications at due date long whenDueDate = calculateNextDueDateReminder(task); + // notifications after due date long whenOverdue = calculateNextOverdueReminder(task); + // For alarms around/before now, increment the now value so the next one will be later + if (whenDueDate <= now || whenOverdue <= now) { + whenDueDate = now; + whenOverdue = now; + now += 30 * DateUtilities.ONE_MINUTE; // Prevents overdue tasks from being scheduled all at once + } + + // if random reminders are too close to due date, favor due date if(whenRandom != NO_ALARM && whenDueDate - whenRandom < DateUtilities.ONE_DAY) whenRandom = NO_ALARM; @@ -235,22 +253,23 @@ public final class ReminderService { * @return */ private long calculateNextOverdueReminder(Task task) { + // Uses getNowValue() instead of DateUtilities.now() if(task.hasDueDate() && task.getFlag(Task.REMINDER_FLAGS, Task.NOTIFY_AFTER_DEADLINE)) { long dueDate = task.getValue(Task.DUE_DATE); long lastReminder = task.getValue(Task.REMINDER_LAST); - if(dueDate > DateUtilities.now()) + if(dueDate > getNowValue()) return dueDate + (long)((0.5f + 2f * random.nextFloat()) * DateUtilities.ONE_HOUR); if(lastReminder < dueDate) - return DateUtilities.now(); + return getNowValue(); - if(DateUtilities.now() - lastReminder < 6 * DateUtilities.ONE_HOUR) - return DateUtilities.now() + (long)((2.0f + + if(getNowValue() - lastReminder < 6 * DateUtilities.ONE_HOUR) + return getNowValue() + (long)((2.0f + task.getValue(Task.IMPORTANCE) + 6f * random.nextFloat()) * DateUtilities.ONE_HOUR); - return DateUtilities.now(); + return getNowValue(); } return NO_ALARM; } @@ -269,9 +288,10 @@ public final class ReminderService { * @return */ private long calculateNextDueDateReminder(Task task) { + // Uses getNowValue() instead of DateUtilities.now() if(task.hasDueDate() && task.getFlag(Task.REMINDER_FLAGS, Task.NOTIFY_AT_DEADLINE)) { long dueDate = task.getValue(Task.DUE_DATE); - long lastReminder = task.getValue(Task.REMINDER_LAST);; + long lastReminder = task.getValue(Task.REMINDER_LAST); long dueDateAlarm; @@ -285,7 +305,7 @@ public final class ReminderService { date.setMinutes(0); date.setSeconds(0); dueDateAlarm = date.getTime(); - if (dueDate > DateUtilities.now() && dueDateAlarm < DateUtilities.now()) { + if (dueDate > getNowValue() && dueDateAlarm < getNowValue()) { // this only happens for tasks due today, cause dueDateAlarm wouldnt be in the past otherwise // if the default reminder is in the past, then reschedule it // on this day before start of quiet hours or after quiet hours @@ -302,8 +322,8 @@ public final class ReminderService { quietHoursEndDate.setMinutes(0); quietHoursEndDate.setSeconds(0); - long millisToQuiet = quietHoursStartDate.getTime() - DateUtilities.now(); - long millisToEndOfDay = dueDate - DateUtilities.now(); + long millisToQuiet = quietHoursStartDate.getTime() - getNowValue(); + long millisToEndOfDay = dueDate - getNowValue(); // int periodDivFactor = 4; @@ -318,17 +338,17 @@ public final class ReminderService { dueDateAlarm = date.getTime(); } else if (hour < quietHoursStart) { // quietHours didnt start yet - millisToQuiet = quietHoursStartDate.getTime() - DateUtilities.now(); + millisToQuiet = quietHoursStartDate.getTime() - getNowValue(); long millisAfterQuiet = dueDate - quietHoursEndDate.getTime(); // if there is more time after quiethours today, select quiethours-end for reminder if (millisAfterQuiet > (millisToQuiet / ((float)(1-(1/periodDivFactor))) )) dueDateAlarm = quietHoursEndDate.getTime(); else - dueDateAlarm = DateUtilities.now() + (long)(millisToQuiet / periodDivFactor); + dueDateAlarm = getNowValue() + (long)(millisToQuiet / periodDivFactor); } else { // after quietHours, reuse dueDate for end of day - dueDateAlarm = DateUtilities.now() + (long)(millisToEndOfDay / periodDivFactor); + dueDateAlarm = getNowValue() + (long)(millisToEndOfDay / periodDivFactor); } } else { // wrap across 24/hour boundary if(hour >= quietHoursStart) { @@ -339,16 +359,16 @@ public final class ReminderService { dueDateAlarm = date.getTime(); } else { // quietHours didnt start yet - millisToQuiet = quietHoursStartDate.getTime() - DateUtilities.now(); - dueDateAlarm = DateUtilities.now() + (long)(millisToQuiet / periodDivFactor); + millisToQuiet = quietHoursStartDate.getTime() - getNowValue(); + dueDateAlarm = getNowValue() + (long)(millisToQuiet / periodDivFactor); } } } else { // Quiet hours not activated, simply schedule the reminder on 1/periodDivFactor towards the end of day - dueDateAlarm = DateUtilities.now() + (long)(millisToEndOfDay / periodDivFactor); + dueDateAlarm = getNowValue() + (long)(millisToEndOfDay / periodDivFactor); } - if(dueDate > DateUtilities.now() && dueDateAlarm < DateUtilities.now()) + if(dueDate > getNowValue() && dueDateAlarm < getNowValue()) dueDateAlarm = dueDate; } }