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

Commit 814d28df authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Update haptics scaling" into main

parents 92414fd8 680034b3
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -33,11 +33,23 @@ parcelable ExternalVibrationScale {
        SCALE_VERY_HIGH = 2
    }

    // TODO(b/345186129): remove this once we finish migrating to scale factor.
    /**
     * The scale level that will be applied to external vibrations.
     */
    ScaleLevel scaleLevel = ScaleLevel.SCALE_NONE;

    /**
     * The scale factor that will be applied to external vibrations.
     *
     * Values in (0,1) will scale down the vibrations, values > 1 will scale up vibrations within
     * hardware limits. A zero scale factor indicates the external vibration should be muted.
     *
     * TODO(b/345186129): update this once we finish migrating, negative should not be expected.
     * Negative values should be ignored in favour of the legacy ScaleLevel.
     */
    float scaleFactor = -1f; // undefined

    /**
     * The adaptive haptics scale that will be applied to external vibrations.
     */
+9 −0
Original line number Diff line number Diff line
@@ -663,6 +663,15 @@ public abstract class VibrationEffect implements Parcelable {
     * @hide
     */
    public static float scale(float intensity, float scaleFactor) {
        if (Flags.hapticsScaleV2Enabled()) {
            if (Float.compare(scaleFactor, 1) <= 0 || Float.compare(intensity, 0) == 0) {
                // Scaling down or scaling zero intensity is straightforward.
                return scaleFactor * intensity;
            }
            // Using S * x / (1 + (S - 1) * x^2) as the scale up function to converge to 1.0.
            return (scaleFactor * intensity) / (1 + (scaleFactor - 1) * intensity * intensity);
        }

        // Applying gamma correction to the scale factor, which is the same as encoding the input
        // value, scaling it, then decoding the scaled value.
        float scale = MathUtils.pow(scaleFactor, 1f / SCALE_GAMMA);
+45 −7
Original line number Diff line number Diff line
@@ -49,8 +49,22 @@ import java.util.Arrays;
 */
public class VibrationConfig {

    /**
     * Hardcoded default scale level gain to be applied between each scale level to define their
     * scale factor value.
     *
     * <p>Default gain defined as 3 dBs.
     */
    private static final float DEFAULT_SCALE_LEVEL_GAIN = 1.4f;

    /**
     * Hardcoded default amplitude to be used when device config is invalid, i.e. not in [1,255].
     */
    private static final int DEFAULT_AMPLITUDE = 255;

    // TODO(b/191150049): move these to vibrator static config file
    private final float mHapticChannelMaxVibrationAmplitude;
    private final int mDefaultVibrationAmplitude;
    private final int mRampStepDurationMs;
    private final int mRampDownDurationMs;
    private final int mRequestVibrationParamsTimeoutMs;
@@ -75,8 +89,10 @@ public class VibrationConfig {

    /** @hide */
    public VibrationConfig(@Nullable Resources resources) {
        mDefaultVibrationAmplitude = resources.getInteger(
                com.android.internal.R.integer.config_defaultVibrationAmplitude);
        mHapticChannelMaxVibrationAmplitude = loadFloat(resources,
                com.android.internal.R.dimen.config_hapticChannelMaxVibrationAmplitude, 0);
                com.android.internal.R.dimen.config_hapticChannelMaxVibrationAmplitude);
        mRampDownDurationMs = loadInteger(resources,
                com.android.internal.R.integer.config_vibrationWaveformRampDownDuration, 0);
        mRampStepDurationMs = loadInteger(resources,
@@ -87,9 +103,9 @@ public class VibrationConfig {
                com.android.internal.R.array.config_requestVibrationParamsForUsages);

        mIgnoreVibrationsOnWirelessCharger = loadBoolean(resources,
                com.android.internal.R.bool.config_ignoreVibrationsOnWirelessCharger, false);
                com.android.internal.R.bool.config_ignoreVibrationsOnWirelessCharger);
        mKeyboardVibrationSettingsSupported = loadBoolean(resources,
                com.android.internal.R.bool.config_keyboardVibrationSettingsSupported, false);
                com.android.internal.R.bool.config_keyboardVibrationSettingsSupported);

        mDefaultAlarmVibrationIntensity = loadDefaultIntensity(resources,
                com.android.internal.R.integer.config_defaultAlarmVibrationIntensity);
@@ -115,16 +131,16 @@ public class VibrationConfig {
        return value;
    }

    private static float loadFloat(@Nullable Resources res, int resId, float defaultValue) {
        return res != null ? res.getFloat(resId) : defaultValue;
    private static float loadFloat(@Nullable Resources res, int resId) {
        return res != null ? res.getFloat(resId) : 0f;
    }

    private static int loadInteger(@Nullable Resources res, int resId, int defaultValue) {
        return res != null ? res.getInteger(resId) : defaultValue;
    }

    private static boolean loadBoolean(@Nullable Resources res, int resId, boolean defaultValue) {
        return res != null ? res.getBoolean(resId) : defaultValue;
    private static boolean loadBoolean(@Nullable Resources res, int resId) {
        return res != null && res.getBoolean(resId);
    }

    private static int[] loadIntArray(@Nullable Resources res, int resId) {
@@ -144,6 +160,26 @@ public class VibrationConfig {
        return mHapticChannelMaxVibrationAmplitude;
    }

    /**
     * Return the device default vibration amplitude value to replace the
     * {@link android.os.VibrationEffect#DEFAULT_AMPLITUDE} constant.
     */
    public int getDefaultVibrationAmplitude() {
        if (mDefaultVibrationAmplitude < 1 || mDefaultVibrationAmplitude > 255) {
            return DEFAULT_AMPLITUDE;
        }
        return mDefaultVibrationAmplitude;
    }

    /**
     * Return the device default gain to be applied between scale levels to define the scale factor
     * for each level.
     */
    public float getDefaultVibrationScaleLevelGain() {
        // TODO(b/356407380): add device config for this
        return DEFAULT_SCALE_LEVEL_GAIN;
    }

    /**
     * The duration, in milliseconds, that should be applied to the ramp to turn off the vibrator
     * when a vibration is cancelled or finished at non-zero amplitude.
@@ -233,6 +269,7 @@ public class VibrationConfig {
    public String toString() {
        return "VibrationConfig{"
                + "mIgnoreVibrationsOnWirelessCharger=" + mIgnoreVibrationsOnWirelessCharger
                + ", mDefaultVibrationAmplitude=" + mDefaultVibrationAmplitude
                + ", mHapticChannelMaxVibrationAmplitude=" + mHapticChannelMaxVibrationAmplitude
                + ", mRampStepDurationMs=" + mRampStepDurationMs
                + ", mRampDownDurationMs=" + mRampDownDurationMs
@@ -258,6 +295,7 @@ public class VibrationConfig {
        pw.println("VibrationConfig:");
        pw.increaseIndent();
        pw.println("ignoreVibrationsOnWirelessCharger = " + mIgnoreVibrationsOnWirelessCharger);
        pw.println("defaultVibrationAmplitude = " + mDefaultVibrationAmplitude);
        pw.println("hapticChannelMaxAmplitude = " + mHapticChannelMaxVibrationAmplitude);
        pw.println("rampStepDurationMs = " + mRampStepDurationMs);
        pw.println("rampDownDurationMs = " + mRampDownDurationMs);
+10 −0
Original line number Diff line number Diff line
@@ -103,3 +103,13 @@ flag {
        purpose: PURPOSE_FEATURE
    }
}

flag {
    namespace: "haptics"
    name: "haptics_scale_v2_enabled"
    description: "Enables new haptics scaling function across all usages"
    bug: "345186129"
    metadata {
        purpose: PURPOSE_FEATURE
    }
}
+43 −2
Original line number Diff line number Diff line
@@ -27,7 +27,11 @@ import android.hardware.vibrator.IVibrator;
import android.os.Parcel;
import android.os.VibrationEffect;
import android.os.VibratorInfo;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -36,6 +40,9 @@ import org.junit.runners.JUnit4;
public class PrimitiveSegmentTest {
    private static final float TOLERANCE = 1e-2f;

    @Rule
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    @Test
    public void testCreation() {
        PrimitiveSegment primitive = new PrimitiveSegment(
@@ -87,7 +94,8 @@ public class PrimitiveSegmentTest {
    }

    @Test
    public void testScale_fullPrimitiveScaleValue() {
    @DisableFlags(Flags.FLAG_HAPTICS_SCALE_V2_ENABLED)
    public void testScale_withLegacyScaling_fullPrimitiveScaleValue() {
        PrimitiveSegment initial = new PrimitiveSegment(
                VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 0);

@@ -102,7 +110,24 @@ public class PrimitiveSegmentTest {
    }

    @Test
    public void testScale_halfPrimitiveScaleValue() {
    @EnableFlags(Flags.FLAG_HAPTICS_SCALE_V2_ENABLED)
    public void testScale_withScalingV2_fullPrimitiveScaleValue() {
        PrimitiveSegment initial = new PrimitiveSegment(
                VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 0);

        assertEquals(1f, initial.scale(1).getScale(), TOLERANCE);
        assertEquals(0.5f, initial.scale(0.5f).getScale(), TOLERANCE);
        // The original value was not scaled up, so this only scales it down.
        assertEquals(1f, initial.scale(1.5f).getScale(), TOLERANCE);
        assertEquals(2 / 3f, initial.scale(1.5f).scale(2 / 3f).getScale(), TOLERANCE);
        // Does not restore to the exact original value because scale up is a bit offset.
        assertEquals(0.8f, initial.scale(0.8f).getScale(), TOLERANCE);
        assertEquals(0.86f, initial.scale(0.8f).scale(1.25f).getScale(), TOLERANCE);
    }

    @Test
    @DisableFlags(Flags.FLAG_HAPTICS_SCALE_V2_ENABLED)
    public void testScale_withLegacyScaling_halfPrimitiveScaleValue() {
        PrimitiveSegment initial = new PrimitiveSegment(
                VibrationEffect.Composition.PRIMITIVE_CLICK, 0.5f, 0);

@@ -116,6 +141,22 @@ public class PrimitiveSegmentTest {
        assertEquals(0.5f, initial.scale(0.8f).scale(1.25f).getScale(), TOLERANCE);
    }

    @Test
    @EnableFlags(Flags.FLAG_HAPTICS_SCALE_V2_ENABLED)
    public void testScale_withScalingV2_halfPrimitiveScaleValue() {
        PrimitiveSegment initial = new PrimitiveSegment(
                VibrationEffect.Composition.PRIMITIVE_CLICK, 0.5f, 0);

        assertEquals(0.5f, initial.scale(1).getScale(), TOLERANCE);
        assertEquals(0.25f, initial.scale(0.5f).getScale(), TOLERANCE);
        // The original value was not scaled up, so this only scales it down.
        assertEquals(0.66f, initial.scale(1.5f).getScale(), TOLERANCE);
        assertEquals(0.44f, initial.scale(1.5f).scale(2 / 3f).getScale(), TOLERANCE);
        // Does not restore to the exact original value because scale up is a bit offset.
        assertEquals(0.4f, initial.scale(0.8f).getScale(), TOLERANCE);
        assertEquals(0.48f, initial.scale(0.8f).scale(1.25f).getScale(), TOLERANCE);
    }

    @Test
    public void testScale_zeroPrimitiveScaleValue() {
        PrimitiveSegment initial = new PrimitiveSegment(
Loading