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

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

Merge "Add ability to loop vibration effects" into main

parents cff23ddf ececfffd
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -34380,6 +34380,8 @@ package android.os {
  public abstract class VibrationEffect implements android.os.Parcelable {
    method public static android.os.VibrationEffect createOneShot(long, int);
    method @NonNull public static android.os.VibrationEffect createPredefined(int);
    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public static android.os.VibrationEffect createRepeatingEffect(@NonNull android.os.VibrationEffect);
    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public static android.os.VibrationEffect createRepeatingEffect(@NonNull android.os.VibrationEffect, @NonNull android.os.VibrationEffect);
    method public static android.os.VibrationEffect createWaveform(long[], int);
    method public static android.os.VibrationEffect createWaveform(long[], int[], int);
    method public int describeContents();
+43 −0
Original line number Diff line number Diff line
@@ -1403,6 +1403,49 @@ public abstract class VibrationEffect implements Parcelable {
                };
    }

    /**
     * Creates a new {@link VibrationEffect} that repeats the given effect indefinitely.
     *
     * <p>The input vibration must not be a repeating vibration. If it is, an
     * {@link IllegalArgumentException} will be thrown.
     *
     * @param effect The {@link VibrationEffect} that will be repeated.
     * @return A {@link VibrationEffect} that repeats the effect indefinitely.
     * @throws IllegalArgumentException if the effect is already a repeating vibration.
     */
    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
    @NonNull
    public static VibrationEffect createRepeatingEffect(@NonNull VibrationEffect effect) {
        return VibrationEffect.startComposition()
                .repeatEffectIndefinitely(effect)
                .compose();
    }

    /**
     * Creates a new {@link VibrationEffect} by merging the preamble and repeating vibration effect.
     *
     * <p>Neither input vibration may already be repeating. An {@link IllegalArgumentException} will
     * be thrown if either input vibration is set to repeat indefinitely.
     *
     * @param preamble        The starting vibration effect, which must be finite.
     * @param repeatingEffect The vibration effect to be repeated indefinitely after the preamble.
     * @return A {@link VibrationEffect} that plays the preamble once followed by the
     * `repeatingEffect` indefinitely.
     * @throws IllegalArgumentException if either preamble or repeatingEffect is already a repeating
     *                                  vibration.
     */
    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
    @NonNull
    public static VibrationEffect createRepeatingEffect(@NonNull VibrationEffect preamble,
            @NonNull VibrationEffect repeatingEffect) {
        Preconditions.checkArgument(preamble.getDuration() < Long.MAX_VALUE,
                "Can't repeat an indefinitely repeating effect.");
        return VibrationEffect.startComposition()
                .addEffect(preamble)
                .repeatEffectIndefinitely(repeatingEffect)
                .compose();
    }

    /**
     * A composition of haptic elements that are combined to be playable as a single
     * {@link VibrationEffect}.
+86 −0
Original line number Diff line number Diff line
@@ -401,6 +401,17 @@ public class VibrationEffectTest {
        assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
    }

    @Test
    @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
    public void computeLegacyPattern_repeatingEffect() {
        VibrationEffect repeatingEffect = VibrationEffect.createRepeatingEffect(TEST_ONE_SHOT,
                TEST_WAVEFORM);
        assertNull(repeatingEffect.computeCreateWaveformOffOnTimingsOrNull());

        repeatingEffect = VibrationEffect.createRepeatingEffect(TEST_WAVEFORM);
        assertNull(repeatingEffect.computeCreateWaveformOffOnTimingsOrNull());
    }

    @Test
    @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
    public void computeLegacyPattern_effectsViaStartWaveformEnvelope() {
@@ -525,6 +536,17 @@ public class VibrationEffectTest {
        assertThat(effect.cropToLengthOrNull(2)).isNull();
    }

    @Test
    @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
    public void cropToLength_repeatingEffect() {
        VibrationEffect repeatingEffect = VibrationEffect.createRepeatingEffect(TEST_ONE_SHOT,
                TEST_WAVEFORM);
        assertThat(repeatingEffect.cropToLengthOrNull(1)).isNull();

        repeatingEffect = VibrationEffect.createRepeatingEffect(TEST_WAVEFORM);
        assertThat(repeatingEffect.cropToLengthOrNull(1)).isNull();
    }

    @Test
    public void getRingtones_noPrebakedRingtones() {
        Resources r = mockRingtoneResources(new String[0]);
@@ -621,6 +643,30 @@ public class VibrationEffectTest {
                .build()
                .validate();

        VibrationEffect.createRepeatingEffect(
                /*preamble=*/ VibrationEffect.startWaveformEnvelope()
                        .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f,
                                /*timeMillis=*/ 20)
                        .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f,
                                /*timeMillis=*/ 50)
                        .build(),
                /*repeatingEffect=*/ VibrationEffect.startWaveformEnvelope()
                        .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f,
                                /*timeMillis=*/ 20)
                        .addControlPoint(/*amplitude=*/ 0.5f, /*frequencyHz=*/ 150f,
                                /*timeMillis=*/ 100)
                        .build()
        ).validate();

        VibrationEffect.createRepeatingEffect(
                /*effect=*/ VibrationEffect.startWaveformEnvelope()
                        .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f,
                                /*timeMillis=*/ 20)
                        .addControlPoint(/*amplitude=*/ 0.5f, /*frequencyHz=*/ 150f,
                                /*timeMillis=*/ 100)
                        .build()
        ).validate();

        assertThrows(IllegalStateException.class,
                () -> VibrationEffect.startWaveformEnvelope().build().validate());
        assertThrows(IllegalArgumentException.class,
@@ -725,6 +771,21 @@ public class VibrationEffectTest {
                .repeatEffectIndefinitely(TEST_ONE_SHOT)
                .compose()
                .validate();
        VibrationEffect.startComposition()
                .addEffect(TEST_ONE_SHOT)
                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_LOW_TICK)
                .addEffect(VibrationEffect.createRepeatingEffect(
                        /*preamble=*/ VibrationEffect.createPredefined(
                                VibrationEffect.EFFECT_DOUBLE_CLICK),
                        /*repeatingEffect=*/ TEST_WAVEFORM))
                .compose()
                .validate();
        VibrationEffect.startComposition()
                .addEffect(TEST_ONE_SHOT)
                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_LOW_TICK)
                .addEffect(VibrationEffect.createRepeatingEffect(TEST_WAVEFORM))
                .compose()
                .validate();

        // Make sure class summary javadoc examples compile and are valid.
        // NOTE: IF THIS IS UPDATED, PLEASE ALSO UPDATE Composition javadocs.
