13a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting/*
23a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting * Copyright (C) 2012 The Android Open Source Project
33a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting *
43a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting * Licensed under the Apache License, Version 2.0 (the "License"); you may not
53a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting * use this file except in compliance with the License. You may obtain a copy of
63a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting * the License at
73a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting *
83a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting * http://www.apache.org/licenses/LICENSE-2.0
93a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting *
103a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting * Unless required by applicable law or agreed to in writing, software
113a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
123a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
133a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting * License for the specific language governing permissions and limitations under
143a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting * the License.
153a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting */
163a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
173a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingpackage com.android.calendar.alerts;
183a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
193a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport android.app.AlarmManager;
203a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport android.database.Cursor;
213a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport android.database.MatrixCursor;
223a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport android.net.Uri;
233a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport android.provider.CalendarContract;
243a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport android.provider.CalendarContract.Instances;
253a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport android.provider.CalendarContract.Reminders;
263a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport android.test.AndroidTestCase;
273a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport android.test.IsolatedContext;
283a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport android.test.mock.MockContentProvider;
293a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport android.test.mock.MockContentResolver;
303a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport android.test.suitebuilder.annotation.SmallTest;
313a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport android.text.format.DateUtils;
323a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport android.text.format.Time;
333a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport android.util.Log;
343a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
353a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport junit.framework.Assert;
363a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
373a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport java.util.ArrayList;
383a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport java.util.Arrays;
393a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingimport java.util.HashSet;
403a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
413a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting@SmallTest
423a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Tingpublic class AlarmSchedulerTest extends AndroidTestCase {
433a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    private static final int BATCH_SIZE = 50;
443a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    private MockProvider mMockProvider;
453a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    private MockAlarmManager mMockAlarmManager;
463a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    private IsolatedContext mIsolatedContext;
473a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
483a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    /**
493a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting     * A helper class to mock query results from the test data.
503a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting     */
513a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    private static class MockProvider extends MockContentProvider {
523a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        private ArrayList<EventInfo> mEvents = new ArrayList<EventInfo>();
533a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        private ArrayList<String> mExpectedRemindersQueries = new ArrayList<String>();
543a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        private int mCurrentReminderQueryIndex = 0;
553a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
563a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        /**
573a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting         * Contains info for a test event and its reminder.
583a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting         */
593a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        private static class EventInfo {
603a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            long mEventId;
613a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            long mBegin;
623a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            boolean mAllDay;
633a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            int mReminderMinutes;
643a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
653a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            public EventInfo(long eventId, boolean allDay, long begin, int reminderMinutes) {
663a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                mEventId = eventId;
673a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                mAllDay = allDay;
683a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                mBegin = begin;
693a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                mReminderMinutes = reminderMinutes;
703a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            }
713a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
723a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        }
733a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
743a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        /**
753a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting         * Adds event/reminder data for testing.  These will always be returned in the mocked
763a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting         * query result cursors.
773a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting         */
783a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        void addEventInfo(long eventId, boolean allDay, long begin, int reminderMinutes) {
793a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            mEvents.add(new EventInfo(eventId, allDay, begin, reminderMinutes));
803a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        }
813a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
823a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        private MatrixCursor getInstancesCursor() {
833a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            MatrixCursor instancesCursor = new MatrixCursor(AlarmScheduler.INSTANCES_PROJECTION);
843a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            int i = 0;
853a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            HashSet<Long> eventIds = new HashSet<Long>();
863a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            for (EventInfo event : mEvents) {
873a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                if (!eventIds.contains(event.mEventId)) {
883a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                    Object[] ca = {
893a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                            event.mEventId,
903a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                            event.mBegin,
913a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                            event.mAllDay ? 1 : 0,
923a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                    };
933a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                    instancesCursor.addRow(ca);
943a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                    eventIds.add(event.mEventId);
953a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                }
963a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            }
973a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            return instancesCursor;
983a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        }
993a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
1003a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        private MatrixCursor getRemindersCursor() {
1013a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            MatrixCursor remindersCursor = new MatrixCursor(AlarmScheduler.REMINDERS_PROJECTION);
1023a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            int i = 0;
1033a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            for (EventInfo event : mEvents) {
1043a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                Object[] ca = {
1053a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                        event.mEventId,
1063a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                        event.mReminderMinutes,
1073a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                        1,
1083a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                };
1093a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                remindersCursor.addRow(ca);
1103a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            }
1113a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            return remindersCursor;
1123a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        }
1133a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
1143a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        @Override
1153a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
1163a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                String sortOrder) {
1173a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            if (uri.toString().startsWith(Instances.CONTENT_URI.toString())) {
1183a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                return getInstancesCursor();
1193a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            } else if (Reminders.CONTENT_URI.equals(uri)) {
1203a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                if (mExpectedRemindersQueries.size() > 0) {
1213a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                    if (mExpectedRemindersQueries.size() <= mCurrentReminderQueryIndex ||
1223a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                            !mExpectedRemindersQueries.get(mCurrentReminderQueryIndex).equals(
1233a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                                    selection)) {
1243a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                        String msg = "Reminders query not as expected.\n";
1253a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                        msg += "  Expected:";
1263a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                        msg += Arrays.deepToString(mExpectedRemindersQueries.toArray());
1273a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                        msg += "\n  Got in position " + mCurrentReminderQueryIndex + ": ";
1283a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                        msg += selection;
1293a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                        fail(msg);
1303a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                    }
1313a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                    mCurrentReminderQueryIndex++;
1323a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                }
1333a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                return getRemindersCursor();
1343a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            } else {
1353a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                return super.query(uri, projection, selection, selectionArgs, sortOrder);
1363a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            }
1373a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        }
1383a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
1393a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        /**
1403a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting         * Optionally set up expectation for the reminders query selection.
1413a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting         */
1423a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        public void addExpectedRemindersQuery(String expectedRemindersQuery) {
1433a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            this.mExpectedRemindersQueries.add(expectedRemindersQuery);
1443a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        }
1453a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    }
1463a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
1473a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    /**
1483a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting     * Expect an alarm for the specified time.
1493a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting     */
1503a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    private void expectAlarmAt(long millis) {
1513a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // AlarmScheduler adds a slight delay to the alarm so account for that here.
1523a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockAlarmManager.expectAlarmTime(AlarmManager.RTC_WAKEUP,
1533a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                millis + AlarmScheduler.ALARM_DELAY_MS);
1543a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    }
1553a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
1563a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    @Override
1573a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    protected void setUp() throws Exception {
1583a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        super.setUp();
1593a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
1603a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider = new MockProvider();
1613a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockAlarmManager = new MockAlarmManager(mContext);
1623a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        MockContentResolver mockResolver = new MockContentResolver();
1633a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mockResolver.addProvider(CalendarContract.AUTHORITY, mMockProvider);
1643a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mIsolatedContext = new IsolatedContext(mockResolver, mContext);
1653a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    }
1663a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
1673a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    public void testNoEvents() {
1683a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager,
1693a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                BATCH_SIZE, System.currentTimeMillis());
1703a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        assertFalse(mMockAlarmManager.isAlarmSet());
1713a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    }
1723a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
1733a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    public void testNonAllDayEvent() {
1743a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Set up mock test data.
1753a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        long currentMillis = System.currentTimeMillis();
1763a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        long startMillis = currentMillis + DateUtils.HOUR_IN_MILLIS;
1773a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        int reminderMin = 10;
1783a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider.addEventInfo(1, false, startMillis, reminderMin);
1793a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        expectAlarmAt(startMillis - reminderMin * DateUtils.MINUTE_IN_MILLIS);
1803a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
1813a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Invoke scheduleNextAlarm and verify alarm was set at the expected time.
1823a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager, BATCH_SIZE,
1833a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                currentMillis);
1843a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        assertTrue(mMockAlarmManager.isAlarmSet());
1853a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    }
1863a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
1873a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    public void testAllDayEvent() {
1883a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Set up mock allday data.
1893a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        long startMillisUtc = Utils.createTimeInMillis(0, 0, 0, 1, 5, 2012, Time.TIMEZONE_UTC);
1903a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        long startMillisLocal = Utils.createTimeInMillis(0, 0, 0, 1, 5, 2012,
1913a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                Time.getCurrentTimezone());
1923a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        long currentMillis = startMillisLocal - DateUtils.DAY_IN_MILLIS;
1933a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        int reminderMin = 15;
1943a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider.addEventInfo(1, true, startMillisUtc, reminderMin);
1953a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        expectAlarmAt(startMillisLocal - reminderMin * DateUtils.MINUTE_IN_MILLIS);
1963a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
1973a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Invoke scheduleNextAlarm and verify alarm was set at the expected time.
1983a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager, BATCH_SIZE,
1993a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                currentMillis);
2003a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        assertTrue(mMockAlarmManager.isAlarmSet());
2013a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    }
2023a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
2033a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    public void testAllDayAndNonAllDayEvents() {
2043a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Set up mock test data.
2053a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        long startMillisUtc = Utils.createTimeInMillis(0, 0, 0, 1, 5, 2012, Time.TIMEZONE_UTC);
2063a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        long startMillisLocal = Utils.createTimeInMillis(0, 0, 0, 1, 5, 2012,
2073a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                Time.getCurrentTimezone());
2083a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        long currentMillis = startMillisLocal - DateUtils.DAY_IN_MILLIS;
2093a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider.addEventInfo(1, true, startMillisUtc, 15);
2103a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider.addEventInfo(1, false, startMillisLocal, 10);
2113a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        expectAlarmAt(startMillisLocal - 15 * DateUtils.MINUTE_IN_MILLIS);
2123a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
2133a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Invoke scheduleNextAlarm and verify alarm was set at the expected time.
2143a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager, BATCH_SIZE,
2153a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                currentMillis);
2163a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        assertTrue(mMockAlarmManager.isAlarmSet());
2173a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    }
2183a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
2193a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    public void testExpiredReminder() {
2203a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Set up mock test data.
2213a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        long currentMillis = System.currentTimeMillis();
2223a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        long startMillis = currentMillis + DateUtils.HOUR_IN_MILLIS;
2233a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        int reminderMin = 61;
2243a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider.addEventInfo(1, false, startMillis, reminderMin);
2253a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
2263a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Invoke scheduleNextAlarm and verify no alarm was set.
2273a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager, BATCH_SIZE,
2283a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                currentMillis);
2293a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        assertFalse(mMockAlarmManager.isAlarmSet());
2303a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    }
2313a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
2323a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    public void testAlarmMax() {
2333a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Set up mock test data for a reminder greater than 1 day in the future.
2343a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // This will be maxed out to 1 day out.
2353a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        long currentMillis = System.currentTimeMillis();
2363a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        long startMillis = currentMillis + DateUtils.DAY_IN_MILLIS * 3;
2373a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        int reminderMin = (int) DateUtils.DAY_IN_MILLIS / (1000 * 60);
2383a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider.addEventInfo(1, false, startMillis, reminderMin);
2393a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        expectAlarmAt(currentMillis + DateUtils.DAY_IN_MILLIS);
2403a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
2413a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Invoke scheduleNextAlarm and verify alarm was set at the expected time.
2423a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager, BATCH_SIZE,
2433a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                currentMillis);
2443a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        assertTrue(mMockAlarmManager.isAlarmSet());
2453a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    }
2463a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
2473a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    public void testMultipleEvents() {
2483a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Set up multiple events where a later event time has an earlier reminder time.
2493a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        long currentMillis = System.currentTimeMillis();
2503a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider.addEventInfo(1, false, currentMillis + DateUtils.DAY_IN_MILLIS, 0);
2513a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider.addEventInfo(2, false, currentMillis + DateUtils.MINUTE_IN_MILLIS * 60, 45);
2523a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider.addEventInfo(3, false, currentMillis + DateUtils.MINUTE_IN_MILLIS * 30, 10);
2533a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
2543a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Expect event 2's reminder.
2553a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        expectAlarmAt(currentMillis + DateUtils.MINUTE_IN_MILLIS * 15);
2563a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
2573a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Invoke scheduleNextAlarm and verify alarm was set at the expected time.
2583a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager, BATCH_SIZE,
2593a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                currentMillis);
2603a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        assertTrue(mMockAlarmManager.isAlarmSet());
2613a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    }
2623a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
2633a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    public void testRecurringEvents() {
2643a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        long currentMillis = System.currentTimeMillis();
2653a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
2663a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Event in 3 days, with a 2 day reminder
2673a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider.addEventInfo(1, false, currentMillis + DateUtils.DAY_IN_MILLIS * 3,
2683a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                (int) DateUtils.DAY_IN_MILLIS * 2 / (1000 * 60) /* 2 day reminder */);
2693a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Event for tomorrow, with a 2 day reminder
2703a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider.addEventInfo(1, false, currentMillis + DateUtils.DAY_IN_MILLIS,
2713a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                (int) DateUtils.DAY_IN_MILLIS * 2 / (1000 * 60) /* 2 day reminder */);
2723a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
2733a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Expect the reminder for the top event because the reminder time for the bottom
2743a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // one already passed.
2753a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        expectAlarmAt(currentMillis + DateUtils.DAY_IN_MILLIS);
2763a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
2773a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Invoke scheduleNextAlarm and verify alarm was set at the expected time.
2783a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager, BATCH_SIZE,
2793a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                currentMillis);
2803a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        assertTrue(mMockAlarmManager.isAlarmSet());
2813a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    }
2823a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
2833a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    public void testMultipleRemindersForEvent() {
2843a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Set up mock test data.
2853a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        long currentMillis = System.currentTimeMillis();
2863a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider.addEventInfo(1,  false, currentMillis + DateUtils.DAY_IN_MILLIS, 10);
2873a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider.addEventInfo(1,  false, currentMillis + DateUtils.DAY_IN_MILLIS, 20);
2883a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider.addEventInfo(1,  false, currentMillis + DateUtils.DAY_IN_MILLIS, 15);
2893a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
2903a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Expect earliest reminder.
2913a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        expectAlarmAt(currentMillis + DateUtils.DAY_IN_MILLIS - DateUtils.MINUTE_IN_MILLIS * 20);
2923a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
2933a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Invoke scheduleNextAlarm and verify alarm was set at the expected time.
2943a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager, BATCH_SIZE,
2953a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                currentMillis);
2963a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        assertTrue(mMockAlarmManager.isAlarmSet());
2973a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    }
2983a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
2993a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    public void testLargeBatch() {
3003a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Add enough events to require several batches.
3013a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        long currentMillis = System.currentTimeMillis();
3023a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        int batchSize = 5;
3033a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        for (int i = 19; i > 0; i--) {
3043a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting            mMockProvider.addEventInfo(i, false, currentMillis + DateUtils.HOUR_IN_MILLIS * i,
3053a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                    10);
3063a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        }
3073a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
3083a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Set up expectations for the batch queries.
3093a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        expectAlarmAt(currentMillis + DateUtils.MINUTE_IN_MILLIS * 50);
3103a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider.addExpectedRemindersQuery("method=1 AND event_id IN (19,18,17,16,15)");
3113a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider.addExpectedRemindersQuery("method=1 AND event_id IN (14,13,12,11,10)");
3123a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider.addExpectedRemindersQuery("method=1 AND event_id IN (9,8,7,6,5)");
3133a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        mMockProvider.addExpectedRemindersQuery("method=1 AND event_id IN (4,3,2,1)");
3143a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting
3153a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        // Invoke scheduleNextAlarm and verify alarm and reminder query batches.
3163a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting        AlarmScheduler.scheduleNextAlarm(mIsolatedContext, mMockAlarmManager, batchSize,
3173a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting                currentMillis);
3183a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting    }
3193a07a68da6460c36a5dbec5b8828baa4355dbe04Sara Ting}
320