diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java index b1d6050f82c2d..6bd7198f3c5b5 100644 --- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java +++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java @@ -603,11 +603,20 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { // Repeating vibrations always take precedence. return null; } - if (mCurrentVibration != null && mCurrentVibration.getVibration().isRepeating()) { - if (DEBUG) { - Slog.d(TAG, "Ignoring incoming vibration in favor of previous alarm vibration"); + if (mCurrentVibration != null) { + if (mCurrentVibration.getVibration().attrs.getUsage() + == VibrationAttributes.USAGE_ALARM) { + if (DEBUG) { + Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration"); + } + return Vibration.Status.IGNORED_FOR_ALARM; + } + if (mCurrentVibration.getVibration().isRepeating()) { + if (DEBUG) { + Slog.d(TAG, "Ignoring incoming vibration in favor of repeating vibration"); + } + return Vibration.Status.IGNORED_FOR_ONGOING; } - return Vibration.Status.IGNORED_FOR_ALARM; } return null; } 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 12ced388d5f77..b0e8ef0bdffe4 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java @@ -565,6 +565,54 @@ public class VibratorManagerServiceTest { eq(AudioAttributes.USAGE_UNKNOWN), anyInt(), anyString()); } + @Test + public void vibrate_withOngoingRepeatingVibration_ignoresEffect() throws Exception { + mockVibrators(1); + mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); + VibratorManagerService service = createSystemReadyService(); + + VibrationEffect repeatingEffect = VibrationEffect.createWaveform( + new long[]{10_000, 10_000}, new int[]{128, 255}, 1); + vibrate(service, repeatingEffect, new VibrationAttributes.Builder().setUsage( + VibrationAttributes.USAGE_UNKNOWN).build()); + + // VibrationThread will start this vibration async, so wait before checking it started. + assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getEffectSegments().isEmpty(), + service, TEST_TIMEOUT_MILLIS)); + + vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), + new VibrationAttributes.Builder().setUsage( + VibrationAttributes.USAGE_TOUCH).build()); + + // Wait before checking it never played a second effect. + assertFalse(waitUntil(s -> mVibratorProviders.get(1).getEffectSegments().size() > 1, + service, /* timeout= */ 50)); + } + + @Test + public void vibrate_withOngoingAlarmVibration_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_ALARM).build()); + + // VibrationThread will start this vibration async, so wait before checking it started. + assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getEffectSegments().isEmpty(), + service, TEST_TIMEOUT_MILLIS)); + + vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), + new VibrationAttributes.Builder().setUsage( + VibrationAttributes.USAGE_TOUCH).build()); + + // Wait before checking it never played a second effect. + assertFalse(waitUntil(s -> mVibratorProviders.get(1).getEffectSegments().size() > 1, + service, /* timeout= */ 50)); + } + @Test public void vibrate_withInputDevices_vibratesInputDevices() throws Exception { mockVibrators(1); @@ -761,22 +809,22 @@ public class VibratorManagerServiceTest { fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK); VibratorManagerService service = createSystemReadyService(); - vibrate(service, CombinedVibrationEffect.startSynced() - .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK)) - .combine(), ALARM_ATTRS); - assertTrue(waitUntil(s -> fakeVibrator.getEffectSegments().size() == 1, - service, TEST_TIMEOUT_MILLIS)); - vibrate(service, CombinedVibrationEffect.startSequential() .addNext(1, VibrationEffect.createOneShot(20, 100)) .combine(), NOTIFICATION_ATTRS); - assertTrue(waitUntil(s -> fakeVibrator.getEffectSegments().size() == 2, + assertTrue(waitUntil(s -> fakeVibrator.getEffectSegments().size() == 1, service, TEST_TIMEOUT_MILLIS)); vibrate(service, VibrationEffect.startComposition() .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f) .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f) .compose(), HAPTIC_FEEDBACK_ATTRS); + assertTrue(waitUntil(s -> fakeVibrator.getEffectSegments().size() == 3, + service, TEST_TIMEOUT_MILLIS)); + + vibrate(service, CombinedVibrationEffect.startSynced() + .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK)) + .combine(), ALARM_ATTRS); assertTrue(waitUntil(s -> fakeVibrator.getEffectSegments().size() == 4, service, TEST_TIMEOUT_MILLIS)); @@ -785,17 +833,17 @@ public class VibratorManagerServiceTest { assertEquals(4, fakeVibrator.getEffectSegments().size()); assertEquals(1, fakeVibrator.getAmplitudes().size()); - // Alarm vibration is always VIBRATION_INTENSITY_HIGH. - PrebakedSegment expected = new PrebakedSegment( - VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_STRONG); - assertEquals(expected, fakeVibrator.getEffectSegments().get(0)); - // Notification vibrations will be scaled with SCALE_VERY_HIGH. assertTrue(0.6 < fakeVibrator.getAmplitudes().get(0)); // Haptic feedback vibrations will be scaled with SCALE_LOW. - assertTrue(0.5 < ((PrimitiveSegment) fakeVibrator.getEffectSegments().get(2)).getScale()); - assertTrue(0.5 > ((PrimitiveSegment) fakeVibrator.getEffectSegments().get(3)).getScale()); + assertTrue(0.5 < ((PrimitiveSegment) fakeVibrator.getEffectSegments().get(1)).getScale()); + assertTrue(0.5 > ((PrimitiveSegment) fakeVibrator.getEffectSegments().get(2)).getScale()); + + // Alarm vibration is always VIBRATION_INTENSITY_HIGH. + PrebakedSegment expected = new PrebakedSegment( + VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_STRONG); + assertEquals(expected, fakeVibrator.getEffectSegments().get(3)); // Ring vibrations have intensity OFF and are not played. }