• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.android.calendar.alerts;
18 
19 import static android.app.Notification.PRIORITY_DEFAULT;
20 import static android.app.Notification.PRIORITY_HIGH;
21 import static android.app.Notification.PRIORITY_MIN;
22 
23 import android.app.AlarmManager;
24 import android.app.PendingIntent;
25 import android.content.SharedPreferences;
26 import android.database.MatrixCursor;
27 import android.provider.CalendarContract.Attendees;
28 import android.provider.CalendarContract.CalendarAlerts;
29 import android.test.AndroidTestCase;
30 import android.test.suitebuilder.annotation.SmallTest;
31 import android.test.suitebuilder.annotation.Smoke;
32 import android.text.format.DateUtils;
33 import android.text.format.Time;
34 
35 import com.android.calendar.GeneralPreferences;
36 import com.android.calendar.alerts.AlertService.NotificationInfo;
37 import com.android.calendar.alerts.AlertService.NotificationWrapper;
38 
39 import junit.framework.Assert;
40 
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.Map;
44 import java.util.Set;
45 
46 public class AlertServiceTest extends AndroidTestCase {
47 
48     class MockSharedPreferences implements SharedPreferences {
49 
50         private Boolean mVibrate;
51         private String mRingtone;
52         private Boolean mPopup;
53 
54         // Strict mode will fail if a preference key is queried more than once.
55         private boolean mStrict = false;
56 
MockSharedPreferences()57         MockSharedPreferences() {
58             this(false);
59         }
60 
MockSharedPreferences(boolean strict)61         MockSharedPreferences(boolean strict) {
62             super();
63             init();
64             this.mStrict = strict;
65         }
66 
init()67         void init() {
68             mVibrate = true;
69             mRingtone = "/some/cool/ringtone";
70             mPopup = true;
71         }
72 
73         @Override
contains(String key)74         public boolean contains(String key) {
75             if (GeneralPreferences.KEY_ALERTS_VIBRATE.equals(key)) {
76                 return true;
77             }
78             return false;
79         }
80 
81         @Override
getBoolean(String key, boolean defValue)82         public boolean getBoolean(String key, boolean defValue) {
83             if (GeneralPreferences.KEY_ALERTS_VIBRATE.equals(key)) {
84                 if (mVibrate == null) {
85                     Assert.fail(GeneralPreferences.KEY_ALERTS_VIBRATE
86                             + " fetched more than once.");
87                 }
88                 boolean val = mVibrate;
89                 if (mStrict) {
90                     mVibrate = null;
91                 }
92                 return val;
93             }
94             if (GeneralPreferences.KEY_ALERTS_POPUP.equals(key)) {
95                 if (mPopup == null) {
96                     Assert.fail(GeneralPreferences.KEY_ALERTS_POPUP + " fetched more than once.");
97                 }
98                 boolean val = mPopup;
99                 if (mStrict) {
100                     mPopup = null;
101                 }
102                 return val;
103             }
104             throw new IllegalArgumentException();
105         }
106 
107         @Override
getString(String key, String defValue)108         public String getString(String key, String defValue) {
109             if (GeneralPreferences.KEY_ALERTS_RINGTONE.equals(key)) {
110                 if (mRingtone == null) {
111                     Assert.fail(GeneralPreferences.KEY_ALERTS_RINGTONE
112                             + " fetched more than once.");
113                 }
114                 String val = mRingtone;
115                 if (mStrict) {
116                     mRingtone = null;
117                 }
118                 return val;
119             }
120             throw new IllegalArgumentException();
121         }
122 
123         @Override
getAll()124         public Map<String, ?> getAll() {
125             throw new IllegalArgumentException();
126         }
127 
128         @Override
getStringSet(String key, Set<String> defValues)129         public Set<String> getStringSet(String key, Set<String> defValues) {
130             throw new IllegalArgumentException();
131         }
132 
133         @Override
getInt(String key, int defValue)134         public int getInt(String key, int defValue) {
135             throw new IllegalArgumentException();
136         }
137 
138         @Override
getLong(String key, long defValue)139         public long getLong(String key, long defValue) {
140             throw new IllegalArgumentException();
141         }
142 
143         @Override
getFloat(String key, float defValue)144         public float getFloat(String key, float defValue) {
145             throw new IllegalArgumentException();
146         }
147 
148         @Override
edit()149         public Editor edit() {
150             throw new IllegalArgumentException();
151         }
152 
153         @Override
registerOnSharedPreferenceChangeListener( OnSharedPreferenceChangeListener listener)154         public void registerOnSharedPreferenceChangeListener(
155                 OnSharedPreferenceChangeListener listener) {
156             throw new IllegalArgumentException();
157         }
158 
159         @Override
unregisterOnSharedPreferenceChangeListener( OnSharedPreferenceChangeListener listener)160         public void unregisterOnSharedPreferenceChangeListener(
161                 OnSharedPreferenceChangeListener listener) {
162             throw new IllegalArgumentException();
163         }
164 
165     }
166 
167     // Created these constants so the test cases are shorter
168     public static final int SCHEDULED = CalendarAlerts.STATE_SCHEDULED;
169     public static final int FIRED = CalendarAlerts.STATE_FIRED;
170     public static final int DISMISSED = CalendarAlerts.STATE_DISMISSED;
171 
172     public static final int ACCEPTED = Attendees.ATTENDEE_STATUS_ACCEPTED;
173     public static final int DECLINED = Attendees.ATTENDEE_STATUS_DECLINED;
174     public static final int INVITED = Attendees.ATTENDEE_STATUS_INVITED;
175     public static final int TENTATIVE = Attendees.ATTENDEE_STATUS_TENTATIVE;
176 
177     class NotificationInstance {
178         int mAlertId;
179         int[] mAlertIdsInDigest;
180         int mPriority;
181 
NotificationInstance(int alertId, int priority)182         public NotificationInstance(int alertId, int priority) {
183             mAlertId = alertId;
184             mPriority = priority;
185         }
186 
NotificationInstance(int[] alertIdsInDigest, int priority)187         public NotificationInstance(int[] alertIdsInDigest, int priority) {
188             mAlertIdsInDigest = alertIdsInDigest;
189             mPriority = priority;
190         }
191     }
192 
193     class Alert {
194         long mEventId;
195         int mAlertStatus;
196         int mResponseStatus;
197         int mAllDay;
198         long mBegin;
199         long mEnd;
200         int mMinute;
201         long mAlarmTime;
202 
Alert(long eventId, int alertStatus, int responseStatus, int allDay, long begin, long end, int minute, long alarmTime)203         public Alert(long eventId, int alertStatus, int responseStatus, int allDay, long begin,
204                 long end, int minute, long alarmTime) {
205             mEventId = eventId;
206             mAlertStatus = alertStatus;
207             mResponseStatus = responseStatus;
208             mAllDay = allDay;
209             mBegin = begin;
210             mEnd = end;
211             mMinute = minute;
212             mAlarmTime = alarmTime;
213         }
214 
215     }
216 
217     class AlertsTable {
218 
219         ArrayList<Alert> mAlerts = new ArrayList<Alert>();
220 
addAlertRow(long eventId, int alertStatus, int responseStatus, int allDay, long begin, long end, long alarmTime)221         int addAlertRow(long eventId, int alertStatus, int responseStatus, int allDay, long begin,
222                 long end, long alarmTime) {
223             Alert a = new Alert(eventId, alertStatus, responseStatus, allDay, begin, end,
224                     5 /* minute */, alarmTime);
225             int id = mAlerts.size();
226             mAlerts.add(a);
227             return id;
228         }
229 
getAlertCursor()230         public MatrixCursor getAlertCursor() {
231             MatrixCursor alertCursor = new MatrixCursor(AlertService.ALERT_PROJECTION);
232 
233             int i = 0;
234             for (Alert a : mAlerts) {
235                 Object[] ca = {
236                         i++,
237                         a.mEventId,
238                         a.mAlertStatus,
239                         "Title" + a.mEventId + " " + a.mMinute,
240                         "Loc" + a.mEventId,
241                         a.mResponseStatus,
242                         a.mAllDay,
243                         a.mAlarmTime > 0 ? a.mAlarmTime : a.mBegin - a.mMinute * 60 * 1000,
244                         a.mMinute,
245                         a.mBegin,
246                         a.mEnd,
247                         "Desc: " + a.mAlarmTime
248                 };
249                 alertCursor.addRow(ca);
250             }
251             return alertCursor;
252         }
253 
254     }
255 
256     class NotificationTestManager extends NotificationMgr {
257         // Expected notifications
258         NotificationInstance[] mExpectedNotifications;
259         NotificationWrapper[] mActualNotifications;
260         boolean[] mCancelled;
261 
262         // CalendarAlerts table
263         private ArrayList<Alert> mAlerts;
264 
NotificationTestManager(ArrayList<Alert> alerts, int maxNotifications)265         public NotificationTestManager(ArrayList<Alert> alerts, int maxNotifications) {
266             assertEquals(0, AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID);
267             mAlerts = alerts;
268             mExpectedNotifications = new NotificationInstance[maxNotifications + 1];
269             mActualNotifications = new NotificationWrapper[mExpectedNotifications.length];
270             mCancelled = new boolean[mExpectedNotifications.length];
271         }
272 
expectTestNotification(int notificationId, int alertId, int highPriority)273         public void expectTestNotification(int notificationId, int alertId, int highPriority) {
274             mExpectedNotifications[notificationId] = new NotificationInstance(alertId,
275                     highPriority);
276         }
277 
expectTestNotification(int notificationId, int[] alertIds, int priority)278         public void expectTestNotification(int notificationId, int[] alertIds, int priority) {
279             mExpectedNotifications[notificationId] = new NotificationInstance(alertIds, priority);
280         }
281 
nullContents(T[] array)282         private <T> boolean nullContents(T[] array) {
283             for (T item : array) {
284                 if (item != null) {
285                     return false;
286                 }
287             }
288             return true;
289         }
290 
validateNotificationsAndReset()291         public void validateNotificationsAndReset() {
292             if (nullContents(mExpectedNotifications)) {
293                 return;
294             }
295 
296             String debugStr = printActualNotifications();
297             for (int id = 0; id < mActualNotifications.length; id++) {
298                 NotificationInstance expected = mExpectedNotifications[id];
299                 NotificationWrapper actual = mActualNotifications[id];
300                 if (expected == null) {
301                     assertNull("Received unexpected notificationId " + id + debugStr, actual);
302                     assertTrue("NotificationId " + id + " should have been cancelled." + debugStr,
303                             mCancelled[id]);
304                 } else {
305                     assertNotNull("Expected notificationId " + id + " but it was not posted."
306                             + debugStr, actual);
307                     assertFalse("NotificationId " + id + " should not have been cancelled."
308                             + debugStr, mCancelled[id]);
309                     assertEquals("Priority not as expected for notification " + id + debugStr,
310                             expected.mPriority, actual.mNotification.priority);
311                     if (expected.mAlertIdsInDigest == null) {
312                         Alert a = mAlerts.get(expected.mAlertId);
313                         assertEquals("Event ID not expected for notification " + id + debugStr,
314                                 a.mEventId, actual.mEventId);
315                         assertEquals("Begin time not expected for notification " + id + debugStr,
316                                 a.mBegin, actual.mBegin);
317                         assertEquals("End time not expected for notification " + id + debugStr,
318                                 a.mEnd, actual.mEnd);
319                     } else {
320                         // Notification should be a digest.
321                         assertNotNull("Posted notification not a digest as expected." + debugStr,
322                                 actual.mNw);
323                         assertEquals("Number of notifications in digest not as expected."
324                                 + debugStr, expected.mAlertIdsInDigest.length, actual.mNw.size());
325                         for (int i = 0; i < actual.mNw.size(); i++) {
326                             Alert a = mAlerts.get(expected.mAlertIdsInDigest[i]);
327                             assertEquals("Digest item " + i + ": Event ID not as expected"
328                                     + debugStr, a.mEventId, actual.mNw.get(i).mEventId);
329                             assertEquals("Digest item " + i + ": Begin time in digest not expected"
330                                     + debugStr, a.mBegin, actual.mNw.get(i).mBegin);
331                             assertEquals("Digest item " + i + ": End time in digest not expected"
332                                     + debugStr, a.mEnd, actual.mNw.get(i).mEnd);
333                         }
334                     }
335                 }
336             }
337 
338             Arrays.fill(mCancelled, false);
339             Arrays.fill(mExpectedNotifications, null);
340             Arrays.fill(mActualNotifications, null);
341         }
342 
printActualNotifications()343         private String printActualNotifications() {
344             StringBuilder s = new StringBuilder();
345             s.append("\n\nNotifications actually posted:\n");
346             for (int i = mActualNotifications.length - 1; i >= 0; i--) {
347                 NotificationWrapper actual = mActualNotifications[i];
348                 if (actual == null) {
349                     continue;
350                 }
351                 s.append("Notification " + i + " -- ");
352                 s.append("priority:" + actual.mNotification.priority);
353                 if (actual.mNw == null) {
354                     s.append(", eventId:" +  actual.mEventId);
355                 } else {
356                     s.append(", eventIds:{");
357                     for (int digestIndex = 0; digestIndex < actual.mNw.size(); digestIndex++) {
358                         s.append(actual.mNw.get(digestIndex).mEventId + ",");
359                     }
360                     s.append("}");
361                 }
362                 s.append("\n");
363             }
364             return s.toString();
365         }
366 
367         ///////////////////////////////
368         // NotificationMgr methods
369         @Override
cancel(int id)370         public void cancel(int id) {
371             assertTrue("id out of bound: " + id, 0 <= id);
372             assertTrue("id out of bound: " + id, id < mCancelled.length);
373             assertNull("id already used", mActualNotifications[id]);
374             assertFalse("id already used", mCancelled[id]);
375             mCancelled[id] = true;
376             assertNull("Unexpected cancel for id " + id, mExpectedNotifications[id]);
377         }
378 
379         @Override
notify(int id, NotificationWrapper nw)380         public void notify(int id, NotificationWrapper nw) {
381             assertTrue("id out of bound: " + id, 0 <= id);
382             assertTrue("id out of bound: " + id, id < mExpectedNotifications.length);
383             assertNull("id already used: " + id, mActualNotifications[id]);
384             mActualNotifications[id] = nw;
385         }
386     }
387 
388     private class MockAlarmManager implements AlarmManagerInterface {
389         private int expectedAlarmType = -1;
390         private long expectedAlarmTime = -1;
391 
expectAlarmTime(int type, long millis)392         public void expectAlarmTime(int type, long millis) {
393             this.expectedAlarmType = type;
394             this.expectedAlarmTime = millis;
395         }
396 
397         @Override
set(int actualAlarmType, long actualAlarmTime, PendingIntent operation)398         public void set(int actualAlarmType, long actualAlarmTime, PendingIntent operation) {
399             assertNotNull(operation);
400             if (expectedAlarmType != -1) {
401                 assertEquals("Alarm type not expected.", expectedAlarmType, actualAlarmType);
402                 assertEquals("Alarm time not expected. Expected:" + DateUtils.formatDateTime(
403                         mContext, expectedAlarmTime, DateUtils.FORMAT_SHOW_TIME) + ", actual:"
404                         + DateUtils.formatDateTime(mContext, actualAlarmTime,
405                         DateUtils.FORMAT_SHOW_TIME), expectedAlarmTime, actualAlarmTime);
406             }
407         }
408     }
409 
410     // TODO
411     // Catch updates of new state, notify time, and received time
412     // Test ringer, vibrate,
413     // Test intents, action email
414 
415     @Smoke
416     @SmallTest
testGenerateAlerts_none()417     public void testGenerateAlerts_none() {
418         MockSharedPreferences prefs = new MockSharedPreferences();
419         AlertsTable at = new AlertsTable();
420         NotificationTestManager ntm = new NotificationTestManager(at.mAlerts,
421                 AlertService.MAX_NOTIFICATIONS);
422 
423         // Test no alert
424         long currentTime = 1000000;
425         AlertService.generateAlerts(mContext, ntm, new MockAlarmManager(), prefs,
426                 at.getAlertCursor(), currentTime, AlertService.MAX_NOTIFICATIONS);
427         ntm.validateNotificationsAndReset();
428     }
429 
430     @Smoke
431     @SmallTest
testGenerateAlerts_single()432     public void testGenerateAlerts_single() {
433         MockSharedPreferences prefs = new MockSharedPreferences();
434         MockAlarmManager alarmMgr = new MockAlarmManager();
435         AlertsTable at = new AlertsTable();
436         NotificationTestManager ntm = new NotificationTestManager(at.mAlerts,
437                 AlertService.MAX_NOTIFICATIONS);
438 
439         int id = at.addAlertRow(100, SCHEDULED, ACCEPTED, 0 /* all day */, 1300000, 2300000, 0);
440 
441         // Test one up coming alert
442         long currentTime = 1000000;
443         ntm.expectTestNotification(1, id, PRIORITY_HIGH);
444 
445         AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(), currentTime,
446                 AlertService.MAX_NOTIFICATIONS);
447         ntm.validateNotificationsAndReset(); // This wipes out notification
448                                              // tests added so far
449 
450         // Test half way into an event
451         currentTime = 2300000;
452         ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID, id, PRIORITY_MIN);
453 
454         AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(), currentTime,
455                 AlertService.MAX_NOTIFICATIONS);
456         ntm.validateNotificationsAndReset();
457 
458         // Test event ended
459         currentTime = 4300000;
460         ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID, id, PRIORITY_MIN);
461 
462         AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(), currentTime,
463                 AlertService.MAX_NOTIFICATIONS);
464         ntm.validateNotificationsAndReset();
465     }
466 
467     @SmallTest
testGenerateAlerts_multiple()468     public void testGenerateAlerts_multiple() {
469         int maxNotifications = 10;
470         MockSharedPreferences prefs = new MockSharedPreferences();
471         MockAlarmManager alarmMgr = new MockAlarmManager();
472         AlertsTable at = new AlertsTable();
473         NotificationTestManager ntm = new NotificationTestManager(at.mAlerts, maxNotifications);
474 
475         // Current time - 5:00
476         long currentTime = createTimeInMillis(5, 0);
477 
478         // Set up future alerts.  The real query implementation sorts by descending start
479         // time so simulate that here with our order of adds to AlertsTable.
480         int id9 = at.addAlertRow(9, SCHEDULED, ACCEPTED, 0, createTimeInMillis(9, 0),
481                 createTimeInMillis(10, 0), 0);
482         int id8 = at.addAlertRow(8, SCHEDULED, ACCEPTED, 0, createTimeInMillis(8, 0),
483                 createTimeInMillis(9, 0), 0);
484         int id7 = at.addAlertRow(7, SCHEDULED, ACCEPTED, 0, createTimeInMillis(7, 0),
485                 createTimeInMillis(8, 0), 0);
486 
487         // Set up concurrent alerts (that started recently).
488         int id6 = at.addAlertRow(6, SCHEDULED, ACCEPTED, 0, createTimeInMillis(5, 0),
489                 createTimeInMillis(5, 40), 0);
490         int id5 = at.addAlertRow(5, SCHEDULED, ACCEPTED, 0, createTimeInMillis(4, 55),
491                 createTimeInMillis(7, 30), 0);
492         int id4 = at.addAlertRow(4, SCHEDULED, ACCEPTED, 0, createTimeInMillis(4, 50),
493                 createTimeInMillis(4, 50), 0);
494 
495         // Set up past alerts.
496         int id3 = at.addAlertRow(3, SCHEDULED, ACCEPTED, 0, createTimeInMillis(3, 0),
497                 createTimeInMillis(4, 0), 0);
498         int id2 = at.addAlertRow(2, SCHEDULED, ACCEPTED, 0, createTimeInMillis(2, 0),
499                 createTimeInMillis(3, 0), 0);
500         int id1 = at.addAlertRow(1, SCHEDULED, ACCEPTED, 0, createTimeInMillis(1, 0),
501                 createTimeInMillis(2, 0), 0);
502 
503         // Check posted notifications.  The order listed here is the order simulates the
504         // order in the real notification bar (last one posted appears on top), so these
505         // should be lowest start time on top.
506         ntm.expectTestNotification(6, id4, PRIORITY_HIGH); // concurrent
507         ntm.expectTestNotification(5, id5, PRIORITY_HIGH); // concurrent
508         ntm.expectTestNotification(4, id6, PRIORITY_HIGH); // concurrent
509         ntm.expectTestNotification(3, id7, PRIORITY_HIGH); // future
510         ntm.expectTestNotification(2, id8, PRIORITY_HIGH); // future
511         ntm.expectTestNotification(1, id9, PRIORITY_HIGH); // future
512         ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID,
513                 new int[] {id3, id2, id1}, PRIORITY_MIN);
514         AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
515                 currentTime, maxNotifications);
516         ntm.validateNotificationsAndReset();
517 
518         // Increase time by 15 minutes to check that some concurrent events dropped
519         // to the low priority bucket.
520         currentTime = createTimeInMillis(5, 15);
521         ntm.expectTestNotification(4, id5, PRIORITY_HIGH); // concurrent
522         ntm.expectTestNotification(3, id7, PRIORITY_HIGH); // future
523         ntm.expectTestNotification(2, id8, PRIORITY_HIGH); // future
524         ntm.expectTestNotification(1, id9, PRIORITY_HIGH); // future
525         ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID,
526                 new int[] {id6, id4, id3, id2, id1}, PRIORITY_MIN);
527         AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
528                 currentTime, maxNotifications);
529         ntm.validateNotificationsAndReset();
530 
531         // Increase time so some of the previously future ones change state.
532         currentTime = createTimeInMillis(8, 15);
533         ntm.expectTestNotification(1, id9, PRIORITY_HIGH); // future
534         ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID,
535                 new int[] {id8, id7, id6, id5, id4, id3, id2, id1}, PRIORITY_MIN);
536         AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
537                 currentTime, maxNotifications);
538         ntm.validateNotificationsAndReset();
539     }
540 
541     @SmallTest
testGenerateAlerts_maxAlerts()542     public void testGenerateAlerts_maxAlerts() {
543         MockSharedPreferences prefs = new MockSharedPreferences();
544         MockAlarmManager alarmMgr = new MockAlarmManager();
545         AlertsTable at = new AlertsTable();
546 
547         // Current time - 5:00
548         long currentTime = createTimeInMillis(5, 0);
549 
550         // Set up future alerts.  The real query implementation sorts by descending start
551         // time so simulate that here with our order of adds to AlertsTable.
552         int id9 = at.addAlertRow(9, SCHEDULED, ACCEPTED, 0, createTimeInMillis(9, 0),
553                 createTimeInMillis(10, 0), 0);
554         int id8 = at.addAlertRow(8, SCHEDULED, ACCEPTED, 0, createTimeInMillis(8, 0),
555                 createTimeInMillis(9, 0), 0);
556         int id7 = at.addAlertRow(7, SCHEDULED, ACCEPTED, 0, createTimeInMillis(7, 0),
557                 createTimeInMillis(8, 0), 0);
558 
559         // Set up concurrent alerts (that started recently).
560         int id6 = at.addAlertRow(6, SCHEDULED, ACCEPTED, 0, createTimeInMillis(5, 0),
561                 createTimeInMillis(5, 40), 0);
562         int id5 = at.addAlertRow(5, SCHEDULED, ACCEPTED, 0, createTimeInMillis(4, 55),
563                 createTimeInMillis(7, 30), 0);
564         int id4 = at.addAlertRow(4, SCHEDULED, ACCEPTED, 0, createTimeInMillis(4, 50),
565                 createTimeInMillis(4, 50), 0);
566 
567         // Set up past alerts.
568         int id3 = at.addAlertRow(3, SCHEDULED, ACCEPTED, 0, createTimeInMillis(3, 0),
569                 createTimeInMillis(4, 0), 0);
570         int id2 = at.addAlertRow(2, SCHEDULED, ACCEPTED, 0, createTimeInMillis(2, 0),
571                 createTimeInMillis(3, 0), 0);
572         int id1 = at.addAlertRow(1, SCHEDULED, ACCEPTED, 0, createTimeInMillis(1, 0),
573                 createTimeInMillis(2, 0), 0);
574 
575         // Test when # alerts = max.
576         int maxNotifications = 6;
577         NotificationTestManager ntm = new NotificationTestManager(at.mAlerts, maxNotifications);
578         ntm.expectTestNotification(6, id4, PRIORITY_HIGH); // concurrent
579         ntm.expectTestNotification(5, id5, PRIORITY_HIGH); // concurrent
580         ntm.expectTestNotification(4, id6, PRIORITY_HIGH); // concurrent
581         ntm.expectTestNotification(3, id7, PRIORITY_HIGH); // future
582         ntm.expectTestNotification(2, id8, PRIORITY_HIGH); // future
583         ntm.expectTestNotification(1, id9, PRIORITY_HIGH); // future
584         ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID,
585                 new int[] {id3, id2, id1}, PRIORITY_MIN);
586         AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
587                 currentTime, maxNotifications);
588         ntm.validateNotificationsAndReset();
589 
590         // Test when # alerts > max.
591         maxNotifications = 4;
592         ntm = new NotificationTestManager(at.mAlerts, maxNotifications);
593         ntm.expectTestNotification(4, id4, PRIORITY_HIGH); // concurrent
594         ntm.expectTestNotification(3, id5, PRIORITY_HIGH); // concurrent
595         ntm.expectTestNotification(2, id6, PRIORITY_HIGH); // concurrent
596         ntm.expectTestNotification(1, id7, PRIORITY_HIGH); // future
597         ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID,
598                 new int[] {id9, id8, id3, id2, id1}, PRIORITY_MIN);
599         AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
600                 currentTime, maxNotifications);
601         ntm.validateNotificationsAndReset();
602     }
603 
604     /**
605      * Test that the SharedPreferences are only fetched once for each setting.
606      */
607     @SmallTest
testGenerateAlerts_sharedPreferences()608     public void testGenerateAlerts_sharedPreferences() {
609         MockSharedPreferences prefs = new MockSharedPreferences(true /* strict mode */);
610         AlertsTable at = new AlertsTable();
611         NotificationTestManager ntm = new NotificationTestManager(at.mAlerts,
612                 AlertService.MAX_NOTIFICATIONS);
613 
614         // Current time - 5:00
615         long currentTime = createTimeInMillis(5, 0);
616 
617         // Set up future alerts.  The real query implementation sorts by descending start
618         // time so simulate that here with our order of adds to AlertsTable.
619         at.addAlertRow(3, SCHEDULED, ACCEPTED, 0, createTimeInMillis(9, 0),
620                 createTimeInMillis(10, 0), 0);
621         at.addAlertRow(2, SCHEDULED, ACCEPTED, 0, createTimeInMillis(8, 0),
622                 createTimeInMillis(9, 0), 0);
623         at.addAlertRow(1, SCHEDULED, ACCEPTED, 0, createTimeInMillis(7, 0),
624                 createTimeInMillis(8, 0), 0);
625 
626         // If this does not result in a failure (MockSharedPreferences fails for duplicate
627         // queries), then test passes.
628         AlertService.generateAlerts(mContext, ntm, new MockAlarmManager(), prefs,
629                 at.getAlertCursor(), currentTime, AlertService.MAX_NOTIFICATIONS);
630     }
631 
testGenerateAlerts_refreshTime()632     public void testGenerateAlerts_refreshTime() {
633         AlertsTable at = new AlertsTable();
634         MockSharedPreferences prefs = new MockSharedPreferences();
635         MockAlarmManager alarmMgr = new MockAlarmManager();
636         NotificationTestManager ntm = new NotificationTestManager(at.mAlerts,
637                 AlertService.MAX_NOTIFICATIONS);
638 
639         // Since AlertService.processQuery uses DateUtils.isToday instead of checking against
640         // the passed in currentTime (not worth allocating the extra Time objects to do so), use
641         // today's date for this test.
642         Time now = new Time();
643         now.setToNow();
644         int day = now.monthDay;
645         int month = now.month;
646         int year = now.year;
647         Time yesterday = new Time();
648         yesterday.set(System.currentTimeMillis() - DateUtils.DAY_IN_MILLIS);
649         Time tomorrow = new Time();
650         tomorrow.set(System.currentTimeMillis() + DateUtils.DAY_IN_MILLIS);
651         long allDayStart = createTimeInMillis(0, 0, 0, day, month, year, Time.TIMEZONE_UTC);
652 
653         /* today 10am - 10:30am */
654         int id4 = at.addAlertRow(4, SCHEDULED, ACCEPTED, 0,
655                 createTimeInMillis(0, 0, 10, day, month, year, Time.getCurrentTimezone()),
656                 createTimeInMillis(0, 30, 10, day, month, year, Time.getCurrentTimezone()), 0);
657         /* today 6am - 6am (0 duration event) */
658         int id3 = at.addAlertRow(3, SCHEDULED, ACCEPTED, 0,
659                 createTimeInMillis(0, 0, 6, day, month, year, Time.getCurrentTimezone()),
660                 createTimeInMillis(0, 0, 6, day, month, year, Time.getCurrentTimezone()), 0);
661         /* today allDay */
662         int id2 = at.addAlertRow(2, SCHEDULED, ACCEPTED, 1, allDayStart,
663                 allDayStart + DateUtils.HOUR_IN_MILLIS * 24, 0);
664         /* yesterday 11pm - today 7am (multiday event) */
665         int id1 = at.addAlertRow(1, SCHEDULED, ACCEPTED, 0,
666                 createTimeInMillis(0, 0, 23, yesterday.monthDay, yesterday.month, yesterday.year,
667                         Time.getCurrentTimezone()),
668                 createTimeInMillis(0, 0, 7, day, month, year, Time.getCurrentTimezone()), 0);
669 
670         // Test at midnight - next refresh should be 15 min later (15 min into the all
671         // day event).
672         long currentTime = createTimeInMillis(0, 0, 0, day, month, year, Time.getCurrentTimezone());
673         alarmMgr.expectAlarmTime(AlarmManager.RTC, currentTime + 15 * DateUtils.MINUTE_IN_MILLIS);
674         ntm.expectTestNotification(4, id1, PRIORITY_HIGH);
675         ntm.expectTestNotification(3, id2, PRIORITY_HIGH);
676         ntm.expectTestNotification(2, id3, PRIORITY_HIGH);
677         ntm.expectTestNotification(1, id4, PRIORITY_HIGH);
678         AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
679                 currentTime, AlertService.MAX_NOTIFICATIONS);
680         ntm.validateNotificationsAndReset();
681 
682         // Test at 12:30am - next refresh should be 30 min later (1/4 into event 'id1').
683         currentTime = createTimeInMillis(0, 30, 0, day, month, year, Time.getCurrentTimezone());
684         alarmMgr.expectAlarmTime(AlarmManager.RTC, currentTime + 30 * DateUtils.MINUTE_IN_MILLIS);
685         ntm.expectTestNotification(3, id1, PRIORITY_HIGH);
686         ntm.expectTestNotification(2, id3, PRIORITY_HIGH);
687         ntm.expectTestNotification(1, id4, PRIORITY_HIGH);
688         ntm.expectTestNotification(4, id2, PRIORITY_DEFAULT);
689         AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
690                 currentTime, AlertService.MAX_NOTIFICATIONS);
691         ntm.validateNotificationsAndReset();
692 
693         // Test at 5:55am - next refresh should be 20 min later (15 min after 'id3').
694         currentTime = createTimeInMillis(0, 55, 5, day, month, year, Time.getCurrentTimezone());
695         alarmMgr.expectAlarmTime(AlarmManager.RTC, currentTime + 20 * DateUtils.MINUTE_IN_MILLIS);
696         ntm.expectTestNotification(2, id3, PRIORITY_HIGH);
697         ntm.expectTestNotification(1, id4, PRIORITY_HIGH);
698         ntm.expectTestNotification(3, id2, PRIORITY_DEFAULT);
699         ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID, id1, PRIORITY_MIN);
700         AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
701                 currentTime, AlertService.MAX_NOTIFICATIONS);
702         ntm.validateNotificationsAndReset();
703 
704         // Test at 10:14am - next refresh should be 1 min later (15 min into event 'id4').
705         currentTime = createTimeInMillis(0, 14, 10, day, month, year, Time.getCurrentTimezone());
706         alarmMgr.expectAlarmTime(AlarmManager.RTC, currentTime + 1 * DateUtils.MINUTE_IN_MILLIS);
707         ntm.expectTestNotification(1, id4, PRIORITY_HIGH);
708         ntm.expectTestNotification(2, id2, PRIORITY_DEFAULT);
709         ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID, new int[] {id3, id1},
710                 PRIORITY_MIN);
711         AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
712                 currentTime, AlertService.MAX_NOTIFICATIONS);
713         ntm.validateNotificationsAndReset();
714 
715         // Test at 10:15am - next refresh should be tomorrow midnight (end of all day event 'id2').
716         currentTime = createTimeInMillis(0, 15, 10, day, month, year, Time.getCurrentTimezone());
717         alarmMgr.expectAlarmTime(AlarmManager.RTC, createTimeInMillis(0, 0, 23, tomorrow.monthDay,
718                 tomorrow.month, tomorrow.year, Time.getCurrentTimezone()));
719         ntm.expectTestNotification(1, id2, PRIORITY_DEFAULT);
720         ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID,
721                 new int[] {id4, id3, id1}, PRIORITY_MIN);
722         AlertService.generateAlerts(mContext, ntm, alarmMgr, prefs, at.getAlertCursor(),
723                 currentTime, AlertService.MAX_NOTIFICATIONS);
724         ntm.validateNotificationsAndReset();
725     }
726 
createNotificationInfo(long eventId)727     private NotificationInfo createNotificationInfo(long eventId) {
728         return new NotificationInfo("eventName", "location", "description", 100L, 200L, eventId,
729                 false, false);
730     }
731 
createTimeInMillis(int hour, int minute)732     private static long createTimeInMillis(int hour, int minute) {
733         return createTimeInMillis(0 /* second */, minute, hour, 1 /* day */, 1 /* month */,
734                 2012 /* year */, Time.getCurrentTimezone());
735     }
736 
createTimeInMillis(int second, int minute, int hour, int monthDay, int month, int year, String timezone)737     private static long createTimeInMillis(int second, int minute, int hour, int monthDay,
738             int month, int year, String timezone) {
739         Time t = new Time(timezone);
740         t.set(second, minute, hour, monthDay, month, year);
741         t.normalize(false);
742         return t.toMillis(false);
743     }
744 
745     @SmallTest
testProcessQuery_skipDeclinedDismissed()746     public void testProcessQuery_skipDeclinedDismissed() {
747         int declinedEventId = 1;
748         int dismissedEventId = 2;
749         int acceptedEventId = 3;
750         long acceptedStartTime = createTimeInMillis(10, 0);
751         long acceptedEndTime = createTimeInMillis(10, 30);
752 
753         AlertsTable at = new AlertsTable();
754         at.addAlertRow(declinedEventId, SCHEDULED, DECLINED, 0, createTimeInMillis(9, 0),
755                 createTimeInMillis(10, 0), 0);
756         at.addAlertRow(dismissedEventId, SCHEDULED, DISMISSED, 0, createTimeInMillis(9, 30),
757                 createTimeInMillis(11, 0), 0);
758         at.addAlertRow(acceptedEventId, SCHEDULED, ACCEPTED, 1, acceptedStartTime, acceptedEndTime,
759                 0);
760 
761         ArrayList<NotificationInfo> highPriority = new ArrayList<NotificationInfo>();
762         ArrayList<NotificationInfo> mediumPriority = new ArrayList<NotificationInfo>();
763         ArrayList<NotificationInfo> lowPriority = new ArrayList<NotificationInfo>();
764         long currentTime = createTimeInMillis(5, 0);
765         AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
766                 mediumPriority, lowPriority);
767 
768         assertEquals(0, lowPriority.size());
769         assertEquals(0, mediumPriority.size());
770         assertEquals(1, highPriority.size());
771         assertEquals(acceptedEventId, highPriority.get(0).eventId);
772         assertEquals(acceptedStartTime, highPriority.get(0).startMillis);
773         assertEquals(acceptedEndTime, highPriority.get(0).endMillis);
774         assertTrue(highPriority.get(0).allDay);
775     }
776 
777     @SmallTest
testProcessQuery_newAlert()778     public void testProcessQuery_newAlert() {
779         int scheduledAlertEventId = 1;
780         int firedAlertEventId = 2;
781 
782         AlertsTable at = new AlertsTable();
783         at.addAlertRow(scheduledAlertEventId, SCHEDULED, ACCEPTED, 0, createTimeInMillis(9, 0),
784                 createTimeInMillis(10, 0), 0);
785         at.addAlertRow(firedAlertEventId, FIRED, ACCEPTED, 0, createTimeInMillis(10, 0),
786                 createTimeInMillis(10, 30), 0);
787 
788         ArrayList<NotificationInfo> highPriority = new ArrayList<NotificationInfo>();
789         ArrayList<NotificationInfo> mediumPriority = new ArrayList<NotificationInfo>();
790         ArrayList<NotificationInfo> lowPriority = new ArrayList<NotificationInfo>();
791         long currentTime = createTimeInMillis(5, 0);
792         AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
793                 mediumPriority, lowPriority);
794 
795         assertEquals(0, lowPriority.size());
796         assertEquals(0, mediumPriority.size());
797         assertEquals(2, highPriority.size());
798         assertEquals(scheduledAlertEventId, highPriority.get(0).eventId);
799         assertTrue("newAlert should be ON for scheduled alerts", highPriority.get(0).newAlert);
800         assertEquals(firedAlertEventId, highPriority.get(1).eventId);
801         assertFalse("newAlert should be OFF for fired alerts", highPriority.get(1).newAlert);
802     }
803 
804     @SmallTest
testProcessQuery_recurringEvent()805     public void testProcessQuery_recurringEvent() {
806         int eventId = 1;
807         long earlierStartTime = createTimeInMillis(10, 0);
808         long laterStartTime = createTimeInMillis(11, 0);
809 
810         ArrayList<NotificationInfo> highPriority = new ArrayList<NotificationInfo>();
811         ArrayList<NotificationInfo> mediumPriority = new ArrayList<NotificationInfo>();
812         ArrayList<NotificationInfo> lowPriority = new ArrayList<NotificationInfo>();
813 
814         AlertsTable at = new AlertsTable();
815         at.addAlertRow(eventId, SCHEDULED, ACCEPTED, 0, laterStartTime,
816                 laterStartTime + DateUtils.HOUR_IN_MILLIS, 0);
817         at.addAlertRow(eventId, FIRED, ACCEPTED, 0, earlierStartTime,
818                 earlierStartTime + DateUtils.HOUR_IN_MILLIS, 0);
819 
820         // Both events in the future: the earliest one should be chosen.
821         long currentTime = earlierStartTime - DateUtils.DAY_IN_MILLIS * 5;
822         AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
823                 mediumPriority, lowPriority);
824         assertEquals(0, lowPriority.size());
825         assertEquals(0, mediumPriority.size());
826         assertEquals(1, highPriority.size());
827         assertEquals("Recurring event with earlier start time expected", earlierStartTime,
828                 highPriority.get(0).startMillis);
829 
830         // Increment time just past the earlier event: the earlier one should be chosen.
831         highPriority.clear();
832         currentTime = earlierStartTime + DateUtils.MINUTE_IN_MILLIS * 10;
833         AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
834                 mediumPriority, lowPriority);
835         assertEquals(0, lowPriority.size());
836         assertEquals(0, mediumPriority.size());
837         assertEquals(1, highPriority.size());
838         assertEquals("Recurring event with earlier start time expected", earlierStartTime,
839                 highPriority.get(0).startMillis);
840 
841         // Increment time to 15 min past the earlier event: the later one should be chosen.
842         highPriority.clear();
843         currentTime = earlierStartTime + DateUtils.MINUTE_IN_MILLIS * 15;
844         AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
845                 mediumPriority, lowPriority);
846         assertEquals(0, lowPriority.size());
847         assertEquals(0, mediumPriority.size());
848         assertEquals(1, highPriority.size());
849         assertEquals("Recurring event with later start time expected", laterStartTime,
850                 highPriority.get(0).startMillis);
851 
852         // Both events in the past: the later one should be chosen (in the low priority bucket).
853         highPriority.clear();
854         currentTime = laterStartTime + DateUtils.DAY_IN_MILLIS * 5;
855         AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
856                 mediumPriority, lowPriority);
857         assertEquals(0, highPriority.size());
858         assertEquals(0, mediumPriority.size());
859         assertEquals(1, lowPriority.size());
860         assertEquals("Recurring event with later start time expected", laterStartTime,
861                 lowPriority.get(0).startMillis);
862     }
863 
864     @SmallTest
testProcessQuery_recurringAllDayEvent()865     public void testProcessQuery_recurringAllDayEvent() {
866         int eventId = 1;
867         long day1 = createTimeInMillis(0, 0, 0, 1, 5, 2012, Time.TIMEZONE_UTC);
868         long day2 = createTimeInMillis(0, 0, 0, 2, 5, 2012, Time.TIMEZONE_UTC);
869 
870         ArrayList<NotificationInfo> highPriority = new ArrayList<NotificationInfo>();
871         ArrayList<NotificationInfo> mediumPriority = new ArrayList<NotificationInfo>();
872         ArrayList<NotificationInfo> lowPriority = new ArrayList<NotificationInfo>();
873 
874         AlertsTable at = new AlertsTable();
875         at.addAlertRow(eventId, SCHEDULED, ACCEPTED, 1, day2, day2 + DateUtils.HOUR_IN_MILLIS * 24,
876                 0);
877         at.addAlertRow(eventId, SCHEDULED, ACCEPTED, 1, day1, day1 + DateUtils.HOUR_IN_MILLIS * 24,
878                 0);
879 
880         // Both events in the future: the earliest one should be chosen.
881         long currentTime = day1 - DateUtils.DAY_IN_MILLIS * 3;
882         AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
883                 mediumPriority, lowPriority);
884         assertEquals(0, lowPriority.size());
885         assertEquals(0, mediumPriority.size());
886         assertEquals(1, highPriority.size());
887         assertEquals("Recurring event with earlier start time expected", day1,
888                 highPriority.get(0).startMillis);
889 
890         // Increment time just past the earlier event (to 12:10am).  The earlier one should
891         // be chosen.
892         highPriority.clear();
893         currentTime = createTimeInMillis(0, 10, 0, 1, 5, 2012, Time.getCurrentTimezone());
894         AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
895                 mediumPriority, lowPriority);
896         assertEquals(0, lowPriority.size());
897         assertEquals(0, mediumPriority.size());
898         assertEquals(1, highPriority.size());
899         assertEquals("Recurring event with earlier start time expected", day1,
900                 highPriority.get(0).startMillis);
901 
902         // Increment time to 15 min past the earlier event: the later one should be chosen.
903         highPriority.clear();
904         currentTime = createTimeInMillis(0, 15, 0, 1, 5, 2012, Time.getCurrentTimezone());
905         AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
906                 mediumPriority, lowPriority);
907         assertEquals(0, lowPriority.size());
908         assertEquals(0, mediumPriority.size());
909         assertEquals(1, highPriority.size());
910         assertEquals("Recurring event with earlier start time expected", day2,
911                 highPriority.get(0).startMillis);
912 
913         // Both events in the past: the later one should be chosen (in the low priority bucket).
914         highPriority.clear();
915         currentTime = day2 + DateUtils.DAY_IN_MILLIS * 1;
916         AlertService.processQuery(at.getAlertCursor(), mContext, currentTime, highPriority,
917                 mediumPriority, lowPriority);
918         assertEquals(0, highPriority.size());
919         assertEquals(0, mediumPriority.size());
920         assertEquals(1, lowPriority.size());
921         assertEquals("Recurring event with later start time expected", day2,
922                 lowPriority.get(0).startMillis);
923     }
924 
925     @SmallTest
testRedistributeBuckets_withinLimits()926     public void testRedistributeBuckets_withinLimits() throws Exception {
927         int maxNotifications = 3;
928         ArrayList<NotificationInfo> threeItemList = new ArrayList<NotificationInfo>();
929         threeItemList.add(createNotificationInfo(5));
930         threeItemList.add(createNotificationInfo(4));
931         threeItemList.add(createNotificationInfo(3));
932 
933         // Test when max notifications at high priority.
934         ArrayList<NotificationInfo> high = threeItemList;
935         ArrayList<NotificationInfo> medium = new ArrayList<NotificationInfo>();
936         ArrayList<NotificationInfo> low = new ArrayList<NotificationInfo>();
937         AlertService.redistributeBuckets(high, medium, low, maxNotifications);
938         assertEquals(3, high.size());
939         assertEquals(0, medium.size());
940         assertEquals(0, low.size());
941 
942         // Test when max notifications at medium priority.
943         high = new ArrayList<NotificationInfo>();
944         medium = threeItemList;
945         low = new ArrayList<NotificationInfo>();
946         AlertService.redistributeBuckets(high, medium, low, maxNotifications);
947         assertEquals(0, high.size());
948         assertEquals(3, medium.size());
949         assertEquals(0, low.size());
950 
951         // Test when max notifications at high and medium priority
952         high = new ArrayList<NotificationInfo>(threeItemList);
953         medium = new ArrayList<NotificationInfo>();
954         medium.add(high.remove(1));
955         low = new ArrayList<NotificationInfo>();
956         AlertService.redistributeBuckets(high, medium, low, maxNotifications);
957         assertEquals(2, high.size());
958         assertEquals(1, medium.size());
959         assertEquals(0, low.size());
960     }
961 
962     @SmallTest
testRedistributeBuckets_tooManyHighPriority()963     public void testRedistributeBuckets_tooManyHighPriority() throws Exception {
964         ArrayList<NotificationInfo> high = new ArrayList<NotificationInfo>();
965         ArrayList<NotificationInfo> medium = new ArrayList<NotificationInfo>();
966         ArrayList<NotificationInfo> low = new ArrayList<NotificationInfo>();
967         high.add(createNotificationInfo(5));
968         high.add(createNotificationInfo(4));
969         high.add(createNotificationInfo(3));
970         high.add(createNotificationInfo(2));
971         high.add(createNotificationInfo(1));
972 
973         // Invoke the method under test.
974         int maxNotifications = 3;
975         AlertService.redistributeBuckets(high, medium, low, maxNotifications);
976 
977         // Verify some high priority were kicked out.
978         assertEquals(3, high.size());
979         assertEquals(3, high.get(0).eventId);
980         assertEquals(2, high.get(1).eventId);
981         assertEquals(1, high.get(2).eventId);
982 
983         // Verify medium priority untouched.
984         assertEquals(0, medium.size());
985 
986         // Verify the extras went to low priority.
987         assertEquals(2, low.size());
988         assertEquals(5, low.get(0).eventId);
989         assertEquals(4, low.get(1).eventId);
990     }
991 
992     @SmallTest
testRedistributeBuckets_tooManyMediumPriority()993     public void testRedistributeBuckets_tooManyMediumPriority() throws Exception {
994         ArrayList<NotificationInfo> high = new ArrayList<NotificationInfo>();
995         ArrayList<NotificationInfo> medium = new ArrayList<NotificationInfo>();
996         ArrayList<NotificationInfo> low = new ArrayList<NotificationInfo>();
997         high.add(createNotificationInfo(5));
998         high.add(createNotificationInfo(4));
999         medium.add(createNotificationInfo(3));
1000         medium.add(createNotificationInfo(2));
1001         medium.add(createNotificationInfo(1));
1002 
1003         // Invoke the method under test.
1004         int maxNotifications = 3;
1005         AlertService.redistributeBuckets(high, medium, low, maxNotifications);
1006 
1007         // Verify high priority untouched.
1008         assertEquals(2, high.size());
1009         assertEquals(5, high.get(0).eventId);
1010         assertEquals(4, high.get(1).eventId);
1011 
1012         // Verify some medium priority were kicked out (the ones near the end of the
1013         // list).
1014         assertEquals(1, medium.size());
1015         assertEquals(3, medium.get(0).eventId);
1016 
1017         // Verify the extras went to low priority.
1018         assertEquals(2, low.size());
1019         assertEquals(2, low.get(0).eventId);
1020         assertEquals(1, low.get(1).eventId);
1021     }
1022 
1023     @SmallTest
testRedistributeBuckets_tooManyHighMediumPriority()1024     public void testRedistributeBuckets_tooManyHighMediumPriority() throws Exception {
1025         ArrayList<NotificationInfo> high = new ArrayList<NotificationInfo>();
1026         ArrayList<NotificationInfo> medium = new ArrayList<NotificationInfo>();
1027         ArrayList<NotificationInfo> low = new ArrayList<NotificationInfo>();
1028         high.add(createNotificationInfo(8));
1029         high.add(createNotificationInfo(7));
1030         high.add(createNotificationInfo(6));
1031         high.add(createNotificationInfo(5));
1032         high.add(createNotificationInfo(4));
1033         medium.add(createNotificationInfo(3));
1034         medium.add(createNotificationInfo(2));
1035         medium.add(createNotificationInfo(1));
1036 
1037         // Invoke the method under test.
1038         int maxNotifications = 3;
1039         AlertService.redistributeBuckets(high, medium, low, maxNotifications);
1040 
1041         // Verify high priority.
1042         assertEquals(3, high.size());
1043         assertEquals(6, high.get(0).eventId);
1044         assertEquals(5, high.get(1).eventId);
1045         assertEquals(4, high.get(2).eventId);
1046 
1047         // Verify some medium priority.
1048         assertEquals(0, medium.size());
1049 
1050         // Verify low priority.
1051         assertEquals(5, low.size());
1052         assertEquals(8, low.get(0).eventId);
1053         assertEquals(7, low.get(1).eventId);
1054         assertEquals(3, low.get(2).eventId);
1055         assertEquals(2, low.get(3).eventId);
1056         assertEquals(1, low.get(4).eventId);
1057     }
1058 }
1059