Merge "Make Adaptive Haptics Scaling Linear" into main
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index c9c91fc..efbd96b 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -591,9 +591,14 @@
/**
* 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 @@
}
/**
+ * 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 a035092..39f8412 100644
--- a/core/java/android/os/vibrator/PrebakedSegment.java
+++ b/core/java/android/os/vibrator/PrebakedSegment.java
@@ -137,6 +137,14 @@
/** @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 95d97bf..3c84bcd 100644
--- a/core/java/android/os/vibrator/PrimitiveSegment.java
+++ b/core/java/android/os/vibrator/PrimitiveSegment.java
@@ -98,8 +98,24 @@
@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 5f9d102..09d2e26 100644
--- a/core/java/android/os/vibrator/RampSegment.java
+++ b/core/java/android/os/vibrator/RampSegment.java
@@ -159,6 +159,21 @@
/** @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 9576a5b..fa083c1 100644
--- a/core/java/android/os/vibrator/StepSegment.java
+++ b/core/java/android/os/vibrator/StepSegment.java
@@ -137,8 +137,25 @@
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 17ac36f..e1fb4e3 100644
--- a/core/java/android/os/vibrator/VibrationEffectSegment.java
+++ b/core/java/android/os/vibrator/VibrationEffectSegment.java
@@ -96,6 +96,9 @@
/**
* 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 <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 4f5f3c0..7dd9e55 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 @@
}
@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 ec5a084..e9a08ae 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 @@
}
@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 5caa86b..01013ab 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 @@
}
@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 44db306..40776ab 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 @@
}
@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 c9805c7..09a177a 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 @@
&& mAdaptiveHapticsScales.size() > 0
&& mAdaptiveHapticsScales.contains(usageHint)) {
float adaptiveScale = mAdaptiveHapticsScales.get(usageHint);
- segment = segment.scale(adaptiveScale);
+ segment = segment.scaleLinearly(adaptiveScale);
}
segments.set(i, segment);