Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 88543203 authored by Lais Andrade's avatar Lais Andrade
Browse files

Split long ramps to fit HAL PWLE primitive limit

Bug: 188431691
Fix: 183519628
Test: StepToRampAdapterTest
Change-Id: I7f0baf387cadfb7f5d5032e98c0bdae2ad770904
parent a1167c2a
Loading
Loading
Loading
Loading
+76 −0
Original line number Diff line number Diff line
@@ -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);
    }
}
+32 −0
Original line number Diff line number Diff line
@@ -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);