Loading libs/vibrator/ExternalVibrationUtils.cpp +21 −5 Original line number Diff line number Diff line Loading @@ -74,11 +74,14 @@ float getHapticScaleFactor(HapticScale scale) { float applyHapticScale(float value, float scaleFactor) { if (android_os_vibrator_haptics_scale_v2_enabled()) { if (scaleFactor <= 1 || value == 0) { return value * scaleFactor; } else { // Using S * x / (1 + (S - 1) * x^2) as the scale up function to converge to 1.0. return (value * scaleFactor) / (1 + (scaleFactor - 1) * value * value); float scaledValue = (scaleFactor <= 1 || value == 0) ? (value * scaleFactor) : (value * scaleFactor) / (1 + (scaleFactor - 1) * value * value); if (android_os_vibrator_vibration_scale_bounds_fix_enabled()) { return std::clamp(scaledValue, -1.0f, 1.0f); } else { return scaledValue; } } float scale = powf(scaleFactor, 1.0f / SCALE_GAMMA); Loading Loading @@ -136,12 +139,25 @@ void applyHapticScale(float* buffer, size_t length, HapticScale scale) { for (size_t i = 0; i < length; i++) { buffer[i] = applyHapticScale(buffer[i], scale, scaleFactor); if (adaptiveScaleFactor >= 0 && adaptiveScaleFactor != 1.0f) { if (android_os_vibrator_vibration_scale_bounds_fix_enabled()) { buffer[i] = std::clamp(buffer[i] * adaptiveScaleFactor, -1.0f, 1.0f); } else { buffer[i] *= adaptiveScaleFactor; } } } } void clipHapticData(float* buffer, size_t length, float limit) { if (android_os_vibrator_vibration_scale_bounds_fix_enabled()) { if (isnan(limit) || limit <= 0 || limit >= 1) { return; } for (size_t i = 0; i < length; i++) { buffer[i] = std::clamp(buffer[i], -limit, limit); } return; } if (isnan(limit) || limit == 0) { return; } Loading libs/vibrator/tests/ExternalVibrationUtilsTest.cpp +49 −0 Original line number Diff line number Diff line Loading @@ -282,6 +282,37 @@ TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestAdaptiveScaleFactorAppliedAfte EXPECT_FLOATS_NEARLY_EQ(expectedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); } TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestBoundedAdaptiveScaleFactorAppliedAfterScaleV2, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled), ACONFIG_FLAG(FLAG_NS, vibration_scale_bounds_fix_enabled))) { // Adaptive scale mutes vibration float expectedMuted[TEST_BUFFER_LENGTH]; std::fill(std::begin(expectedMuted), std::end(expectedMuted), 0); scaleBuffer(HapticLevel::VERY_HIGH, 0.0f /* adaptiveScaleFactor */); EXPECT_FLOATS_NEARLY_EQ(expectedMuted, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); // Haptic level scale up then adaptive scale down float expectedVeryHigh[TEST_BUFFER_LENGTH] = {0.2, -0.2, 0.15f, -0.07f}; scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */); EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); // Haptic level scale up then adaptive scale up float expectedHigh[TEST_BUFFER_LENGTH] = {1, -1, 0.95f, -0.41f}; scaleBuffer(HapticLevel::HIGH, 1.5f /* adaptiveScaleFactor */); EXPECT_FLOATS_NEARLY_EQ(expectedHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); // Haptic level scale down then adaptive scale down float expectedLow[TEST_BUFFER_LENGTH] = {0.42f, -0.42f, 0.21f, -0.08f}; scaleBuffer(HapticLevel::LOW, 0.6f /* adaptiveScaleFactor */); EXPECT_FLOATS_NEARLY_EQ(expectedLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); // Haptic level scale down then adaptive scale up float expectedVeryLow[TEST_BUFFER_LENGTH] = {1, -1, 0.51f, -0.2f}; scaleBuffer(HapticLevel::VERY_LOW, 2 /* adaptiveScaleFactor */); EXPECT_FLOATS_NEARLY_EQ(expectedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); } TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestLimitAppliedAfterScale, REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) { // Scaled = { 0.2, -0.2, 0.16f, -0.13f }; Loading @@ -307,3 +338,21 @@ TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestLimitAppliedAfterScaleV2, scaleBuffer(HapticLevel::VERY_LOW, 2 /* adaptiveScaleFactor */, 0.7f /* limit */); EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); } TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestInvalidLimitIgnored, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled), ACONFIG_FLAG(FLAG_NS, vibration_scale_bounds_fix_enabled))) { float expectedClippedVeryHigh[TEST_BUFFER_LENGTH] = {0.2f, -0.2f, 0.15f, -0.07f}; scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */, 0 /* limit */); EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */, NAN /* limit */); EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */, -0.5f /* limit */); EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */, 1.5f /* limit */); EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); } Loading
libs/vibrator/ExternalVibrationUtils.cpp +21 −5 Original line number Diff line number Diff line Loading @@ -74,11 +74,14 @@ float getHapticScaleFactor(HapticScale scale) { float applyHapticScale(float value, float scaleFactor) { if (android_os_vibrator_haptics_scale_v2_enabled()) { if (scaleFactor <= 1 || value == 0) { return value * scaleFactor; } else { // Using S * x / (1 + (S - 1) * x^2) as the scale up function to converge to 1.0. return (value * scaleFactor) / (1 + (scaleFactor - 1) * value * value); float scaledValue = (scaleFactor <= 1 || value == 0) ? (value * scaleFactor) : (value * scaleFactor) / (1 + (scaleFactor - 1) * value * value); if (android_os_vibrator_vibration_scale_bounds_fix_enabled()) { return std::clamp(scaledValue, -1.0f, 1.0f); } else { return scaledValue; } } float scale = powf(scaleFactor, 1.0f / SCALE_GAMMA); Loading Loading @@ -136,12 +139,25 @@ void applyHapticScale(float* buffer, size_t length, HapticScale scale) { for (size_t i = 0; i < length; i++) { buffer[i] = applyHapticScale(buffer[i], scale, scaleFactor); if (adaptiveScaleFactor >= 0 && adaptiveScaleFactor != 1.0f) { if (android_os_vibrator_vibration_scale_bounds_fix_enabled()) { buffer[i] = std::clamp(buffer[i] * adaptiveScaleFactor, -1.0f, 1.0f); } else { buffer[i] *= adaptiveScaleFactor; } } } } void clipHapticData(float* buffer, size_t length, float limit) { if (android_os_vibrator_vibration_scale_bounds_fix_enabled()) { if (isnan(limit) || limit <= 0 || limit >= 1) { return; } for (size_t i = 0; i < length; i++) { buffer[i] = std::clamp(buffer[i], -limit, limit); } return; } if (isnan(limit) || limit == 0) { return; } Loading
libs/vibrator/tests/ExternalVibrationUtilsTest.cpp +49 −0 Original line number Diff line number Diff line Loading @@ -282,6 +282,37 @@ TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestAdaptiveScaleFactorAppliedAfte EXPECT_FLOATS_NEARLY_EQ(expectedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); } TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestBoundedAdaptiveScaleFactorAppliedAfterScaleV2, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled), ACONFIG_FLAG(FLAG_NS, vibration_scale_bounds_fix_enabled))) { // Adaptive scale mutes vibration float expectedMuted[TEST_BUFFER_LENGTH]; std::fill(std::begin(expectedMuted), std::end(expectedMuted), 0); scaleBuffer(HapticLevel::VERY_HIGH, 0.0f /* adaptiveScaleFactor */); EXPECT_FLOATS_NEARLY_EQ(expectedMuted, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); // Haptic level scale up then adaptive scale down float expectedVeryHigh[TEST_BUFFER_LENGTH] = {0.2, -0.2, 0.15f, -0.07f}; scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */); EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); // Haptic level scale up then adaptive scale up float expectedHigh[TEST_BUFFER_LENGTH] = {1, -1, 0.95f, -0.41f}; scaleBuffer(HapticLevel::HIGH, 1.5f /* adaptiveScaleFactor */); EXPECT_FLOATS_NEARLY_EQ(expectedHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); // Haptic level scale down then adaptive scale down float expectedLow[TEST_BUFFER_LENGTH] = {0.42f, -0.42f, 0.21f, -0.08f}; scaleBuffer(HapticLevel::LOW, 0.6f /* adaptiveScaleFactor */); EXPECT_FLOATS_NEARLY_EQ(expectedLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); // Haptic level scale down then adaptive scale up float expectedVeryLow[TEST_BUFFER_LENGTH] = {1, -1, 0.51f, -0.2f}; scaleBuffer(HapticLevel::VERY_LOW, 2 /* adaptiveScaleFactor */); EXPECT_FLOATS_NEARLY_EQ(expectedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); } TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestLimitAppliedAfterScale, REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) { // Scaled = { 0.2, -0.2, 0.16f, -0.13f }; Loading @@ -307,3 +338,21 @@ TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestLimitAppliedAfterScaleV2, scaleBuffer(HapticLevel::VERY_LOW, 2 /* adaptiveScaleFactor */, 0.7f /* limit */); EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); } TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestInvalidLimitIgnored, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled), ACONFIG_FLAG(FLAG_NS, vibration_scale_bounds_fix_enabled))) { float expectedClippedVeryHigh[TEST_BUFFER_LENGTH] = {0.2f, -0.2f, 0.15f, -0.07f}; scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */, 0 /* limit */); EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */, NAN /* limit */); EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */, -0.5f /* limit */); EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */, 1.5f /* limit */); EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); }