Merge "actually cancel sounds when we get a quiet update" into nyc-dev

This commit is contained in:
Chris Wren
2016-04-01 19:58:44 +00:00
committed by Android (Google) Code Review
2 changed files with 685 additions and 98 deletions

View File

@@ -120,6 +120,7 @@ import android.view.accessibility.AccessibilityManager;
import android.widget.Toast; import android.widget.Toast;
import com.android.internal.R; import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions; import com.android.internal.util.Preconditions;
@@ -226,7 +227,7 @@ public class NotificationManagerService extends SystemService {
private VrManagerInternal mVrManagerInternal; private VrManagerInternal mVrManagerInternal;
final IBinder mForegroundToken = new Binder(); final IBinder mForegroundToken = new Binder();
private WorkerHandler mHandler; private Handler mHandler;
private final HandlerThread mRankingThread = new HandlerThread("ranker", private final HandlerThread mRankingThread = new HandlerThread("ranker",
Process.THREAD_PRIORITY_BACKGROUND); Process.THREAD_PRIORITY_BACKGROUND);
@@ -572,33 +573,9 @@ public class NotificationManagerService extends SystemService {
public void clearEffects() { public void clearEffects() {
synchronized (mNotificationList) { synchronized (mNotificationList) {
if (DBG) Slog.d(TAG, "clearEffects"); if (DBG) Slog.d(TAG, "clearEffects");
clearSoundLocked();
// sound clearVibrateLocked();
mSoundNotificationKey = null; clearLightsLocked();
long identity = Binder.clearCallingIdentity();
try {
final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
if (player != null) {
player.stopAsync();
}
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(identity);
}
// vibrate
mVibrateNotificationKey = null;
identity = Binder.clearCallingIdentity();
try {
mVibrator.cancel();
} finally {
Binder.restoreCallingIdentity(identity);
}
// light
mLights.clear();
updateLightsLocked();
} }
} }
@@ -658,6 +635,36 @@ public class NotificationManagerService extends SystemService {
} }
}; };
private void clearSoundLocked() {
mSoundNotificationKey = null;
long identity = Binder.clearCallingIdentity();
try {
final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
if (player != null) {
player.stopAsync();
}
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(identity);
}
}
private void clearVibrateLocked() {
mVibrateNotificationKey = null;
long identity = Binder.clearCallingIdentity();
try {
mVibrator.cancel();
} finally {
Binder.restoreCallingIdentity(identity);
}
}
private void clearLightsLocked() {
// light
mLights.clear();
updateLightsLocked();
}
private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() { private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
@@ -863,6 +870,26 @@ public class NotificationManagerService extends SystemService {
super(context); super(context);
} }
@VisibleForTesting
void setAudioManager(AudioManager audioMananger) {
mAudioManager = audioMananger;
}
@VisibleForTesting
void setVibrator(Vibrator vibrator) {
mVibrator = vibrator;
}
@VisibleForTesting
void setSystemReady(boolean systemReady) {
mSystemReady = systemReady;
}
@VisibleForTesting
void setHandler(Handler handler) {
mHandler = handler;
}
@Override @Override
public void onStart() { public void onStart() {
Resources resources = getContext().getResources(); Resources resources = getContext().getResources();
@@ -2492,12 +2519,14 @@ public class NotificationManagerService extends SystemService {
return false; return false;
} }
private void buzzBeepBlinkLocked(NotificationRecord record) { @VisibleForTesting
void buzzBeepBlinkLocked(NotificationRecord record) {
boolean buzz = false; boolean buzz = false;
boolean beep = false; boolean beep = false;
boolean blink = false; boolean blink = false;
final Notification notification = record.sbn.getNotification(); final Notification notification = record.sbn.getNotification();
final String key = record.getKey();
// Should this notification make noise, vibe, or use the LED? // Should this notification make noise, vibe, or use the LED?
final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT; final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT;
@@ -2521,9 +2550,15 @@ public class NotificationManagerService extends SystemService {
if (disableEffects != null) { if (disableEffects != null) {
ZenLog.traceDisableEffects(record, disableEffects); ZenLog.traceDisableEffects(record, disableEffects);
} }
// Remember if this notification already owns the notification channels.
boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
// These are set inside the conditional if the notification is allowed to make noise.
boolean hasValidVibrate = false;
boolean hasValidSound = false;
if (disableEffects == null if (disableEffects == null
&& (!(record.isUpdate
&& (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
&& (record.getUserId() == UserHandle.USER_ALL || && (record.getUserId() == UserHandle.USER_ALL ||
record.getUserId() == currentUser || record.getUserId() == currentUser ||
mUserProfiles.isCurrentProfile(record.getUserId())) mUserProfiles.isCurrentProfile(record.getUserId()))
@@ -2532,10 +2567,6 @@ public class NotificationManagerService extends SystemService {
&& mAudioManager != null) { && mAudioManager != null) {
if (DBG) Slog.v(TAG, "Interrupting!"); if (DBG) Slog.v(TAG, "Interrupting!");
sendAccessibilityEvent(notification, record.sbn.getPackageName());
// sound
// should we use the default notification sound? (indicated either by // should we use the default notification sound? (indicated either by
// DEFAULT_SOUND or because notification.sound is pointing at // DEFAULT_SOUND or because notification.sound is pointing at
// Settings.System.NOTIFICATION_SOUND) // Settings.System.NOTIFICATION_SOUND)
@@ -2545,8 +2576,6 @@ public class NotificationManagerService extends SystemService {
.equals(notification.sound); .equals(notification.sound);
Uri soundUri = null; Uri soundUri = null;
boolean hasValidSound = false;
if (useDefaultSound) { if (useDefaultSound) {
soundUri = Settings.System.DEFAULT_NOTIFICATION_URI; soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
@@ -2559,88 +2588,105 @@ public class NotificationManagerService extends SystemService {
hasValidSound = (soundUri != null); hasValidSound = (soundUri != null);
} }
if (hasValidSound) {
boolean looping =
(notification.flags & Notification.FLAG_INSISTENT) != 0;
AudioAttributes audioAttributes = audioAttributesForNotification(notification);
mSoundNotificationKey = record.getKey();
// do not play notifications if stream volume is 0 (typically because
// ringer mode is silent) or if there is a user of exclusive audio focus
if ((mAudioManager.getStreamVolume(
AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
&& !mAudioManager.isAudioFocusExclusive()) {
final long identity = Binder.clearCallingIdentity();
try {
final IRingtonePlayer player =
mAudioManager.getRingtonePlayer();
if (player != null) {
if (DBG) Slog.v(TAG, "Playing sound " + soundUri
+ " with attributes " + audioAttributes);
player.playAsync(soundUri, record.sbn.getUser(), looping,
audioAttributes);
beep = true;
}
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}
// vibrate
// Does the notification want to specify its own vibration? // Does the notification want to specify its own vibration?
final boolean hasCustomVibrate = notification.vibrate != null; final boolean hasCustomVibrate = notification.vibrate != null;
// new in 4.2: if there was supposed to be a sound and we're in vibrate // new in 4.2: if there was supposed to be a sound and we're in vibrate
// mode, and no other vibration is specified, we fall back to vibration // mode, and no other vibration is specified, we fall back to vibration
final boolean convertSoundToVibration = final boolean convertSoundToVibration =
!hasCustomVibrate !hasCustomVibrate
&& hasValidSound && hasValidSound
&& (mAudioManager.getRingerModeInternal() && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE);
== AudioManager.RINGER_MODE_VIBRATE);
// The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback. // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
final boolean useDefaultVibrate = final boolean useDefaultVibrate =
(notification.defaults & Notification.DEFAULT_VIBRATE) != 0; (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate) hasValidVibrate = useDefaultVibrate || convertSoundToVibration ||
&& !(mAudioManager.getRingerModeInternal() hasCustomVibrate;
== AudioManager.RINGER_MODE_SILENT)) {
mVibrateNotificationKey = record.getKey();
if (useDefaultVibrate || convertSoundToVibration) { // We can alert, and we're allowed to alert, but if the developer asked us to only do
// Escalate privileges so we can use the vibrator even if the // it once, and we already have, then don't.
// notifying app does not have the VIBRATE permission. if (!(record.isUpdate
long identity = Binder.clearCallingIdentity(); && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) {
try {
mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(), sendAccessibilityEvent(notification, record.sbn.getPackageName());
useDefaultVibrate ? mDefaultVibrationPattern
: mFallbackVibrationPattern, if (hasValidSound) {
((notification.flags & Notification.FLAG_INSISTENT) != 0) boolean looping =
? 0: -1, audioAttributesForNotification(notification)); (notification.flags & Notification.FLAG_INSISTENT) != 0;
buzz = true; AudioAttributes audioAttributes = audioAttributesForNotification(notification);
} finally { mSoundNotificationKey = key;
Binder.restoreCallingIdentity(identity); // do not play notifications if stream volume is 0 (typically because
// ringer mode is silent) or if there is a user of exclusive audio focus
if ((mAudioManager.getStreamVolume(
AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
&& !mAudioManager.isAudioFocusExclusive()) {
final long identity = Binder.clearCallingIdentity();
try {
final IRingtonePlayer player =
mAudioManager.getRingtonePlayer();
if (player != null) {
if (DBG) Slog.v(TAG, "Playing sound " + soundUri
+ " with attributes " + audioAttributes);
player.playAsync(soundUri, record.sbn.getUser(), looping,
audioAttributes);
beep = true;
}
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}
if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
== AudioManager.RINGER_MODE_SILENT)) {
mVibrateNotificationKey = key;
if (useDefaultVibrate || convertSoundToVibration) {
// Escalate privileges so we can use the vibrator even if the
// notifying app does not have the VIBRATE permission.
long identity = Binder.clearCallingIdentity();
try {
mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
useDefaultVibrate ? mDefaultVibrationPattern
: mFallbackVibrationPattern,
((notification.flags & Notification.FLAG_INSISTENT) != 0)
? 0: -1, audioAttributesForNotification(notification));
buzz = true;
} finally {
Binder.restoreCallingIdentity(identity);
}
} else if (notification.vibrate.length > 1) {
// If you want your own vibration pattern, you need the VIBRATE
// permission
mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
notification.vibrate,
((notification.flags & Notification.FLAG_INSISTENT) != 0)
? 0: -1, audioAttributesForNotification(notification));
buzz = true;
} }
} else if (notification.vibrate.length > 1) {
// If you want your own vibration pattern, you need the VIBRATE
// permission
mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
notification.vibrate,
((notification.flags & Notification.FLAG_INSISTENT) != 0)
? 0: -1, audioAttributesForNotification(notification));
buzz = true;
} }
} }
}
// If a notification is updated to remove the actively playing sound or vibrate,
// cancel that feedback now
if (wasBeep && !hasValidSound) {
clearSoundLocked();
}
if (wasBuzz && !hasValidVibrate) {
clearVibrateLocked();
} }
// light // light
// release the light // release the light
boolean wasShowLights = mLights.remove(record.getKey()); boolean wasShowLights = mLights.remove(key);
if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
&& ((record.getSuppressedVisualEffects() && ((record.getSuppressedVisualEffects()
& NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) { & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
mLights.add(record.getKey()); mLights.add(key);
updateLightsLocked(); updateLightsLocked();
if (mUseAttentionLight) { if (mUseAttentionLight) {
mAttentionLight.pulse(); mAttentionLight.pulse();
@@ -2654,7 +2700,7 @@ public class NotificationManagerService extends SystemService {
& NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) { & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on"); if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
} else { } else {
EventLogTags.writeNotificationAlert(record.getKey(), EventLogTags.writeNotificationAlert(key,
buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0); buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
mHandler.post(mBuzzBeepBlinked); mHandler.post(mBuzzBeepBlinked);
} }

View File

@@ -0,0 +1,541 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.notification;
import android.app.ActivityManager;
import android.app.Notification;
import android.app.Notification.Builder;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.Vibrator;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.StatusBarNotification;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class BuzzBeepBlinkTest extends AndroidTestCase {
@Mock AudioManager mAudioManager;
@Mock Vibrator mVibrator;
@Mock android.media.IRingtonePlayer mRingtonePlayer;
@Mock Handler mHandler;
private NotificationManagerService mService;
private String mPkg = "com.android.server.notification";
private int mId = 1001;
private int mOtherId = 1002;
private String mTag = null;
private int mUid = 1000;
private int mPid = 2000;
private int mScore = 10;
private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
@Override
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mAudioManager.isAudioFocusExclusive()).thenReturn(false);
when(mAudioManager.getRingtonePlayer()).thenReturn(mRingtonePlayer);
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
mService = new NotificationManagerService(getContext());
mService.setAudioManager(mAudioManager);
mService.setVibrator(mVibrator);
mService.setSystemReady(true);
mService.setHandler(mHandler);
}
//
// Convenience functions for creating notification records
//
private NotificationRecord getNoisyOtherNotification() {
return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
true /* noisy */, true /* buzzy*/);
}
private NotificationRecord getBeepyNotification() {
return getNotificationRecord(mId, false /* insistent */, false /* once */,
true /* noisy */, false /* buzzy*/);
}
private NotificationRecord getBeepyOnceNotification() {
return getNotificationRecord(mId, false /* insistent */, true /* once */,
true /* noisy */, false /* buzzy*/);
}
private NotificationRecord getQuietNotification() {
return getNotificationRecord(mId, false /* insistent */, false /* once */,
false /* noisy */, false /* buzzy*/);
}
private NotificationRecord getQuietOtherNotification() {
return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
false /* noisy */, false /* buzzy*/);
}
private NotificationRecord getQuietOnceNotification() {
return getNotificationRecord(mId, false /* insistent */, true /* once */,
false /* noisy */, false /* buzzy*/);
}
private NotificationRecord getInsistentBeepyNotification() {
return getNotificationRecord(mId, true /* insistent */, false /* once */,
true /* noisy */, false /* buzzy*/);
}
private NotificationRecord getBuzzyNotification() {
return getNotificationRecord(mId, false /* insistent */, false /* once */,
false /* noisy */, true /* buzzy*/);
}
private NotificationRecord getBuzzyOnceNotification() {
return getNotificationRecord(mId, false /* insistent */, true /* once */,
false /* noisy */, true /* buzzy*/);
}
private NotificationRecord getInsistentBuzzyNotification() {
return getNotificationRecord(mId, true /* insistent */, false /* once */,
false /* noisy */, true /* buzzy*/);
}
private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
boolean noisy, boolean buzzy) {
final Builder builder = new Builder(getContext())
.setContentTitle("foo")
.setSmallIcon(android.R.drawable.sym_def_app_icon)
.setPriority(Notification.PRIORITY_HIGH)
.setOnlyAlertOnce(once);
int defaults = 0;
if (noisy) {
defaults |= Notification.DEFAULT_SOUND;
}
if (buzzy) {
defaults |= Notification.DEFAULT_VIBRATE;
}
builder.setDefaults(defaults);
Notification n = builder.build();
if (insistent) {
n.flags |= Notification.FLAG_INSISTENT;
}
StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid, mPid,
mScore, n, mUser, System.currentTimeMillis());
return new NotificationRecord(getContext(), sbn);
}
//
// Convenience functions for interacting with mocks
//
private void verifyNeverBeep() throws RemoteException {
verify(mRingtonePlayer, never()).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
anyBoolean(), (AudioAttributes) anyObject());
}
private void verifyBeep() throws RemoteException {
verify(mRingtonePlayer, times(1)).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
eq(true), (AudioAttributes) anyObject());
}
private void verifyBeepLooped() throws RemoteException {
verify(mRingtonePlayer, times(1)).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
eq(false), (AudioAttributes) anyObject());
}
private void verifyNeverStopAudio() throws RemoteException {
verify(mRingtonePlayer, never()).stopAsync();
}
private void verifyStopAudio() throws RemoteException {
verify(mRingtonePlayer, times(1)).stopAsync();
}
private void verifyNeverVibrate() {
verify(mVibrator, never()).vibrate(anyInt(), anyString(), (long[]) anyObject(),
anyInt(), (AudioAttributes) anyObject());
}
private void verifyVibrate() {
verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), (long[]) anyObject(),
eq(-1), (AudioAttributes) anyObject());
}
private void verifyVibrateLooped() {
verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), (long[]) anyObject(),
eq(0), (AudioAttributes) anyObject());
}
private void verifyStopVibrate() {
verify(mVibrator, times(1)).cancel();
}
private void verifyNeverStopVibrate() throws RemoteException {
verify(mVibrator, never()).cancel();
}
@SmallTest
public void testBeep() throws Exception {
NotificationRecord r = getBeepyNotification();
mService.buzzBeepBlinkLocked(r);
verifyBeepLooped();
verifyNeverVibrate();
}
//
// Tests
//
@SmallTest
public void testBeepInsistently() throws Exception {
NotificationRecord r = getInsistentBeepyNotification();
mService.buzzBeepBlinkLocked(r);
verifyBeep();
}
@SmallTest
public void testNoInterruptionForMin() throws Exception {
NotificationRecord r = getBeepyNotification();
r.setImportance(Ranking.IMPORTANCE_MIN, "foo");
mService.buzzBeepBlinkLocked(r);
verifyNeverBeep();
verifyNeverVibrate();
}
@SmallTest
public void testNoInterruptionForIntercepted() throws Exception {
NotificationRecord r = getBeepyNotification();
r.setIntercepted(true);
mService.buzzBeepBlinkLocked(r);
verifyNeverBeep();
verifyNeverVibrate();
}
@SmallTest
public void testBeepTwice() throws Exception {
NotificationRecord r = getBeepyNotification();
// set up internal state
mService.buzzBeepBlinkLocked(r);
Mockito.reset(mRingtonePlayer);
// update should beep
r.isUpdate = true;
mService.buzzBeepBlinkLocked(r);
verifyBeepLooped();
}
@SmallTest
public void testHonorAlertOnlyOnceForBeep() throws Exception {
NotificationRecord r = getBeepyNotification();
NotificationRecord s = getBeepyOnceNotification();
s.isUpdate = true;
// set up internal state
mService.buzzBeepBlinkLocked(r);
Mockito.reset(mRingtonePlayer);
// update should not beep
mService.buzzBeepBlinkLocked(s);
verifyNeverBeep();
}
@SmallTest
public void testNoisyUpdateDoesNotCancelAudio() throws Exception {
NotificationRecord r = getBeepyNotification();
mService.buzzBeepBlinkLocked(r);
r.isUpdate = true;
mService.buzzBeepBlinkLocked(r);
verifyNeverStopAudio();
}
@SmallTest
public void testNoisyOnceUpdateDoesNotCancelAudio() throws Exception {
NotificationRecord r = getBeepyNotification();
NotificationRecord s = getBeepyOnceNotification();
s.isUpdate = true;
mService.buzzBeepBlinkLocked(r);
mService.buzzBeepBlinkLocked(s);
verifyNeverStopAudio();
}
@SmallTest
public void testQuietUpdateDoesNotCancelAudioFromOther() throws Exception {
NotificationRecord r = getBeepyNotification();
NotificationRecord s = getQuietNotification();
s.isUpdate = true;
NotificationRecord other = getNoisyOtherNotification();
// set up internal state
mService.buzzBeepBlinkLocked(r);
mService.buzzBeepBlinkLocked(other); // this takes the audio stream
Mockito.reset(mRingtonePlayer);
// should not stop noise, since we no longer own it
mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
verifyNeverStopAudio();
}
@SmallTest
public void testQuietInterloperDoesNotCancelAudio() throws Exception {
NotificationRecord r = getBeepyNotification();
NotificationRecord other = getQuietOtherNotification();
// set up internal state
mService.buzzBeepBlinkLocked(r);
Mockito.reset(mRingtonePlayer);
// should not stop noise, since it does not own it
mService.buzzBeepBlinkLocked(other);
verifyNeverStopAudio();
}
@SmallTest
public void testQuietUpdateCancelsAudio() throws Exception {
NotificationRecord r = getBeepyNotification();
NotificationRecord s = getQuietNotification();
s.isUpdate = true;
// set up internal state
mService.buzzBeepBlinkLocked(r);
Mockito.reset(mRingtonePlayer);
// quiet update should stop making noise
mService.buzzBeepBlinkLocked(s);
verifyStopAudio();
}
@SmallTest
public void testQuietOnceUpdateCancelsAudio() throws Exception {
NotificationRecord r = getBeepyNotification();
NotificationRecord s = getQuietOnceNotification();
s.isUpdate = true;
// set up internal state
mService.buzzBeepBlinkLocked(r);
Mockito.reset(mRingtonePlayer);
// stop making noise - this is a weird corner case, but quiet should override once
mService.buzzBeepBlinkLocked(s);
verifyStopAudio();
}
@SmallTest
public void testDemoteSoundToVibrate() throws Exception {
NotificationRecord r = getBeepyNotification();
// the phone is quiet
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
mService.buzzBeepBlinkLocked(r);
verifyNeverBeep();
verifyVibrate();
}
@SmallTest
public void testDemotInsistenteSoundToVibrate() throws Exception {
NotificationRecord r = getInsistentBeepyNotification();
// the phone is quiet
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
mService.buzzBeepBlinkLocked(r);
verifyVibrateLooped();
}
@SmallTest
public void testVibrate() throws Exception {
NotificationRecord r = getBuzzyNotification();
mService.buzzBeepBlinkLocked(r);
verifyNeverBeep();
verifyVibrate();
}
@SmallTest
public void testInsistenteVibrate() throws Exception {
NotificationRecord r = getInsistentBuzzyNotification();
mService.buzzBeepBlinkLocked(r);
verifyVibrateLooped();
}
@SmallTest
public void testVibratTwice() throws Exception {
NotificationRecord r = getBuzzyNotification();
// set up internal state
mService.buzzBeepBlinkLocked(r);
Mockito.reset(mVibrator);
// update should vibrate
r.isUpdate = true;
mService.buzzBeepBlinkLocked(r);
verifyVibrate();
}
@SmallTest
public void testHonorAlertOnlyOnceForBuzz() throws Exception {
NotificationRecord r = getBuzzyNotification();
NotificationRecord s = getBuzzyOnceNotification();
s.isUpdate = true;
// set up internal state
mService.buzzBeepBlinkLocked(r);
Mockito.reset(mVibrator);
// update should not beep
mService.buzzBeepBlinkLocked(s);
verifyNeverVibrate();
}
@SmallTest
public void testNoisyUpdateDoesNotCancelVibrate() throws Exception {
NotificationRecord r = getBuzzyNotification();
mService.buzzBeepBlinkLocked(r);
r.isUpdate = true;
mService.buzzBeepBlinkLocked(r);
verifyNeverStopVibrate();
}
@SmallTest
public void testNoisyOnceUpdateDoesNotCancelVibrate() throws Exception {
NotificationRecord r = getBuzzyNotification();
NotificationRecord s = getBuzzyOnceNotification();
s.isUpdate = true;
mService.buzzBeepBlinkLocked(r);
mService.buzzBeepBlinkLocked(s);
verifyNeverStopVibrate();
}
@SmallTest
public void testQuietUpdateDoesNotCancelVibrateFromOther() throws Exception {
NotificationRecord r = getBuzzyNotification();
NotificationRecord s = getQuietNotification();
s.isUpdate = true;
NotificationRecord other = getNoisyOtherNotification();
// set up internal state
mService.buzzBeepBlinkLocked(r);
mService.buzzBeepBlinkLocked(other); // this takes the vibrate stream
Mockito.reset(mVibrator);
// should not stop vibrate, since we no longer own it
mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
verifyNeverStopVibrate();
}
@SmallTest
public void testQuietInterloperDoesNotCancelVibrate() throws Exception {
NotificationRecord r = getBuzzyNotification();
NotificationRecord other = getQuietOtherNotification();
// set up internal state
mService.buzzBeepBlinkLocked(r);
Mockito.reset(mVibrator);
// should not stop noise, since it does not own it
mService.buzzBeepBlinkLocked(other);
verifyNeverStopVibrate();
}
@SmallTest
public void testQuietUpdateCancelsVibrate() throws Exception {
NotificationRecord r = getBuzzyNotification();
NotificationRecord s = getQuietNotification();
s.isUpdate = true;
// set up internal state
mService.buzzBeepBlinkLocked(r);
// quiet update should stop making noise
mService.buzzBeepBlinkLocked(s);
verifyStopVibrate();
}
@SmallTest
public void testQuietOnceUpdateCancelsvibrate() throws Exception {
NotificationRecord r = getBuzzyNotification();
NotificationRecord s = getQuietOnceNotification();
s.isUpdate = true;
// set up internal state
mService.buzzBeepBlinkLocked(r);
Mockito.reset(mVibrator);
// stop making noise - this is a weird corner case, but quiet should override once
mService.buzzBeepBlinkLocked(s);
verifyStopVibrate();
}
@SmallTest
public void testQuietUpdateCancelsDemotedVibrate() throws Exception {
NotificationRecord r = getBeepyNotification();
NotificationRecord s = getQuietNotification();
// the phone is quiet
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
mService.buzzBeepBlinkLocked(r);
// quiet update should stop making noise
mService.buzzBeepBlinkLocked(s);
verifyStopVibrate();
}
}