Merge "Fix ordering issue with vibration" into qt-dev
diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java
index b5ff31d..2909b72 100644
--- a/src/com/android/server/telecom/Ringer.java
+++ b/src/com/android/server/telecom/Ringer.java
@@ -146,6 +146,8 @@
      */
     private CompletableFuture<Void> mBlockOnRingingFuture = null;
 
+    private CompletableFuture<Void> mVibrateFuture = CompletableFuture.completedFuture(null);
+
     private InCallTonePlayer mCallWaitingPlayer;
     private RingtoneFactory mRingtoneFactory;
 
@@ -324,8 +326,7 @@
         }
 
         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 @@
                 }
             });
             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 @@
 
         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();
diff --git a/tests/src/com/android/server/telecom/tests/RingerTest.java b/tests/src/com/android/server/telecom/tests/RingerTest.java
index 5434acc..75e89bc 100644
--- a/tests/src/com/android/server/telecom/tests/RingerTest.java
+++ b/tests/src/com/android/server/telecom/tests/RingerTest.java
@@ -24,6 +24,7 @@
 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;
@@ -302,6 +303,31 @@
 
     @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 {
         mRingerUnderTest.startCallWaiting(mockCall1);
         Ringtone mockRingtone = mock(Ringtone.class);