AlertServiceTest.java revision 25b09db869f377b131052447f62ad02e2505cd87
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
17package com.android.calendar.alerts;
18
19import static android.app.Notification.PRIORITY_DEFAULT;
20import static android.app.Notification.PRIORITY_HIGH;
21import static android.app.Notification.PRIORITY_MIN;
22
23import android.content.SharedPreferences;
24import android.database.MatrixCursor;
25import android.provider.CalendarContract.Attendees;
26import android.provider.CalendarContract.CalendarAlerts;
27import android.test.AndroidTestCase;
28import android.test.suitebuilder.annotation.SmallTest;
29import android.test.suitebuilder.annotation.Smoke;
30
31import com.android.calendar.GeneralPreferences;
32import com.android.calendar.alerts.AlertService.NotificationWrapper;
33
34import java.util.ArrayList;
35import java.util.Arrays;
36import java.util.Map;
37import java.util.Set;
38
39public class AlertServiceTest extends AndroidTestCase {
40
41    class MockSharedPreferences implements SharedPreferences {
42
43        /* "always", "silent", depends on ringer mode */
44        private String mVibrateWhen = "always";
45        private String mRingtone = "/some/cool/ringtone";
46        private boolean mPopup = true;
47
48        @Override
49        public boolean contains(String key) {
50            if (GeneralPreferences.KEY_ALERTS_VIBRATE_WHEN.equals(key)) {
51                return true;
52            }
53            return false;
54        }
55
56        @Override
57        public boolean getBoolean(String key, boolean defValue) {
58            if (GeneralPreferences.KEY_ALERTS_POPUP.equals(key)) {
59                return mPopup;
60            }
61            throw new IllegalArgumentException();
62        }
63
64        @Override
65        public String getString(String key, String defValue) {
66            if (GeneralPreferences.KEY_ALERTS_VIBRATE_WHEN.equals(key)) {
67                return mVibrateWhen;
68            }
69            if (GeneralPreferences.KEY_ALERTS_RINGTONE.equals(key)) {
70                return mRingtone;
71            }
72            throw new IllegalArgumentException();
73        }
74
75        @Override
76        public Map<String, ?> getAll() {
77            throw new IllegalArgumentException();
78        }
79
80        @Override
81        public Set<String> getStringSet(String key, Set<String> defValues) {
82            throw new IllegalArgumentException();
83        }
84
85        @Override
86        public int getInt(String key, int defValue) {
87            throw new IllegalArgumentException();
88        }
89
90        @Override
91        public long getLong(String key, long defValue) {
92            throw new IllegalArgumentException();
93        }
94
95        @Override
96        public float getFloat(String key, float defValue) {
97            throw new IllegalArgumentException();
98        }
99
100        @Override
101        public Editor edit() {
102            throw new IllegalArgumentException();
103        }
104
105        @Override
106        public void registerOnSharedPreferenceChangeListener(
107                OnSharedPreferenceChangeListener listener) {
108            throw new IllegalArgumentException();
109        }
110
111        @Override
112        public void unregisterOnSharedPreferenceChangeListener(
113                OnSharedPreferenceChangeListener listener) {
114            throw new IllegalArgumentException();
115        }
116
117    }
118
119    // Created these constants so the test cases are shorter
120    public static final int SCHEDULED = CalendarAlerts.STATE_SCHEDULED;
121    public static final int FIRED = CalendarAlerts.STATE_FIRED;
122    public static final int DISMISSED = CalendarAlerts.STATE_DISMISSED;
123
124    public static final int ACCEPTED = Attendees.ATTENDEE_STATUS_ACCEPTED;
125    public static final int DECLINED = Attendees.ATTENDEE_STATUS_DECLINED;
126    public static final int INVITED = Attendees.ATTENDEE_STATUS_INVITED;
127    public static final int TENTATIVE = Attendees.ATTENDEE_STATUS_TENTATIVE;
128
129    class NotificationInstance {
130        int mAlertId;
131        int mPriority;
132
133        public NotificationInstance(int alertId, int priority) {
134            mAlertId = alertId;
135            mPriority = priority;
136        }
137    }
138
139    class Alert {
140        long mEventId;
141        int mAlertStatus;
142        int mResponseStatus;
143        int mAllDay;
144        long mBegin;
145        long mEnd;
146        int mMinute;
147        long mAlarmTime;
148
149        public Alert(long eventId, int alertStatus, int responseStatus, int allDay, long begin,
150                long end, int minute, long alarmTime) {
151            mEventId = eventId;
152            mAlertStatus = alertStatus;
153            mResponseStatus = responseStatus;
154            mAllDay = allDay;
155            mBegin = begin;
156            mEnd = end;
157            mMinute = minute;
158            mAlarmTime = alarmTime;
159        }
160
161    }
162
163    class AlertsTable {
164
165        ArrayList<Alert> mAlerts = new ArrayList<Alert>();
166
167        int addAlertRow(long eventId, int alertStatus, int responseStatus, int allDay, long begin,
168                long end, int minute, long alarmTime) {
169            Alert a = new Alert(eventId, alertStatus, responseStatus, allDay, begin, end, minute,
170                    alarmTime);
171            int id = mAlerts.size();
172            mAlerts.add(a);
173            return id;
174        }
175
176        public MatrixCursor getAlertCursor() {
177            MatrixCursor alertCursor = new MatrixCursor(AlertService.ALERT_PROJECTION);
178
179            int i = 0;
180            for (Alert a : mAlerts) {
181                Object[] ca = {
182                        i++,
183                        a.mEventId,
184                        a.mAlertStatus,
185                        "Title" + a.mEventId + " " + a.mMinute,
186                        "Loc" + a.mEventId,
187                        a.mResponseStatus,
188                        a.mAllDay,
189                        a.mAlarmTime > 0 ? a.mAlarmTime : a.mBegin - a.mMinute * 60 * 1000,
190                        a.mMinute,
191                        a.mBegin,
192                        a.mEnd,
193                        "Desc: " + a.mAlarmTime
194                };
195                alertCursor.addRow(ca);
196            }
197            return alertCursor;
198        }
199
200    }
201
202    class NotificationTestManager implements NotificationMgr {
203        // Expected notifications
204        NotificationInstance[] mNotifications =
205                new NotificationInstance[AlertService.MAX_NOTIFICATIONS + 1];
206
207        // Flag to know which notification has been posted or canceled
208        boolean[] mDone;
209
210        // CalendarAlerts table
211        private ArrayList<Alert> mAlerts;
212
213        public NotificationTestManager(ArrayList<Alert> alerts) {
214            assertEquals(0, AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID);
215            mAlerts = alerts;
216        }
217
218        public void expectTestNotification(int notificationId, int alertId, int highPriority) {
219            mNotifications[notificationId] = new NotificationInstance(alertId, highPriority);
220        }
221
222        private void verifyNotification(int id, NotificationWrapper nw) {
223            assertEquals(mNotifications[id].mPriority, nw.mNotification.priority);
224            Alert a = mAlerts.get(mNotifications[id].mAlertId);
225            assertEquals(a.mEventId, nw.mEventId);
226            assertEquals(a.mBegin, nw.mBegin);
227            assertEquals(a.mEnd, nw.mEnd);
228        }
229
230        public void validateNotificationsAndReset() {
231            for (int i = 0; i < mDone.length; i++) {
232                assertTrue("Notification id " + i + " has not been posted", mDone[i]);
233            }
234            Arrays.fill(mDone, false);
235            Arrays.fill(mNotifications, null);
236        }
237
238        ///////////////////////////////
239        // NotificationMgr methods
240        @Override
241        public void cancel(int id) {
242            if (mDone == null) {
243                mDone = new boolean[mNotifications.length];
244            }
245            assertTrue("id out of bound: " + id, 0 <= id);
246            assertTrue("id out of bound: " + id, id < mDone.length);
247            assertFalse("id already used", mDone[id]);
248            mDone[id] = true;
249            assertNull("Unexpected cancel for id " + id, mNotifications[id]);
250        }
251
252        @Override
253        public void cancel(String tag, int id) {
254            throw new IllegalArgumentException();
255        }
256
257        @Override
258        public void cancelAll() {
259            for (int i = 0; i < mNotifications.length; i++) {
260                assertNull("Expecting notification id " + i + ". Got cancelAll", mNotifications[i]);
261
262                if (mDone != null) {
263                    assertFalse("Notification id " + i + " is done but got cancelAll", mDone[i]);
264                }
265            }
266
267            assertNull(mDone); // this should have been null since nothing
268                               // should have been posted
269            mDone = new boolean[mNotifications.length];
270            Arrays.fill(mDone, true);
271        }
272
273        @Override
274        public void notify(int id, NotificationWrapper nw) {
275            if (mDone == null) {
276                mDone = new boolean[mNotifications.length];
277            }
278            assertTrue("id out of bound: " + id, 0 <= id);
279            assertTrue("id out of bound: " + id, id < mDone.length);
280            assertFalse("id already used", mDone[id]);
281            mDone[id] = true;
282
283            assertNotNull("Unexpected notify for id " + id, mNotifications[id]);
284
285            verifyNotification(id, nw);
286        }
287
288        @Override
289        public void notify(String tag, int id, NotificationWrapper nw) {
290            throw new IllegalArgumentException();
291        }
292    }
293
294    // TODO
295    // Catch updates of new state, notify time, and received time
296    // Test ringer, vibrate,
297    // Test digest notifications
298    // Test intents, action email
299    // Catch alarmmgr calls
300
301    @Smoke
302    @SmallTest
303    public void testNoAlerts() {
304        MockSharedPreferences prefs = new MockSharedPreferences();
305        AlertsTable at = new AlertsTable();
306        NotificationTestManager ntm = new NotificationTestManager(at.mAlerts);
307
308        // Test no alert
309        long currentTime = 1000000;
310        AlertService.generateAlerts(mContext, ntm, prefs, at.getAlertCursor(), currentTime);
311        ntm.validateNotificationsAndReset();
312    }
313
314    @Smoke
315    @SmallTest
316    public void testSingleAlert() {
317        MockSharedPreferences prefs = new MockSharedPreferences();
318        AlertsTable at = new AlertsTable();
319        NotificationTestManager ntm = new NotificationTestManager(at.mAlerts);
320
321        int id = at.addAlertRow(100, SCHEDULED, ACCEPTED, 0 /* all day */, 1300000, 2300000, 5, 0);
322
323        // Test one up coming alert
324        long currentTime = 1000000;
325        ntm.expectTestNotification(1, id, PRIORITY_HIGH);
326
327        AlertService.generateAlerts(mContext, ntm, prefs, at.getAlertCursor(), currentTime);
328        ntm.validateNotificationsAndReset(); // This wipes out notification
329                                             // tests added so far
330
331        // Test half way into an event
332        currentTime = 2300000;
333        ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID, id, PRIORITY_DEFAULT);
334
335        AlertService.generateAlerts(mContext, ntm, prefs, at.getAlertCursor(), currentTime);
336        ntm.validateNotificationsAndReset();
337
338        // Test event ended
339        currentTime = 4300000;
340        ntm.expectTestNotification(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID, id, PRIORITY_MIN);
341
342        AlertService.generateAlerts(mContext, ntm, prefs, at.getAlertCursor(), currentTime);
343        ntm.validateNotificationsAndReset();
344    }
345}
346