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