Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ea0eb5f5 authored by Jean-Michel Trivi's avatar Jean-Michel Trivi
Browse files

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
parent d2638591
Loading
Loading
Loading
Loading
+31 −12
Original line number Diff line number Diff line
@@ -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 VibrationEffect effect;
            try {
                final boolean insistent =
                        (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
            final VibrationEffect effect = VibrationEffect.createWaveform(
                effect = VibrationEffect.createWaveform(
                        vibration, insistent ? 0 : -1 /*repeatIndex*/);
            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;
            }
            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;
        } finally{
            Binder.restoreCallingIdentity(identity);
        }
+12 −5
Original line number Diff line number Diff line
@@ -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