diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java index 8ecc51b3087cd..3e364314e10f8 100644 --- a/services/core/java/com/android/server/vibrator/Vibration.java +++ b/services/core/java/com/android/server/vibrator/Vibration.java @@ -66,6 +66,7 @@ final class Vibration { IGNORED_FOR_ONGOING, IGNORED_FOR_POWER, IGNORED_FOR_RINGER_MODE, + IGNORED_FOR_RINGTONE, IGNORED_FOR_SETTINGS, IGNORED_SUPERSEDED, } diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java index bf3298558cd64..d7341cb376853 100644 --- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java +++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java @@ -733,6 +733,12 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { + attrs); } break; + case IGNORED_FOR_RINGTONE: + if (DEBUG) { + Slog.d(TAG, "Ignoring incoming vibration in favor of ringtone vibration"); + } + break; + default: if (DEBUG) { Slog.d(TAG, "Vibration for uid=" + uid + " and with attrs=" + attrs @@ -809,6 +815,10 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { return Vibration.Status.IGNORED_FOR_ALARM; } + if (currentVibration.attrs.getUsage() == VibrationAttributes.USAGE_RINGTONE) { + return Vibration.Status.IGNORED_FOR_RINGTONE; + } + if (currentVibration.isRepeating()) { return Vibration.Status.IGNORED_FOR_ONGOING; } diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java index f3d494d160f28..4fbf0065f78d7 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java @@ -602,10 +602,15 @@ public class VibratorManagerServiceTest { VibrationEffect.EFFECT_HEAVY_CLICK, VibrationEffect.EFFECT_DOUBLE_CLICK); VibratorManagerService service = createSystemReadyService(); mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE); + + // The haptic feedback should be ignored in low power, but not the ringtone. The end + // of the test asserts which actual effects ended up playing. vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_TICK), HAPTIC_FEEDBACK_ATTRS); vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), RINGTONE_ATTRS); assertTrue(waitUntil(s -> fakeVibrator.getAllEffectSegments().size() == 1, service, TEST_TIMEOUT_MILLIS)); + // Allow the ringtone to complete, as the other vibrations won't cancel it. + assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE); vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK), @@ -814,6 +819,29 @@ public class VibratorManagerServiceTest { service, /* timeout= */ 50)); } + @Test + public void vibrate_withOngoingRingtoneVibration_ignoresEffect() throws Exception { + mockVibrators(1); + mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); + VibratorManagerService service = createSystemReadyService(); + + VibrationEffect alarmEffect = VibrationEffect.createWaveform( + new long[]{10_000, 10_000}, new int[]{128, 255}, -1); + vibrate(service, alarmEffect, new VibrationAttributes.Builder().setUsage( + VibrationAttributes.USAGE_RINGTONE).build()); + + // VibrationThread will start this vibration async, so wait before checking it started. + assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(), + service, TEST_TIMEOUT_MILLIS)); + + vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), + HAPTIC_FEEDBACK_ATTRS); + + // Wait before checking it never played a second effect. + assertFalse(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() > 1, + service, /* timeout= */ 50)); + } + @Test public void vibrate_withInputDevices_vibratesInputDevices() throws Exception { mockVibrators(1);