blob: d51f2d8152ac6ad93373046a23392e6406ed88e8 [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);
Chris Wrend4054312016-06-24 17:07:40 -040079 mService.setSystemNotificationSound("beep!");
Chris Wren93bb8b82016-03-29 14:35:05 -040080 }
81
82 //
83 // Convenience functions for creating notification records
84 //
85
86 private NotificationRecord getNoisyOtherNotification() {
87 return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
88 true /* noisy */, true /* buzzy*/);
89 }
90
91 private NotificationRecord getBeepyNotification() {
92 return getNotificationRecord(mId, false /* insistent */, false /* once */,
93 true /* noisy */, false /* buzzy*/);
94 }
95
96 private NotificationRecord getBeepyOnceNotification() {
97 return getNotificationRecord(mId, false /* insistent */, true /* once */,
98 true /* noisy */, false /* buzzy*/);
99 }
100
101 private NotificationRecord getQuietNotification() {
102 return getNotificationRecord(mId, false /* insistent */, false /* once */,
103 false /* noisy */, false /* buzzy*/);
104 }
105
106 private NotificationRecord getQuietOtherNotification() {
107 return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
108 false /* noisy */, false /* buzzy*/);
109 }
110
111 private NotificationRecord getQuietOnceNotification() {
112 return getNotificationRecord(mId, false /* insistent */, true /* once */,
113 false /* noisy */, false /* buzzy*/);
114 }
115
116 private NotificationRecord getInsistentBeepyNotification() {
117 return getNotificationRecord(mId, true /* insistent */, false /* once */,
118 true /* noisy */, false /* buzzy*/);
119 }
120
121 private NotificationRecord getBuzzyNotification() {
122 return getNotificationRecord(mId, false /* insistent */, false /* once */,
123 false /* noisy */, true /* buzzy*/);
124 }
125
126 private NotificationRecord getBuzzyOnceNotification() {
127 return getNotificationRecord(mId, false /* insistent */, true /* once */,
128 false /* noisy */, true /* buzzy*/);
129 }
130
131 private NotificationRecord getInsistentBuzzyNotification() {
132 return getNotificationRecord(mId, true /* insistent */, false /* once */,
133 false /* noisy */, true /* buzzy*/);
134 }
135
136 private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
137 boolean noisy, boolean buzzy) {
138 final Builder builder = new Builder(getContext())
139 .setContentTitle("foo")
140 .setSmallIcon(android.R.drawable.sym_def_app_icon)
141 .setPriority(Notification.PRIORITY_HIGH)
142 .setOnlyAlertOnce(once);
143
144 int defaults = 0;
145 if (noisy) {
146 defaults |= Notification.DEFAULT_SOUND;
147 }
148 if (buzzy) {
149 defaults |= Notification.DEFAULT_VIBRATE;
150 }
151 builder.setDefaults(defaults);
152
153 Notification n = builder.build();
154 if (insistent) {
155 n.flags |= Notification.FLAG_INSISTENT;
156 }
157 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid, mPid,
158 mScore, n, mUser, System.currentTimeMillis());
159 return new NotificationRecord(getContext(), sbn);
160 }
161
162 //
163 // Convenience functions for interacting with mocks
164 //
165
166 private void verifyNeverBeep() throws RemoteException {
167 verify(mRingtonePlayer, never()).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
168 anyBoolean(), (AudioAttributes) anyObject());
169 }
170
171 private void verifyBeep() throws RemoteException {
172 verify(mRingtonePlayer, times(1)).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
173 eq(true), (AudioAttributes) anyObject());
174 }
175
176 private void verifyBeepLooped() throws RemoteException {
177 verify(mRingtonePlayer, times(1)).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
178 eq(false), (AudioAttributes) anyObject());
179 }
180
181 private void verifyNeverStopAudio() throws RemoteException {
182 verify(mRingtonePlayer, never()).stopAsync();
183 }
184
185 private void verifyStopAudio() throws RemoteException {
186 verify(mRingtonePlayer, times(1)).stopAsync();
187 }
188
189 private void verifyNeverVibrate() {
190 verify(mVibrator, never()).vibrate(anyInt(), anyString(), (long[]) anyObject(),
191 anyInt(), (AudioAttributes) anyObject());
192 }
193
194 private void verifyVibrate() {
195 verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), (long[]) anyObject(),
196 eq(-1), (AudioAttributes) anyObject());
197 }
198
199 private void verifyVibrateLooped() {
200 verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), (long[]) anyObject(),
201 eq(0), (AudioAttributes) anyObject());
202 }
203
204 private void verifyStopVibrate() {
205 verify(mVibrator, times(1)).cancel();
206 }
207
208 private void verifyNeverStopVibrate() throws RemoteException {
209 verify(mVibrator, never()).cancel();
210 }
211
212 @SmallTest
213 public void testBeep() throws Exception {
214 NotificationRecord r = getBeepyNotification();
215
216 mService.buzzBeepBlinkLocked(r);
217
218 verifyBeepLooped();
219 verifyNeverVibrate();
220 }
221
222 //
223 // Tests
224 //
225
226 @SmallTest
227 public void testBeepInsistently() throws Exception {
228 NotificationRecord r = getInsistentBeepyNotification();
229
230 mService.buzzBeepBlinkLocked(r);
231
232 verifyBeep();
233 }
234
235 @SmallTest
236 public void testNoInterruptionForMin() throws Exception {
237 NotificationRecord r = getBeepyNotification();
238 r.setImportance(Ranking.IMPORTANCE_MIN, "foo");
239
240 mService.buzzBeepBlinkLocked(r);
241
242 verifyNeverBeep();
243 verifyNeverVibrate();
244 }
245
246 @SmallTest
247 public void testNoInterruptionForIntercepted() throws Exception {
248 NotificationRecord r = getBeepyNotification();
249 r.setIntercepted(true);
250
251 mService.buzzBeepBlinkLocked(r);
252
253 verifyNeverBeep();
254 verifyNeverVibrate();
255 }
256
257 @SmallTest
258 public void testBeepTwice() throws Exception {
259 NotificationRecord r = getBeepyNotification();
260
261 // set up internal state
262 mService.buzzBeepBlinkLocked(r);
263 Mockito.reset(mRingtonePlayer);
264
265 // update should beep
266 r.isUpdate = true;
267 mService.buzzBeepBlinkLocked(r);
268 verifyBeepLooped();
269 }
270
271 @SmallTest
272 public void testHonorAlertOnlyOnceForBeep() throws Exception {
273 NotificationRecord r = getBeepyNotification();
274 NotificationRecord s = getBeepyOnceNotification();
275 s.isUpdate = true;
276
277 // set up internal state
278 mService.buzzBeepBlinkLocked(r);
279 Mockito.reset(mRingtonePlayer);
280
281 // update should not beep
282 mService.buzzBeepBlinkLocked(s);
283 verifyNeverBeep();
284 }
285
286 @SmallTest
287 public void testNoisyUpdateDoesNotCancelAudio() throws Exception {
288 NotificationRecord r = getBeepyNotification();
289
290 mService.buzzBeepBlinkLocked(r);
291 r.isUpdate = true;
292 mService.buzzBeepBlinkLocked(r);
293
294 verifyNeverStopAudio();
295 }
296
297 @SmallTest
298 public void testNoisyOnceUpdateDoesNotCancelAudio() throws Exception {
299 NotificationRecord r = getBeepyNotification();
300 NotificationRecord s = getBeepyOnceNotification();
301 s.isUpdate = true;
302
303 mService.buzzBeepBlinkLocked(r);
304 mService.buzzBeepBlinkLocked(s);
305
306 verifyNeverStopAudio();
307 }
308
309 @SmallTest
310 public void testQuietUpdateDoesNotCancelAudioFromOther() throws Exception {
311 NotificationRecord r = getBeepyNotification();
312 NotificationRecord s = getQuietNotification();
313 s.isUpdate = true;
314 NotificationRecord other = getNoisyOtherNotification();
315
316 // set up internal state
317 mService.buzzBeepBlinkLocked(r);
318 mService.buzzBeepBlinkLocked(other); // this takes the audio stream
319 Mockito.reset(mRingtonePlayer);
320
321 // should not stop noise, since we no longer own it
322 mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
323 verifyNeverStopAudio();
324 }
325
326 @SmallTest
327 public void testQuietInterloperDoesNotCancelAudio() throws Exception {
328 NotificationRecord r = getBeepyNotification();
329 NotificationRecord other = getQuietOtherNotification();
330
331 // set up internal state
332 mService.buzzBeepBlinkLocked(r);
333 Mockito.reset(mRingtonePlayer);
334
335 // should not stop noise, since it does not own it
336 mService.buzzBeepBlinkLocked(other);
337 verifyNeverStopAudio();
338 }
339
340 @SmallTest
341 public void testQuietUpdateCancelsAudio() throws Exception {
342 NotificationRecord r = getBeepyNotification();
343 NotificationRecord s = getQuietNotification();
344 s.isUpdate = true;
345
346 // set up internal state
347 mService.buzzBeepBlinkLocked(r);
348 Mockito.reset(mRingtonePlayer);
349
350 // quiet update should stop making noise
351 mService.buzzBeepBlinkLocked(s);
352 verifyStopAudio();
353 }
354
355 @SmallTest
356 public void testQuietOnceUpdateCancelsAudio() throws Exception {
357 NotificationRecord r = getBeepyNotification();
358 NotificationRecord s = getQuietOnceNotification();
359 s.isUpdate = true;
360
361 // set up internal state
362 mService.buzzBeepBlinkLocked(r);
363 Mockito.reset(mRingtonePlayer);
364
365 // stop making noise - this is a weird corner case, but quiet should override once
366 mService.buzzBeepBlinkLocked(s);
367 verifyStopAudio();
368 }
369
370 @SmallTest
371 public void testDemoteSoundToVibrate() throws Exception {
372 NotificationRecord r = getBeepyNotification();
373
374 // the phone is quiet
375 when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
376 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
377
378 mService.buzzBeepBlinkLocked(r);
379
380 verifyNeverBeep();
381 verifyVibrate();
382 }
383
384 @SmallTest
385 public void testDemotInsistenteSoundToVibrate() throws Exception {
386 NotificationRecord r = getInsistentBeepyNotification();
387
388 // the phone is quiet
389 when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
390 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
391
392 mService.buzzBeepBlinkLocked(r);
393
394 verifyVibrateLooped();
395 }
396
397 @SmallTest
398 public void testVibrate() throws Exception {
399 NotificationRecord r = getBuzzyNotification();
400
401 mService.buzzBeepBlinkLocked(r);
402
403 verifyNeverBeep();
404 verifyVibrate();
405 }
406
407 @SmallTest
408 public void testInsistenteVibrate() throws Exception {
409 NotificationRecord r = getInsistentBuzzyNotification();
410
411 mService.buzzBeepBlinkLocked(r);
412 verifyVibrateLooped();
413 }
414
415 @SmallTest
416 public void testVibratTwice() throws Exception {
417 NotificationRecord r = getBuzzyNotification();
418
419 // set up internal state
420 mService.buzzBeepBlinkLocked(r);
421 Mockito.reset(mVibrator);
422
423 // update should vibrate
424 r.isUpdate = true;
425 mService.buzzBeepBlinkLocked(r);
426 verifyVibrate();
427 }
428
429 @SmallTest
430 public void testHonorAlertOnlyOnceForBuzz() throws Exception {
431 NotificationRecord r = getBuzzyNotification();
432 NotificationRecord s = getBuzzyOnceNotification();
433 s.isUpdate = true;
434
435 // set up internal state
436 mService.buzzBeepBlinkLocked(r);
437 Mockito.reset(mVibrator);
438
439 // update should not beep
440 mService.buzzBeepBlinkLocked(s);
441 verifyNeverVibrate();
442 }
443
444 @SmallTest
445 public void testNoisyUpdateDoesNotCancelVibrate() throws Exception {
446 NotificationRecord r = getBuzzyNotification();
447
448 mService.buzzBeepBlinkLocked(r);
449 r.isUpdate = true;
450 mService.buzzBeepBlinkLocked(r);
451
452 verifyNeverStopVibrate();
453 }
454
455 @SmallTest
456 public void testNoisyOnceUpdateDoesNotCancelVibrate() throws Exception {
457 NotificationRecord r = getBuzzyNotification();
458 NotificationRecord s = getBuzzyOnceNotification();
459 s.isUpdate = true;
460
461 mService.buzzBeepBlinkLocked(r);
462 mService.buzzBeepBlinkLocked(s);
463
464 verifyNeverStopVibrate();
465 }
466
467 @SmallTest
468 public void testQuietUpdateDoesNotCancelVibrateFromOther() throws Exception {
469 NotificationRecord r = getBuzzyNotification();
470 NotificationRecord s = getQuietNotification();
471 s.isUpdate = true;
472 NotificationRecord other = getNoisyOtherNotification();
473
474 // set up internal state
475 mService.buzzBeepBlinkLocked(r);
476 mService.buzzBeepBlinkLocked(other); // this takes the vibrate stream
477 Mockito.reset(mVibrator);
478
479 // should not stop vibrate, since we no longer own it
480 mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
481 verifyNeverStopVibrate();
482 }
483
484 @SmallTest
485 public void testQuietInterloperDoesNotCancelVibrate() throws Exception {
486 NotificationRecord r = getBuzzyNotification();
487 NotificationRecord other = getQuietOtherNotification();
488
489 // set up internal state
490 mService.buzzBeepBlinkLocked(r);
491 Mockito.reset(mVibrator);
492
493 // should not stop noise, since it does not own it
494 mService.buzzBeepBlinkLocked(other);
495 verifyNeverStopVibrate();
496 }
497
498 @SmallTest
499 public void testQuietUpdateCancelsVibrate() throws Exception {
500 NotificationRecord r = getBuzzyNotification();
501 NotificationRecord s = getQuietNotification();
502 s.isUpdate = true;
503
504 // set up internal state
505 mService.buzzBeepBlinkLocked(r);
506
507 // quiet update should stop making noise
508 mService.buzzBeepBlinkLocked(s);
509 verifyStopVibrate();
510 }
511
512 @SmallTest
513 public void testQuietOnceUpdateCancelsvibrate() throws Exception {
514 NotificationRecord r = getBuzzyNotification();
515 NotificationRecord s = getQuietOnceNotification();
516 s.isUpdate = true;
517
518 // set up internal state
519 mService.buzzBeepBlinkLocked(r);
520 Mockito.reset(mVibrator);
521
522 // stop making noise - this is a weird corner case, but quiet should override once
523 mService.buzzBeepBlinkLocked(s);
524 verifyStopVibrate();
525 }
526
527 @SmallTest
528 public void testQuietUpdateCancelsDemotedVibrate() throws Exception {
529 NotificationRecord r = getBeepyNotification();
530 NotificationRecord s = getQuietNotification();
531
532 // the phone is quiet
533 when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
534 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
535
536 mService.buzzBeepBlinkLocked(r);
537
538 // quiet update should stop making noise
539 mService.buzzBeepBlinkLocked(s);
540 verifyStopVibrate();
541 }
542}