blob: 83a59fd85d294f17d16d01169c0f6d8cefafc082 [file] [log] [blame]
Chris Wren93bb8b82016-03-29 14:35:05 -04001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.server.notification;
17
18
19import android.app.ActivityManager;
20import android.app.Notification;
21import android.app.Notification.Builder;
22import android.media.AudioAttributes;
23import android.media.AudioManager;
24import android.net.Uri;
25import android.os.Handler;
26import android.os.RemoteException;
27import android.os.UserHandle;
28import android.os.Vibrator;
29import android.service.notification.NotificationListenerService.Ranking;
30import android.service.notification.StatusBarNotification;
31import android.test.AndroidTestCase;
32import android.test.suitebuilder.annotation.SmallTest;
33
34import org.mockito.Mock;
35import org.mockito.Mockito;
36import org.mockito.MockitoAnnotations;
37
38import static org.mockito.Matchers.anyBoolean;
39import static org.mockito.Matchers.anyInt;
40import static org.mockito.Matchers.anyObject;
41import static org.mockito.Matchers.anyString;
42import static org.mockito.Matchers.eq;
43import static org.mockito.Mockito.never;
44import static org.mockito.Mockito.times;
45import static org.mockito.Mockito.verify;
46import static org.mockito.Mockito.when;
47
48public class BuzzBeepBlinkTest extends AndroidTestCase {
49
50 @Mock AudioManager mAudioManager;
51 @Mock Vibrator mVibrator;
52 @Mock android.media.IRingtonePlayer mRingtonePlayer;
53 @Mock Handler mHandler;
54
55 private NotificationManagerService mService;
56 private String mPkg = "com.android.server.notification";
57 private int mId = 1001;
58 private int mOtherId = 1002;
59 private String mTag = null;
60 private int mUid = 1000;
61 private int mPid = 2000;
62 private int mScore = 10;
63 private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
64
65 @Override
66 public void setUp() {
67 MockitoAnnotations.initMocks(this);
68
69 when(mAudioManager.isAudioFocusExclusive()).thenReturn(false);
70 when(mAudioManager.getRingtonePlayer()).thenReturn(mRingtonePlayer);
71 when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
72 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
73
74 mService = new NotificationManagerService(getContext());
75 mService.setAudioManager(mAudioManager);
76 mService.setVibrator(mVibrator);
77 mService.setSystemReady(true);
78 mService.setHandler(mHandler);
79 }
80
81 //
82 // Convenience functions for creating notification records
83 //
84
85 private NotificationRecord getNoisyOtherNotification() {
86 return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
87 true /* noisy */, true /* buzzy*/);
88 }
89
90 private NotificationRecord getBeepyNotification() {
91 return getNotificationRecord(mId, false /* insistent */, false /* once */,
92 true /* noisy */, false /* buzzy*/);
93 }
94
95 private NotificationRecord getBeepyOnceNotification() {
96 return getNotificationRecord(mId, false /* insistent */, true /* once */,
97 true /* noisy */, false /* buzzy*/);
98 }
99
100 private NotificationRecord getQuietNotification() {
101 return getNotificationRecord(mId, false /* insistent */, false /* once */,
102 false /* noisy */, false /* buzzy*/);
103 }
104
105 private NotificationRecord getQuietOtherNotification() {
106 return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
107 false /* noisy */, false /* buzzy*/);
108 }
109
110 private NotificationRecord getQuietOnceNotification() {
111 return getNotificationRecord(mId, false /* insistent */, true /* once */,
112 false /* noisy */, false /* buzzy*/);
113 }
114
115 private NotificationRecord getInsistentBeepyNotification() {
116 return getNotificationRecord(mId, true /* insistent */, false /* once */,
117 true /* noisy */, false /* buzzy*/);
118 }
119
120 private NotificationRecord getBuzzyNotification() {
121 return getNotificationRecord(mId, false /* insistent */, false /* once */,
122 false /* noisy */, true /* buzzy*/);
123 }
124
125 private NotificationRecord getBuzzyOnceNotification() {
126 return getNotificationRecord(mId, false /* insistent */, true /* once */,
127 false /* noisy */, true /* buzzy*/);
128 }
129
130 private NotificationRecord getInsistentBuzzyNotification() {
131 return getNotificationRecord(mId, true /* insistent */, false /* once */,
132 false /* noisy */, true /* buzzy*/);
133 }
134
135 private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
136 boolean noisy, boolean buzzy) {
137 final Builder builder = new Builder(getContext())
138 .setContentTitle("foo")
139 .setSmallIcon(android.R.drawable.sym_def_app_icon)
140 .setPriority(Notification.PRIORITY_HIGH)
141 .setOnlyAlertOnce(once);
142
143 int defaults = 0;
144 if (noisy) {
145 defaults |= Notification.DEFAULT_SOUND;
146 }
147 if (buzzy) {
148 defaults |= Notification.DEFAULT_VIBRATE;
149 }
150 builder.setDefaults(defaults);
151
152 Notification n = builder.build();
153 if (insistent) {
154 n.flags |= Notification.FLAG_INSISTENT;
155 }
156 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid, mPid,
157 mScore, n, mUser, System.currentTimeMillis());
158 return new NotificationRecord(getContext(), sbn);
159 }
160
161 //
162 // Convenience functions for interacting with mocks
163 //
164
165 private void verifyNeverBeep() throws RemoteException {
166 verify(mRingtonePlayer, never()).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
167 anyBoolean(), (AudioAttributes) anyObject());
168 }
169
170 private void verifyBeep() throws RemoteException {
171 verify(mRingtonePlayer, times(1)).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
172 eq(true), (AudioAttributes) anyObject());
173 }
174
175 private void verifyBeepLooped() throws RemoteException {
176 verify(mRingtonePlayer, times(1)).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
177 eq(false), (AudioAttributes) anyObject());
178 }
179
180 private void verifyNeverStopAudio() throws RemoteException {
181 verify(mRingtonePlayer, never()).stopAsync();
182 }
183
184 private void verifyStopAudio() throws RemoteException {
185 verify(mRingtonePlayer, times(1)).stopAsync();
186 }
187
188 private void verifyNeverVibrate() {
189 verify(mVibrator, never()).vibrate(anyInt(), anyString(), (long[]) anyObject(),
190 anyInt(), (AudioAttributes) anyObject());
191 }
192
193 private void verifyVibrate() {
194 verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), (long[]) anyObject(),
195 eq(-1), (AudioAttributes) anyObject());
196 }
197
198 private void verifyVibrateLooped() {
199 verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), (long[]) anyObject(),
200 eq(0), (AudioAttributes) anyObject());
201 }
202
203 private void verifyStopVibrate() {
204 verify(mVibrator, times(1)).cancel();
205 }
206
207 private void verifyNeverStopVibrate() throws RemoteException {
208 verify(mVibrator, never()).cancel();
209 }
210
211 @SmallTest
212 public void testBeep() throws Exception {
213 NotificationRecord r = getBeepyNotification();
214
215 mService.buzzBeepBlinkLocked(r);
216
217 verifyBeepLooped();
218 verifyNeverVibrate();
219 }
220
221 //
222 // Tests
223 //
224
225 @SmallTest
226 public void testBeepInsistently() throws Exception {
227 NotificationRecord r = getInsistentBeepyNotification();
228
229 mService.buzzBeepBlinkLocked(r);
230
231 verifyBeep();
232 }
233
234 @SmallTest
235 public void testNoInterruptionForMin() throws Exception {
236 NotificationRecord r = getBeepyNotification();
237 r.setImportance(Ranking.IMPORTANCE_MIN, "foo");
238
239 mService.buzzBeepBlinkLocked(r);
240
241 verifyNeverBeep();
242 verifyNeverVibrate();
243 }
244
245 @SmallTest
246 public void testNoInterruptionForIntercepted() throws Exception {
247 NotificationRecord r = getBeepyNotification();
248 r.setIntercepted(true);
249
250 mService.buzzBeepBlinkLocked(r);
251
252 verifyNeverBeep();
253 verifyNeverVibrate();
254 }
255
256 @SmallTest
257 public void testBeepTwice() throws Exception {
258 NotificationRecord r = getBeepyNotification();
259
260 // set up internal state
261 mService.buzzBeepBlinkLocked(r);
262 Mockito.reset(mRingtonePlayer);
263
264 // update should beep
265 r.isUpdate = true;
266 mService.buzzBeepBlinkLocked(r);
267 verifyBeepLooped();
268 }
269
270 @SmallTest
271 public void testHonorAlertOnlyOnceForBeep() throws Exception {
272 NotificationRecord r = getBeepyNotification();
273 NotificationRecord s = getBeepyOnceNotification();
274 s.isUpdate = true;
275
276 // set up internal state
277 mService.buzzBeepBlinkLocked(r);
278 Mockito.reset(mRingtonePlayer);
279
280 // update should not beep
281 mService.buzzBeepBlinkLocked(s);
282 verifyNeverBeep();
283 }
284
285 @SmallTest
286 public void testNoisyUpdateDoesNotCancelAudio() throws Exception {
287 NotificationRecord r = getBeepyNotification();
288
289 mService.buzzBeepBlinkLocked(r);
290 r.isUpdate = true;
291 mService.buzzBeepBlinkLocked(r);
292
293 verifyNeverStopAudio();
294 }
295
296 @SmallTest
297 public void testNoisyOnceUpdateDoesNotCancelAudio() throws Exception {
298 NotificationRecord r = getBeepyNotification();
299 NotificationRecord s = getBeepyOnceNotification();
300 s.isUpdate = true;
301
302 mService.buzzBeepBlinkLocked(r);
303 mService.buzzBeepBlinkLocked(s);
304
305 verifyNeverStopAudio();
306 }
307
308 @SmallTest
309 public void testQuietUpdateDoesNotCancelAudioFromOther() throws Exception {
310 NotificationRecord r = getBeepyNotification();
311 NotificationRecord s = getQuietNotification();
312 s.isUpdate = true;
313 NotificationRecord other = getNoisyOtherNotification();
314
315 // set up internal state
316 mService.buzzBeepBlinkLocked(r);
317 mService.buzzBeepBlinkLocked(other); // this takes the audio stream
318 Mockito.reset(mRingtonePlayer);
319
320 // should not stop noise, since we no longer own it
321 mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
322 verifyNeverStopAudio();
323 }
324
325 @SmallTest
326 public void testQuietInterloperDoesNotCancelAudio() throws Exception {
327 NotificationRecord r = getBeepyNotification();
328 NotificationRecord other = getQuietOtherNotification();
329
330 // set up internal state
331 mService.buzzBeepBlinkLocked(r);
332 Mockito.reset(mRingtonePlayer);
333
334 // should not stop noise, since it does not own it
335 mService.buzzBeepBlinkLocked(other);
336 verifyNeverStopAudio();
337 }
338
339 @SmallTest
340 public void testQuietUpdateCancelsAudio() throws Exception {
341 NotificationRecord r = getBeepyNotification();
342 NotificationRecord s = getQuietNotification();
343 s.isUpdate = true;
344
345 // set up internal state
346 mService.buzzBeepBlinkLocked(r);
347 Mockito.reset(mRingtonePlayer);
348
349 // quiet update should stop making noise
350 mService.buzzBeepBlinkLocked(s);
351 verifyStopAudio();
352 }
353
354 @SmallTest
355 public void testQuietOnceUpdateCancelsAudio() throws Exception {
356 NotificationRecord r = getBeepyNotification();
357 NotificationRecord s = getQuietOnceNotification();
358 s.isUpdate = true;
359
360 // set up internal state
361 mService.buzzBeepBlinkLocked(r);
362 Mockito.reset(mRingtonePlayer);
363
364 // stop making noise - this is a weird corner case, but quiet should override once
365 mService.buzzBeepBlinkLocked(s);
366 verifyStopAudio();
367 }
368
369 @SmallTest
370 public void testDemoteSoundToVibrate() throws Exception {
371 NotificationRecord r = getBeepyNotification();
372
373 // the phone is quiet
374 when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
375 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
376
377 mService.buzzBeepBlinkLocked(r);
378
379 verifyNeverBeep();
380 verifyVibrate();
381 }
382
383 @SmallTest
384 public void testDemotInsistenteSoundToVibrate() throws Exception {
385 NotificationRecord r = getInsistentBeepyNotification();
386
387 // the phone is quiet
388 when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
389 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
390
391 mService.buzzBeepBlinkLocked(r);
392
393 verifyVibrateLooped();
394 }
395
396 @SmallTest
397 public void testVibrate() throws Exception {
398 NotificationRecord r = getBuzzyNotification();
399
400 mService.buzzBeepBlinkLocked(r);
401
402 verifyNeverBeep();
403 verifyVibrate();
404 }
405
406 @SmallTest
407 public void testInsistenteVibrate() throws Exception {
408 NotificationRecord r = getInsistentBuzzyNotification();
409
410 mService.buzzBeepBlinkLocked(r);
411 verifyVibrateLooped();
412 }
413
414 @SmallTest
415 public void testVibratTwice() throws Exception {
416 NotificationRecord r = getBuzzyNotification();
417
418 // set up internal state
419 mService.buzzBeepBlinkLocked(r);
420 Mockito.reset(mVibrator);
421
422 // update should vibrate
423 r.isUpdate = true;
424 mService.buzzBeepBlinkLocked(r);
425 verifyVibrate();
426 }
427
428 @SmallTest
429 public void testHonorAlertOnlyOnceForBuzz() throws Exception {
430 NotificationRecord r = getBuzzyNotification();
431 NotificationRecord s = getBuzzyOnceNotification();
432 s.isUpdate = true;
433
434 // set up internal state
435 mService.buzzBeepBlinkLocked(r);
436 Mockito.reset(mVibrator);
437
438 // update should not beep
439 mService.buzzBeepBlinkLocked(s);
440 verifyNeverVibrate();
441 }
442
443 @SmallTest
444 public void testNoisyUpdateDoesNotCancelVibrate() throws Exception {
445 NotificationRecord r = getBuzzyNotification();
446
447 mService.buzzBeepBlinkLocked(r);
448 r.isUpdate = true;
449 mService.buzzBeepBlinkLocked(r);
450
451 verifyNeverStopVibrate();
452 }
453
454 @SmallTest
455 public void testNoisyOnceUpdateDoesNotCancelVibrate() throws Exception {
456 NotificationRecord r = getBuzzyNotification();
457 NotificationRecord s = getBuzzyOnceNotification();
458 s.isUpdate = true;
459
460 mService.buzzBeepBlinkLocked(r);
461 mService.buzzBeepBlinkLocked(s);
462
463 verifyNeverStopVibrate();
464 }
465
466 @SmallTest
467 public void testQuietUpdateDoesNotCancelVibrateFromOther() throws Exception {
468 NotificationRecord r = getBuzzyNotification();
469 NotificationRecord s = getQuietNotification();
470 s.isUpdate = true;
471 NotificationRecord other = getNoisyOtherNotification();
472
473 // set up internal state
474 mService.buzzBeepBlinkLocked(r);
475 mService.buzzBeepBlinkLocked(other); // this takes the vibrate stream
476 Mockito.reset(mVibrator);
477
478 // should not stop vibrate, since we no longer own it
479 mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
480 verifyNeverStopVibrate();
481 }
482
483 @SmallTest
484 public void testQuietInterloperDoesNotCancelVibrate() throws Exception {
485 NotificationRecord r = getBuzzyNotification();
486 NotificationRecord other = getQuietOtherNotification();
487
488 // set up internal state
489 mService.buzzBeepBlinkLocked(r);
490 Mockito.reset(mVibrator);
491
492 // should not stop noise, since it does not own it
493 mService.buzzBeepBlinkLocked(other);
494 verifyNeverStopVibrate();
495 }
496
497 @SmallTest
498 public void testQuietUpdateCancelsVibrate() throws Exception {
499 NotificationRecord r = getBuzzyNotification();
500 NotificationRecord s = getQuietNotification();
501 s.isUpdate = true;
502
503 // set up internal state
504 mService.buzzBeepBlinkLocked(r);
505
506 // quiet update should stop making noise
507 mService.buzzBeepBlinkLocked(s);
508 verifyStopVibrate();
509 }
510
511 @SmallTest
512 public void testQuietOnceUpdateCancelsvibrate() throws Exception {
513 NotificationRecord r = getBuzzyNotification();
514 NotificationRecord s = getQuietOnceNotification();
515 s.isUpdate = true;
516
517 // set up internal state
518 mService.buzzBeepBlinkLocked(r);
519 Mockito.reset(mVibrator);
520
521 // stop making noise - this is a weird corner case, but quiet should override once
522 mService.buzzBeepBlinkLocked(s);
523 verifyStopVibrate();
524 }
525
526 @SmallTest
527 public void testQuietUpdateCancelsDemotedVibrate() throws Exception {
528 NotificationRecord r = getBeepyNotification();
529 NotificationRecord s = getQuietNotification();
530
531 // the phone is quiet
532 when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
533 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
534
535 mService.buzzBeepBlinkLocked(r);
536
537 // quiet update should stop making noise
538 mService.buzzBeepBlinkLocked(s);
539 verifyStopVibrate();
540 }
541}