Loading services/core/java/com/android/server/vibrator/StepToRampAdapter.java +76 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.os.vibrator.RampSegment; import android.os.vibrator.StepSegment; import android.os.vibrator.VibrationEffectSegment; import java.util.ArrayList; import java.util.List; /** Loading Loading @@ -59,6 +60,7 @@ final class StepToRampAdapter implements VibrationEffectAdapters.SegmentsAdapter convertStepsToRamps(segments); int newRepeatIndex = addRampDownToZeroAmplitudeSegments(segments, repeatIndex); newRepeatIndex = addRampDownToLoop(segments, newRepeatIndex); newRepeatIndex = splitLongRampSegments(info, segments, newRepeatIndex); return newRepeatIndex; } Loading Loading @@ -210,11 +212,70 @@ final class StepToRampAdapter implements VibrationEffectAdapters.SegmentsAdapter return repeatIndex; } /** * Split {@link RampSegment} entries that have duration longer than {@link * VibratorInfo#getPwlePrimitiveDurationMax()}. */ private int splitLongRampSegments(VibratorInfo info, List<VibrationEffectSegment> segments, int repeatIndex) { int maxDuration = info.getPwlePrimitiveDurationMax(); if (maxDuration <= 0) { // No limit set to PWLE primitive duration. return repeatIndex; } int segmentCount = segments.size(); for (int i = 0; i < segmentCount; i++) { if (!(segments.get(i) instanceof RampSegment)) { continue; } RampSegment ramp = (RampSegment) segments.get(i); int splits = ((int) ramp.getDuration() + maxDuration - 1) / maxDuration; if (splits <= 1) { continue; } segments.remove(i); segments.addAll(i, splitRampSegment(ramp, splits)); int addedSegments = splits - 1; if (repeatIndex > i) { repeatIndex += addedSegments; } i += addedSegments; segmentCount += addedSegments; } return repeatIndex; } private static RampSegment apply(StepSegment segment) { return new RampSegment(segment.getAmplitude(), segment.getAmplitude(), segment.getFrequency(), segment.getFrequency(), (int) segment.getDuration()); } private static List<RampSegment> splitRampSegment(RampSegment ramp, int splits) { List<RampSegment> ramps = new ArrayList<>(splits); long splitDuration = ramp.getDuration() / splits; float previousAmplitude = ramp.getStartAmplitude(); float previousFrequency = ramp.getStartFrequency(); long accumulatedDuration = 0; for (int i = 1; i < splits; i++) { accumulatedDuration += splitDuration; RampSegment rampSplit = new RampSegment( previousAmplitude, interpolateAmplitude(ramp, accumulatedDuration), previousFrequency, interpolateFrequency(ramp, accumulatedDuration), (int) splitDuration); ramps.add(rampSplit); previousAmplitude = rampSplit.getEndAmplitude(); previousFrequency = rampSplit.getEndFrequency(); } ramps.add(new RampSegment(previousAmplitude, ramp.getEndAmplitude(), previousFrequency, ramp.getEndFrequency(), (int) (ramp.getDuration() - accumulatedDuration))); return ramps; } private static RampSegment createRampDown(float amplitude, float frequency, long duration) { return new RampSegment(amplitude, /* endAmplitude= */ 0, frequency, frequency, (int) duration); Loading Loading @@ -244,4 +305,19 @@ final class StepToRampAdapter implements VibrationEffectAdapters.SegmentsAdapter } return false; } private static float interpolateAmplitude(RampSegment ramp, long duration) { return interpolate(ramp.getStartAmplitude(), ramp.getEndAmplitude(), duration, ramp.getDuration()); } private static float interpolateFrequency(RampSegment ramp, long duration) { return interpolate(ramp.getStartFrequency(), ramp.getEndFrequency(), duration, ramp.getDuration()); } private static float interpolate(float start, float end, long duration, long totalDuration) { float position = (float) duration / totalDuration; return start + position * (end - start); } } services/tests/servicestests/src/com/android/server/vibrator/StepToRampAdapterTest.java +32 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,38 @@ public class StepToRampAdapterTest { assertEquals(originalSegments, segments); } @Test public void testRampSegments_withPwleDurationLimit_splitsLongRamps() { List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList( new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f, /* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 10), new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 1, /* startFrequency= */ 0, /* endFrequency= */ -1, /* duration= */ 25), new RampSegment(/* startAmplitude= */ 1, /* endAmplitude*/ 1, /* startFrequency= */ 0, /* endFrequency= */ 1, /* duration= */ 5))); List<VibrationEffectSegment> expectedSegments = Arrays.asList( new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f, /* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 10), new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 0.32f, /* startFrequency= */ 0, /* endFrequency= */ -0.32f, /* duration= */ 8), new RampSegment(/* startAmplitude= */ 0.32f, /* endAmplitude= */ 0.64f, /* startFrequency= */ -0.32f, /* endFrequency= */ -0.64f, /* duration= */ 8), new RampSegment(/* startAmplitude= */ 0.64f, /* endAmplitude= */ 1, /* startFrequency= */ -0.64f, /* endFrequency= */ -1, /* duration= */ 9), new RampSegment(/* startAmplitude= */ 1, /* endAmplitude*/ 1, /* startFrequency= */ 0, /* endFrequency= */ 1, /* duration= */ 5)); VibratorInfo vibratorInfo = new VibratorInfo.Builder(0) .setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS) .setPwlePrimitiveDurationMax(10) .build(); // Update repeat index to skip the ramp splits. assertEquals(4, mAdapter.apply(segments, 2, vibratorInfo)); assertEquals(expectedSegments, segments); } @Test public void testStepAndRampSegments_withoutPwleCapability_keepsListUnchanged() { mAdapter = new StepToRampAdapter(50); Loading Loading
services/core/java/com/android/server/vibrator/StepToRampAdapter.java +76 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.os.vibrator.RampSegment; import android.os.vibrator.StepSegment; import android.os.vibrator.VibrationEffectSegment; import java.util.ArrayList; import java.util.List; /** Loading Loading @@ -59,6 +60,7 @@ final class StepToRampAdapter implements VibrationEffectAdapters.SegmentsAdapter convertStepsToRamps(segments); int newRepeatIndex = addRampDownToZeroAmplitudeSegments(segments, repeatIndex); newRepeatIndex = addRampDownToLoop(segments, newRepeatIndex); newRepeatIndex = splitLongRampSegments(info, segments, newRepeatIndex); return newRepeatIndex; } Loading Loading @@ -210,11 +212,70 @@ final class StepToRampAdapter implements VibrationEffectAdapters.SegmentsAdapter return repeatIndex; } /** * Split {@link RampSegment} entries that have duration longer than {@link * VibratorInfo#getPwlePrimitiveDurationMax()}. */ private int splitLongRampSegments(VibratorInfo info, List<VibrationEffectSegment> segments, int repeatIndex) { int maxDuration = info.getPwlePrimitiveDurationMax(); if (maxDuration <= 0) { // No limit set to PWLE primitive duration. return repeatIndex; } int segmentCount = segments.size(); for (int i = 0; i < segmentCount; i++) { if (!(segments.get(i) instanceof RampSegment)) { continue; } RampSegment ramp = (RampSegment) segments.get(i); int splits = ((int) ramp.getDuration() + maxDuration - 1) / maxDuration; if (splits <= 1) { continue; } segments.remove(i); segments.addAll(i, splitRampSegment(ramp, splits)); int addedSegments = splits - 1; if (repeatIndex > i) { repeatIndex += addedSegments; } i += addedSegments; segmentCount += addedSegments; } return repeatIndex; } private static RampSegment apply(StepSegment segment) { return new RampSegment(segment.getAmplitude(), segment.getAmplitude(), segment.getFrequency(), segment.getFrequency(), (int) segment.getDuration()); } private static List<RampSegment> splitRampSegment(RampSegment ramp, int splits) { List<RampSegment> ramps = new ArrayList<>(splits); long splitDuration = ramp.getDuration() / splits; float previousAmplitude = ramp.getStartAmplitude(); float previousFrequency = ramp.getStartFrequency(); long accumulatedDuration = 0; for (int i = 1; i < splits; i++) { accumulatedDuration += splitDuration; RampSegment rampSplit = new RampSegment( previousAmplitude, interpolateAmplitude(ramp, accumulatedDuration), previousFrequency, interpolateFrequency(ramp, accumulatedDuration), (int) splitDuration); ramps.add(rampSplit); previousAmplitude = rampSplit.getEndAmplitude(); previousFrequency = rampSplit.getEndFrequency(); } ramps.add(new RampSegment(previousAmplitude, ramp.getEndAmplitude(), previousFrequency, ramp.getEndFrequency(), (int) (ramp.getDuration() - accumulatedDuration))); return ramps; } private static RampSegment createRampDown(float amplitude, float frequency, long duration) { return new RampSegment(amplitude, /* endAmplitude= */ 0, frequency, frequency, (int) duration); Loading Loading @@ -244,4 +305,19 @@ final class StepToRampAdapter implements VibrationEffectAdapters.SegmentsAdapter } return false; } private static float interpolateAmplitude(RampSegment ramp, long duration) { return interpolate(ramp.getStartAmplitude(), ramp.getEndAmplitude(), duration, ramp.getDuration()); } private static float interpolateFrequency(RampSegment ramp, long duration) { return interpolate(ramp.getStartFrequency(), ramp.getEndFrequency(), duration, ramp.getDuration()); } private static float interpolate(float start, float end, long duration, long totalDuration) { float position = (float) duration / totalDuration; return start + position * (end - start); } }
services/tests/servicestests/src/com/android/server/vibrator/StepToRampAdapterTest.java +32 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,38 @@ public class StepToRampAdapterTest { assertEquals(originalSegments, segments); } @Test public void testRampSegments_withPwleDurationLimit_splitsLongRamps() { List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList( new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f, /* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 10), new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 1, /* startFrequency= */ 0, /* endFrequency= */ -1, /* duration= */ 25), new RampSegment(/* startAmplitude= */ 1, /* endAmplitude*/ 1, /* startFrequency= */ 0, /* endFrequency= */ 1, /* duration= */ 5))); List<VibrationEffectSegment> expectedSegments = Arrays.asList( new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f, /* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 10), new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 0.32f, /* startFrequency= */ 0, /* endFrequency= */ -0.32f, /* duration= */ 8), new RampSegment(/* startAmplitude= */ 0.32f, /* endAmplitude= */ 0.64f, /* startFrequency= */ -0.32f, /* endFrequency= */ -0.64f, /* duration= */ 8), new RampSegment(/* startAmplitude= */ 0.64f, /* endAmplitude= */ 1, /* startFrequency= */ -0.64f, /* endFrequency= */ -1, /* duration= */ 9), new RampSegment(/* startAmplitude= */ 1, /* endAmplitude*/ 1, /* startFrequency= */ 0, /* endFrequency= */ 1, /* duration= */ 5)); VibratorInfo vibratorInfo = new VibratorInfo.Builder(0) .setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS) .setPwlePrimitiveDurationMax(10) .build(); // Update repeat index to skip the ramp splits. assertEquals(4, mAdapter.apply(segments, 2, vibratorInfo)); assertEquals(expectedSegments, segments); } @Test public void testStepAndRampSegments_withoutPwleCapability_keepsListUnchanged() { mAdapter = new StepToRampAdapter(50); Loading