diff options
author | 2024-09-11 22:17:52 +0000 | |
---|---|---|
committer | 2024-09-11 22:17:52 +0000 | |
commit | cfe1e76d5cd02c691a5fc802192b76edb1dc65ef (patch) | |
tree | e41e8ceee82d401ebc01f9720932341dddd2bb5a | |
parent | 0b3be83fda03783a9c6dee8515354784aa5f22f6 (diff) | |
parent | 1d88585fc435a9511304c53281f0f8ca48ec22eb (diff) |
Merge "Fix haptics scaling to match VibrationEffect function" into main
-rw-r--r-- | libs/vibrator/Android.bp | 13 | ||||
-rw-r--r-- | libs/vibrator/ExternalVibrationUtils.cpp | 67 | ||||
-rw-r--r-- | libs/vibrator/TEST_MAPPING | 7 | ||||
-rw-r--r-- | libs/vibrator/tests/Android.bp | 53 | ||||
-rw-r--r-- | libs/vibrator/tests/ExternalVibrationTest.cpp | 109 | ||||
-rw-r--r-- | libs/vibrator/tests/ExternalVibrationUtilsTest.cpp | 237 | ||||
-rw-r--r-- | libs/vibrator/tests/test_utils.h | 31 |
7 files changed, 510 insertions, 7 deletions
diff --git a/libs/vibrator/Android.bp b/libs/vibrator/Android.bp index 2af51a722c..d3b3a734f9 100644 --- a/libs/vibrator/Android.bp +++ b/libs/vibrator/Android.bp @@ -24,6 +24,10 @@ package { cc_defaults { name: "libvibrator_defaults", + defaults: [ + "aconfig_lib_cc_shared_link.defaults", + ], + cflags: [ "-Wall", "-Werror", @@ -50,9 +54,11 @@ cc_library { "libbinder", "liblog", "libutils", + "server_configurable_flags", ], whole_static_libs: [ + "android.os.vibrator.flags-aconfig-cc", "libvibratorutils", ], @@ -79,8 +85,14 @@ cc_library { vendor_available: true, double_loadable: true, + static_libs: [ + "android.os.vibrator.flags-aconfig-cc", + ], + shared_libs: [ + "liblog", "libutils", + "server_configurable_flags", ], srcs: [ @@ -89,6 +101,7 @@ cc_library { visibility: [ "//frameworks/native/libs/vibrator", + "//frameworks/native/libs/vibrator/tests", "//frameworks/av/media/libeffects/hapticgenerator", ], } diff --git a/libs/vibrator/ExternalVibrationUtils.cpp b/libs/vibrator/ExternalVibrationUtils.cpp index 761ac1bf3b..706f3d7a56 100644 --- a/libs/vibrator/ExternalVibrationUtils.cpp +++ b/libs/vibrator/ExternalVibrationUtils.cpp @@ -15,6 +15,9 @@ */ #include <cstring> +#include <android_os_vibrator.h> + +#include <algorithm> #include <math.h> #include <vibrator/ExternalVibrationUtils.h> @@ -25,8 +28,9 @@ namespace { static constexpr float HAPTIC_SCALE_VERY_LOW_RATIO = 2.0f / 3.0f; static constexpr float HAPTIC_SCALE_LOW_RATIO = 3.0f / 4.0f; static constexpr float HAPTIC_MAX_AMPLITUDE_FLOAT = 1.0f; +static constexpr float SCALE_GAMMA = 0.65f; // Same as VibrationEffect.SCALE_GAMMA -float getHapticScaleGamma(HapticLevel level) { +float getOldHapticScaleGamma(HapticLevel level) { switch (level) { case HapticLevel::VERY_LOW: return 2.0f; @@ -41,7 +45,7 @@ float getHapticScaleGamma(HapticLevel level) { } } -float getHapticMaxAmplitudeRatio(HapticLevel level) { +float getOldHapticMaxAmplitudeRatio(HapticLevel level) { switch (level) { case HapticLevel::VERY_LOW: return HAPTIC_SCALE_VERY_LOW_RATIO; @@ -56,6 +60,52 @@ float getHapticMaxAmplitudeRatio(HapticLevel level) { } } +/* Same as VibrationScaler.SCALE_LEVEL_* */ +float getHapticScaleFactor(HapticLevel level) { + switch (level) { + case HapticLevel::VERY_LOW: + return 0.6f; + case HapticLevel::LOW: + return 0.8f; + case HapticLevel::HIGH: + return 1.2f; + case HapticLevel::VERY_HIGH: + return 1.4f; + default: + return 1.0f; + } +} + +float applyOldHapticScale(float value, float gamma, float maxAmplitudeRatio) { + float sign = value >= 0 ? 1.0 : -1.0; + return powf(fabsf(value / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma) + * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * sign; +} + +float applyNewHapticScale(float value, float scaleFactor) { + float scale = powf(scaleFactor, 1.0f / SCALE_GAMMA); + if (scaleFactor <= 1) { + // Scale down is simply a gamma corrected application of scaleFactor to the intensity. + // Scale up requires a different curve to ensure the intensity will not become > 1. + return value * scale; + } + + float sign = value >= 0 ? 1.0f : -1.0f; + float extraScale = powf(scaleFactor, 4.0f - scaleFactor); + float x = fabsf(value) * scale * extraScale; + float maxX = scale * extraScale; // scaled x for intensity == 1 + + float expX = expf(x); + float expMaxX = expf(maxX); + + // Using f = tanh as the scale up function so the max value will converge. + // a = 1/f(maxX), used to scale f so that a*f(maxX) = 1 (the value will converge to 1). + float a = (expMaxX + 1.0f) / (expMaxX - 1.0f); + float fx = (expX - 1.0f) / (expX + 1.0f); + + return sign * std::clamp(a * fx, 0.0f, 1.0f); +} + void applyHapticScale(float* buffer, size_t length, HapticScale scale) { if (scale.isScaleMute()) { memset(buffer, 0, length * sizeof(float)); @@ -65,15 +115,18 @@ void applyHapticScale(float* buffer, size_t length, HapticScale scale) { return; } HapticLevel hapticLevel = scale.getLevel(); + float scaleFactor = getHapticScaleFactor(hapticLevel); float adaptiveScaleFactor = scale.getAdaptiveScaleFactor(); - float gamma = getHapticScaleGamma(hapticLevel); - float maxAmplitudeRatio = getHapticMaxAmplitudeRatio(hapticLevel); + float oldGamma = getOldHapticScaleGamma(hapticLevel); + float oldMaxAmplitudeRatio = getOldHapticMaxAmplitudeRatio(hapticLevel); for (size_t i = 0; i < length; i++) { if (hapticLevel != HapticLevel::NONE) { - float sign = buffer[i] >= 0 ? 1.0 : -1.0; - buffer[i] = powf(fabsf(buffer[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma) - * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * sign; + if (android_os_vibrator_fix_audio_coupled_haptics_scaling()) { + buffer[i] = applyNewHapticScale(buffer[i], scaleFactor); + } else { + buffer[i] = applyOldHapticScale(buffer[i], oldGamma, oldMaxAmplitudeRatio); + } } if (adaptiveScaleFactor != 1.0f) { diff --git a/libs/vibrator/TEST_MAPPING b/libs/vibrator/TEST_MAPPING new file mode 100644 index 0000000000..d782b43b57 --- /dev/null +++ b/libs/vibrator/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "postsubmit": [ + { + "name": "libvibrator_test" + } + ] +} diff --git a/libs/vibrator/tests/Android.bp b/libs/vibrator/tests/Android.bp new file mode 100644 index 0000000000..2921a6275b --- /dev/null +++ b/libs/vibrator/tests/Android.bp @@ -0,0 +1,53 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package { + default_team: "trendy_team_haptics_framework", + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + +cc_test { + name: "libvibrator_test", + test_suites: ["general-tests"], + defaults: [ + "aconfig_lib_cc_shared_link.defaults", + ], + srcs: [ + "ExternalVibrationTest.cpp", + "ExternalVibrationUtilsTest.cpp", + ], + cflags: [ + "-Wall", + "-Werror", + "-Wextra", + ], + static_libs: [ + "android.os.vibrator.flags-aconfig-cc", + "libflagtest", + "libgtest", + "liblog", + "libvibrator", + "libvibratorutils", + ], + shared_libs: [ + "libbase", + "libbinder", + "libutils", + "server_configurable_flags", + ], +} diff --git a/libs/vibrator/tests/ExternalVibrationTest.cpp b/libs/vibrator/tests/ExternalVibrationTest.cpp new file mode 100644 index 0000000000..3141380219 --- /dev/null +++ b/libs/vibrator/tests/ExternalVibrationTest.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <binder/Parcel.h> +#include <gtest/gtest.h> +#include <vibrator/ExternalVibration.h> + +using namespace android; +using namespace testing; + +using HapticLevel = os::HapticLevel; +using ScaleLevel = os::ExternalVibrationScale::ScaleLevel; + +class TestVibrationController : public os::IExternalVibrationController { +public: + explicit TestVibrationController() {} + IBinder *onAsBinder() override { return nullptr; } + binder::Status mute(/*out*/ bool *ret) override { + *ret = false; + return binder::Status::ok(); + }; + binder::Status unmute(/*out*/ bool *ret) override { + *ret = false; + return binder::Status::ok(); + }; +}; + +class ExternalVibrationTest : public Test { +protected: + HapticLevel toHapticLevel(ScaleLevel level) { + os::ExternalVibrationScale externalVibrationScale; + externalVibrationScale.scaleLevel = level; + os::HapticScale hapticScale = + os::ExternalVibration::externalVibrationScaleToHapticScale(externalVibrationScale); + return hapticScale.getLevel(); + } +}; + +TEST_F(ExternalVibrationTest, TestReadAndWriteToParcel) { + int32_t uid = 1; + std::string pkg("package.name"); + audio_attributes_t originalAttrs; + originalAttrs.content_type = AUDIO_CONTENT_TYPE_SONIFICATION; + originalAttrs.usage = AUDIO_USAGE_ASSISTANCE_SONIFICATION; + originalAttrs.source = AUDIO_SOURCE_VOICE_COMMUNICATION; + originalAttrs.flags = AUDIO_FLAG_BYPASS_MUTE; + sp<TestVibrationController> vibrationController = new TestVibrationController(); + ASSERT_NE(vibrationController, nullptr); + sp<os::ExternalVibration> original = + new os::ExternalVibration(uid, pkg, originalAttrs, vibrationController); + ASSERT_NE(original, nullptr); + EXPECT_EQ(original->getUid(), uid); + EXPECT_EQ(original->getPackage(), pkg); + EXPECT_EQ(original->getAudioAttributes().content_type, originalAttrs.content_type); + EXPECT_EQ(original->getAudioAttributes().usage, originalAttrs.usage); + EXPECT_EQ(original->getAudioAttributes().source, originalAttrs.source); + EXPECT_EQ(original->getAudioAttributes().flags, originalAttrs.flags); + EXPECT_EQ(original->getController(), vibrationController); + audio_attributes_t defaultAttrs; + defaultAttrs.content_type = AUDIO_CONTENT_TYPE_UNKNOWN; + defaultAttrs.usage = AUDIO_USAGE_UNKNOWN; + defaultAttrs.source = AUDIO_SOURCE_DEFAULT; + defaultAttrs.flags = AUDIO_FLAG_NONE; + sp<os::ExternalVibration> parceled = + new os::ExternalVibration(0, std::string(""), defaultAttrs, nullptr); + ASSERT_NE(parceled, nullptr); + Parcel parcel; + original->writeToParcel(&parcel); + parcel.setDataPosition(0); + parceled->readFromParcel(&parcel); + EXPECT_EQ(parceled->getUid(), uid); + EXPECT_EQ(parceled->getPackage(), pkg); + EXPECT_EQ(parceled->getAudioAttributes().content_type, originalAttrs.content_type); + EXPECT_EQ(parceled->getAudioAttributes().usage, originalAttrs.usage); + EXPECT_EQ(parceled->getAudioAttributes().source, originalAttrs.source); + EXPECT_EQ(parceled->getAudioAttributes().flags, originalAttrs.flags); + // TestVibrationController does not implement onAsBinder, skip controller parcel in this test. +} + +TEST_F(ExternalVibrationTest, TestExternalVibrationScaleToHapticScale) { + os::ExternalVibrationScale externalVibrationScale; + externalVibrationScale.scaleLevel = ScaleLevel::SCALE_HIGH; + externalVibrationScale.adaptiveHapticsScale = 0.8f; + os::HapticScale hapticScale = + os::ExternalVibration::externalVibrationScaleToHapticScale(externalVibrationScale); + // Check scale factor is forwarded. + EXPECT_EQ(hapticScale.getLevel(), HapticLevel::HIGH); + EXPECT_EQ(hapticScale.getAdaptiveScaleFactor(), 0.8f); + // Check conversion for all levels. + EXPECT_EQ(toHapticLevel(ScaleLevel::SCALE_MUTE), HapticLevel::MUTE); + EXPECT_EQ(toHapticLevel(ScaleLevel::SCALE_VERY_LOW), HapticLevel::VERY_LOW); + EXPECT_EQ(toHapticLevel(ScaleLevel::SCALE_LOW), HapticLevel::LOW); + EXPECT_EQ(toHapticLevel(ScaleLevel::SCALE_NONE), HapticLevel::NONE); + EXPECT_EQ(toHapticLevel(ScaleLevel::SCALE_HIGH), HapticLevel::HIGH); + EXPECT_EQ(toHapticLevel(ScaleLevel::SCALE_VERY_HIGH), HapticLevel::VERY_HIGH); +} diff --git a/libs/vibrator/tests/ExternalVibrationUtilsTest.cpp b/libs/vibrator/tests/ExternalVibrationUtilsTest.cpp new file mode 100644 index 0000000000..3d8dd9cb5b --- /dev/null +++ b/libs/vibrator/tests/ExternalVibrationUtilsTest.cpp @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android_os_vibrator.h> +#include <flag_macros.h> +#include <gtest/gtest.h> +#include <vibrator/ExternalVibrationUtils.h> + +#include "test_utils.h" + +#define FLAG_NS android::os::vibrator + +using namespace android; +using namespace testing; + +using HapticScale = os::HapticScale; +using HapticLevel = os::HapticLevel; + +static constexpr float TEST_TOLERANCE = 1e-2f; +static constexpr size_t TEST_BUFFER_LENGTH = 4; +static float TEST_BUFFER[TEST_BUFFER_LENGTH] = { 1, -1, 0.5f, -0.2f }; + +class ExternalVibrationUtilsTest : public Test { +public: + void SetUp() override { + std::copy(std::begin(TEST_BUFFER), std::end(TEST_BUFFER), std::begin(mBuffer)); + } + +protected: + void scaleBuffer(HapticLevel hapticLevel) { + scaleBuffer(HapticScale(hapticLevel), 0 /* limit */); + } + + void scaleBuffer(HapticLevel hapticLevel, float adaptiveScaleFactor) { + scaleBuffer(hapticLevel, adaptiveScaleFactor, 0 /* limit */); + } + + void scaleBuffer(HapticLevel hapticLevel, float adaptiveScaleFactor, float limit) { + scaleBuffer(HapticScale(hapticLevel, adaptiveScaleFactor), limit); + } + + void scaleBuffer(HapticScale hapticScale, float limit) { + std::copy(std::begin(TEST_BUFFER), std::end(TEST_BUFFER), std::begin(mBuffer)); + os::scaleHapticData(&mBuffer[0], TEST_BUFFER_LENGTH, hapticScale, limit); + } + + float mBuffer[TEST_BUFFER_LENGTH]; +}; + +TEST_F_WITH_FLAGS( + ExternalVibrationUtilsTest, + TestLegacyScaleMute, + REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling)) +) { + float expected[TEST_BUFFER_LENGTH]; + std::fill(std::begin(expected), std::end(expected), 0); + + scaleBuffer(HapticLevel::MUTE); + EXPECT_FLOATS_NEARLY_EQ(expected, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); +} + +TEST_F_WITH_FLAGS( + ExternalVibrationUtilsTest, + TestFixedScaleMute, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling)) +) { + float expected[TEST_BUFFER_LENGTH]; + std::fill(std::begin(expected), std::end(expected), 0); + + scaleBuffer(HapticLevel::MUTE); + EXPECT_FLOATS_NEARLY_EQ(expected, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); +} + +TEST_F_WITH_FLAGS( + ExternalVibrationUtilsTest, + TestLegacyScaleNone, + REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling)) +) { + float expected[TEST_BUFFER_LENGTH]; + std::copy(std::begin(TEST_BUFFER), std::end(TEST_BUFFER), std::begin(expected)); + + scaleBuffer(HapticLevel::NONE); + EXPECT_FLOATS_NEARLY_EQ(expected, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); +} + +TEST_F_WITH_FLAGS( + ExternalVibrationUtilsTest, + TestFixedScaleNone, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling)) +) { + float expected[TEST_BUFFER_LENGTH]; + std::copy(std::begin(TEST_BUFFER), std::end(TEST_BUFFER), std::begin(expected)); + + scaleBuffer(HapticLevel::NONE); + EXPECT_FLOATS_NEARLY_EQ(expected, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); +} + +TEST_F_WITH_FLAGS( + ExternalVibrationUtilsTest, + TestLegacyScaleToHapticLevel, + REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling)) +) { + float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 1, -1, 0.84f, -0.66f }; + scaleBuffer(HapticLevel::VERY_HIGH); + EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); + + float expectedHigh[TEST_BUFFER_LENGTH] = { 1, -1, 0.7f, -0.44f }; + scaleBuffer(HapticLevel::HIGH); + EXPECT_FLOATS_NEARLY_EQ(expectedHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); + + float expectedLow[TEST_BUFFER_LENGTH] = { 0.75f, -0.75f, 0.26f, -0.06f }; + scaleBuffer(HapticLevel::LOW); + EXPECT_FLOATS_NEARLY_EQ(expectedLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); + + float expectedVeryLow[TEST_BUFFER_LENGTH] = { 0.66f, -0.66f, 0.16f, -0.02f }; + scaleBuffer(HapticLevel::VERY_LOW); + EXPECT_FLOATS_NEARLY_EQ(expectedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); +} + +TEST_F_WITH_FLAGS( + ExternalVibrationUtilsTest, + TestFixedScaleToHapticLevel, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling)) +) { + 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, + TestAdaptiveScaleFactorAppliedAfterLegacyScale, + REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling)) +) { + // Haptic level scale up then adaptive scale down + float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 0.2, -0.2, 0.16f, -0.13f }; + 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.5f, -1.5f, 1.06f, -0.67f }; + 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.45f, -0.45f, 0.15f, -0.04f }; + 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.33f, -1.33f, 0.33f, -0.05f }; + scaleBuffer(HapticLevel::VERY_LOW, 2 /* adaptiveScaleFactor */); + EXPECT_FLOATS_NEARLY_EQ(expectedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); +} + +TEST_F_WITH_FLAGS( + ExternalVibrationUtilsTest, + TestAdaptiveScaleFactorAppliedAfterFixedScale, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling)) +) { + // Haptic level scale up then adaptive scale down + float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 0.2, -0.2, 0.16f, -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.5f, -1.5f, 0.93f, -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] = { 0.91f, -0.91f, 0.45f, -0.18f }; + scaleBuffer(HapticLevel::VERY_LOW, 2 /* adaptiveScaleFactor */); + EXPECT_FLOATS_NEARLY_EQ(expectedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); +} + +TEST_F_WITH_FLAGS( + ExternalVibrationUtilsTest, + TestLimitAppliedAfterLegacyScale, + REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling)) +) { + // Scaled = { 0.2, -0.2, 0.16f, -0.13f }; + float expectedClippedVeryHigh[TEST_BUFFER_LENGTH] = { 0.15f, -0.15f, 0.15f, -0.13f }; + scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */, 0.15f /* limit */); + EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); + + // Scaled = { 1, -1, 0.5f, -0.2f }; + float expectedClippedVeryLow[TEST_BUFFER_LENGTH] = { 0.7f, -0.7f, 0.33f, -0.05f }; + 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, + TestLimitAppliedAfterFixedScale, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling)) +) { + // Scaled = { 0.2, -0.2, 0.16f, -0.13f }; + float expectedClippedVeryHigh[TEST_BUFFER_LENGTH] = { 0.15f, -0.15f, 0.15f, -0.07f }; + scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */, 0.15f /* limit */); + EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); + + // Scaled = { 1, -1, 0.5f, -0.2f }; + float expectedClippedVeryLow[TEST_BUFFER_LENGTH] = { 0.7f, -0.7f, 0.45f, -0.18f }; + scaleBuffer(HapticLevel::VERY_LOW, 2 /* adaptiveScaleFactor */, 0.7f /* limit */); + EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); +} diff --git a/libs/vibrator/tests/test_utils.h b/libs/vibrator/tests/test_utils.h new file mode 100644 index 0000000000..f491ea1f49 --- /dev/null +++ b/libs/vibrator/tests/test_utils.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBVIBRATOR_TEST_UTILS_H +#define LIBVIBRATOR_TEST_UTILS_H + +#include <gtest/gtest.h> + +#if !defined(EXPECT_FLOATS_NEARLY_EQ) +#define EXPECT_FLOATS_NEARLY_EQ(expected, actual, length, epsilon) \ + for (size_t i = 0; i < length; i++) { \ + EXPECT_NEAR(expected[i], actual[i], epsilon) << " at Index: " << i; \ + } +#else +#error Macro EXPECT_FLOATS_NEARLY_EQ already defined +#endif + +#endif //LIBVIBRATOR_TEST_UTILS_H |