Fix calendar alarms not being triggered after 22h

Fix two bugs:

1) scheduleNextAlarmLocked is supposed to schedule the next check for
   alarms in (24h - 15min) if it can't find any alarms within the next
   24h. It doesn't, because the comparison at the end

   if (nextAlarmTime == Long.MAX_VALUE)

   is never true, since nextAlarmTime is set to the value of the
   variable end at the beginning.

   Fix this by introducing a new boolean, mAlarmScheduled, which is
   set true by scheduleAlarm.

2) With the first issue fixed, we still have a blind spot of 1h 45min
   where no alarm would be triggered, because the end variable is
   calculated from start, which is always set to two hours before the
   function is run; end adds 24h to this, so we end up 22h in the
   future and don't look for any alarms past that. When we schedule
   the next check, we do so 23h 45min in the future and thereby end up
   with a 1h 45min window in which no alarm would be triggered.

   Fix this by calculating end from currentMillis instead. Also use
   DateUtils.DAY_IN_MILLIS for consistency.

Also, schedule the next alarm based on the value of end instead of a
constant for more flexibility and less risk of future breakage.

Test: Tested using the android emulator and an offline calendar app
(https://play.google.com/store/apps/details?id=org.sufficientlysecure
.localcalendar&hl=en) in the following manner:

1) Temporarily changed the time scale to 10 minutes instead of 24
   hours for feasibility. To do this, the second fix had to be applied,
   since without it the window we're looking at is two hours back. That
   is, line 281 was changed to

   final long end = currentMillis + (10 * 60 * 1000);

   and lines 478-479 to

   scheduleNextAlarmCheck(end);

2) With no further changes I verified the bug by adding one event with
   the alarm set within ten minutes from the current time and one
   with the alarm set for later than ten minutes after the first
   alarm. The first triggers, but the second doesn't.

3) Applied the rest and did the same test again to verify that both
   alarms now trigger.

Bug: 69456806
Test: atest packages/providers/CalendarProvider/tests/
Change-Id: I7635258dc55257e5c8616a07f611d20b04fe0ff8
Signed-off-by: Kim Lindberger <kim.lindberger@gmail.com>
diff --git a/src/com/android/providers/calendar/CalendarAlarmManager.java b/src/com/android/providers/calendar/CalendarAlarmManager.java
index c77b654..8586e6b 100644
--- a/src/com/android/providers/calendar/CalendarAlarmManager.java
+++ b/src/com/android/providers/calendar/CalendarAlarmManager.java
@@ -63,16 +63,6 @@
     /* package */static final Uri SCHEDULE_ALARM_URI = Uri.withAppendedPath(
             CalendarContract.CONTENT_URI, SCHEDULE_ALARM_PATH);
 
-    /**
-     * If no alarms are scheduled in the next 24h, check for future alarms again after this period
-     * has passed. Scheduling the check 15 minutes earlier than 24h to prevent the scheduler alarm
-     * from using up the alarms quota for reminders during dozing.
-     *
-     * @see AlarmManager#setExactAndAllowWhileIdle
-     */
-    private static final long ALARM_CHECK_WHEN_NO_ALARM_IS_SCHEDULED_INTERVAL_MILLIS =
-            DateUtils.DAY_IN_MILLIS - (15 * DateUtils.MINUTE_IN_MILLIS);
-
     static final String INVALID_CALENDARALERTS_SELECTOR =
     "_id IN (SELECT ca." + CalendarAlerts._ID + " FROM "
             + Tables.CALENDAR_ALERTS + " AS ca"
@@ -278,7 +268,10 @@
 
         final long currentMillis = System.currentTimeMillis();
         final long start = currentMillis - SCHEDULE_ALARM_SLACK;
-        final long end = start + (24 * 60 * 60 * 1000);
+        final long end = currentMillis + DateUtils.DAY_IN_MILLIS;
+
+        boolean alarmScheduled = false;
+
         if (Log.isLoggable(CalendarProvider2.TAG, Log.DEBUG)) {
             time.set(start);
             String startTimeStr = time.format(" %a, %b %d, %Y %I:%M%P");
@@ -459,6 +452,7 @@
                 }
 
                 scheduleAlarm(alarmTime);
+                alarmScheduled = true;
             }
         } finally {
             if (cursor != null) {
@@ -469,14 +463,17 @@
         // Refresh notification bar
         if (rowsDeleted > 0) {
             scheduleAlarm(currentMillis);
+            alarmScheduled = true;
         }
 
-        // No event alarm is scheduled, check again in 24 hours. If a new
-        // event is inserted before the next alarm check, then this method
-        // will be run again when the new event is inserted.
-        if (nextAlarmTime == Long.MAX_VALUE) {
-            scheduleNextAlarmCheck(
-                    currentMillis + ALARM_CHECK_WHEN_NO_ALARM_IS_SCHEDULED_INTERVAL_MILLIS);
+        // No event alarm is scheduled, check again in 24 hours - 15
+        // minutes. Scheduling the check 15 minutes earlier than 24
+        // hours to prevent the scheduler alarm from using up the
+        // alarms quota for reminders during dozing. If a new event is
+        // inserted before the next alarm check, then this method will
+        // be run again when the new event is inserted.
+        if (!alarmScheduled) {
+            scheduleNextAlarmCheck(end - (15 * DateUtils.MINUTE_IN_MILLIS));
         }
     }
 
@@ -516,6 +513,10 @@
         mAlarmManager.cancel(operation);
     }
 
+    /**
+     * Only run inside scheduleNextAlarmLocked, please!
+     * mAlarmScheduled is specific to that method, currently.
+     */
     public void scheduleAlarm(long alarmTime) {
         // Debug log for investigating dozing related bugs, remove it once we confirm it is stable.
         if (Build.IS_DEBUGGABLE) {