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

Commit 40633698 authored by Ahmad Khalil's avatar Ahmad Khalil Committed by Android (Google) Code Review
Browse files

Merge "Add tests for SplitPwleSegmentsAdapter" into main

parents 430d8155 b5cdd53a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -94,7 +94,7 @@ final class ComposePwleV2VibratorStep extends AbstractComposedVibratorStep {

        // Loop once after reaching the limit to see if breaking it will really be necessary, then
        // apply the best break position found, otherwise return the full list as it fits the limit.
        for (int i = startIndex; pwlePoints.size() < limit; i++) {
        for (int i = startIndex; pwlePoints.size() <= limit; i++) {
            if (i == segmentCount) {
                if (repeatIndex >= 0) {
                    i = repeatIndex;
+3 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.vibrator;

import android.hardware.vibrator.IVibrator;
import android.os.VibratorInfo;
import android.os.vibrator.Flags;
import android.os.vibrator.PwleSegment;
import android.os.vibrator.VibrationEffectSegment;
import android.util.MathUtils;
@@ -40,7 +41,8 @@ final class SplitPwleSegmentsAdapter implements VibrationSegmentsAdapter {
    @Override
    public int adaptToVibrator(VibratorInfo info, List<VibrationEffectSegment> segments,
            int repeatIndex) {
        if (!info.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2)) {
        if (!Flags.normalizedPwleEffects()
                || !info.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2)) {
            // The vibrator does not have PWLE v2 capability, so keep the segments unchanged.
            return repeatIndex;
        }
+150 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.vibrator;

import static com.google.common.truth.Truth.assertThat;

import android.hardware.vibrator.IVibrator;
import android.os.VibratorInfo;
import android.os.vibrator.Flags;
import android.os.vibrator.PwleSegment;
import android.os.vibrator.VibrationEffectSegment;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;

public class SplitPwleSegmentsAdapterTest {
    private static final float TEST_RESONANT_FREQUENCY = 150;
    private static final float[] TEST_FREQUENCIES =
            new float[]{90f, 120f, 150f, 60f, 30f, 210f, 270f, 300f, 240f, 180f};
    private static final float[] TEST_OUTPUT_ACCELERATIONS =
            new float[]{1.2f, 1.8f, 2.4f, 0.6f, 0.1f, 2.2f, 1.0f, 0.5f, 1.9f, 3.0f};

    private static final VibratorInfo.FrequencyProfile TEST_FREQUENCY_PROFILE =
            new VibratorInfo.FrequencyProfile(TEST_RESONANT_FREQUENCY, TEST_FREQUENCIES,
                    TEST_OUTPUT_ACCELERATIONS);

    private SplitPwleSegmentsAdapter mAdapter;

    @Rule
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    @Before
    public void setUp() throws Exception {
        mAdapter = new SplitPwleSegmentsAdapter();
    }

    @Test
    @DisableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
    public void testSplitPwleSegmentsAdapter_withFeatureFlagDisabled_returnsOriginalSegments() {
        List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
                //  startAmplitude, endAmplitude, startFrequencyHz, endFrequencyHz, duration
                new PwleSegment(0.0f, 1.0f, 300.0f, 300.0f, 5000)));
        List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments);

        VibratorInfo vibratorInfo = createVibratorInfo(
                /*maxEnvelopeControlPointDuration=*/1000, TEST_FREQUENCY_PROFILE,
                IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2);

        assertThat(mAdapter.adaptToVibrator(vibratorInfo, segments, /*repeatIndex= */ -1))
                .isEqualTo(-1);
        assertThat(mAdapter.adaptToVibrator(vibratorInfo, segments, /*repeatIndex= */ 1))
                .isEqualTo(1);

        assertThat(segments).isEqualTo(originalSegments);
    }

    @Test
    @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
    public void testSplitPwleSegmentsAdapter_noPwleCapability_returnsOriginalSegments() {
        List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
                //  startAmplitude, endAmplitude, startFrequencyHz, endFrequencyHz, duration
                new PwleSegment(0.0f, 1.0f, 300.0f, 300.0f, 5000)));
        List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments);

        VibratorInfo vibratorInfo = createVibratorInfo(
                /*maxEnvelopeControlPointDuration=*/1000, TEST_FREQUENCY_PROFILE);

        assertThat(mAdapter.adaptToVibrator(vibratorInfo, segments, /*repeatIndex= */ -1))
                .isEqualTo(-1);
        assertThat(mAdapter.adaptToVibrator(vibratorInfo, segments, /*repeatIndex= */ 1))
                .isEqualTo(1);

        assertThat(segments).isEqualTo(originalSegments);
    }

    @Test
    @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
    public void testSplitPwleSegmentsAdapter_noMaxEnvelopeEffectSize_returnsOriginalSegments() {
        List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
                //  startAmplitude, endAmplitude, startFrequencyHz, endFrequencyHz, duration
                new PwleSegment(0.0f, 1.0f, 300.0f, 300.0f, 5000)));
        List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments);
        VibratorInfo vibratorInfo = createVibratorInfo(/*maxEnvelopeControlPointDuration=*/ 0,
                TEST_FREQUENCY_PROFILE, IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2);

        assertThat(mAdapter.adaptToVibrator(vibratorInfo, segments, /*repeatIndex= */ -1))
                .isEqualTo(-1);
        assertThat(mAdapter.adaptToVibrator(vibratorInfo, segments, /*repeatIndex= */ 1))
                .isEqualTo(1);

        assertThat(segments).isEqualTo(originalSegments);
    }

    @Test
    @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
    public void testSplitPwleSegmentsAdapter_withPwleCapability_adaptSegmentsCorrectly() {
        List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
                //  startAmplitude, endAmplitude, startFrequencyHz, endFrequencyHz, duration
                new PwleSegment(0.0f, 1.0f, 200.0f, 200.0f, 1000),
                new PwleSegment(0.0f, 1.0f, 300.0f, 300.0f, 5000)));
        List<VibrationEffectSegment> expectedSegments = Arrays.asList(
                //  startAmplitude, endAmplitude, startFrequencyHz, endFrequencyHz, duration
                new PwleSegment(0.0f, 1.0f, 200.0f, 200.0f, 1000),
                new PwleSegment(0.0f, 0.2f, 300.0f, 300.0f, 1000),
                new PwleSegment(0.2f, 0.4f, 300.0f, 300.0f, 1000),
                new PwleSegment(0.4f, 0.6f, 300.0f, 300.0f, 1000),
                new PwleSegment(0.6f, 0.8f, 300.0f, 300.0f, 1000),
                new PwleSegment(0.8f, 1.0f, 300.0f, 300.0f, 1000));
        VibratorInfo vibratorInfo = createVibratorInfo(
                /*maxEnvelopeControlPointDuration=*/1000, TEST_FREQUENCY_PROFILE,
                IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2);

        assertThat(mAdapter.adaptToVibrator(vibratorInfo, segments, /*repeatIndex= */ 0))
                .isEqualTo(0);
        assertThat(segments).isEqualTo(expectedSegments);
    }

    private static VibratorInfo createVibratorInfo(int maxEnvelopeControlPointDuration,
            VibratorInfo.FrequencyProfile frequencyProfile, int... capabilities) {
        return new VibratorInfo.Builder(0)
                .setCapabilities(IntStream.of(capabilities).reduce((a, b) -> a | b).orElse(0))
                .setFrequencyProfile(frequencyProfile)
                .setMaxEnvelopeEffectSize(1)
                .setMaxEnvelopeEffectControlPointDurationMillis(maxEnvelopeControlPointDuration)
                .build();
    }
}
+42 −0
Original line number Diff line number Diff line
@@ -1000,6 +1000,48 @@ public class VibrationThreadTest {

    }

    @Test
    @EnableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
    public void vibrate_singleVibratorPwle_TooManyControlPoints_splitsAndRunsComposePwleV2() {
        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
        fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2);
        fakeVibrator.setResonantFrequency(150);
        fakeVibrator.setFrequenciesHz(new float[]{30f, 50f, 100f, 120f, 150f});
        fakeVibrator.setOutputAccelerationsGs(new float[]{0.3f, 0.5f, 1.0f, 0.8f, 0.6f});
        fakeVibrator.setMaxEnvelopeEffectSize(3);
        fakeVibrator.setMinEnvelopeEffectControlPointDurationMillis(20);

        VibrationEffect effect = new VibrationEffect.WaveformEnvelopeBuilder()
                .addControlPoint(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 100f, /*durationMillis=*/ 30)
                .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 100f, /*durationMillis=*/ 30)
                // Waveform will be split here, after vibration goes to zero amplitude
                .addControlPoint(/*amplitude=*/ 0.9f, /*frequencyHz=*/ 100f, /*durationMillis=*/ 30)
                .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 100f, /*durationMillis=*/ 30)
                // Waveform will be split here at lowest amplitude.
                .addControlPoint(/*amplitude=*/ 0.6f, /*frequencyHz=*/ 100f, /*durationMillis=*/ 30)
                .addControlPoint(/*amplitude=*/ 0.7f, /*frequencyHz=*/ 100f, /*durationMillis=*/ 30)
                .build();
        HalVibration vibration = startThreadAndDispatcher(effect);
        waitForCompletion();

        verifyCallbacksTriggered(vibration, Status.FINISHED);
        // Vibrator compose called 3 times with 2 segments instead of 2 times with 3 segments.
        // Using best split points instead of max-packing PWLEs.
        verify(mControllerCallbacks, times(3)).onComplete(eq(VIBRATOR_ID), eq(vibration.id));
        assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());

        assertEquals(Arrays.asList(
                expectedPwle(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 0),
                expectedPwle(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 30),
                expectedPwle(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 30),
                expectedPwle(/*amplitude=*/ 0.9f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 0),
                expectedPwle(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 30),
                expectedPwle(/*amplitude=*/ 0.6f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 0),
                expectedPwle(/*amplitude=*/ 0.7f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 30)
        ), fakeVibrator.getEffectPwlePoints(vibration.id));

    }

    @Test
    @DisableFlags(android.os.vibrator.Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
    public void vibrate_singleVibratorPwle_runsComposePwle() {