blob: 1e55b1521956d74facba0f7f6c2276e8f0517fbf [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
Julia Reynoldsa79c3712017-04-21 10:29:57 -040018import static android.app.Notification.GROUP_ALERT_ALL;
19import static android.app.Notification.GROUP_ALERT_CHILDREN;
20import static android.app.Notification.GROUP_ALERT_SUMMARY;
Julia Reynoldsca80d162017-04-23 12:39:32 -040021import static android.app.NotificationManager.IMPORTANCE_HIGH;
Julia Reynolds28149f62018-07-03 10:43:35 -040022import static android.app.NotificationManager.IMPORTANCE_LOW;
Julia Reynolds94187562017-10-10 13:58:49 -040023import static android.app.NotificationManager.IMPORTANCE_MIN;
Julia Reynolds28149f62018-07-03 10:43:35 -040024import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
Julia Reynolds181ff7c2019-10-18 12:16:31 -040025import static android.media.AudioAttributes.USAGE_NOTIFICATION;
Julia Reynolds714ff5f2019-10-14 11:19:53 -040026import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
Julia Reynoldsca80d162017-04-23 12:39:32 -040027
Julia Reynolds1fac86e2018-03-07 08:30:37 -050028import static junit.framework.Assert.assertFalse;
Julia Reynolds0c299d42016-11-15 14:37:04 -050029import static junit.framework.Assert.assertNull;
30import static junit.framework.Assert.assertTrue;
31
Gus Prevas7306b902018-12-11 10:57:06 -050032import static org.junit.Assert.assertEquals;
33import static org.junit.Assert.assertNotEquals;
Julia Reynolds76c096d2017-06-19 08:16:04 -040034import static org.mockito.Matchers.any;
Chris Wren93bb8b82016-03-29 14:35:05 -040035import static org.mockito.Matchers.anyBoolean;
36import static org.mockito.Matchers.anyInt;
37import static org.mockito.Matchers.anyObject;
38import static org.mockito.Matchers.anyString;
Michael Wright71216972017-01-31 18:33:54 +000039import static org.mockito.Matchers.argThat;
Chris Wren93bb8b82016-03-29 14:35:05 -040040import static org.mockito.Matchers.eq;
41import static org.mockito.Mockito.never;
Tony Mantlerab55f0f2017-06-16 10:50:00 -070042import static org.mockito.Mockito.spy;
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -070043import static org.mockito.Mockito.timeout;
Chris Wren93bb8b82016-03-29 14:35:05 -040044import static org.mockito.Mockito.times;
45import static org.mockito.Mockito.verify;
46import static org.mockito.Mockito.when;
47
Tony Mantlerab55f0f2017-06-16 10:50:00 -070048import android.app.ActivityManager;
49import android.app.Notification;
50import android.app.Notification.Builder;
51import android.app.NotificationChannel;
52import android.app.NotificationManager;
Qiao (Adora) Zhanga9d0bff2019-04-15 17:45:43 +000053import android.content.Context;
Tony Mantlerab55f0f2017-06-16 10:50:00 -070054import android.content.pm.PackageManager;
55import android.graphics.Color;
56import android.media.AudioAttributes;
57import android.media.AudioManager;
58import android.net.Uri;
59import android.os.Handler;
60import android.os.RemoteException;
61import android.os.UserHandle;
62import android.os.VibrationEffect;
63import android.os.Vibrator;
64import android.provider.Settings;
Julia Reynoldsdb7081e2019-01-03 14:35:38 -050065import android.service.notification.NotificationListenerService;
Tony Mantlerab55f0f2017-06-16 10:50:00 -070066import android.service.notification.StatusBarNotification;
Tony Mantlerab55f0f2017-06-16 10:50:00 -070067import android.test.suitebuilder.annotation.SmallTest;
Julia Reynolds94187562017-10-10 13:58:49 -040068import android.view.accessibility.AccessibilityEvent;
69import android.view.accessibility.AccessibilityManager;
70import android.view.accessibility.IAccessibilityManager;
71import android.view.accessibility.IAccessibilityManagerClient;
Tony Mantlerab55f0f2017-06-16 10:50:00 -070072
Brett Chabot84151d92019-02-27 15:37:59 -080073import androidx.test.runner.AndroidJUnit4;
74
Julia Reynolds94187562017-10-10 13:58:49 -040075import com.android.internal.util.IntPair;
Jason Monk74f5e362017-12-06 08:56:33 -050076import com.android.server.UiServiceTestCase;
Tony Mantlerab55f0f2017-06-16 10:50:00 -070077import com.android.server.lights.Light;
78
79import org.junit.Before;
80import org.junit.Test;
81import org.junit.runner.RunWith;
82import org.mockito.ArgumentMatcher;
83import org.mockito.Mock;
84import org.mockito.Mockito;
85import org.mockito.MockitoAnnotations;
86
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -040087@SmallTest
88@RunWith(AndroidJUnit4.class)
Jason Monk74f5e362017-12-06 08:56:33 -050089public class BuzzBeepBlinkTest extends UiServiceTestCase {
Chris Wren93bb8b82016-03-29 14:35:05 -040090
91 @Mock AudioManager mAudioManager;
92 @Mock Vibrator mVibrator;
93 @Mock android.media.IRingtonePlayer mRingtonePlayer;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040094 @Mock Light mLight;
Julia Reynoldseb3dca72017-07-11 10:39:58 -040095 @Mock
96 NotificationManagerService.WorkerHandler mHandler;
Julia Reynolds76c096d2017-06-19 08:16:04 -040097 @Mock
98 NotificationUsageStats mUsageStats;
Julia Reynolds94187562017-10-10 13:58:49 -040099 @Mock
100 IAccessibilityManager mAccessibilityService;
Chris Wren93bb8b82016-03-29 14:35:05 -0400101
102 private NotificationManagerService mService;
103 private String mPkg = "com.android.server.notification";
104 private int mId = 1001;
105 private int mOtherId = 1002;
106 private String mTag = null;
107 private int mUid = 1000;
108 private int mPid = 2000;
Chris Wren93bb8b82016-03-29 14:35:05 -0400109 private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400110 private NotificationChannel mChannel;
Chris Wren93bb8b82016-03-29 14:35:05 -0400111
Michael Wright71216972017-01-31 18:33:54 +0000112 private VibrateRepeatMatcher mVibrateOnceMatcher = new VibrateRepeatMatcher(-1);
113 private VibrateRepeatMatcher mVibrateLoopMatcher = new VibrateRepeatMatcher(0);
114
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400115 private static final long[] CUSTOM_VIBRATION = new long[] {
116 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
117 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
118 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400 };
119 private static final Uri CUSTOM_SOUND = Settings.System.DEFAULT_ALARM_ALERT_URI;
Julia Reynolds619a69f2017-01-27 15:11:38 -0500120 private static final AudioAttributes CUSTOM_ATTRIBUTES = new AudioAttributes.Builder()
121 .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
Julia Reynoldsdb7081e2019-01-03 14:35:38 -0500122 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
Julia Reynolds619a69f2017-01-27 15:11:38 -0500123 .build();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400124 private static final int CUSTOM_LIGHT_COLOR = Color.BLACK;
125 private static final int CUSTOM_LIGHT_ON = 10000;
126 private static final int CUSTOM_LIGHT_OFF = 10000;
Michael Wright71216972017-01-31 18:33:54 +0000127 private static final long[] FALLBACK_VIBRATION_PATTERN = new long[] {100, 100, 100};
128 private static final VibrationEffect FALLBACK_VIBRATION =
129 VibrationEffect.createWaveform(FALLBACK_VIBRATION_PATTERN, -1);
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -0700130 private static final int MAX_VIBRATION_DELAY = 1000;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400131
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400132 @Before
Julia Reynolds94187562017-10-10 13:58:49 -0400133 public void setUp() throws Exception {
Chris Wren93bb8b82016-03-29 14:35:05 -0400134 MockitoAnnotations.initMocks(this);
135
136 when(mAudioManager.isAudioFocusExclusive()).thenReturn(false);
137 when(mAudioManager.getRingtonePlayer()).thenReturn(mRingtonePlayer);
138 when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
139 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
Julia Reynolds76c096d2017-06-19 08:16:04 -0400140 when(mUsageStats.isAlertRateLimited(any())).thenReturn(false);
141
Julia Reynolds94187562017-10-10 13:58:49 -0400142 long serviceReturnValue = IntPair.of(
143 AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED,
144 AccessibilityEvent.TYPES_ALL_MASK);
145 when(mAccessibilityService.addClient(any(), anyInt())).thenReturn(serviceReturnValue);
146 AccessibilityManager accessibilityManager =
147 new AccessibilityManager(Handler.getMain(), mAccessibilityService, 0);
148 verify(mAccessibilityService).addClient(any(IAccessibilityManagerClient.class), anyInt());
149 assertTrue(accessibilityManager.isEnabled());
150
Qiao (Adora) Zhanga9d0bff2019-04-15 17:45:43 +0000151 mService = spy(new NotificationManagerService(getContext()));
Chris Wren93bb8b82016-03-29 14:35:05 -0400152 mService.setAudioManager(mAudioManager);
153 mService.setVibrator(mVibrator);
154 mService.setSystemReady(true);
155 mService.setHandler(mHandler);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400156 mService.setLights(mLight);
157 mService.setScreenOn(false);
Michael Wright71216972017-01-31 18:33:54 +0000158 mService.setFallbackVibrationPattern(FALLBACK_VIBRATION_PATTERN);
Julia Reynolds76c096d2017-06-19 08:16:04 -0400159 mService.setUsageStats(mUsageStats);
Julia Reynolds94187562017-10-10 13:58:49 -0400160 mService.setAccessibilityManager(accessibilityManager);
Julia Reynolds28149f62018-07-03 10:43:35 -0400161 mService.mScreenOn = false;
Eric Laurent7412abc2019-07-12 18:26:29 -0700162 mService.mInCallStateOffHook = false;
Julia Reynolds28149f62018-07-03 10:43:35 -0400163 mService.mNotificationPulseEnabled = true;
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400164
165 mChannel = new NotificationChannel("test", "test", IMPORTANCE_HIGH);
Chris Wren93bb8b82016-03-29 14:35:05 -0400166 }
167
168 //
169 // Convenience functions for creating notification records
170 //
171
172 private NotificationRecord getNoisyOtherNotification() {
173 return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400174 true /* noisy */, true /* buzzy*/, false /* lights */);
Chris Wren93bb8b82016-03-29 14:35:05 -0400175 }
176
177 private NotificationRecord getBeepyNotification() {
178 return getNotificationRecord(mId, false /* insistent */, false /* once */,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400179 true /* noisy */, false /* buzzy*/, false /* lights */);
Chris Wren93bb8b82016-03-29 14:35:05 -0400180 }
181
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400182 private NotificationRecord getBeepyOtherNotification() {
183 return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
184 true /* noisy */, false /* buzzy*/, false /* lights */);
185 }
186
Chris Wren93bb8b82016-03-29 14:35:05 -0400187 private NotificationRecord getBeepyOnceNotification() {
188 return getNotificationRecord(mId, false /* insistent */, true /* once */,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400189 true /* noisy */, false /* buzzy*/, false /* lights */);
Chris Wren93bb8b82016-03-29 14:35:05 -0400190 }
191
192 private NotificationRecord getQuietNotification() {
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400193 return getNotificationRecord(mId, false /* insistent */, true /* once */,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400194 false /* noisy */, false /* buzzy*/, false /* lights */);
Chris Wren93bb8b82016-03-29 14:35:05 -0400195 }
196
197 private NotificationRecord getQuietOtherNotification() {
198 return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400199 false /* noisy */, false /* buzzy*/, false /* lights */);
Chris Wren93bb8b82016-03-29 14:35:05 -0400200 }
201
202 private NotificationRecord getQuietOnceNotification() {
203 return getNotificationRecord(mId, false /* insistent */, true /* once */,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400204 false /* noisy */, false /* buzzy*/, false /* lights */);
Chris Wren93bb8b82016-03-29 14:35:05 -0400205 }
206
207 private NotificationRecord getInsistentBeepyNotification() {
208 return getNotificationRecord(mId, true /* insistent */, false /* once */,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400209 true /* noisy */, false /* buzzy*/, false /* lights */);
Chris Wren93bb8b82016-03-29 14:35:05 -0400210 }
211
Tyler Gunn48f86272018-07-03 12:38:49 -0700212 private NotificationRecord getInsistentBeepyOnceNotification() {
213 return getNotificationRecord(mId, true /* insistent */, true /* once */,
214 true /* noisy */, false /* buzzy*/, false /* lights */);
215 }
216
Tony Mantlerab55f0f2017-06-16 10:50:00 -0700217 private NotificationRecord getInsistentBeepyLeanbackNotification() {
218 return getLeanbackNotificationRecord(mId, true /* insistent */, false /* once */,
219 true /* noisy */, false /* buzzy*/, false /* lights */);
220 }
221
Chris Wren93bb8b82016-03-29 14:35:05 -0400222 private NotificationRecord getBuzzyNotification() {
223 return getNotificationRecord(mId, false /* insistent */, false /* once */,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400224 false /* noisy */, true /* buzzy*/, false /* lights */);
Chris Wren93bb8b82016-03-29 14:35:05 -0400225 }
226
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400227 private NotificationRecord getBuzzyOtherNotification() {
228 return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
229 false /* noisy */, true /* buzzy*/, false /* lights */);
230 }
231
Chris Wren93bb8b82016-03-29 14:35:05 -0400232 private NotificationRecord getBuzzyOnceNotification() {
233 return getNotificationRecord(mId, false /* insistent */, true /* once */,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400234 false /* noisy */, true /* buzzy*/, false /* lights */);
Chris Wren93bb8b82016-03-29 14:35:05 -0400235 }
236
237 private NotificationRecord getInsistentBuzzyNotification() {
238 return getNotificationRecord(mId, true /* insistent */, false /* once */,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400239 false /* noisy */, true /* buzzy*/, false /* lights */);
240 }
241
Julia Reynolds0c299d42016-11-15 14:37:04 -0500242 private NotificationRecord getBuzzyBeepyNotification() {
243 return getNotificationRecord(mId, false /* insistent */, false /* once */,
244 true /* noisy */, true /* buzzy*/, false /* lights */);
245 }
246
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400247 private NotificationRecord getLightsNotification() {
Julia Reynolds28149f62018-07-03 10:43:35 -0400248 return getNotificationRecord(mId, false /* insistent */, false /* once */,
249 false /* noisy */, false /* buzzy*/, true /* lights */);
250 }
251
252 private NotificationRecord getLightsOnceNotification() {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400253 return getNotificationRecord(mId, false /* insistent */, true /* once */,
Julia Reynolds28149f62018-07-03 10:43:35 -0400254 false /* noisy */, false /* buzzy*/, true /* lights */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400255 }
256
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400257 private NotificationRecord getCallRecord(int id, NotificationChannel channel, boolean looping) {
258 final Builder builder = new Builder(getContext())
259 .setContentTitle("foo")
260 .setSmallIcon(android.R.drawable.sym_def_app_icon)
261 .setPriority(Notification.PRIORITY_HIGH);
262 Notification n = builder.build();
263 if (looping) {
264 n.flags |= Notification.FLAG_INSISTENT;
265 }
266 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid,
267 mPid, n, mUser, null, System.currentTimeMillis());
268 NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
269 mService.addNotification(r);
270
271 return r;
Chris Wren93bb8b82016-03-29 14:35:05 -0400272 }
273
274 private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400275 boolean noisy, boolean buzzy, boolean lights) {
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400276 return getNotificationRecord(id, insistent, once, noisy, buzzy, lights, buzzy, noisy,
277 lights, null, Notification.GROUP_ALERT_ALL, false);
Tony Mantlerab55f0f2017-06-16 10:50:00 -0700278 }
279
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400280 private NotificationRecord getLeanbackNotificationRecord(int id, boolean insistent,
281 boolean once,
Tony Mantlerab55f0f2017-06-16 10:50:00 -0700282 boolean noisy, boolean buzzy, boolean lights) {
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400283 return getNotificationRecord(id, insistent, once, noisy, buzzy, lights, true, true,
284 true,
Tony Mantlerab55f0f2017-06-16 10:50:00 -0700285 null, Notification.GROUP_ALERT_ALL, true);
Julia Reynoldsa79c3712017-04-21 10:29:57 -0400286 }
287
288 private NotificationRecord getBeepyNotificationRecord(String groupKey, int groupAlertBehavior) {
289 return getNotificationRecord(mId, false, false, true, false, false, true, true, true,
Tony Mantlerab55f0f2017-06-16 10:50:00 -0700290 groupKey, groupAlertBehavior, false);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400291 }
292
Julia Reynolds28149f62018-07-03 10:43:35 -0400293 private NotificationRecord getLightsNotificationRecord(String groupKey,
294 int groupAlertBehavior) {
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400295 return getNotificationRecord(mId, false, false, false, false, true /*lights*/, true,
296 true, true, groupKey, groupAlertBehavior, false);
Julia Reynolds28149f62018-07-03 10:43:35 -0400297 }
298
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400299 private NotificationRecord getNotificationRecord(int id,
300 boolean insistent, boolean once,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400301 boolean noisy, boolean buzzy, boolean lights, boolean defaultVibration,
Tony Mantlerab55f0f2017-06-16 10:50:00 -0700302 boolean defaultSound, boolean defaultLights, String groupKey, int groupAlertBehavior,
303 boolean isLeanback) {
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400304
Qiao (Adora) Zhanga9d0bff2019-04-15 17:45:43 +0000305 final Builder builder = new Builder(getContext())
Chris Wren93bb8b82016-03-29 14:35:05 -0400306 .setContentTitle("foo")
307 .setSmallIcon(android.R.drawable.sym_def_app_icon)
308 .setPriority(Notification.PRIORITY_HIGH)
309 .setOnlyAlertOnce(once);
310
311 int defaults = 0;
312 if (noisy) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400313 if (defaultSound) {
314 defaults |= Notification.DEFAULT_SOUND;
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400315 mChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
Julia Reynolds619a69f2017-01-27 15:11:38 -0500316 Notification.AUDIO_ATTRIBUTES_DEFAULT);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400317 } else {
318 builder.setSound(CUSTOM_SOUND);
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400319 mChannel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400320 }
Julia Reynolds184b86d2017-04-12 13:27:58 -0400321 } else {
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400322 mChannel.setSound(null, null);
Chris Wren93bb8b82016-03-29 14:35:05 -0400323 }
324 if (buzzy) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400325 if (defaultVibration) {
326 defaults |= Notification.DEFAULT_VIBRATE;
327 } else {
328 builder.setVibrate(CUSTOM_VIBRATION);
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400329 mChannel.setVibrationPattern(CUSTOM_VIBRATION);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400330 }
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400331 mChannel.enableVibration(true);
332 } else {
333 mChannel.setVibrationPattern(null);
334 mChannel.enableVibration(false);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400335 }
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400336
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400337 if (lights) {
338 if (defaultLights) {
339 defaults |= Notification.DEFAULT_LIGHTS;
340 } else {
341 builder.setLights(CUSTOM_LIGHT_COLOR, CUSTOM_LIGHT_ON, CUSTOM_LIGHT_OFF);
342 }
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400343 mChannel.enableLights(true);
344 } else {
345 mChannel.enableLights(false);
Chris Wren93bb8b82016-03-29 14:35:05 -0400346 }
347 builder.setDefaults(defaults);
348
Julia Reynoldsa79c3712017-04-21 10:29:57 -0400349 builder.setGroup(groupKey);
350 builder.setGroupAlertBehavior(groupAlertBehavior);
351
Chris Wren93bb8b82016-03-29 14:35:05 -0400352 Notification n = builder.build();
353 if (insistent) {
354 n.flags |= Notification.FLAG_INSISTENT;
355 }
Julia Reynolds0c299d42016-11-15 14:37:04 -0500356
Qiao (Adora) Zhanga9d0bff2019-04-15 17:45:43 +0000357 Context context = spy(getContext());
358 PackageManager packageManager = spy(context.getPackageManager());
359 when(context.getPackageManager()).thenReturn(packageManager);
Tony Mantlerab55f0f2017-06-16 10:50:00 -0700360 when(packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK))
361 .thenReturn(isLeanback);
362
Julia Reynolds924eed12017-01-19 09:52:07 -0500363 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid,
Julia Reynolds423b9fc2016-11-09 09:51:08 -0500364 mPid, n, mUser, null, System.currentTimeMillis());
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400365 NotificationRecord r = new NotificationRecord(context, sbn, mChannel);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400366 mService.addNotification(r);
367 return r;
Chris Wren93bb8b82016-03-29 14:35:05 -0400368 }
369
370 //
371 // Convenience functions for interacting with mocks
372 //
373
374 private void verifyNeverBeep() throws RemoteException {
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400375 verify(mRingtonePlayer, never()).playAsync(any(), any(), anyBoolean(), any());
Chris Wren93bb8b82016-03-29 14:35:05 -0400376 }
377
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400378 private void verifyBeepUnlooped() throws RemoteException {
379 verify(mRingtonePlayer, times(1)).playAsync(any(), any(), eq(false), any());
Chris Wren93bb8b82016-03-29 14:35:05 -0400380 }
381
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400382 private void verifyBeepLooped() throws RemoteException {
383 verify(mRingtonePlayer, times(1)).playAsync(any(), any(), eq(true), any());
384 }
385
386 private void verifyBeep(int times) throws RemoteException {
387 verify(mRingtonePlayer, times(times)).playAsync(any(), any(), anyBoolean(), any());
Chris Wren93bb8b82016-03-29 14:35:05 -0400388 }
389
390 private void verifyNeverStopAudio() throws RemoteException {
391 verify(mRingtonePlayer, never()).stopAsync();
392 }
393
394 private void verifyStopAudio() throws RemoteException {
395 verify(mRingtonePlayer, times(1)).stopAsync();
396 }
397
398 private void verifyNeverVibrate() {
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400399 verify(mVibrator, never()).vibrate(anyInt(), anyString(), any(), anyString(), any());
Chris Wren93bb8b82016-03-29 14:35:05 -0400400 }
401
402 private void verifyVibrate() {
Michael Wright71216972017-01-31 18:33:54 +0000403 verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), argThat(mVibrateOnceMatcher),
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400404 anyString(), any());
405 }
406
407 private void verifyVibrate(int times) {
408 verify(mVibrator, times(times)).vibrate(anyInt(), anyString(), any(), anyString(), any());
Chris Wren93bb8b82016-03-29 14:35:05 -0400409 }
410
411 private void verifyVibrateLooped() {
Michael Wright71216972017-01-31 18:33:54 +0000412 verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), argThat(mVibrateLoopMatcher),
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400413 anyString(), any());
Chris Wren93bb8b82016-03-29 14:35:05 -0400414 }
415
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -0700416 private void verifyDelayedVibrateLooped() {
417 verify(mVibrator, timeout(MAX_VIBRATION_DELAY).times(1)).vibrate(anyInt(), anyString(),
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400418 argThat(mVibrateLoopMatcher), anyString(), any());
419 }
420
421 private void verifyDelayedVibrate() {
422 verify(mVibrator, timeout(MAX_VIBRATION_DELAY).times(1)).vibrate(anyInt(), anyString(),
423 argThat(mVibrateOnceMatcher), anyString(), any());
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -0700424 }
425
Chris Wren93bb8b82016-03-29 14:35:05 -0400426 private void verifyStopVibrate() {
427 verify(mVibrator, times(1)).cancel();
428 }
429
430 private void verifyNeverStopVibrate() throws RemoteException {
431 verify(mVibrator, never()).cancel();
432 }
433
Julia Reynolds28149f62018-07-03 10:43:35 -0400434 private void verifyNeverLights() {
435 verify(mLight, never()).setFlashing(anyInt(), anyInt(), anyInt(), anyInt());
436 }
437
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400438 private void verifyLights() {
Julia Reynolds033a4122017-01-31 16:50:38 -0500439 verify(mLight, times(1)).setFlashing(anyInt(), anyInt(), anyInt(), anyInt());
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400440 }
441
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400442 //
443 // Tests
444 //
445
446 @Test
447 public void testLights() throws Exception {
448 NotificationRecord r = getLightsNotification();
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400449 r.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400450
451 mService.buzzBeepBlinkLocked(r);
452
453 verifyLights();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500454 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500455 assertEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400456 }
457
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400458 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -0400459 public void testBeep() throws Exception {
460 NotificationRecord r = getBeepyNotification();
461
462 mService.buzzBeepBlinkLocked(r);
463
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400464 verifyBeepUnlooped();
Chris Wren93bb8b82016-03-29 14:35:05 -0400465 verifyNeverVibrate();
Julia Reynolds94187562017-10-10 13:58:49 -0400466 verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500467 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500468 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400469 }
470
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400471 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -0400472 public void testBeepInsistently() throws Exception {
473 NotificationRecord r = getInsistentBeepyNotification();
474
475 mService.buzzBeepBlinkLocked(r);
476
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400477 verifyBeepLooped();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500478 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500479 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400480 }
481
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400482 @Test
Tony Mantlerab55f0f2017-06-16 10:50:00 -0700483 public void testNoLeanbackBeep() throws Exception {
484 NotificationRecord r = getInsistentBeepyLeanbackNotification();
485
486 mService.buzzBeepBlinkLocked(r);
487
488 verifyNeverBeep();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500489 assertFalse(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500490 assertEquals(-1, r.getLastAudiblyAlertedMs());
Tony Mantlerab55f0f2017-06-16 10:50:00 -0700491 }
492
493 @Test
Qiao (Adora) Zhang47b553c2019-04-15 20:42:57 +0000494 public void testNoBeepForAutomotiveIfEffectsDisabled() throws Exception {
Adora Zhang963328f2018-11-15 18:17:19 -0800495 mService.setIsAutomotive(true);
Qiao (Adora) Zhang47b553c2019-04-15 20:42:57 +0000496 mService.setNotificationEffectsEnabledForAutomotive(false);
497
498 NotificationRecord r = getBeepyNotification();
499 r.setSystemImportance(NotificationManager.IMPORTANCE_HIGH);
500
501 mService.buzzBeepBlinkLocked(r);
502
503 verifyNeverBeep();
504 assertFalse(r.isInterruptive());
505 }
506
507 @Test
508 public void testNoBeepForImportanceDefaultInAutomotiveIfEffectsEnabled() throws Exception {
509 mService.setIsAutomotive(true);
510 mService.setNotificationEffectsEnabledForAutomotive(true);
Adora Zhang963328f2018-11-15 18:17:19 -0800511
512 NotificationRecord r = getBeepyNotification();
513 r.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT);
514
515 mService.buzzBeepBlinkLocked(r);
516
517 verifyNeverBeep();
518 assertFalse(r.isInterruptive());
519 }
520
521 @Test
Qiao (Adora) Zhang47b553c2019-04-15 20:42:57 +0000522 public void testBeepForImportanceHighInAutomotiveIfEffectsEnabled() throws Exception {
Adora Zhang963328f2018-11-15 18:17:19 -0800523 mService.setIsAutomotive(true);
Qiao (Adora) Zhang47b553c2019-04-15 20:42:57 +0000524 mService.setNotificationEffectsEnabledForAutomotive(true);
Adora Zhang963328f2018-11-15 18:17:19 -0800525
526 NotificationRecord r = getBeepyNotification();
Qiao (Adora) Zhang47b553c2019-04-15 20:42:57 +0000527 r.setSystemImportance(NotificationManager.IMPORTANCE_HIGH);
Adora Zhang963328f2018-11-15 18:17:19 -0800528
529 mService.buzzBeepBlinkLocked(r);
530
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400531 verifyBeepUnlooped();
Adora Zhang963328f2018-11-15 18:17:19 -0800532 assertTrue(r.isInterruptive());
533 }
534
535 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -0400536 public void testNoInterruptionForMin() throws Exception {
537 NotificationRecord r = getBeepyNotification();
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400538 r.setSystemImportance(NotificationManager.IMPORTANCE_MIN);
Chris Wren93bb8b82016-03-29 14:35:05 -0400539
540 mService.buzzBeepBlinkLocked(r);
541
542 verifyNeverBeep();
543 verifyNeverVibrate();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500544 assertFalse(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500545 assertEquals(-1, r.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400546 }
547
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400548 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -0400549 public void testNoInterruptionForIntercepted() throws Exception {
550 NotificationRecord r = getBeepyNotification();
551 r.setIntercepted(true);
552
553 mService.buzzBeepBlinkLocked(r);
554
555 verifyNeverBeep();
556 verifyNeverVibrate();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500557 assertFalse(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500558 assertEquals(-1, r.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400559 }
560
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400561 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -0400562 public void testBeepTwice() throws Exception {
563 NotificationRecord r = getBeepyNotification();
564
565 // set up internal state
566 mService.buzzBeepBlinkLocked(r);
567 Mockito.reset(mRingtonePlayer);
568
569 // update should beep
570 r.isUpdate = true;
571 mService.buzzBeepBlinkLocked(r);
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400572 verifyBeepUnlooped();
Julia Reynolds94187562017-10-10 13:58:49 -0400573 verify(mAccessibilityService, times(2)).sendAccessibilityEvent(any(), anyInt());
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500574 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500575 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400576 }
577
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400578 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -0400579 public void testHonorAlertOnlyOnceForBeep() throws Exception {
580 NotificationRecord r = getBeepyNotification();
581 NotificationRecord s = getBeepyOnceNotification();
582 s.isUpdate = true;
583
584 // set up internal state
585 mService.buzzBeepBlinkLocked(r);
586 Mockito.reset(mRingtonePlayer);
587
588 // update should not beep
589 mService.buzzBeepBlinkLocked(s);
590 verifyNeverBeep();
Julia Reynolds94187562017-10-10 13:58:49 -0400591 verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
Chris Wren93bb8b82016-03-29 14:35:05 -0400592 }
593
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400594 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -0400595 public void testNoisyUpdateDoesNotCancelAudio() throws Exception {
596 NotificationRecord r = getBeepyNotification();
597
598 mService.buzzBeepBlinkLocked(r);
599 r.isUpdate = true;
600 mService.buzzBeepBlinkLocked(r);
601
602 verifyNeverStopAudio();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500603 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500604 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400605 }
606
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400607 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -0400608 public void testNoisyOnceUpdateDoesNotCancelAudio() throws Exception {
609 NotificationRecord r = getBeepyNotification();
610 NotificationRecord s = getBeepyOnceNotification();
611 s.isUpdate = true;
612
613 mService.buzzBeepBlinkLocked(r);
614 mService.buzzBeepBlinkLocked(s);
615
616 verifyNeverStopAudio();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500617 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500618 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500619 assertFalse(s.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500620 assertEquals(-1, s.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400621 }
622
Tyler Gunn48f86272018-07-03 12:38:49 -0700623 /**
624 * Tests the case where the user re-posts a {@link Notification} with looping sound where
625 * {@link Notification.Builder#setOnlyAlertOnce(true)} has been called. This should silence
626 * the sound associated with the notification.
627 * @throws Exception
628 */
629 @Test
630 public void testNoisyOnceUpdateDoesCancelAudio() throws Exception {
631 NotificationRecord r = getInsistentBeepyNotification();
632 NotificationRecord s = getInsistentBeepyOnceNotification();
633 s.isUpdate = true;
634
635 mService.buzzBeepBlinkLocked(r);
636 mService.buzzBeepBlinkLocked(s);
637
638 verifyStopAudio();
639 }
640
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400641 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -0400642 public void testQuietUpdateDoesNotCancelAudioFromOther() throws Exception {
643 NotificationRecord r = getBeepyNotification();
644 NotificationRecord s = getQuietNotification();
645 s.isUpdate = true;
646 NotificationRecord other = getNoisyOtherNotification();
647
648 // set up internal state
649 mService.buzzBeepBlinkLocked(r);
650 mService.buzzBeepBlinkLocked(other); // this takes the audio stream
651 Mockito.reset(mRingtonePlayer);
652
653 // should not stop noise, since we no longer own it
654 mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
655 verifyNeverStopAudio();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500656 assertTrue(other.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500657 assertNotEquals(-1, other.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400658 }
659
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400660 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -0400661 public void testQuietInterloperDoesNotCancelAudio() throws Exception {
662 NotificationRecord r = getBeepyNotification();
663 NotificationRecord other = getQuietOtherNotification();
664
665 // set up internal state
666 mService.buzzBeepBlinkLocked(r);
667 Mockito.reset(mRingtonePlayer);
668
669 // should not stop noise, since it does not own it
670 mService.buzzBeepBlinkLocked(other);
671 verifyNeverStopAudio();
672 }
673
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400674 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -0400675 public void testQuietUpdateCancelsAudio() throws Exception {
676 NotificationRecord r = getBeepyNotification();
677 NotificationRecord s = getQuietNotification();
678 s.isUpdate = true;
679
680 // set up internal state
681 mService.buzzBeepBlinkLocked(r);
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500682 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500683 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400684 Mockito.reset(mRingtonePlayer);
685
686 // quiet update should stop making noise
687 mService.buzzBeepBlinkLocked(s);
688 verifyStopAudio();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500689 assertFalse(s.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500690 assertEquals(-1, s.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400691 }
692
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400693 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -0400694 public void testQuietOnceUpdateCancelsAudio() throws Exception {
695 NotificationRecord r = getBeepyNotification();
696 NotificationRecord s = getQuietOnceNotification();
697 s.isUpdate = true;
698
699 // set up internal state
700 mService.buzzBeepBlinkLocked(r);
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500701 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500702 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400703 Mockito.reset(mRingtonePlayer);
704
705 // stop making noise - this is a weird corner case, but quiet should override once
706 mService.buzzBeepBlinkLocked(s);
707 verifyStopAudio();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500708 assertFalse(s.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500709 assertEquals(-1, s.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400710 }
711
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400712 @Test
Beverly5d463b62017-07-26 14:13:40 -0400713 public void testInCallNotification() throws Exception {
714 NotificationRecord r = getBeepyNotification();
715
716 // set up internal state
717 mService.buzzBeepBlinkLocked(r);
718 Mockito.reset(mRingtonePlayer);
719
Eric Laurent7412abc2019-07-12 18:26:29 -0700720 mService.mInCallStateOffHook = true;
Beverly5d463b62017-07-26 14:13:40 -0400721 mService.buzzBeepBlinkLocked(r);
722
Julia Reynolds94187562017-10-10 13:58:49 -0400723 verify(mService, times(1)).playInCallNotification();
Beverly5d463b62017-07-26 14:13:40 -0400724 verifyNeverBeep(); // doesn't play normal beep
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500725 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500726 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Beverly5d463b62017-07-26 14:13:40 -0400727 }
728
729 @Test
Julia Reynolds0c299d42016-11-15 14:37:04 -0500730 public void testNoDemoteSoundToVibrateIfVibrateGiven() throws Exception {
731 NotificationRecord r = getBuzzyBeepyNotification();
732 assertTrue(r.getSound() != null);
Chris Wren93bb8b82016-03-29 14:35:05 -0400733
734 // the phone is quiet
Chris Wren93bb8b82016-03-29 14:35:05 -0400735 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
Julia Reynolds85896572017-09-20 12:54:52 -0400736 when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
Chris Wren93bb8b82016-03-29 14:35:05 -0400737
738 mService.buzzBeepBlinkLocked(r);
739
Michael Wright71216972017-01-31 18:33:54 +0000740 VibrationEffect effect = VibrationEffect.createWaveform(r.getVibration(), -1);
741
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -0700742 verify(mVibrator, timeout(MAX_VIBRATION_DELAY).times(1)).vibrate(anyInt(), anyString(),
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100743 eq(effect), anyString(),
744 (AudioAttributes) anyObject());
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500745 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500746 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400747 }
748
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400749 @Test
Julia Reynolds85896572017-09-20 12:54:52 -0400750 public void testNoDemoteSoundToVibrateIfNonNotificationStream() throws Exception {
751 NotificationRecord r = getBeepyNotification();
752 assertTrue(r.getSound() != null);
753 assertNull(r.getVibration());
754
755 // the phone is quiet
756 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
757 when(mAudioManager.getStreamVolume(anyInt())).thenReturn(1);
758
759 mService.buzzBeepBlinkLocked(r);
760
761 verifyNeverVibrate();
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400762 verifyBeepUnlooped();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500763 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500764 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds85896572017-09-20 12:54:52 -0400765 }
766
767 @Test
Julia Reynolds0c299d42016-11-15 14:37:04 -0500768 public void testDemoteSoundToVibrate() throws Exception {
769 NotificationRecord r = getBeepyNotification();
770 assertTrue(r.getSound() != null);
771 assertNull(r.getVibration());
772
773 // the phone is quiet
774 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
Julia Reynolds85896572017-09-20 12:54:52 -0400775 when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
Julia Reynolds0c299d42016-11-15 14:37:04 -0500776
777 mService.buzzBeepBlinkLocked(r);
778
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -0700779 verify(mVibrator, timeout(MAX_VIBRATION_DELAY).times(1)).vibrate(anyInt(), anyString(),
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100780 eq(FALLBACK_VIBRATION), anyString(), (AudioAttributes) anyObject());
Julia Reynolds619a69f2017-01-27 15:11:38 -0500781 verify(mRingtonePlayer, never()).playAsync
782 (anyObject(), anyObject(), anyBoolean(), anyObject());
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500783 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500784 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds0c299d42016-11-15 14:37:04 -0500785 }
786
787 @Test
788 public void testDemoteInsistentSoundToVibrate() throws Exception {
Chris Wren93bb8b82016-03-29 14:35:05 -0400789 NotificationRecord r = getInsistentBeepyNotification();
Julia Reynolds0c299d42016-11-15 14:37:04 -0500790 assertTrue(r.getSound() != null);
791 assertNull(r.getVibration());
Chris Wren93bb8b82016-03-29 14:35:05 -0400792
793 // the phone is quiet
794 when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
795 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
796
797 mService.buzzBeepBlinkLocked(r);
798
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -0700799 verifyDelayedVibrateLooped();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500800 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500801 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400802 }
803
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400804 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -0400805 public void testVibrate() throws Exception {
806 NotificationRecord r = getBuzzyNotification();
807
808 mService.buzzBeepBlinkLocked(r);
809
810 verifyNeverBeep();
811 verifyVibrate();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500812 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500813 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400814 }
815
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400816 @Test
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500817 public void testInsistentVibrate() {
Chris Wren93bb8b82016-03-29 14:35:05 -0400818 NotificationRecord r = getInsistentBuzzyNotification();
819
820 mService.buzzBeepBlinkLocked(r);
821 verifyVibrateLooped();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500822 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500823 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400824 }
825
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400826 @Test
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500827 public void testVibrateTwice() {
Chris Wren93bb8b82016-03-29 14:35:05 -0400828 NotificationRecord r = getBuzzyNotification();
829
830 // set up internal state
831 mService.buzzBeepBlinkLocked(r);
832 Mockito.reset(mVibrator);
833
834 // update should vibrate
835 r.isUpdate = true;
836 mService.buzzBeepBlinkLocked(r);
837 verifyVibrate();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500838 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500839 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400840 }
841
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400842 @Test
Julia Reynoldsa79c3712017-04-21 10:29:57 -0400843 public void testGroupAlertSummarySilenceChild() throws Exception {
844 NotificationRecord child = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY);
845
846 mService.buzzBeepBlinkLocked(child);
847
848 verifyNeverBeep();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500849 assertFalse(child.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500850 assertEquals(-1, child.getLastAudiblyAlertedMs());
Julia Reynoldsa79c3712017-04-21 10:29:57 -0400851 }
852
853 @Test
854 public void testGroupAlertSummaryNoSilenceSummary() throws Exception {
855 NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY);
856 summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
857
858 mService.buzzBeepBlinkLocked(summary);
859
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400860 verifyBeepUnlooped();
Julia Reynolds28149f62018-07-03 10:43:35 -0400861 // summaries are never interruptive for notification counts
862 assertFalse(summary.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500863 assertNotEquals(-1, summary.getLastAudiblyAlertedMs());
Julia Reynoldsa79c3712017-04-21 10:29:57 -0400864 }
865
866 @Test
867 public void testGroupAlertSummaryNoSilenceNonGroupChild() throws Exception {
868 NotificationRecord nonGroup = getBeepyNotificationRecord(null, GROUP_ALERT_SUMMARY);
869
870 mService.buzzBeepBlinkLocked(nonGroup);
871
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400872 verifyBeepUnlooped();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500873 assertTrue(nonGroup.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500874 assertNotEquals(-1, nonGroup.getLastAudiblyAlertedMs());
Julia Reynoldsa79c3712017-04-21 10:29:57 -0400875 }
876
877 @Test
878 public void testGroupAlertChildSilenceSummary() throws Exception {
879 NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_CHILDREN);
880 summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
881
882 mService.buzzBeepBlinkLocked(summary);
883
884 verifyNeverBeep();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500885 assertFalse(summary.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500886 assertEquals(-1, summary.getLastAudiblyAlertedMs());
Julia Reynoldsa79c3712017-04-21 10:29:57 -0400887 }
888
889 @Test
890 public void testGroupAlertChildNoSilenceChild() throws Exception {
891 NotificationRecord child = getBeepyNotificationRecord("a", GROUP_ALERT_CHILDREN);
892
893 mService.buzzBeepBlinkLocked(child);
894
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400895 verifyBeepUnlooped();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500896 assertTrue(child.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500897 assertNotEquals(-1, child.getLastAudiblyAlertedMs());
Julia Reynoldsa79c3712017-04-21 10:29:57 -0400898 }
899
900 @Test
901 public void testGroupAlertChildNoSilenceNonGroupSummary() throws Exception {
902 NotificationRecord nonGroup = getBeepyNotificationRecord(null, GROUP_ALERT_CHILDREN);
903
904 mService.buzzBeepBlinkLocked(nonGroup);
905
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400906 verifyBeepUnlooped();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500907 assertTrue(nonGroup.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500908 assertNotEquals(-1, nonGroup.getLastAudiblyAlertedMs());
Julia Reynoldsa79c3712017-04-21 10:29:57 -0400909 }
910
911 @Test
912 public void testGroupAlertAllNoSilenceGroup() throws Exception {
913 NotificationRecord group = getBeepyNotificationRecord("a", GROUP_ALERT_ALL);
914
915 mService.buzzBeepBlinkLocked(group);
916
Julia Reynolds714ff5f2019-10-14 11:19:53 -0400917 verifyBeepUnlooped();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500918 assertTrue(group.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500919 assertNotEquals(-1, group.getLastAudiblyAlertedMs());
Julia Reynoldsa79c3712017-04-21 10:29:57 -0400920 }
921
922 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -0400923 public void testHonorAlertOnlyOnceForBuzz() throws Exception {
924 NotificationRecord r = getBuzzyNotification();
925 NotificationRecord s = getBuzzyOnceNotification();
926 s.isUpdate = true;
927
928 // set up internal state
929 mService.buzzBeepBlinkLocked(r);
930 Mockito.reset(mVibrator);
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500931 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500932 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400933
934 // update should not beep
935 mService.buzzBeepBlinkLocked(s);
936 verifyNeverVibrate();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500937 assertFalse(s.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500938 assertEquals(-1, s.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400939 }
940
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400941 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -0400942 public void testNoisyUpdateDoesNotCancelVibrate() throws Exception {
943 NotificationRecord r = getBuzzyNotification();
944
945 mService.buzzBeepBlinkLocked(r);
946 r.isUpdate = true;
947 mService.buzzBeepBlinkLocked(r);
948
949 verifyNeverStopVibrate();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500950 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500951 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400952 }
953
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400954 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -0400955 public void testNoisyOnceUpdateDoesNotCancelVibrate() throws Exception {
956 NotificationRecord r = getBuzzyNotification();
957 NotificationRecord s = getBuzzyOnceNotification();
958 s.isUpdate = true;
959
960 mService.buzzBeepBlinkLocked(r);
961 mService.buzzBeepBlinkLocked(s);
962
963 verifyNeverStopVibrate();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500964 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500965 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500966 assertFalse(s.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500967 assertEquals(-1, s.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400968 }
969
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400970 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -0400971 public void testQuietUpdateDoesNotCancelVibrateFromOther() throws Exception {
972 NotificationRecord r = getBuzzyNotification();
973 NotificationRecord s = getQuietNotification();
974 s.isUpdate = true;
975 NotificationRecord other = getNoisyOtherNotification();
976
977 // set up internal state
978 mService.buzzBeepBlinkLocked(r);
979 mService.buzzBeepBlinkLocked(other); // this takes the vibrate stream
980 Mockito.reset(mVibrator);
981
982 // should not stop vibrate, since we no longer own it
983 mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
984 verifyNeverStopVibrate();
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500985 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500986 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500987 assertTrue(other.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500988 assertNotEquals(-1, other.getLastAudiblyAlertedMs());
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500989 assertFalse(s.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -0500990 assertEquals(-1, s.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -0400991 }
992
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -0400993 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -0400994 public void testQuietInterloperDoesNotCancelVibrate() throws Exception {
995 NotificationRecord r = getBuzzyNotification();
996 NotificationRecord other = getQuietOtherNotification();
997
998 // set up internal state
999 mService.buzzBeepBlinkLocked(r);
1000 Mockito.reset(mVibrator);
1001
1002 // should not stop noise, since it does not own it
1003 mService.buzzBeepBlinkLocked(other);
1004 verifyNeverStopVibrate();
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001005 assertFalse(other.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001006 assertEquals(-1, other.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -04001007 }
1008
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -04001009 @Test
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001010 public void testQuietUpdateCancelsVibrate() {
Chris Wren93bb8b82016-03-29 14:35:05 -04001011 NotificationRecord r = getBuzzyNotification();
1012 NotificationRecord s = getQuietNotification();
1013 s.isUpdate = true;
1014
1015 // set up internal state
1016 mService.buzzBeepBlinkLocked(r);
Julia Reynolds0c299d42016-11-15 14:37:04 -05001017 verifyVibrate();
Chris Wren93bb8b82016-03-29 14:35:05 -04001018
1019 // quiet update should stop making noise
1020 mService.buzzBeepBlinkLocked(s);
1021 verifyStopVibrate();
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001022 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001023 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001024 assertFalse(s.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001025 assertEquals(-1, s.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -04001026 }
1027
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -04001028 @Test
Julia Reynolds0c299d42016-11-15 14:37:04 -05001029 public void testQuietOnceUpdateCancelVibrate() throws Exception {
Chris Wren93bb8b82016-03-29 14:35:05 -04001030 NotificationRecord r = getBuzzyNotification();
1031 NotificationRecord s = getQuietOnceNotification();
1032 s.isUpdate = true;
1033
1034 // set up internal state
1035 mService.buzzBeepBlinkLocked(r);
Julia Reynolds0c299d42016-11-15 14:37:04 -05001036 verifyVibrate();
Chris Wren93bb8b82016-03-29 14:35:05 -04001037
1038 // stop making noise - this is a weird corner case, but quiet should override once
1039 mService.buzzBeepBlinkLocked(s);
1040 verifyStopVibrate();
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001041 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001042 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001043 assertFalse(s.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001044 assertEquals(-1, s.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -04001045 }
1046
Geoffrey Pitsch0ffe7552016-08-29 10:07:40 -04001047 @Test
Chris Wren93bb8b82016-03-29 14:35:05 -04001048 public void testQuietUpdateCancelsDemotedVibrate() throws Exception {
1049 NotificationRecord r = getBeepyNotification();
1050 NotificationRecord s = getQuietNotification();
1051
1052 // the phone is quiet
1053 when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
1054 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
1055
1056 mService.buzzBeepBlinkLocked(r);
1057
1058 // quiet update should stop making noise
1059 mService.buzzBeepBlinkLocked(s);
1060 verifyStopVibrate();
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001061 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001062 assertNotEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001063 assertFalse(s.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001064 assertEquals(-1, s.getLastAudiblyAlertedMs());
Chris Wren93bb8b82016-03-29 14:35:05 -04001065 }
Michael Wright71216972017-01-31 18:33:54 +00001066
Julia Reynoldsca80d162017-04-23 12:39:32 -04001067 @Test
1068 public void testEmptyUriSoundTreatedAsNoSound() throws Exception {
1069 NotificationChannel channel = new NotificationChannel("test", "test", IMPORTANCE_HIGH);
1070 channel.setSound(Uri.EMPTY, null);
Qiao (Adora) Zhanga9d0bff2019-04-15 17:45:43 +00001071 final Notification n = new Builder(getContext(), "test")
Julia Reynoldsca80d162017-04-23 12:39:32 -04001072 .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
1073
1074 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid,
1075 mPid, n, mUser, null, System.currentTimeMillis());
Qiao (Adora) Zhanga9d0bff2019-04-15 17:45:43 +00001076 NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
Julia Reynoldsca80d162017-04-23 12:39:32 -04001077 mService.addNotification(r);
1078
1079 mService.buzzBeepBlinkLocked(r);
Julia Reynoldsca80d162017-04-23 12:39:32 -04001080 verifyNeverBeep();
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001081 assertFalse(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001082 assertEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynoldsca80d162017-04-23 12:39:32 -04001083 }
1084
Julia Reynolds76c096d2017-06-19 08:16:04 -04001085 @Test
1086 public void testRepeatedSoundOverLimitMuted() throws Exception {
1087 when(mUsageStats.isAlertRateLimited(any())).thenReturn(true);
1088
1089 NotificationRecord r = getBeepyNotification();
1090
1091 mService.buzzBeepBlinkLocked(r);
1092 verifyNeverBeep();
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001093 assertFalse(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001094 assertEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds76c096d2017-06-19 08:16:04 -04001095 }
1096
1097 @Test
1098 public void testPostingSilentNotificationDoesNotAffectRateLimiting() throws Exception {
1099 NotificationRecord r = getQuietNotification();
1100 mService.buzzBeepBlinkLocked(r);
1101
1102 verify(mUsageStats, never()).isAlertRateLimited(any());
1103 }
1104
1105 @Test
Julia Reynolds65b85cf2017-07-20 09:19:20 -04001106 public void testPostingGroupSuppressedDoesNotAffectRateLimiting() throws Exception {
1107 NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_CHILDREN);
1108 summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
1109
1110 mService.buzzBeepBlinkLocked(summary);
Julia Reynolds65b85cf2017-07-20 09:19:20 -04001111 verify(mUsageStats, never()).isAlertRateLimited(any());
1112 }
1113
1114 @Test
Julia Reynolds79dfdd62018-04-17 15:36:33 -04001115 public void testGroupSuppressionFailureDoesNotAffectRateLimiting() {
1116 NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY);
1117 summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
1118
1119 mService.buzzBeepBlinkLocked(summary);
1120 verify(mUsageStats, times(1)).isAlertRateLimited(any());
1121 }
1122
1123 @Test
Julia Reynolds76c096d2017-06-19 08:16:04 -04001124 public void testCrossUserSoundMuted() throws Exception {
Qiao (Adora) Zhanga9d0bff2019-04-15 17:45:43 +00001125 final Notification n = new Builder(getContext(), "test")
Julia Reynolds76c096d2017-06-19 08:16:04 -04001126 .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
1127
1128 int userId = mUser.getIdentifier() + 1;
1129 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid,
1130 mPid, n, UserHandle.of(userId), null, System.currentTimeMillis());
Qiao (Adora) Zhanga9d0bff2019-04-15 17:45:43 +00001131 NotificationRecord r = new NotificationRecord(getContext(), sbn,
Julia Reynolds76c096d2017-06-19 08:16:04 -04001132 new NotificationChannel("test", "test", IMPORTANCE_HIGH));
1133
1134 mService.buzzBeepBlinkLocked(r);
1135 verifyNeverBeep();
Julia Reynolds1fac86e2018-03-07 08:30:37 -05001136 assertFalse(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001137 assertEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds76c096d2017-06-19 08:16:04 -04001138 }
1139
Julia Reynolds94187562017-10-10 13:58:49 -04001140 @Test
1141 public void testA11yMinInitialPost() throws Exception {
1142 NotificationRecord r = getQuietNotification();
Julia Reynoldsefcdff42018-08-09 09:42:56 -04001143 r.setSystemImportance(IMPORTANCE_MIN);
Julia Reynolds94187562017-10-10 13:58:49 -04001144 mService.buzzBeepBlinkLocked(r);
1145 verify(mAccessibilityService, never()).sendAccessibilityEvent(any(), anyInt());
1146 }
1147
1148 @Test
1149 public void testA11yQuietInitialPost() throws Exception {
1150 NotificationRecord r = getQuietNotification();
1151 mService.buzzBeepBlinkLocked(r);
1152 verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
1153 }
1154
1155 @Test
1156 public void testA11yQuietUpdate() throws Exception {
1157 NotificationRecord r = getQuietNotification();
1158 mService.buzzBeepBlinkLocked(r);
1159 r.isUpdate = true;
1160 mService.buzzBeepBlinkLocked(r);
1161 verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
1162 }
1163
Julia Reynolds28149f62018-07-03 10:43:35 -04001164 @Test
1165 public void testLightsScreenOn() {
1166 mService.mScreenOn = true;
1167 NotificationRecord r = getLightsNotification();
1168 mService.buzzBeepBlinkLocked(r);
1169 verifyNeverLights();
1170 assertFalse(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001171 assertEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds28149f62018-07-03 10:43:35 -04001172 }
1173
1174 @Test
1175 public void testLightsInCall() {
Eric Laurent7412abc2019-07-12 18:26:29 -07001176 mService.mInCallStateOffHook = true;
Julia Reynolds28149f62018-07-03 10:43:35 -04001177 NotificationRecord r = getLightsNotification();
1178 mService.buzzBeepBlinkLocked(r);
1179 verifyNeverLights();
1180 assertFalse(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001181 assertEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds28149f62018-07-03 10:43:35 -04001182 }
1183
1184 @Test
1185 public void testLightsSilentUpdate() {
1186 NotificationRecord r = getLightsOnceNotification();
1187 mService.buzzBeepBlinkLocked(r);
1188 verifyLights();
1189 assertTrue(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001190 assertEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds28149f62018-07-03 10:43:35 -04001191
1192 r = getLightsOnceNotification();
1193 r.isUpdate = true;
1194 mService.buzzBeepBlinkLocked(r);
1195 // checks that lights happened once, i.e. this new call didn't trigger them again
1196 verifyLights();
1197 assertFalse(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001198 assertEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds28149f62018-07-03 10:43:35 -04001199 }
1200
1201 @Test
1202 public void testLightsUnimportant() {
1203 NotificationRecord r = getLightsNotification();
Julia Reynoldsefcdff42018-08-09 09:42:56 -04001204 r.setSystemImportance(IMPORTANCE_LOW);
Julia Reynolds28149f62018-07-03 10:43:35 -04001205 mService.buzzBeepBlinkLocked(r);
1206 verifyNeverLights();
1207 assertFalse(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001208 assertEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds28149f62018-07-03 10:43:35 -04001209 }
1210
1211 @Test
1212 public void testLightsNoLights() {
1213 NotificationRecord r = getQuietNotification();
1214 mService.buzzBeepBlinkLocked(r);
1215 verifyNeverLights();
1216 assertFalse(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001217 assertEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds28149f62018-07-03 10:43:35 -04001218 }
1219
1220 @Test
1221 public void testLightsNoLightOnDevice() {
1222 mService.mHasLight = false;
1223 NotificationRecord r = getLightsNotification();
1224 mService.buzzBeepBlinkLocked(r);
1225 verifyNeverLights();
1226 assertFalse(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001227 assertEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds28149f62018-07-03 10:43:35 -04001228 }
1229
1230 @Test
1231 public void testLightsLightsOffGlobally() {
1232 mService.mNotificationPulseEnabled = false;
1233 NotificationRecord r = getLightsNotification();
1234 mService.buzzBeepBlinkLocked(r);
1235 verifyNeverLights();
1236 assertFalse(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001237 assertEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds28149f62018-07-03 10:43:35 -04001238 }
1239
1240 @Test
1241 public void testLightsDndIntercepted() {
1242 NotificationRecord r = getLightsNotification();
1243 r.setSuppressedVisualEffects(SUPPRESSED_EFFECT_LIGHTS);
1244 mService.buzzBeepBlinkLocked(r);
1245 verifyNeverLights();
1246 assertFalse(r.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001247 assertEquals(-1, r.getLastAudiblyAlertedMs());
Julia Reynolds28149f62018-07-03 10:43:35 -04001248 }
1249
1250 @Test
1251 public void testGroupAlertSummaryNoLightsChild() {
1252 NotificationRecord child = getLightsNotificationRecord("a", GROUP_ALERT_SUMMARY);
1253
1254 mService.buzzBeepBlinkLocked(child);
1255
1256 verifyNeverLights();
1257 assertFalse(child.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001258 assertEquals(-1, child.getLastAudiblyAlertedMs());
Julia Reynolds28149f62018-07-03 10:43:35 -04001259 }
1260
1261 @Test
1262 public void testGroupAlertSummaryLightsSummary() {
1263 NotificationRecord summary = getLightsNotificationRecord("a", GROUP_ALERT_SUMMARY);
1264 summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
1265
1266 mService.buzzBeepBlinkLocked(summary);
1267
1268 verifyLights();
1269 // summaries should never count for interruptiveness counts
1270 assertFalse(summary.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001271 assertEquals(-1, summary.getLastAudiblyAlertedMs());
Julia Reynolds28149f62018-07-03 10:43:35 -04001272 }
1273
1274 @Test
1275 public void testGroupAlertSummaryLightsNonGroupChild() {
1276 NotificationRecord nonGroup = getLightsNotificationRecord(null, GROUP_ALERT_SUMMARY);
1277
1278 mService.buzzBeepBlinkLocked(nonGroup);
1279
1280 verifyLights();
1281 assertTrue(nonGroup.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001282 assertEquals(-1, nonGroup.getLastAudiblyAlertedMs());
Julia Reynolds28149f62018-07-03 10:43:35 -04001283 }
1284
1285 @Test
1286 public void testGroupAlertChildNoLightsSummary() {
1287 NotificationRecord summary = getLightsNotificationRecord("a", GROUP_ALERT_CHILDREN);
1288 summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
1289
1290 mService.buzzBeepBlinkLocked(summary);
1291
1292 verifyNeverLights();
1293 assertFalse(summary.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001294 assertEquals(-1, summary.getLastAudiblyAlertedMs());
Julia Reynolds28149f62018-07-03 10:43:35 -04001295 }
1296
1297 @Test
1298 public void testGroupAlertChildLightsChild() {
1299 NotificationRecord child = getLightsNotificationRecord("a", GROUP_ALERT_CHILDREN);
1300
1301 mService.buzzBeepBlinkLocked(child);
1302
1303 verifyLights();
1304 assertTrue(child.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001305 assertEquals(-1, child.getLastAudiblyAlertedMs());
Julia Reynolds28149f62018-07-03 10:43:35 -04001306 }
1307
1308 @Test
1309 public void testGroupAlertChildLightsNonGroupSummary() {
1310 NotificationRecord nonGroup = getLightsNotificationRecord(null, GROUP_ALERT_CHILDREN);
1311
1312 mService.buzzBeepBlinkLocked(nonGroup);
1313
1314 verifyLights();
1315 assertTrue(nonGroup.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001316 assertEquals(-1, nonGroup.getLastAudiblyAlertedMs());
Julia Reynolds28149f62018-07-03 10:43:35 -04001317 }
1318
1319 @Test
1320 public void testGroupAlertAllLightsGroup() {
1321 NotificationRecord group = getLightsNotificationRecord("a", GROUP_ALERT_ALL);
1322
1323 mService.buzzBeepBlinkLocked(group);
1324
1325 verifyLights();
1326 assertTrue(group.isInterruptive());
Gus Prevas7306b902018-12-11 10:57:06 -05001327 assertEquals(-1, group.getLastAudiblyAlertedMs());
Julia Reynolds28149f62018-07-03 10:43:35 -04001328 }
1329
Julia Reynoldsdb7081e2019-01-03 14:35:38 -05001330 @Test
1331 public void testListenerHintCall() throws Exception {
Julia Reynolds714ff5f2019-10-14 11:19:53 -04001332 NotificationChannel ringtoneChannel =
1333 new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
1334 ringtoneChannel.setSound(Settings.System.DEFAULT_RINGTONE_URI,
1335 new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
1336 NotificationRecord r = getCallRecord(1, ringtoneChannel, true);
Julia Reynoldsdb7081e2019-01-03 14:35:38 -05001337
1338 mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
1339
1340 mService.buzzBeepBlinkLocked(r);
1341
1342 verifyNeverBeep();
1343 }
1344
1345 @Test
1346 public void testListenerHintCall_notificationSound() throws Exception {
1347 NotificationRecord r = getBeepyNotification();
1348
1349 mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
1350
1351 mService.buzzBeepBlinkLocked(r);
1352
Julia Reynolds714ff5f2019-10-14 11:19:53 -04001353 verifyBeepUnlooped();
Julia Reynoldsdb7081e2019-01-03 14:35:38 -05001354 }
1355
1356 @Test
1357 public void testListenerHintNotification() throws Exception {
1358 NotificationRecord r = getBeepyNotification();
1359
1360 mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1361
1362 mService.buzzBeepBlinkLocked(r);
1363
1364 verifyNeverBeep();
1365 }
1366
1367 @Test
1368 public void testListenerHintBoth() throws Exception {
Julia Reynolds714ff5f2019-10-14 11:19:53 -04001369 NotificationChannel ringtoneChannel =
1370 new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
1371 ringtoneChannel.setSound(Settings.System.DEFAULT_RINGTONE_URI,
1372 new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
1373 NotificationRecord r = getCallRecord(1, ringtoneChannel, true);
Julia Reynoldsdb7081e2019-01-03 14:35:38 -05001374 NotificationRecord s = getBeepyNotification();
1375
1376 mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
1377 | NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
1378
1379 mService.buzzBeepBlinkLocked(r);
1380 mService.buzzBeepBlinkLocked(s);
1381
1382 verifyNeverBeep();
1383 }
1384
1385 @Test
1386 public void testListenerHintNotification_callSound() throws Exception {
Julia Reynolds714ff5f2019-10-14 11:19:53 -04001387 NotificationChannel ringtoneChannel =
1388 new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
1389 ringtoneChannel.setSound(Settings.System.DEFAULT_RINGTONE_URI,
1390 new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
1391 NotificationRecord r = getCallRecord(1, ringtoneChannel, true);
Julia Reynoldsdb7081e2019-01-03 14:35:38 -05001392
1393 mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1394
1395 mService.buzzBeepBlinkLocked(r);
1396
1397 verifyBeepLooped();
1398 }
1399
Julia Reynolds714ff5f2019-10-14 11:19:53 -04001400 @Test
1401 public void testCannotInterruptRingtoneInsistentBeep() throws Exception {
1402 NotificationChannel ringtoneChannel =
1403 new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
1404 ringtoneChannel.setSound(Settings.System.DEFAULT_RINGTONE_URI,
1405 new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
1406 NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
1407 mService.addNotification(ringtoneNotification);
1408
1409 mService.buzzBeepBlinkLocked(ringtoneNotification);
1410 verifyBeepLooped();
1411
1412 NotificationRecord interrupter = getBeepyOtherNotification();
1413 assertTrue(mService.shouldMuteNotificationLocked(interrupter));
1414 mService.buzzBeepBlinkLocked(interrupter);
1415
1416 verifyBeep(1);
1417
1418 assertFalse(interrupter.isInterruptive());
1419 assertEquals(-1, interrupter.getLastAudiblyAlertedMs());
1420 }
1421
1422 @Test
1423 public void testCannotInterruptRingtoneInsistentBuzz() {
1424 NotificationChannel ringtoneChannel =
1425 new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
1426 ringtoneChannel.setSound(Uri.EMPTY,
1427 new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
1428 ringtoneChannel.enableVibration(true);
1429 NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
1430 assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
1431
1432 mService.buzzBeepBlinkLocked(ringtoneNotification);
1433 verifyVibrateLooped();
1434
1435 NotificationRecord interrupter = getBuzzyOtherNotification();
1436 assertTrue(mService.shouldMuteNotificationLocked(interrupter));
1437 mService.buzzBeepBlinkLocked(interrupter);
1438
1439 verifyVibrate(1);
1440
1441 assertFalse(interrupter.isInterruptive());
1442 assertEquals(-1, interrupter.getLastAudiblyAlertedMs());
1443 }
1444
1445 @Test
1446 public void testCanInterruptRingtoneNonInsistentBeep() throws Exception {
1447 NotificationChannel ringtoneChannel =
1448 new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
1449 ringtoneChannel.setSound(Settings.System.DEFAULT_RINGTONE_URI,
1450 new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
1451 NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, false);
1452
1453 mService.buzzBeepBlinkLocked(ringtoneNotification);
1454 verifyBeepUnlooped();
1455
1456 NotificationRecord interrupter = getBeepyOtherNotification();
1457 mService.buzzBeepBlinkLocked(interrupter);
1458
1459 verifyBeep(2);
1460
1461 assertTrue(interrupter.isInterruptive());
1462 }
1463
1464 @Test
1465 public void testCanInterruptRingtoneNonInsistentBuzz() {
1466 NotificationChannel ringtoneChannel =
1467 new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
1468 ringtoneChannel.setSound(null,
1469 new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
1470 ringtoneChannel.enableVibration(true);
1471 NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, false);
1472
1473 mService.buzzBeepBlinkLocked(ringtoneNotification);
1474 verifyVibrate();
1475
1476 NotificationRecord interrupter = getBuzzyOtherNotification();
1477 mService.buzzBeepBlinkLocked(interrupter);
1478
1479 verifyVibrate(2);
1480
1481 assertTrue(interrupter.isInterruptive());
1482 }
1483
1484 @Test
1485 public void testRingtoneInsistentBeep_doesNotBlockFutureSoundsOnceStopped() throws Exception {
1486 NotificationChannel ringtoneChannel =
1487 new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
1488 ringtoneChannel.setSound(Settings.System.DEFAULT_RINGTONE_URI,
1489 new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
1490 NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
1491
1492 mService.buzzBeepBlinkLocked(ringtoneNotification);
1493 verifyBeepLooped();
1494
1495 mService.clearSoundLocked();
1496
1497 NotificationRecord interrupter = getBeepyOtherNotification();
1498 mService.buzzBeepBlinkLocked(interrupter);
1499
1500 verifyBeep(2);
1501
1502 assertTrue(interrupter.isInterruptive());
1503 }
1504
1505 @Test
1506 public void testRingtoneInsistentBuzz_doesNotBlockFutureSoundsOnceStopped() {
1507 NotificationChannel ringtoneChannel =
1508 new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
1509 ringtoneChannel.setSound(null,
1510 new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
1511 ringtoneChannel.enableVibration(true);
1512 NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
1513
1514 mService.buzzBeepBlinkLocked(ringtoneNotification);
1515 verifyVibrateLooped();
1516
1517 mService.clearVibrateLocked();
1518
1519 NotificationRecord interrupter = getBuzzyOtherNotification();
1520 mService.buzzBeepBlinkLocked(interrupter);
1521
1522 verifyVibrate(2);
1523
1524 assertTrue(interrupter.isInterruptive());
1525 }
1526
1527 @Test
1528 public void testCanInterruptNonRingtoneInsistentBeep() throws Exception {
1529 NotificationChannel fakeRingtoneChannel =
1530 new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
1531 NotificationRecord ringtoneNotification = getCallRecord(1, fakeRingtoneChannel, true);
1532
1533 mService.buzzBeepBlinkLocked(ringtoneNotification);
1534 verifyBeepLooped();
1535
1536 NotificationRecord interrupter = getBeepyOtherNotification();
1537 mService.buzzBeepBlinkLocked(interrupter);
1538
1539 verifyBeep(2);
1540
1541 assertTrue(interrupter.isInterruptive());
1542 }
1543
1544 @Test
Julia Reynolds181ff7c2019-10-18 12:16:31 -04001545 public void testCanInterruptNonRingtoneInsistentBuzz() {
Julia Reynolds714ff5f2019-10-14 11:19:53 -04001546 NotificationChannel fakeRingtoneChannel =
1547 new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
1548 fakeRingtoneChannel.enableVibration(true);
Julia Reynolds181ff7c2019-10-18 12:16:31 -04001549 fakeRingtoneChannel.setSound(null,
1550 new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION).build());
Julia Reynolds714ff5f2019-10-14 11:19:53 -04001551 NotificationRecord ringtoneNotification = getCallRecord(1, fakeRingtoneChannel, true);
1552
1553 mService.buzzBeepBlinkLocked(ringtoneNotification);
1554
1555 NotificationRecord interrupter = getBuzzyOtherNotification();
1556 mService.buzzBeepBlinkLocked(interrupter);
1557
1558 verifyVibrate(2);
1559
1560 assertTrue(interrupter.isInterruptive());
1561 }
1562
Michael Wright71216972017-01-31 18:33:54 +00001563 static class VibrateRepeatMatcher implements ArgumentMatcher<VibrationEffect> {
1564 private final int mRepeatIndex;
1565
1566 VibrateRepeatMatcher(int repeatIndex) {
1567 mRepeatIndex = repeatIndex;
1568 }
1569
1570 @Override
1571 public boolean matches(VibrationEffect actual) {
1572 if (actual instanceof VibrationEffect.Waveform &&
1573 ((VibrationEffect.Waveform) actual).getRepeatIndex() == mRepeatIndex) {
1574 return true;
1575 }
1576 // All non-waveform effects are essentially one shots.
1577 return mRepeatIndex == -1;
1578 }
1579
1580 @Override
1581 public String toString() {
1582 return "repeatIndex=" + mRepeatIndex;
1583 }
1584 }
Chris Wren93bb8b82016-03-29 14:35:05 -04001585}