diff options
| author | 2024-02-21 15:27:45 +0000 | |
|---|---|---|
| committer | 2024-02-21 15:27:45 +0000 | |
| commit | 893a4d5d2113b25d3d749615ea8bb1b8f2003764 (patch) | |
| tree | 05cfecaf2d0525884668b1a3de16b92f1ce0832a | |
| parent | 2f7214b0db43dcd0be8c80a5e1c6702854a17e67 (diff) | |
| parent | 5fea2aa6b4c2c9d8941325f424d1cf7ab4078e83 (diff) | |
Merge "Make Adaptive Haptics Scaling Linear" into main
11 files changed, 184 insertions, 5 deletions
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java index c9c91fc49aeb..efbd96bc35cb 100644 --- a/core/java/android/os/VibrationEffect.java +++ b/core/java/android/os/VibrationEffect.java @@ -591,9 +591,14 @@ public abstract class VibrationEffect implements Parcelable { /** * Scale given vibration intensity by the given factor. * + * <p> This scale is not necessarily linear and may apply a gamma correction to the scale + * factor before using it. + * * @param intensity relative intensity of the effect, must be between 0 and 1 * @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 the scaled intensity which will be values within [0, 1]. + * * @hide */ public static float scale(float intensity, float scaleFactor) { @@ -624,6 +629,20 @@ public abstract class VibrationEffect implements Parcelable { } /** + * Performs a linear scaling on the given vibration intensity by the given factor. + * + * @param intensity relative intensity of the effect, must be between 0 and 1. + * @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 the scaled intensity which will be values within [0, 1]. + * + * @hide + */ + public static float scaleLinearly(float intensity, float scaleFactor) { + return MathUtils.constrain(intensity * scaleFactor, 0f, 1f); + } + + /** * Returns a compact version of the {@link #toString()} result for debugging purposes. * * @hide diff --git a/core/java/android/os/vibrator/PrebakedSegment.java b/core/java/android/os/vibrator/PrebakedSegment.java index a035092e314f..39f841226e4e 100644 --- a/core/java/android/os/vibrator/PrebakedSegment.java +++ b/core/java/android/os/vibrator/PrebakedSegment.java @@ -137,6 +137,14 @@ public final class PrebakedSegment extends VibrationEffectSegment { /** @hide */ @NonNull @Override + public PrebakedSegment scaleLinearly(float scaleFactor) { + // Prebaked effect strength cannot be scaled with this method. + return this; + } + + /** @hide */ + @NonNull + @Override public PrebakedSegment applyEffectStrength(int effectStrength) { if (effectStrength != mEffectStrength && isValidEffectStrength(effectStrength)) { return new PrebakedSegment(mEffectId, mFallback, effectStrength); diff --git a/core/java/android/os/vibrator/PrimitiveSegment.java b/core/java/android/os/vibrator/PrimitiveSegment.java index 95d97bfe4ad1..3c84bcda639b 100644 --- a/core/java/android/os/vibrator/PrimitiveSegment.java +++ b/core/java/android/os/vibrator/PrimitiveSegment.java @@ -98,8 +98,24 @@ public final class PrimitiveSegment extends VibrationEffectSegment { @NonNull @Override public PrimitiveSegment scale(float scaleFactor) { - return new PrimitiveSegment(mPrimitiveId, VibrationEffect.scale(mScale, scaleFactor), - mDelay); + float newScale = VibrationEffect.scale(mScale, scaleFactor); + if (Float.compare(mScale, newScale) == 0) { + return this; + } + + return new PrimitiveSegment(mPrimitiveId, newScale, mDelay); + } + + /** @hide */ + @NonNull + @Override + public PrimitiveSegment scaleLinearly(float scaleFactor) { + float newScale = VibrationEffect.scaleLinearly(mScale, scaleFactor); + if (Float.compare(mScale, newScale) == 0) { + return this; + } + + return new PrimitiveSegment(mPrimitiveId, newScale, mDelay); } /** @hide */ diff --git a/core/java/android/os/vibrator/RampSegment.java b/core/java/android/os/vibrator/RampSegment.java index 5f9d1024d9a5..09d2e26be2a5 100644 --- a/core/java/android/os/vibrator/RampSegment.java +++ b/core/java/android/os/vibrator/RampSegment.java @@ -159,6 +159,21 @@ public final class RampSegment extends VibrationEffectSegment { /** @hide */ @NonNull @Override + public RampSegment scaleLinearly(float scaleFactor) { + float newStartAmplitude = VibrationEffect.scaleLinearly(mStartAmplitude, scaleFactor); + float newEndAmplitude = VibrationEffect.scaleLinearly(mEndAmplitude, scaleFactor); + if (Float.compare(mStartAmplitude, newStartAmplitude) == 0 + && Float.compare(mEndAmplitude, newEndAmplitude) == 0) { + return this; + } + return new RampSegment(newStartAmplitude, newEndAmplitude, mStartFrequencyHz, + mEndFrequencyHz, + mDuration); + } + + /** @hide */ + @NonNull + @Override public RampSegment applyEffectStrength(int effectStrength) { return this; } diff --git a/core/java/android/os/vibrator/StepSegment.java b/core/java/android/os/vibrator/StepSegment.java index 9576a5bba1f1..fa083c176a27 100644 --- a/core/java/android/os/vibrator/StepSegment.java +++ b/core/java/android/os/vibrator/StepSegment.java @@ -137,8 +137,25 @@ public final class StepSegment extends VibrationEffectSegment { if (Float.compare(mAmplitude, VibrationEffect.DEFAULT_AMPLITUDE) == 0) { return this; } - return new StepSegment(VibrationEffect.scale(mAmplitude, scaleFactor), mFrequencyHz, - mDuration); + float newAmplitude = VibrationEffect.scale(mAmplitude, scaleFactor); + if (Float.compare(newAmplitude, mAmplitude) == 0) { + return this; + } + return new StepSegment(newAmplitude, mFrequencyHz, mDuration); + } + + /** @hide */ + @NonNull + @Override + public StepSegment scaleLinearly(float scaleFactor) { + if (Float.compare(mAmplitude, VibrationEffect.DEFAULT_AMPLITUDE) == 0) { + return this; + } + float newAmplitude = VibrationEffect.scaleLinearly(mAmplitude, scaleFactor); + if (Float.compare(newAmplitude, mAmplitude) == 0) { + return this; + } + return new StepSegment(newAmplitude, mFrequencyHz, mDuration); } /** @hide */ diff --git a/core/java/android/os/vibrator/VibrationEffectSegment.java b/core/java/android/os/vibrator/VibrationEffectSegment.java index 17ac36f3ab37..e1fb4e361008 100644 --- a/core/java/android/os/vibrator/VibrationEffectSegment.java +++ b/core/java/android/os/vibrator/VibrationEffectSegment.java @@ -96,6 +96,9 @@ public abstract class VibrationEffectSegment implements Parcelable { /** * Scale the segment intensity with the given factor. * + * <p> This scale is not necessarily linear and may apply a gamma correction to the scale + * factor before using it. + * * @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 * @@ -105,6 +108,17 @@ public abstract class VibrationEffectSegment implements Parcelable { public abstract <T extends VibrationEffectSegment> T scale(float scaleFactor); /** + * Performs a linear scaling on the segment intensity with the given factor. + * + * @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 + * + * @hide + */ + @NonNull + public abstract <T extends VibrationEffectSegment> T scaleLinearly(float scaleFactor); + + /** * Applies given effect strength to prebaked effects. * * @param effectStrength new effect strength to be applied, one of diff --git a/core/tests/vibrator/src/android/os/vibrator/PrebakedSegmentTest.java b/core/tests/vibrator/src/android/os/vibrator/PrebakedSegmentTest.java index 4f5f3c0ddeaf..7dd9e55f8f3e 100644 --- a/core/tests/vibrator/src/android/os/vibrator/PrebakedSegmentTest.java +++ b/core/tests/vibrator/src/android/os/vibrator/PrebakedSegmentTest.java @@ -106,6 +106,13 @@ public class PrebakedSegmentTest { } @Test + public void testScaleLinearly_ignoresAndReturnsSameEffect() { + PrebakedSegment prebaked = new PrebakedSegment( + VibrationEffect.EFFECT_CLICK, true, VibrationEffect.EFFECT_STRENGTH_MEDIUM); + assertSame(prebaked, prebaked.scaleLinearly(0.5f)); + } + + @Test public void testDuration() { assertEquals(-1, new PrebakedSegment( VibrationEffect.EFFECT_CLICK, true, VibrationEffect.EFFECT_STRENGTH_MEDIUM) diff --git a/core/tests/vibrator/src/android/os/vibrator/PrimitiveSegmentTest.java b/core/tests/vibrator/src/android/os/vibrator/PrimitiveSegmentTest.java index ec5a084c2ddb..e9a08aef4856 100644 --- a/core/tests/vibrator/src/android/os/vibrator/PrimitiveSegmentTest.java +++ b/core/tests/vibrator/src/android/os/vibrator/PrimitiveSegmentTest.java @@ -129,6 +129,27 @@ public class PrimitiveSegmentTest { } @Test + public void testScaleLinearly() { + PrimitiveSegment initial = new PrimitiveSegment( + VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 0); + + assertEquals(1f, initial.scaleLinearly(1).getScale(), TOLERANCE); + assertEquals(0.5f, initial.scaleLinearly(0.5f).getScale(), TOLERANCE); + assertEquals(1f, initial.scaleLinearly(1.5f).getScale(), TOLERANCE); + assertEquals(0.8f, initial.scaleLinearly(0.8f).getScale(), TOLERANCE); + // Restores back to the exact original value since this is a linear scaling. + assertEquals(1f, initial.scaleLinearly(0.8f).scaleLinearly(1.25f).getScale(), TOLERANCE); + + initial = new PrimitiveSegment(VibrationEffect.Composition.PRIMITIVE_CLICK, 0, 0); + + assertEquals(0f, initial.scaleLinearly(1).getScale(), TOLERANCE); + assertEquals(0f, initial.scaleLinearly(0.5f).getScale(), TOLERANCE); + assertEquals(0f, initial.scaleLinearly(1.5f).getScale(), TOLERANCE); + assertEquals(0f, initial.scaleLinearly(1.5f).scaleLinearly(2 / 3f).getScale(), TOLERANCE); + assertEquals(0f, initial.scaleLinearly(0.8f).scaleLinearly(1.25f).getScale(), TOLERANCE); + } + + @Test public void testDuration() { assertEquals(-1, new PrimitiveSegment( VibrationEffect.Composition.PRIMITIVE_NOOP, 1, 10).getDuration()); diff --git a/core/tests/vibrator/src/android/os/vibrator/RampSegmentTest.java b/core/tests/vibrator/src/android/os/vibrator/RampSegmentTest.java index 5caa86bb9fb5..01013ab69f85 100644 --- a/core/tests/vibrator/src/android/os/vibrator/RampSegmentTest.java +++ b/core/tests/vibrator/src/android/os/vibrator/RampSegmentTest.java @@ -131,6 +131,37 @@ public class RampSegmentTest { } @Test + public void testScaleLinearly() { + RampSegment initial = new RampSegment(0, 1, 0, 0, 0); + + assertEquals(0f, initial.scaleLinearly(1f).getStartAmplitude(), TOLERANCE); + assertEquals(0f, initial.scaleLinearly(0.5f).getStartAmplitude(), TOLERANCE); + assertEquals(0f, initial.scaleLinearly(1.5f).getStartAmplitude(), TOLERANCE); + assertEquals(0f, initial.scaleLinearly(1.5f).scaleLinearly(2 / 3f).getStartAmplitude(), + TOLERANCE); + assertEquals(0f, initial.scaleLinearly(0.8f).scaleLinearly(1.25f).getStartAmplitude(), + TOLERANCE); + + assertEquals(1f, initial.scaleLinearly(1f).getEndAmplitude(), TOLERANCE); + assertEquals(0.5f, initial.scaleLinearly(0.5f).getEndAmplitude(), TOLERANCE); + assertEquals(1f, initial.scaleLinearly(1.5f).getEndAmplitude(), TOLERANCE); + assertEquals(0.8f, initial.scaleLinearly(0.8f).getEndAmplitude(), TOLERANCE); + // Restores back to the exact original value since this is a linear scaling. + assertEquals(0.8f, initial.scaleLinearly(1.5f).scaleLinearly(0.8f).getEndAmplitude(), + TOLERANCE); + + initial = new RampSegment(0.5f, 1, 0, 0, 0); + + assertEquals(0.5f, initial.scaleLinearly(1).getStartAmplitude(), TOLERANCE); + assertEquals(0.25f, initial.scaleLinearly(0.5f).getStartAmplitude(), TOLERANCE); + assertEquals(0.75f, initial.scaleLinearly(1.5f).getStartAmplitude(), TOLERANCE); + assertEquals(0.4f, initial.scaleLinearly(0.8f).getStartAmplitude(), TOLERANCE); + // Restores back to the exact original value since this is a linear scaling. + assertEquals(0.5f, initial.scaleLinearly(0.8f).scaleLinearly(1.25f).getStartAmplitude(), + TOLERANCE); + } + + @Test public void testDuration() { assertEquals(10, new RampSegment(0.5f, 1, 0, 0, 10).getDuration()); } diff --git a/core/tests/vibrator/src/android/os/vibrator/StepSegmentTest.java b/core/tests/vibrator/src/android/os/vibrator/StepSegmentTest.java index 44db30603089..40776abc0291 100644 --- a/core/tests/vibrator/src/android/os/vibrator/StepSegmentTest.java +++ b/core/tests/vibrator/src/android/os/vibrator/StepSegmentTest.java @@ -141,6 +141,37 @@ public class StepSegmentTest { } @Test + public void testScaleLinearly_fullAmplitude() { + StepSegment initial = new StepSegment(1f, 0, 0); + + assertEquals(1f, initial.scaleLinearly(1).getAmplitude(), TOLERANCE); + assertEquals(0.5f, initial.scaleLinearly(0.5f).getAmplitude(), TOLERANCE); + assertEquals(1f, initial.scaleLinearly(1.5f).getAmplitude(), TOLERANCE); + assertEquals(0.8f, initial.scaleLinearly(0.8f).getAmplitude(), TOLERANCE); + // Restores back to the exact original value since this is a linear scaling. + assertEquals(1f, initial.scaleLinearly(0.8f).scaleLinearly(1.25f).getAmplitude(), + TOLERANCE); + + initial = new StepSegment(0, 0, 0); + + assertEquals(0f, initial.scaleLinearly(1).getAmplitude(), TOLERANCE); + assertEquals(0f, initial.scaleLinearly(0.5f).getAmplitude(), TOLERANCE); + assertEquals(0f, initial.scaleLinearly(1.5f).getAmplitude(), TOLERANCE); + } + + @Test + public void testScaleLinearly_defaultAmplitude() { + StepSegment initial = new StepSegment(VibrationEffect.DEFAULT_AMPLITUDE, 0, 0); + + assertEquals(VibrationEffect.DEFAULT_AMPLITUDE, initial.scaleLinearly(1).getAmplitude(), + TOLERANCE); + assertEquals(VibrationEffect.DEFAULT_AMPLITUDE, initial.scaleLinearly(0.5f).getAmplitude(), + TOLERANCE); + assertEquals(VibrationEffect.DEFAULT_AMPLITUDE, initial.scaleLinearly(1.5f).getAmplitude(), + TOLERANCE); + } + + @Test public void testDuration() { assertEquals(5, new StepSegment(0, 0, 5).getDuration()); } diff --git a/services/core/java/com/android/server/vibrator/VibrationScaler.java b/services/core/java/com/android/server/vibrator/VibrationScaler.java index c9805c706fbc..09a177a6951b 100644 --- a/services/core/java/com/android/server/vibrator/VibrationScaler.java +++ b/services/core/java/com/android/server/vibrator/VibrationScaler.java @@ -149,7 +149,7 @@ final class VibrationScaler { && mAdaptiveHapticsScales.size() > 0 && mAdaptiveHapticsScales.contains(usageHint)) { float adaptiveScale = mAdaptiveHapticsScales.get(usageHint); - segment = segment.scale(adaptiveScale); + segment = segment.scaleLinearly(adaptiveScale); } segments.set(i, segment); |