Loading core/java/android/os/VibrationEffect.java +58 −0 Original line number Diff line number Diff line Loading @@ -546,6 +546,30 @@ public abstract class VibrationEffect implements Parcelable { return false; } /** * Resolve default values into integer amplitude numbers. * * @param defaultAmplitude the default amplitude to apply, must be between 0 and * MAX_AMPLITUDE * @return this if amplitude value is already set, or a copy of this effect with given default * amplitude otherwise * * @hide */ public abstract <T extends VibrationEffect> T resolve(int defaultAmplitude); /** * Scale the vibration effect intensity with the given constraints. * * @param scaleFactor scale factor to be applied to the intensity. Values within [0,1) will * scale down the intensity, values larger than 1 will scale up * @return this if there is no scaling to be done, or a copy of this effect with scaled * vibration intensity otherwise * * @hide */ public abstract <T extends VibrationEffect> T scale(float scaleFactor); /** * Ensures that the effect is repeating indefinitely or not. This is a lossy operation and * should only be applied once to an original effect - it shouldn't be applied to the Loading Loading @@ -819,6 +843,40 @@ public abstract class VibrationEffect implements Parcelable { return totalDuration <= MAX_HAPTIC_FEEDBACK_DURATION; } /** @hide */ @NonNull @Override public Composed resolve(int defaultAmplitude) { int segmentCount = mSegments.size(); ArrayList<VibrationEffectSegment> resolvedSegments = new ArrayList<>(segmentCount); for (int i = 0; i < segmentCount; i++) { resolvedSegments.add(mSegments.get(i).resolve(defaultAmplitude)); } if (resolvedSegments.equals(mSegments)) { return this; } Composed resolved = new Composed(resolvedSegments, mRepeatIndex); resolved.validate(); return resolved; } /** @hide */ @NonNull @Override public Composed scale(float scaleFactor) { int segmentCount = mSegments.size(); ArrayList<VibrationEffectSegment> scaledSegments = new ArrayList<>(segmentCount); for (int i = 0; i < segmentCount; i++) { scaledSegments.add(mSegments.get(i).scale(scaleFactor)); } if (scaledSegments.equals(mSegments)) { return this; } Composed scaled = new Composed(scaledSegments, mRepeatIndex); scaled.validate(); return scaled; } /** @hide */ @NonNull @Override Loading core/tests/coretests/src/android/os/VibrationEffectTest.java +84 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,8 @@ import android.content.res.Resources; import android.hardware.vibrator.IVibrator; import android.net.Uri; import android.os.VibrationEffect.Composition.UnreachableAfterRepeatingIndefinitelyException; import android.os.vibrator.PrimitiveSegment; import android.os.vibrator.StepSegment; import android.platform.test.annotations.Presubmit; import androidx.test.InstrumentationRegistry; Loading Loading @@ -634,6 +636,88 @@ public class VibrationEffectTest { .validate()); } @Test public void testResolveOneShot() { VibrationEffect.Composed resolved = DEFAULT_ONE_SHOT.resolve(51); assertEquals(0.2f, ((StepSegment) resolved.getSegments().get(0)).getAmplitude()); assertThrows(IllegalArgumentException.class, () -> DEFAULT_ONE_SHOT.resolve(1000)); } @Test public void testResolveWaveform() { VibrationEffect.Composed resolved = TEST_WAVEFORM.resolve(102); assertEquals(0.4f, ((StepSegment) resolved.getSegments().get(2)).getAmplitude()); assertThrows(IllegalArgumentException.class, () -> TEST_WAVEFORM.resolve(1000)); } @Test public void testResolvePrebaked() { VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); assertEquals(effect, effect.resolve(51)); } @Test public void testResolveComposed() { VibrationEffect effect = VibrationEffect.startComposition() .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 1) .compose(); assertEquals(effect, effect.resolve(51)); VibrationEffect.Composed resolved = VibrationEffect.startComposition() .addEffect(DEFAULT_ONE_SHOT) .compose() .resolve(51); assertEquals(0.2f, ((StepSegment) resolved.getSegments().get(0)).getAmplitude()); } @Test public void testScaleOneShot() { VibrationEffect.Composed scaledUp = TEST_ONE_SHOT.scale(1.5f); assertTrue(100 / 255f < ((StepSegment) scaledUp.getSegments().get(0)).getAmplitude()); VibrationEffect.Composed scaledDown = TEST_ONE_SHOT.scale(0.5f); assertTrue(100 / 255f > ((StepSegment) scaledDown.getSegments().get(0)).getAmplitude()); } @Test public void testScaleWaveform() { VibrationEffect.Composed scaledUp = TEST_WAVEFORM.scale(1.5f); assertEquals(1f, ((StepSegment) scaledUp.getSegments().get(0)).getAmplitude(), 1e-5f); VibrationEffect.Composed scaledDown = TEST_WAVEFORM.scale(0.5f); assertTrue(1f > ((StepSegment) scaledDown.getSegments().get(0)).getAmplitude()); } @Test public void testScalePrebaked() { VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); VibrationEffect.Composed scaledUp = effect.scale(1.5f); assertEquals(effect, scaledUp); VibrationEffect.Composed scaledDown = effect.scale(0.5f); assertEquals(effect, scaledDown); } @Test public void testScaleComposed() { VibrationEffect.Composed effect = (VibrationEffect.Composed) VibrationEffect.startComposition() .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0.5f, 1) .addEffect(TEST_ONE_SHOT) .compose(); VibrationEffect.Composed scaledUp = effect.scale(1.5f); assertTrue(0.5f < ((PrimitiveSegment) scaledUp.getSegments().get(0)).getScale()); assertTrue(100 / 255f < ((StepSegment) scaledUp.getSegments().get(1)).getAmplitude()); VibrationEffect.Composed scaledDown = effect.scale(0.5f); assertTrue(0.5f > ((PrimitiveSegment) scaledDown.getSegments().get(0)).getScale()); assertTrue(100 / 255f > ((StepSegment) scaledDown.getSegments().get(1)).getAmplitude()); } private void doTestApplyRepeatingWithNonRepeatingOriginal(@NotNull VibrationEffect original) { assertTrue(original.getDuration() != Long.MAX_VALUE); int loopDelayMs = 123; Loading Loading
core/java/android/os/VibrationEffect.java +58 −0 Original line number Diff line number Diff line Loading @@ -546,6 +546,30 @@ public abstract class VibrationEffect implements Parcelable { return false; } /** * Resolve default values into integer amplitude numbers. * * @param defaultAmplitude the default amplitude to apply, must be between 0 and * MAX_AMPLITUDE * @return this if amplitude value is already set, or a copy of this effect with given default * amplitude otherwise * * @hide */ public abstract <T extends VibrationEffect> T resolve(int defaultAmplitude); /** * Scale the vibration effect intensity with the given constraints. * * @param scaleFactor scale factor to be applied to the intensity. Values within [0,1) will * scale down the intensity, values larger than 1 will scale up * @return this if there is no scaling to be done, or a copy of this effect with scaled * vibration intensity otherwise * * @hide */ public abstract <T extends VibrationEffect> T scale(float scaleFactor); /** * Ensures that the effect is repeating indefinitely or not. This is a lossy operation and * should only be applied once to an original effect - it shouldn't be applied to the Loading Loading @@ -819,6 +843,40 @@ public abstract class VibrationEffect implements Parcelable { return totalDuration <= MAX_HAPTIC_FEEDBACK_DURATION; } /** @hide */ @NonNull @Override public Composed resolve(int defaultAmplitude) { int segmentCount = mSegments.size(); ArrayList<VibrationEffectSegment> resolvedSegments = new ArrayList<>(segmentCount); for (int i = 0; i < segmentCount; i++) { resolvedSegments.add(mSegments.get(i).resolve(defaultAmplitude)); } if (resolvedSegments.equals(mSegments)) { return this; } Composed resolved = new Composed(resolvedSegments, mRepeatIndex); resolved.validate(); return resolved; } /** @hide */ @NonNull @Override public Composed scale(float scaleFactor) { int segmentCount = mSegments.size(); ArrayList<VibrationEffectSegment> scaledSegments = new ArrayList<>(segmentCount); for (int i = 0; i < segmentCount; i++) { scaledSegments.add(mSegments.get(i).scale(scaleFactor)); } if (scaledSegments.equals(mSegments)) { return this; } Composed scaled = new Composed(scaledSegments, mRepeatIndex); scaled.validate(); return scaled; } /** @hide */ @NonNull @Override Loading
core/tests/coretests/src/android/os/VibrationEffectTest.java +84 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,8 @@ import android.content.res.Resources; import android.hardware.vibrator.IVibrator; import android.net.Uri; import android.os.VibrationEffect.Composition.UnreachableAfterRepeatingIndefinitelyException; import android.os.vibrator.PrimitiveSegment; import android.os.vibrator.StepSegment; import android.platform.test.annotations.Presubmit; import androidx.test.InstrumentationRegistry; Loading Loading @@ -634,6 +636,88 @@ public class VibrationEffectTest { .validate()); } @Test public void testResolveOneShot() { VibrationEffect.Composed resolved = DEFAULT_ONE_SHOT.resolve(51); assertEquals(0.2f, ((StepSegment) resolved.getSegments().get(0)).getAmplitude()); assertThrows(IllegalArgumentException.class, () -> DEFAULT_ONE_SHOT.resolve(1000)); } @Test public void testResolveWaveform() { VibrationEffect.Composed resolved = TEST_WAVEFORM.resolve(102); assertEquals(0.4f, ((StepSegment) resolved.getSegments().get(2)).getAmplitude()); assertThrows(IllegalArgumentException.class, () -> TEST_WAVEFORM.resolve(1000)); } @Test public void testResolvePrebaked() { VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); assertEquals(effect, effect.resolve(51)); } @Test public void testResolveComposed() { VibrationEffect effect = VibrationEffect.startComposition() .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 1) .compose(); assertEquals(effect, effect.resolve(51)); VibrationEffect.Composed resolved = VibrationEffect.startComposition() .addEffect(DEFAULT_ONE_SHOT) .compose() .resolve(51); assertEquals(0.2f, ((StepSegment) resolved.getSegments().get(0)).getAmplitude()); } @Test public void testScaleOneShot() { VibrationEffect.Composed scaledUp = TEST_ONE_SHOT.scale(1.5f); assertTrue(100 / 255f < ((StepSegment) scaledUp.getSegments().get(0)).getAmplitude()); VibrationEffect.Composed scaledDown = TEST_ONE_SHOT.scale(0.5f); assertTrue(100 / 255f > ((StepSegment) scaledDown.getSegments().get(0)).getAmplitude()); } @Test public void testScaleWaveform() { VibrationEffect.Composed scaledUp = TEST_WAVEFORM.scale(1.5f); assertEquals(1f, ((StepSegment) scaledUp.getSegments().get(0)).getAmplitude(), 1e-5f); VibrationEffect.Composed scaledDown = TEST_WAVEFORM.scale(0.5f); assertTrue(1f > ((StepSegment) scaledDown.getSegments().get(0)).getAmplitude()); } @Test public void testScalePrebaked() { VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); VibrationEffect.Composed scaledUp = effect.scale(1.5f); assertEquals(effect, scaledUp); VibrationEffect.Composed scaledDown = effect.scale(0.5f); assertEquals(effect, scaledDown); } @Test public void testScaleComposed() { VibrationEffect.Composed effect = (VibrationEffect.Composed) VibrationEffect.startComposition() .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0.5f, 1) .addEffect(TEST_ONE_SHOT) .compose(); VibrationEffect.Composed scaledUp = effect.scale(1.5f); assertTrue(0.5f < ((PrimitiveSegment) scaledUp.getSegments().get(0)).getScale()); assertTrue(100 / 255f < ((StepSegment) scaledUp.getSegments().get(1)).getAmplitude()); VibrationEffect.Composed scaledDown = effect.scale(0.5f); assertTrue(0.5f > ((PrimitiveSegment) scaledDown.getSegments().get(0)).getScale()); assertTrue(100 / 255f > ((StepSegment) scaledDown.getSegments().get(1)).getAmplitude()); } private void doTestApplyRepeatingWithNonRepeatingOriginal(@NotNull VibrationEffect original) { assertTrue(original.getDuration() != Long.MAX_VALUE); int loopDelayMs = 123; Loading