diff options
| -rw-r--r-- | core/api/current.txt | 2 | ||||
| -rw-r--r-- | core/java/android/os/VibrationEffect.java | 43 | ||||
| -rw-r--r-- | core/tests/vibrator/src/android/os/VibrationEffectTest.java | 86 |
3 files changed, 131 insertions, 0 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 4cb791a9db1f..69728d37ccef 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -34373,6 +34373,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(); diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java index d8094ab0f748..a3844e244edb 100644 --- a/core/java/android/os/VibrationEffect.java +++ b/core/java/android/os/VibrationEffect.java @@ -1404,6 +1404,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}. * diff --git a/core/tests/vibrator/src/android/os/VibrationEffectTest.java b/core/tests/vibrator/src/android/os/VibrationEffectTest.java index 8a250bdd5459..beb69858a85c 100644 --- a/core/tests/vibrator/src/android/os/VibrationEffectTest.java +++ b/core/tests/vibrator/src/android/os/VibrationEffectTest.java @@ -403,6 +403,17 @@ public class VibrationEffectTest { @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() { // Effects created via startWaveformEnvelope are not expected to be converted to long[] // patterns, as they are not configured to always play with the default amplitude. @@ -526,6 +537,17 @@ public class VibrationEffectTest { } @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]); Context context = mockContext(r); @@ -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 |