@@ -787,6 +848,31 @@ public class VibrationEffectTest {
                        .addEffect(TEST_ONE_SHOT)
                        .compose()
                        .validate());

        assertThrows(UnreachableAfterRepeatingIndefinitelyException.class,
                () -> VibrationEffect.startComposition()
                        .addEffect(VibrationEffect.createRepeatingEffect(
                                /*preamble=*/ VibrationEffect.createPredefined(
                                        VibrationEffect.EFFECT_DOUBLE_CLICK),
                                /*repeatingEffect=*/ TEST_WAVEFORM))
                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
                        .compose()
                        .validate());
        assertThrows(UnreachableAfterRepeatingIndefinitelyException.class,
                () -> VibrationEffect.startComposition()
                        .addEffect(VibrationEffect.createRepeatingEffect(
                                        /*preamble=*/ VibrationEffect.createPredefined(
                                                VibrationEffect.EFFECT_DOUBLE_CLICK),
                                        /*repeatingEffect=*/ TEST_WAVEFORM))
                        .addEffect(TEST_ONE_SHOT)
                        .compose()
                        .validate());
        assertThrows(UnreachableAfterRepeatingIndefinitelyException.class,
                () -> VibrationEffect.startComposition()
                        .addEffect(VibrationEffect.createRepeatingEffect(TEST_WAVEFORM))
                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
                        .compose()
                        .validate());
    }

    @Test