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

Commit c9a1008f authored by Lais Andrade's avatar Lais Andrade Committed by Automerger Merge Worker
Browse files

Merge "Split long ramps to fit HAL PWLE primitive limit" into sc-dev am: a6689c52 am: afeb6280

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14980856

Change-Id: I5f2d85e31fd96c1f9c65544614180c9fd08f6cd4
parents 08396ab0 afeb6280
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);