Loading services/core/java/com/android/server/vibrator/DeviceVibrationEffectAdapter.java +78 −6 Original line number Diff line number Diff line Loading @@ -26,11 +26,14 @@ import android.util.MathUtils; import android.util.Range; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** Adapts a {@link VibrationEffect} to a specific device, taking into account its capabilities. */ final class DeviceVibrationEffectAdapter implements VibrationEffectModifier<VibratorInfo> { private static final int RAMP_STEP_DURATION_MILLIS = 5; /** Adapts a sequence of {@link VibrationEffectSegment} to device's capabilities. */ interface SegmentsAdapter { Loading @@ -38,16 +41,17 @@ final class DeviceVibrationEffectAdapter implements VibrationEffectModifier<Vibr * Modifies the given segments list by adding/removing segments to it based on the * device capabilities specified by given {@link VibratorInfo}. * * @param segments List of {@link VibrationEffectSegment} to be adapter to the device. * @param repeatIndex Repeat index on the current segment list. * @param segments List of {@link VibrationEffectSegment} to be modified. * @param repeatIndex Repeat index of the vibration with given segment list. * @param info The device vibrator info that the segments must be adapted to. * @return The new repeat index on the modifies list. * @return The new repeat index to be used for the modified list. */ int apply(List<VibrationEffectSegment> segments, int repeatIndex, VibratorInfo info); } private final SegmentsAdapter mAmplitudeFrequencyAdapter; private final SegmentsAdapter mStepToRampAdapter; private final SegmentsAdapter mRampToStepsAdapter; DeviceVibrationEffectAdapter() { this(new ClippingAmplitudeFrequencyAdapter()); Loading @@ -56,6 +60,7 @@ final class DeviceVibrationEffectAdapter implements VibrationEffectModifier<Vibr DeviceVibrationEffectAdapter(SegmentsAdapter amplitudeFrequencyAdapter) { mAmplitudeFrequencyAdapter = amplitudeFrequencyAdapter; mStepToRampAdapter = new StepToRampAdapter(); mRampToStepsAdapter = new RampToStepsAdapter(RAMP_STEP_DURATION_MILLIS); } @Override Loading @@ -68,7 +73,10 @@ final class DeviceVibrationEffectAdapter implements VibrationEffectModifier<Vibr List<VibrationEffectSegment> newSegments = new ArrayList<>(composed.getSegments()); int newRepeatIndex = composed.getRepeatIndex(); // Maps steps that should be handled by PWLE to ramps. // Replace ramps with a sequence of fixed steps, or no-op if PWLE capability present. newRepeatIndex = mRampToStepsAdapter.apply(newSegments, newRepeatIndex, info); // Replace steps that should be handled by PWLE to ramps, or no-op if capability missing. // This should be done before frequency is converted from relative to absolute values. newRepeatIndex = mStepToRampAdapter.apply(newSegments, newRepeatIndex, info); Loading @@ -76,7 +84,6 @@ final class DeviceVibrationEffectAdapter implements VibrationEffectModifier<Vibr // to absolute values in Hertz. newRepeatIndex = mAmplitudeFrequencyAdapter.apply(newSegments, newRepeatIndex, info); // TODO(b/167947076): add ramp to step adapter // TODO(b/167947076): add filter that removes unsupported primitives // TODO(b/167947076): add filter that replaces unsupported prebaked with fallback Loading @@ -86,7 +93,7 @@ final class DeviceVibrationEffectAdapter implements VibrationEffectModifier<Vibr /** * Adapter that converts step segments that should be handled as PWLEs to ramp segments. * * <p>This leves the list unchanged if the device do not have compose PWLE capability. * <p>This leaves the list unchanged if the device do not have compose PWLE capability. */ private static final class StepToRampAdapter implements SegmentsAdapter { @Override Loading Loading @@ -123,6 +130,71 @@ final class DeviceVibrationEffectAdapter implements VibrationEffectModifier<Vibr } } /** * Adapter that converts ramp segments that to a sequence of fixed step segments. * * <p>This leaves the list unchanged if the device have compose PWLE capability. */ private static final class RampToStepsAdapter implements SegmentsAdapter { private final int mStepDuration; RampToStepsAdapter(int stepDuration) { mStepDuration = stepDuration; } @Override public int apply(List<VibrationEffectSegment> segments, int repeatIndex, VibratorInfo info) { if (info.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) { // The vibrator have PWLE capability, so keep the segments unchanged. return repeatIndex; } int segmentCount = segments.size(); for (int i = 0; i < segmentCount; i++) { VibrationEffectSegment segment = segments.get(i); if (!(segment instanceof RampSegment)) { continue; } List<StepSegment> steps = apply((RampSegment) segment); segments.remove(i); segments.addAll(i, steps); int addedSegments = steps.size() - 1; if (repeatIndex > i) { repeatIndex += addedSegments; } i += addedSegments; segmentCount += addedSegments; } return repeatIndex; } private List<StepSegment> apply(RampSegment ramp) { if (Float.compare(ramp.getStartAmplitude(), ramp.getEndAmplitude()) == 0) { // Amplitude is the same, so return a single step to simulate this ramp. return Arrays.asList( new StepSegment(ramp.getStartAmplitude(), ramp.getStartFrequency(), (int) ramp.getDuration())); } List<StepSegment> steps = new ArrayList<>(); int stepCount = (int) (ramp.getDuration() + mStepDuration - 1) / mStepDuration; for (int i = 0; i < stepCount - 1; i++) { float pos = (float) i / stepCount; steps.add(new StepSegment( interpolate(ramp.getStartAmplitude(), ramp.getEndAmplitude(), pos), interpolate(ramp.getStartFrequency(), ramp.getEndFrequency(), pos), mStepDuration)); } int duration = (int) ramp.getDuration() - mStepDuration * (stepCount - 1); steps.add(new StepSegment(ramp.getEndAmplitude(), ramp.getEndFrequency(), duration)); return steps; } private static float interpolate(float start, float end, float position) { return start + position * (end - start); } } /** * Adapter that clips frequency values to {@link VibratorInfo#getFrequencyRange()} and * amplitude values to respective {@link VibratorInfo#getMaxAmplitude}. Loading services/tests/servicestests/src/com/android/server/vibrator/DeviceVibrationEffectAdapterTest.java +51 −8 Original line number Diff line number Diff line Loading @@ -76,6 +76,38 @@ public class DeviceVibrationEffectAdapterTest { assertEquals(effect, mAdapter.apply(effect, createVibratorInfo(TEST_FREQUENCY_MAPPING))); } @Test public void testStepAndRampSegments_withoutPwleCapability_convertsRampsToSteps() { VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList( new StepSegment(/* amplitude= */ 0, /* frequency= */ 1, /* duration= */ 10), new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 100), new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 0.2f, /* startFrequency= */ -4, /* endFrequency= */ 2, /* duration= */ 10), new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.2f, /* startFrequency= */ 0, /* endFrequency= */ 0, /* duration= */ 11), new RampSegment(/* startAmplitude= */ 0.65f, /* endAmplitude= */ 0.65f, /* startFrequency= */ 0, /* endFrequency= */ 1, /* duration= */ 200)), /* repeatIndex= */ 3); VibrationEffect.Composed expected = new VibrationEffect.Composed(Arrays.asList( new StepSegment(/* amplitude= */ 0, Float.NaN, /* duration= */ 10), new StepSegment(/* amplitude= */ 0.5f, Float.NaN, /* duration= */ 100), // 10ms ramp becomes 2 steps new StepSegment(/* amplitude= */ 1, Float.NaN, /* duration= */ 5), new StepSegment(/* amplitude= */ 0.2f, Float.NaN, /* duration= */ 5), // 11ms ramp becomes 3 steps new StepSegment(/* amplitude= */ 0.8f, Float.NaN, /* duration= */ 5), new StepSegment(/* amplitude= */ 0.6f, Float.NaN, /* duration= */ 5), new StepSegment(/* amplitude= */ 0.2f, Float.NaN, /* duration= */ 1), // 200ms ramp with same amplitude becomes a single step new StepSegment(/* amplitude= */ 0.65f, Float.NaN, /* duration= */ 200)), // Repeat index fixed after intermediate steps added /* repeatIndex= */ 4); VibratorInfo info = createVibratorInfo(EMPTY_FREQUENCY_MAPPING); assertEquals(expected, mAdapter.apply(effect, info)); } @Test public void testStepAndRampSegments_withPwleCapability_convertsStepsToRamps() { VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList( Loading Loading @@ -131,7 +163,7 @@ public class DeviceVibrationEffectAdapterTest { } @Test public void testStepAndRampSegments_emptyMapping_returnsSameAmplitudesAndFrequencyZero() { public void testStepAndRampSegments_withEmptyFreqMapping_returnsSameAmplitudesAndZeroFreq() { VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList( new StepSegment(/* amplitude= */ 0, /* frequency= */ 1, /* duration= */ 10), new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 100), Loading @@ -142,8 +174,11 @@ public class DeviceVibrationEffectAdapterTest { /* repeatIndex= */ 2); VibrationEffect.Composed expected = new VibrationEffect.Composed(Arrays.asList( new StepSegment(/* amplitude= */ 0, /* frequency= */ Float.NaN, /* duration= */ 10), new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ Float.NaN, new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 0, /* startFrequency= */ Float.NaN, /* endFrequency= */ Float.NaN, /* duration= */ 10), new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude= */ 0.5f, /* startFrequency= */ Float.NaN, /* endFrequency= */ Float.NaN, /* duration= */ 100), new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 1, /* startFrequency= */ Float.NaN, /* endFrequency= */ Float.NaN, Loading @@ -153,11 +188,13 @@ public class DeviceVibrationEffectAdapterTest { /* duration= */ 20)), /* repeatIndex= */ 2); assertEquals(expected, mAdapter.apply(effect, createVibratorInfo(EMPTY_FREQUENCY_MAPPING))); VibratorInfo info = createVibratorInfo(EMPTY_FREQUENCY_MAPPING, IVibrator.CAP_COMPOSE_PWLE_EFFECTS); assertEquals(expected, mAdapter.apply(effect, info)); } @Test public void testStepAndRampSegments_nonEmptyMapping_returnsClippedValues() { public void testStepAndRampSegments_withValidFreqMapping_returnsClippedValues() { VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList( new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 10), new StepSegment(/* amplitude= */ 1, /* frequency= */ -1, /* duration= */ 100), Loading @@ -168,15 +205,21 @@ public class DeviceVibrationEffectAdapterTest { /* repeatIndex= */ 2); VibrationEffect.Composed expected = new VibrationEffect.Composed(Arrays.asList( new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 150, /* duration= */ 10), new StepSegment(/* amplitude= */ 0.8f, /* frequency= */ 125, /* duration= */ 100), new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude= */ 0.5f, /* startFrequency= */ 150, /* endFrequency= */ 150, /* duration= */ 10), new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.8f, /* startFrequency= */ 125, /* endFrequency= */ 125, /* duration= */ 100), new RampSegment(/* startAmplitude= */ 0.1f, /* endAmplitude= */ 0.8f, /* startFrequency= */ 50, /* endFrequency= */ 200, /* duration= */ 50), new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.1f, /* startFrequency= */ 200, /* endFrequency= */ 50, /* duration= */ 20)), /* repeatIndex= */ 2); assertEquals(expected, mAdapter.apply(effect, createVibratorInfo(TEST_FREQUENCY_MAPPING))); VibratorInfo info = createVibratorInfo(TEST_FREQUENCY_MAPPING, IVibrator.CAP_COMPOSE_PWLE_EFFECTS); assertEquals(expected, mAdapter.apply(effect, info)); } private static VibratorInfo createVibratorInfo(VibratorInfo.FrequencyMapping frequencyMapping, Loading Loading
services/core/java/com/android/server/vibrator/DeviceVibrationEffectAdapter.java +78 −6 Original line number Diff line number Diff line Loading @@ -26,11 +26,14 @@ import android.util.MathUtils; import android.util.Range; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** Adapts a {@link VibrationEffect} to a specific device, taking into account its capabilities. */ final class DeviceVibrationEffectAdapter implements VibrationEffectModifier<VibratorInfo> { private static final int RAMP_STEP_DURATION_MILLIS = 5; /** Adapts a sequence of {@link VibrationEffectSegment} to device's capabilities. */ interface SegmentsAdapter { Loading @@ -38,16 +41,17 @@ final class DeviceVibrationEffectAdapter implements VibrationEffectModifier<Vibr * Modifies the given segments list by adding/removing segments to it based on the * device capabilities specified by given {@link VibratorInfo}. * * @param segments List of {@link VibrationEffectSegment} to be adapter to the device. * @param repeatIndex Repeat index on the current segment list. * @param segments List of {@link VibrationEffectSegment} to be modified. * @param repeatIndex Repeat index of the vibration with given segment list. * @param info The device vibrator info that the segments must be adapted to. * @return The new repeat index on the modifies list. * @return The new repeat index to be used for the modified list. */ int apply(List<VibrationEffectSegment> segments, int repeatIndex, VibratorInfo info); } private final SegmentsAdapter mAmplitudeFrequencyAdapter; private final SegmentsAdapter mStepToRampAdapter; private final SegmentsAdapter mRampToStepsAdapter; DeviceVibrationEffectAdapter() { this(new ClippingAmplitudeFrequencyAdapter()); Loading @@ -56,6 +60,7 @@ final class DeviceVibrationEffectAdapter implements VibrationEffectModifier<Vibr DeviceVibrationEffectAdapter(SegmentsAdapter amplitudeFrequencyAdapter) { mAmplitudeFrequencyAdapter = amplitudeFrequencyAdapter; mStepToRampAdapter = new StepToRampAdapter(); mRampToStepsAdapter = new RampToStepsAdapter(RAMP_STEP_DURATION_MILLIS); } @Override Loading @@ -68,7 +73,10 @@ final class DeviceVibrationEffectAdapter implements VibrationEffectModifier<Vibr List<VibrationEffectSegment> newSegments = new ArrayList<>(composed.getSegments()); int newRepeatIndex = composed.getRepeatIndex(); // Maps steps that should be handled by PWLE to ramps. // Replace ramps with a sequence of fixed steps, or no-op if PWLE capability present. newRepeatIndex = mRampToStepsAdapter.apply(newSegments, newRepeatIndex, info); // Replace steps that should be handled by PWLE to ramps, or no-op if capability missing. // This should be done before frequency is converted from relative to absolute values. newRepeatIndex = mStepToRampAdapter.apply(newSegments, newRepeatIndex, info); Loading @@ -76,7 +84,6 @@ final class DeviceVibrationEffectAdapter implements VibrationEffectModifier<Vibr // to absolute values in Hertz. newRepeatIndex = mAmplitudeFrequencyAdapter.apply(newSegments, newRepeatIndex, info); // TODO(b/167947076): add ramp to step adapter // TODO(b/167947076): add filter that removes unsupported primitives // TODO(b/167947076): add filter that replaces unsupported prebaked with fallback Loading @@ -86,7 +93,7 @@ final class DeviceVibrationEffectAdapter implements VibrationEffectModifier<Vibr /** * Adapter that converts step segments that should be handled as PWLEs to ramp segments. * * <p>This leves the list unchanged if the device do not have compose PWLE capability. * <p>This leaves the list unchanged if the device do not have compose PWLE capability. */ private static final class StepToRampAdapter implements SegmentsAdapter { @Override Loading Loading @@ -123,6 +130,71 @@ final class DeviceVibrationEffectAdapter implements VibrationEffectModifier<Vibr } } /** * Adapter that converts ramp segments that to a sequence of fixed step segments. * * <p>This leaves the list unchanged if the device have compose PWLE capability. */ private static final class RampToStepsAdapter implements SegmentsAdapter { private final int mStepDuration; RampToStepsAdapter(int stepDuration) { mStepDuration = stepDuration; } @Override public int apply(List<VibrationEffectSegment> segments, int repeatIndex, VibratorInfo info) { if (info.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) { // The vibrator have PWLE capability, so keep the segments unchanged. return repeatIndex; } int segmentCount = segments.size(); for (int i = 0; i < segmentCount; i++) { VibrationEffectSegment segment = segments.get(i); if (!(segment instanceof RampSegment)) { continue; } List<StepSegment> steps = apply((RampSegment) segment); segments.remove(i); segments.addAll(i, steps); int addedSegments = steps.size() - 1; if (repeatIndex > i) { repeatIndex += addedSegments; } i += addedSegments; segmentCount += addedSegments; } return repeatIndex; } private List<StepSegment> apply(RampSegment ramp) { if (Float.compare(ramp.getStartAmplitude(), ramp.getEndAmplitude()) == 0) { // Amplitude is the same, so return a single step to simulate this ramp. return Arrays.asList( new StepSegment(ramp.getStartAmplitude(), ramp.getStartFrequency(), (int) ramp.getDuration())); } List<StepSegment> steps = new ArrayList<>(); int stepCount = (int) (ramp.getDuration() + mStepDuration - 1) / mStepDuration; for (int i = 0; i < stepCount - 1; i++) { float pos = (float) i / stepCount; steps.add(new StepSegment( interpolate(ramp.getStartAmplitude(), ramp.getEndAmplitude(), pos), interpolate(ramp.getStartFrequency(), ramp.getEndFrequency(), pos), mStepDuration)); } int duration = (int) ramp.getDuration() - mStepDuration * (stepCount - 1); steps.add(new StepSegment(ramp.getEndAmplitude(), ramp.getEndFrequency(), duration)); return steps; } private static float interpolate(float start, float end, float position) { return start + position * (end - start); } } /** * Adapter that clips frequency values to {@link VibratorInfo#getFrequencyRange()} and * amplitude values to respective {@link VibratorInfo#getMaxAmplitude}. Loading
services/tests/servicestests/src/com/android/server/vibrator/DeviceVibrationEffectAdapterTest.java +51 −8 Original line number Diff line number Diff line Loading @@ -76,6 +76,38 @@ public class DeviceVibrationEffectAdapterTest { assertEquals(effect, mAdapter.apply(effect, createVibratorInfo(TEST_FREQUENCY_MAPPING))); } @Test public void testStepAndRampSegments_withoutPwleCapability_convertsRampsToSteps() { VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList( new StepSegment(/* amplitude= */ 0, /* frequency= */ 1, /* duration= */ 10), new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 100), new RampSegment(/* startAmplitude= */ 1, /* endAmplitude= */ 0.2f, /* startFrequency= */ -4, /* endFrequency= */ 2, /* duration= */ 10), new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.2f, /* startFrequency= */ 0, /* endFrequency= */ 0, /* duration= */ 11), new RampSegment(/* startAmplitude= */ 0.65f, /* endAmplitude= */ 0.65f, /* startFrequency= */ 0, /* endFrequency= */ 1, /* duration= */ 200)), /* repeatIndex= */ 3); VibrationEffect.Composed expected = new VibrationEffect.Composed(Arrays.asList( new StepSegment(/* amplitude= */ 0, Float.NaN, /* duration= */ 10), new StepSegment(/* amplitude= */ 0.5f, Float.NaN, /* duration= */ 100), // 10ms ramp becomes 2 steps new StepSegment(/* amplitude= */ 1, Float.NaN, /* duration= */ 5), new StepSegment(/* amplitude= */ 0.2f, Float.NaN, /* duration= */ 5), // 11ms ramp becomes 3 steps new StepSegment(/* amplitude= */ 0.8f, Float.NaN, /* duration= */ 5), new StepSegment(/* amplitude= */ 0.6f, Float.NaN, /* duration= */ 5), new StepSegment(/* amplitude= */ 0.2f, Float.NaN, /* duration= */ 1), // 200ms ramp with same amplitude becomes a single step new StepSegment(/* amplitude= */ 0.65f, Float.NaN, /* duration= */ 200)), // Repeat index fixed after intermediate steps added /* repeatIndex= */ 4); VibratorInfo info = createVibratorInfo(EMPTY_FREQUENCY_MAPPING); assertEquals(expected, mAdapter.apply(effect, info)); } @Test public void testStepAndRampSegments_withPwleCapability_convertsStepsToRamps() { VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList( Loading Loading @@ -131,7 +163,7 @@ public class DeviceVibrationEffectAdapterTest { } @Test public void testStepAndRampSegments_emptyMapping_returnsSameAmplitudesAndFrequencyZero() { public void testStepAndRampSegments_withEmptyFreqMapping_returnsSameAmplitudesAndZeroFreq() { VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList( new StepSegment(/* amplitude= */ 0, /* frequency= */ 1, /* duration= */ 10), new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 100), Loading @@ -142,8 +174,11 @@ public class DeviceVibrationEffectAdapterTest { /* repeatIndex= */ 2); VibrationEffect.Composed expected = new VibrationEffect.Composed(Arrays.asList( new StepSegment(/* amplitude= */ 0, /* frequency= */ Float.NaN, /* duration= */ 10), new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ Float.NaN, new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 0, /* startFrequency= */ Float.NaN, /* endFrequency= */ Float.NaN, /* duration= */ 10), new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude= */ 0.5f, /* startFrequency= */ Float.NaN, /* endFrequency= */ Float.NaN, /* duration= */ 100), new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 1, /* startFrequency= */ Float.NaN, /* endFrequency= */ Float.NaN, Loading @@ -153,11 +188,13 @@ public class DeviceVibrationEffectAdapterTest { /* duration= */ 20)), /* repeatIndex= */ 2); assertEquals(expected, mAdapter.apply(effect, createVibratorInfo(EMPTY_FREQUENCY_MAPPING))); VibratorInfo info = createVibratorInfo(EMPTY_FREQUENCY_MAPPING, IVibrator.CAP_COMPOSE_PWLE_EFFECTS); assertEquals(expected, mAdapter.apply(effect, info)); } @Test public void testStepAndRampSegments_nonEmptyMapping_returnsClippedValues() { public void testStepAndRampSegments_withValidFreqMapping_returnsClippedValues() { VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList( new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 0, /* duration= */ 10), new StepSegment(/* amplitude= */ 1, /* frequency= */ -1, /* duration= */ 100), Loading @@ -168,15 +205,21 @@ public class DeviceVibrationEffectAdapterTest { /* repeatIndex= */ 2); VibrationEffect.Composed expected = new VibrationEffect.Composed(Arrays.asList( new StepSegment(/* amplitude= */ 0.5f, /* frequency= */ 150, /* duration= */ 10), new StepSegment(/* amplitude= */ 0.8f, /* frequency= */ 125, /* duration= */ 100), new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude= */ 0.5f, /* startFrequency= */ 150, /* endFrequency= */ 150, /* duration= */ 10), new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.8f, /* startFrequency= */ 125, /* endFrequency= */ 125, /* duration= */ 100), new RampSegment(/* startAmplitude= */ 0.1f, /* endAmplitude= */ 0.8f, /* startFrequency= */ 50, /* endFrequency= */ 200, /* duration= */ 50), new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.1f, /* startFrequency= */ 200, /* endFrequency= */ 50, /* duration= */ 20)), /* repeatIndex= */ 2); assertEquals(expected, mAdapter.apply(effect, createVibratorInfo(TEST_FREQUENCY_MAPPING))); VibratorInfo info = createVibratorInfo(TEST_FREQUENCY_MAPPING, IVibrator.CAP_COMPOSE_PWLE_EFFECTS); assertEquals(expected, mAdapter.apply(effect, info)); } private static VibratorInfo createVibratorInfo(VibratorInfo.FrequencyMapping frequencyMapping, Loading