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

Commit f430e0a9 authored by Hall Liu's avatar Hall Liu
Browse files

Fix ordering issue with vibration

When someone calls stopRinging, also cancel the pending
completablefuture that's supported to start vibration.

Prior to this change, if a user picked up a call really quickly before
the haptics lookup had a chance to complete, stopRinging would get
called before the vibration even started. Then, when the haptics lookup
completes, it'll trigger the vibration to start. With nothing to stop
it, the vibration will continue until the user reboots the device or
receives another call.

Fixes: 134833743
Test: unit, manual
Change-Id: I6968a1ed0693e0eb839b3d9be032d5bed9525f77
parent 92d32918
Loading
Loading
Loading
Loading
+10 −6
Original line number Diff line number Diff line
@@ -146,6 +146,8 @@ public class Ringer {
     */
    private CompletableFuture<Void> mBlockOnRingingFuture = null;

    private CompletableFuture<Void> mVibrateFuture = CompletableFuture.completedFuture(null);

    private InCallTonePlayer mCallWaitingPlayer;
    private RingtoneFactory mRingtoneFactory;

@@ -324,8 +326,7 @@ public class Ringer {
        }

        if (hapticsFuture != null) {
            CompletableFuture<Void> vibrateFuture =
                    hapticsFuture.thenAccept(isUsingAudioCoupledHaptics -> {
           mVibrateFuture = hapticsFuture.thenAccept(isUsingAudioCoupledHaptics -> {
                if (!isUsingAudioCoupledHaptics || !mIsHapticPlaybackSupportedByDevice) {
                    Log.i(this, "startRinging: fileHasHaptics=%b, hapticsSupported=%b",
                            isUsingAudioCoupledHaptics, mIsHapticPlaybackSupportedByDevice);
@@ -337,10 +338,7 @@ public class Ringer {
                }
            });
            if (mBlockOnRingingFuture != null) {
                vibrateFuture.thenCompose( v -> {
                    mBlockOnRingingFuture.complete(null);
                    return null;
                });
                mVibrateFuture.whenComplete((v, e) -> mBlockOnRingingFuture.complete(null));
            }
        } else {
            if (mBlockOnRingingFuture != null) {
@@ -438,6 +436,12 @@ public class Ringer {

        mRingtonePlayer.stop();

        // If we haven't started vibrating because we were waiting for the haptics info, cancel
        // it and don't vibrate at all.
        if (mVibrateFuture != null) {
            mVibrateFuture.cancel(true);
        }

        if (mIsVibrating) {
            Log.addEvent(mVibratingCall, LogUtils.Events.STOP_VIBRATOR);
            mVibrator.cancel();
+26 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.media.Ringtone;
import android.media.VolumeShaper;
import android.net.Uri;
import android.os.Bundle;
import android.os.Looper;
import android.os.Parcel;
import android.os.VibrationEffect;
import android.os.Vibrator;
@@ -300,6 +301,31 @@ public class RingerTest extends TelecomTestCase {
                any(AudioAttributes.class));
    }

    @SmallTest
    @Test
    public void testStopRingingBeforeHapticsLookupComplete() throws Exception {
        enableVibrationWhenRinging();
        Ringtone mockRingtone = mock(Ringtone.class);
        when(mockRingtoneFactory.getRingtone(nullable(Call.class))).thenReturn(mockRingtone);
        when(mockAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);

        mRingerUnderTest.startRinging(mockCall1, false);
        // Make sure we haven't started the vibrator yet, but have started ringing.
        verify(mockRingtonePlayer).play(nullable(RingtoneFactory.class), nullable(Call.class),
                nullable(VolumeShaper.Configuration.class), anyBoolean());
        verify(mockVibrator, never()).vibrate(nullable(VibrationEffect.class),
                nullable(AudioAttributes.class));
        // Simulate something stopping the ringer
        mRingerUnderTest.stopRinging();
        verify(mockRingtonePlayer).stop();
        verify(mockVibrator, never()).cancel();
        // Simulate the haptics computation finishing
        mFuture.complete(false);
        // Then make sure that we don't actually start vibrating.
        verify(mockVibrator, never()).vibrate(nullable(VibrationEffect.class),
                nullable(AudioAttributes.class));
    }

    @SmallTest
    @Test
    public void testCustomVibrationForRingtone() throws Exception {