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

Commit 456c8511 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: f784fe75

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

Change-Id: I491bf3bb80076698caa5fb5fe9c5a9ab29f01cae
parents d5e43103 f784fe75
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);