Split long ramps to fit HAL PWLE primitive limit
Bug: 188431691 Fix: 183519628 Test: StepToRampAdapterTest Change-Id: I7f0baf387cadfb7f5d5032e98c0bdae2ad770904
This commit is contained in:
@@ -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;
|
||||
|
||||
/**
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user