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

Commit 47fa3c0d authored by Lais Andrade's avatar Lais Andrade
Browse files

Apply device config vibration scales for external vibrations

Apply scale factor sent by the ExternalVibratorService directly to the
haptic channels when the device config feature flag is enabled.

If no scale factor is provided this will fallback to the scaling V2 for
calculating the scale factor based on the scale level, for consistency.

Bug: 427503922
Test: ExternalVibrationUtilsTest
Flag: android.os.vibrator.vibration_scale_device_config_enabled
Change-Id: Id4f719830adc6444e7a0387ebd8459f274f47b0a
parent d9e3619d
Loading
Loading
Loading
Loading
+19 −5
Original line number Diff line number Diff line
@@ -104,6 +104,24 @@ float applyHapticScale(float value, float scaleFactor) {
    return sign * std::clamp(a * fx, 0.0f, 1.0f);
}

// TODO(b/345186129): remove this once flag android_os_vibrator_haptics_scale_v2_enabled removed
float applyHapticScale(float value, HapticScale scale, float scaleFactor) {
    if (android_os_vibrator_vibration_scale_device_config_enabled()) {
        if (scale.getScaleFactor() >= 0) {
            // Has device configured scale factor, use scale v2 for it.
            scaleFactor = scale.getScaleFactor();
            float scaledValue = (scaleFactor <= 1 || value == 0)
                    ? (value * scaleFactor)
                    : (value * scaleFactor) / (1 + (scaleFactor - 1) * value * value);
            return std::clamp(scaledValue, -1.0f, 1.0f);
        } // else apply regular scaling
    }
    if (scale.getLevel() == HapticLevel::NONE) {
        return value;
    }
    return applyHapticScale(value, scaleFactor);
}

void applyHapticScale(float* buffer, size_t length, HapticScale scale) {
    if (scale.isScaleMute()) {
        memset(buffer, 0, length * sizeof(float));
@@ -112,15 +130,11 @@ void applyHapticScale(float* buffer, size_t length, HapticScale scale) {
    if (scale.isScaleNone()) {
        return;
    }
    HapticLevel hapticLevel = scale.getLevel();
    float scaleFactor = getHapticScaleFactor(scale);
    float adaptiveScaleFactor = scale.getAdaptiveScaleFactor();

    for (size_t i = 0; i < length; i++) {
        if (hapticLevel != HapticLevel::NONE) {
            buffer[i] = applyHapticScale(buffer[i], scaleFactor);
        }

        buffer[i] = applyHapticScale(buffer[i], scale, scaleFactor);
        if (adaptiveScaleFactor >= 0 && adaptiveScaleFactor != 1.0f) {
            buffer[i] *= adaptiveScaleFactor;
        }
+1 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@

namespace android::os {

// TODO(b/345186129): remove this once flag android_os_vibrator_haptics_scale_v2_enabled removed
enum class HapticLevel : int32_t {
    MUTE = -100,
    VERY_LOW = -2,
+43 −0
Original line number Diff line number Diff line
@@ -167,6 +167,49 @@ TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestScaleV2ToScaleFactorIgnoresLev
    EXPECT_FLOATS_NEARLY_EQ(expectedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
}

TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestScaleConfigWithScaleFactorAppliesFactor,
                  REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS,
                                                      vibration_scale_device_config_enabled))) {
    constexpr float adaptiveScaleNone = 1.0f;

    float expectedVeryHigh[TEST_BUFFER_LENGTH] = {1, -1, 1, -0.55f};
    scaleBuffer(HapticScale(HapticLevel::LOW, 3.0f /* scaleFactor */, adaptiveScaleNone));
    EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);

    float expectedHigh[TEST_BUFFER_LENGTH] = {1, -1, 0.66f, -0.29f};
    scaleBuffer(HapticScale(HapticLevel::LOW, 1.5f /* scaleFactor */, adaptiveScaleNone));
    EXPECT_FLOATS_NEARLY_EQ(expectedHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);

    float expectedLow[TEST_BUFFER_LENGTH] = {0.8f, -0.8f, 0.4f, -0.16f};
    scaleBuffer(HapticScale(HapticLevel::HIGH, 0.8f /* scaleFactor */, adaptiveScaleNone));
    EXPECT_FLOATS_NEARLY_EQ(expectedLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);

    float expectedVeryLow[TEST_BUFFER_LENGTH] = {0.4f, -0.4f, 0.2f, -0.08f};
    scaleBuffer(HapticScale(HapticLevel::HIGH, 0.4f /* scaleFactor */, adaptiveScaleNone));
    EXPECT_FLOATS_NEARLY_EQ(expectedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
}

TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestScaleConfigWithoutScaleFactorAppliesScaleLevel,
                  REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled)),
                  REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS,
                                                      vibration_scale_device_config_enabled))) {
    float expectedVeryHigh[TEST_BUFFER_LENGTH] = {1, -1, 0.79f, -0.39f};
    scaleBuffer(HapticLevel::VERY_HIGH);
    EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);

    float expectedHigh[TEST_BUFFER_LENGTH] = {1, -1, 0.62f, -0.27f};
    scaleBuffer(HapticLevel::HIGH);
    EXPECT_FLOATS_NEARLY_EQ(expectedHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);

    float expectedLow[TEST_BUFFER_LENGTH] = {0.70f, -0.70f, 0.35f, -0.14f};
    scaleBuffer(HapticLevel::LOW);
    EXPECT_FLOATS_NEARLY_EQ(expectedLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);

    float expectedVeryLow[TEST_BUFFER_LENGTH] = {0.45f, -0.45f, 0.22f, -0.09f};
    scaleBuffer(HapticLevel::VERY_LOW);
    EXPECT_FLOATS_NEARLY_EQ(expectedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
}

TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestAdaptiveScaleFactorUndefinedIgnoredScale,
                  REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) {
    float expectedVeryHigh[TEST_BUFFER_LENGTH] = {1, -1, 0.79f, -0.39f};