Delay notification vibration to synchronize with notif sound
Delay the vibration associated with a notification by the length of the ramp time preceding a notification sound. Do this only for notifications that play a sound. Tests: verify that calls to Vibrator.vibrate() method are within the max delay that could be applied to a notification sound/vibration. Test: play notification with vibration, verify vibration syncs with sound Test: runtest systemui-notification Bug: 35152866 Change-Id: I571eb5620d654265d19f45aca2073e8ccc4799df
This commit is contained in:
@@ -3714,7 +3714,7 @@ public class NotificationManagerService extends SystemService {
|
||||
if (!mInCall && hasValidVibrate && !ringerModeSilent) {
|
||||
mVibrateNotificationKey = key;
|
||||
|
||||
buzz = playVibration(record, vibration);
|
||||
buzz = playVibration(record, vibration, hasValidSound);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3788,22 +3788,41 @@ public class NotificationManagerService extends SystemService {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean playVibration(final NotificationRecord record, long[] vibration) {
|
||||
private boolean playVibration(final NotificationRecord record, long[] vibration,
|
||||
boolean delayVibForSound) {
|
||||
// Escalate privileges so we can use the vibrator even if the
|
||||
// notifying app does not have the VIBRATE permission.
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
final boolean insistent =
|
||||
(record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
|
||||
final VibrationEffect effect = VibrationEffect.createWaveform(
|
||||
vibration, insistent ? 0 : -1 /*repeatIndex*/);
|
||||
mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
|
||||
effect, record.getAudioAttributes());
|
||||
final VibrationEffect effect;
|
||||
try {
|
||||
final boolean insistent =
|
||||
(record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
|
||||
effect = VibrationEffect.createWaveform(
|
||||
vibration, insistent ? 0 : -1 /*repeatIndex*/);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Slog.e(TAG, "Error creating vibration waveform with pattern: " +
|
||||
Arrays.toString(vibration));
|
||||
return false;
|
||||
}
|
||||
if (delayVibForSound) {
|
||||
new Thread(() -> {
|
||||
// delay the vibration by the same amount as the notification sound
|
||||
final int waitMs = mAudioManager.getFocusRampTimeMs(
|
||||
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
|
||||
record.getAudioAttributes());
|
||||
if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
|
||||
try {
|
||||
Thread.sleep(waitMs);
|
||||
} catch (InterruptedException e) { }
|
||||
mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
|
||||
effect, record.getAudioAttributes());
|
||||
}).start();
|
||||
} else {
|
||||
mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
|
||||
effect, record.getAudioAttributes());
|
||||
}
|
||||
return true;
|
||||
} catch (IllegalArgumentException e) {
|
||||
Slog.e(TAG, "Error creating vibration waveform with pattern: " +
|
||||
Arrays.toString(vibration));
|
||||
return false;
|
||||
} finally{
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.argThat;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.timeout;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -102,6 +103,7 @@ public class BuzzBeepBlinkTest extends NotificationTestCase {
|
||||
private static final long[] FALLBACK_VIBRATION_PATTERN = new long[] {100, 100, 100};
|
||||
private static final VibrationEffect FALLBACK_VIBRATION =
|
||||
VibrationEffect.createWaveform(FALLBACK_VIBRATION_PATTERN, -1);
|
||||
private static final int MAX_VIBRATION_DELAY = 1000;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -309,6 +311,11 @@ public class BuzzBeepBlinkTest extends NotificationTestCase {
|
||||
(AudioAttributes) anyObject());
|
||||
}
|
||||
|
||||
private void verifyDelayedVibrateLooped() {
|
||||
verify(mVibrator, timeout(MAX_VIBRATION_DELAY).times(1)).vibrate(anyInt(), anyString(),
|
||||
argThat(mVibrateLoopMatcher), (AudioAttributes) anyObject());
|
||||
}
|
||||
|
||||
private void verifyStopVibrate() {
|
||||
verify(mVibrator, times(1)).cancel();
|
||||
}
|
||||
@@ -506,8 +513,8 @@ public class BuzzBeepBlinkTest extends NotificationTestCase {
|
||||
|
||||
VibrationEffect effect = VibrationEffect.createWaveform(r.getVibration(), -1);
|
||||
|
||||
verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), eq(effect),
|
||||
(AudioAttributes) anyObject());
|
||||
verify(mVibrator, timeout(MAX_VIBRATION_DELAY).times(1)).vibrate(anyInt(), anyString(),
|
||||
eq(effect), (AudioAttributes) anyObject());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -521,8 +528,8 @@ public class BuzzBeepBlinkTest extends NotificationTestCase {
|
||||
|
||||
mService.buzzBeepBlinkLocked(r);
|
||||
|
||||
verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), eq(FALLBACK_VIBRATION),
|
||||
(AudioAttributes) anyObject());
|
||||
verify(mVibrator, timeout(MAX_VIBRATION_DELAY).times(1)).vibrate(anyInt(), anyString(),
|
||||
eq(FALLBACK_VIBRATION), (AudioAttributes) anyObject());
|
||||
verify(mRingtonePlayer, never()).playAsync
|
||||
(anyObject(), anyObject(), anyBoolean(), anyObject());
|
||||
}
|
||||
@@ -539,7 +546,7 @@ public class BuzzBeepBlinkTest extends NotificationTestCase {
|
||||
|
||||
mService.buzzBeepBlinkLocked(r);
|
||||
|
||||
verifyVibrateLooped();
|
||||
verifyDelayedVibrateLooped();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user