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

Commit 60be0649 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Apply intensity settings to composed vibration effects" into rvc-dev...

Merge "Apply intensity settings to composed vibration effects" into rvc-dev am: 896cdcca am: 1391b985 am: 280fc575

Change-Id: I82aaa421cad7af80cc4ba360733a9d6472ac99e8
parents 4df4028f 280fc575
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -897,6 +897,34 @@ public abstract class VibrationEffect implements Parcelable {
            return -1;
        }

        /**
         * Scale all primitives of this effect.
         *
         * @param gamma the gamma adjustment to apply
         * @param maxAmplitude the new maximum amplitude of the effect, must be between 0 and
         *         MAX_AMPLITUDE
         * @throws IllegalArgumentException if maxAmplitude less than 0 or more than MAX_AMPLITUDE
         *
         * @return A {@link Composed} effect with same but scaled primitives.
         */
        public Composed scale(float gamma, int maxAmplitude) {
            if (maxAmplitude > MAX_AMPLITUDE || maxAmplitude < 0) {
                throw new IllegalArgumentException(
                        "Amplitude is negative or greater than MAX_AMPLITUDE");
            }
            if (gamma == 1.0f && maxAmplitude == MAX_AMPLITUDE) {
                // Just return a copy of the original if there's no scaling to be done.
                return new Composed(mPrimitiveEffects);
            }
            List<Composition.PrimitiveEffect> scaledPrimitives = new ArrayList<>();
            for (Composition.PrimitiveEffect primitive : mPrimitiveEffects) {
                float adjustedScale = MathUtils.pow(primitive.scale, gamma);
                float newScale = adjustedScale * maxAmplitude / (float) MAX_AMPLITUDE;
                scaledPrimitives.add(new Composition.PrimitiveEffect(
                        primitive.id, newScale, primitive.delay));
            }
            return new Composed(scaledPrimitives);
        }

        /**
         * @hide
+96 −6
Original line number Diff line number Diff line
@@ -22,9 +22,12 @@ import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import android.content.ContentInterface;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.net.Uri;
@@ -37,6 +40,8 @@ import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class VibrationEffectTest {
    private static final float SCALE_TOLERANCE = 1e-2f;

    private static final String RINGTONE_URI_1 = "content://test/system/ringtone_1";
    private static final String RINGTONE_URI_2 = "content://test/system/ringtone_2";
    private static final String RINGTONE_URI_3 = "content://test/system/ringtone_3";
@@ -54,6 +59,12 @@ public class VibrationEffectTest {
            VibrationEffect.createOneShot(TEST_TIMING, VibrationEffect.DEFAULT_AMPLITUDE);
    private static final VibrationEffect TEST_WAVEFORM =
            VibrationEffect.createWaveform(TEST_TIMINGS, TEST_AMPLITUDES, -1);
    private static final VibrationEffect TEST_COMPOSED =
            VibrationEffect.startComposition()
                    .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
                    .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0.5f, 10)
                    .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0, 100)
                    .compose();

    @Test
    public void getRingtones_noPrebakedRingtones() {
@@ -123,8 +134,14 @@ public class VibrationEffectTest {

    @Test
    public void testScaleWaveform() {
        VibrationEffect.Waveform scaled =
                ((VibrationEffect.Waveform) TEST_WAVEFORM).scale(1.1f, 200);
        VibrationEffect.Waveform initial = (VibrationEffect.Waveform) TEST_WAVEFORM;

        VibrationEffect.Waveform copied = initial.scale(1f, 255);
        assertEquals(255, copied.getAmplitudes()[0]);
        assertEquals(0, copied.getAmplitudes()[1]);
        assertEquals(-1, copied.getAmplitudes()[2]);

        VibrationEffect.Waveform scaled = initial.scale(1.1f, 200);
        assertEquals(200, scaled.getAmplitudes()[0]);
        assertEquals(0, scaled.getAmplitudes()[1]);
    }
@@ -156,6 +173,66 @@ public class VibrationEffectTest {
        }
    }

    @Test
    public void testScaleComposed() {
        VibrationEffect.Composed initial = (VibrationEffect.Composed) TEST_COMPOSED;

        VibrationEffect.Composed copied = initial.scale(1, 255);
        assertEquals(1f, copied.getPrimitiveEffects().get(0).scale);
        assertEquals(0.5f, copied.getPrimitiveEffects().get(1).scale);
        assertEquals(0f, copied.getPrimitiveEffects().get(2).scale);

        VibrationEffect.Composed halved = initial.scale(1, 128);
        assertEquals(0.5f, halved.getPrimitiveEffects().get(0).scale, SCALE_TOLERANCE);
        assertEquals(0.25f, halved.getPrimitiveEffects().get(1).scale, SCALE_TOLERANCE);
        assertEquals(0f, halved.getPrimitiveEffects().get(2).scale);

        VibrationEffect.Composed scaledUp = initial.scale(0.5f, 255);
        assertEquals(1f, scaledUp.getPrimitiveEffects().get(0).scale); // does not scale up from 1
        assertTrue(0.5f < scaledUp.getPrimitiveEffects().get(1).scale);
        assertEquals(0f, scaledUp.getPrimitiveEffects().get(2).scale);

        VibrationEffect.Composed restored = scaledUp.scale(2, 255);
        assertEquals(1f, restored.getPrimitiveEffects().get(0).scale, SCALE_TOLERANCE);
        assertEquals(0.5f, restored.getPrimitiveEffects().get(1).scale, SCALE_TOLERANCE);
        assertEquals(0f, restored.getPrimitiveEffects().get(2).scale);

        VibrationEffect.Composed scaledDown = initial.scale(2, 255);
        assertEquals(1f, scaledDown.getPrimitiveEffects().get(0).scale, SCALE_TOLERANCE);
        assertTrue(0.5f > scaledDown.getPrimitiveEffects().get(1).scale);
        assertEquals(0f, scaledDown.getPrimitiveEffects().get(2).scale, SCALE_TOLERANCE);

        VibrationEffect.Composed changeMax = initial.scale(1f, 51);
        assertEquals(0.2f, changeMax.getPrimitiveEffects().get(0).scale, SCALE_TOLERANCE);
        assertEquals(0.1f, changeMax.getPrimitiveEffects().get(1).scale, SCALE_TOLERANCE);
        assertEquals(0f, changeMax.getPrimitiveEffects().get(2).scale);
    }

    @Test
    public void testScaleComposedFailsWhenMaxAmplitudeAboveThreshold() {
        try {
            ((VibrationEffect.Composed) TEST_COMPOSED).scale(1.1f, 1000);
            fail("Max amplitude above threshold, should throw IllegalArgumentException");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testScaleAppliesSameAdjustmentsOnAllEffects() {
        VibrationEffect.OneShot oneShot = new VibrationEffect.OneShot(TEST_TIMING, TEST_AMPLITUDE);
        VibrationEffect.Waveform waveform = new VibrationEffect.Waveform(
                new long[] { TEST_TIMING }, new int[]{ TEST_AMPLITUDE }, -1);
        VibrationEffect.Composed composed =
                (VibrationEffect.Composed) VibrationEffect.startComposition()
                    .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, TEST_AMPLITUDE / 255f)
                    .compose();

        assertEquals(oneShot.scale(2f, 128).getAmplitude(),
                waveform.scale(2f, 128).getAmplitudes()[0]);
        assertEquals(oneShot.scale(2f, 128).getAmplitude() / 255f, // convert amplitude to scale
                composed.scale(2f, 128).getPrimitiveEffects().get(0).scale,
                SCALE_TOLERANCE);
    }

    private Resources mockRingtoneResources() {
        return mockRingtoneResources(new String[] {
@@ -172,9 +249,22 @@ public class VibrationEffectTest {
        return mockResources;
    }

    private Context mockContext(Resources r) {
        Context ctx = mock(Context.class);
        when(ctx.getResources()).thenReturn(r);
        return ctx;
    private Context mockContext(Resources resources) {
        Context context = mock(Context.class);
        ContentInterface contentInterface = mock(ContentInterface.class);
        ContentResolver contentResolver = ContentResolver.wrap(contentInterface);

        try {
            // ContentResolver#uncanonicalize is final, so we need to mock the ContentInterface it
            // delegates the call to for the tests that require matching with the mocked URIs.
            when(contentInterface.uncanonicalize(any())).then(
                    invocation -> invocation.getArgument(0));
            when(context.getContentResolver()).thenReturn(contentResolver);
            when(context.getResources()).thenReturn(resources);
        } catch (RemoteException e) {
            throw new RuntimeException(e);
        }

        return context;
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -1034,6 +1034,9 @@ public class VibratorService extends IVibratorService.Stub
            VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
            waveform = waveform.resolve(mDefaultVibrationAmplitude);
            scaledEffect = waveform.scale(scale.gamma, scale.maxAmplitude);
        } else if (vib.effect instanceof VibrationEffect.Composed) {
            VibrationEffect.Composed composed = (VibrationEffect.Composed) vib.effect;
            scaledEffect = composed.scale(scale.gamma, scale.maxAmplitude);
        } else {
            Slog.w(TAG, "Unable to apply intensity scaling, unknown VibrationEffect type");
        }