Fix vibration patterns with zero duration steps.
Removing steps with zero duration in the vibration pattern to prevent cases where it becomes un-synced with the requested vibration. Bug: 287549459 Test: com.android.server.vibrator.VibrationThreadTest Change-Id: I49874c64e8fe0f0a31adca023fe7273e32149a9b
This commit is contained in:
@@ -179,7 +179,9 @@ final class SetAmplitudeVibratorStep extends AbstractVibratorStep {
|
|||||||
while (i < segmentCount) {
|
while (i < segmentCount) {
|
||||||
VibrationEffectSegment segment = segments.get(i);
|
VibrationEffectSegment segment = segments.get(i);
|
||||||
if (!(segment instanceof StepSegment)
|
if (!(segment instanceof StepSegment)
|
||||||
|| ((StepSegment) segment).getAmplitude() == 0) {
|
// play() will ignore segments with zero duration, so it's important that
|
||||||
|
// zero-duration segments don't affect this method.
|
||||||
|
|| (segment.getDuration() > 0 && ((StepSegment) segment).getAmplitude() == 0)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
timing += segment.getDuration();
|
timing += segment.getDuration();
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ package com.android.server.vibrator;
|
|||||||
import static android.os.VibrationEffect.VibrationParameter.targetAmplitude;
|
import static android.os.VibrationEffect.VibrationParameter.targetAmplitude;
|
||||||
import static android.os.VibrationEffect.VibrationParameter.targetFrequency;
|
import static android.os.VibrationEffect.VibrationParameter.targetFrequency;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
@@ -304,6 +306,80 @@ public class VibrationThreadTest {
|
|||||||
fakeVibrator.getEffectSegments(vibrationId));
|
fakeVibrator.getEffectSegments(vibrationId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void vibrate_singleVibratorPatternWithZeroDurationSteps_skipsZeroDurationSteps() {
|
||||||
|
mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
|
||||||
|
|
||||||
|
VibrationEffect effect = VibrationEffect.createWaveform(
|
||||||
|
/* timings= */ new long[]{0, 100, 50, 100, 0, 0, 0, 50}, /* repeat= */ -1);
|
||||||
|
VibrationStepConductor conductor = startThreadAndDispatcher(effect);
|
||||||
|
long vibrationId = conductor.getVibration().id;
|
||||||
|
waitForCompletion();
|
||||||
|
|
||||||
|
verify(mManagerHooks).noteVibratorOn(eq(UID), eq(300L));
|
||||||
|
verify(mManagerHooks).noteVibratorOff(eq(UID));
|
||||||
|
|
||||||
|
verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
|
||||||
|
assertThat(mControllers.get(VIBRATOR_ID).isVibrating()).isFalse();
|
||||||
|
|
||||||
|
assertThat(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibrationId))
|
||||||
|
.isEqualTo(expectedOneShots(100L, 150L));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void vibrate_singleVibratorPatternWithZeroDurationAndAmplitude_skipsZeroDurationSteps() {
|
||||||
|
mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
|
||||||
|
|
||||||
|
int[] amplitudes = new int[]{1, 2, 0, 3, 4, 5, 0, 6};
|
||||||
|
VibrationEffect effect = VibrationEffect.createWaveform(
|
||||||
|
/* timings= */ new long[]{0, 100, 0, 50, 50, 0, 100, 50}, amplitudes,
|
||||||
|
/* repeat= */ -1);
|
||||||
|
VibrationStepConductor conductor = startThreadAndDispatcher(effect);
|
||||||
|
long vibrationId = conductor.getVibration().id;
|
||||||
|
waitForCompletion();
|
||||||
|
|
||||||
|
verify(mManagerHooks).noteVibratorOn(eq(UID), eq(350L));
|
||||||
|
verify(mManagerHooks).noteVibratorOff(eq(UID));
|
||||||
|
|
||||||
|
verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
|
||||||
|
assertThat(mControllers.get(VIBRATOR_ID).isVibrating()).isFalse();
|
||||||
|
|
||||||
|
assertThat(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibrationId))
|
||||||
|
.isEqualTo(expectedOneShots(200L, 50L));
|
||||||
|
}
|
||||||
|
|
||||||
|
@LargeTest
|
||||||
|
@Test
|
||||||
|
public void vibrate_singleVibratorRepeatingPatternWithZeroDurationSteps_repeatsEffectCorrectly()
|
||||||
|
throws Exception {
|
||||||
|
FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
|
||||||
|
fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
|
||||||
|
|
||||||
|
VibrationEffect effect = VibrationEffect.createWaveform(
|
||||||
|
/* timings= */ new long[]{0, 200, 50, 100, 0, 50, 50, 100}, /* repeat= */ 0);
|
||||||
|
VibrationStepConductor conductor = startThreadAndDispatcher(effect);
|
||||||
|
long vibrationId = conductor.getVibration().id;
|
||||||
|
// We are expect this test to repeat the vibration effect twice, which would result in 5
|
||||||
|
// segments being played:
|
||||||
|
// 200ms ON
|
||||||
|
// 150ms ON (100ms + 50ms, skips 0ms)
|
||||||
|
// 300ms ON (100ms + 200ms looping to the start and skipping first 0ms)
|
||||||
|
// 150ms ON (100ms + 50ms, skips 0ms)
|
||||||
|
// 300ms ON (100ms + 200ms looping to the start and skipping first 0ms)
|
||||||
|
assertTrue(waitUntil(() -> fakeVibrator.getEffectSegments(vibrationId).size() >= 5,
|
||||||
|
5000L + TEST_TIMEOUT_MILLIS));
|
||||||
|
conductor.notifyCancelled(
|
||||||
|
new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_USER),
|
||||||
|
/* immediate= */ false);
|
||||||
|
waitForCompletion();
|
||||||
|
|
||||||
|
verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_USER);
|
||||||
|
assertThat(mControllers.get(VIBRATOR_ID).isVibrating()).isFalse();
|
||||||
|
|
||||||
|
assertThat(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibrationId).subList(0, 5))
|
||||||
|
.isEqualTo(expectedOneShots(200L, 150L, 300L, 150L, 300L));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void vibrate_singleVibratorRepeatingPwle_generatesLargestPwles() throws Exception {
|
public void vibrate_singleVibratorRepeatingPwle_generatesLargestPwles() throws Exception {
|
||||||
FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
|
FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
|
||||||
@@ -1640,6 +1716,12 @@ public class VibrationThreadTest {
|
|||||||
/* frequencyHz= */ 0, (int) millis);
|
/* frequencyHz= */ 0, (int) millis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<VibrationEffectSegment> expectedOneShots(long... millis) {
|
||||||
|
return Arrays.stream(millis)
|
||||||
|
.mapToObj(this::expectedOneShot)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
private VibrationEffectSegment expectedPrebaked(int effectId) {
|
private VibrationEffectSegment expectedPrebaked(int effectId) {
|
||||||
return new PrebakedSegment(effectId, false, VibrationEffect.EFFECT_STRENGTH_MEDIUM);
|
return new PrebakedSegment(effectId, false, VibrationEffect.EFFECT_STRENGTH_MEDIUM);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user