Add support for querying resonant frequency and Q factor.
Bug: 181276733
Test: atest libvibratorservice_test
Change-Id: I7bebc96ddc09fe13716ce8ea51cbf99cf4054955
diff --git a/services/vibratorservice/VibratorHalController.cpp b/services/vibratorservice/VibratorHalController.cpp
index 537e49b..2de2e0e 100644
--- a/services/vibratorservice/VibratorHalController.cpp
+++ b/services/vibratorservice/VibratorHalController.cpp
@@ -209,6 +209,18 @@
return apply(getSupportedPrimitivesFn, "getSupportedPrimitives");
}
+HalResult<float> HalController::getResonantFrequency() {
+ hal_fn<float> getResonantFrequencyFn = [](std::shared_ptr<HalWrapper> hal) {
+ return hal->getResonantFrequency();
+ };
+ return apply(getResonantFrequencyFn, "getResonantFrequency");
+}
+
+HalResult<float> HalController::getQFactor() {
+ hal_fn<float> getQFactorFn = [](std::shared_ptr<HalWrapper> hal) { return hal->getQFactor(); };
+ return apply(getQFactorFn, "getQFactor");
+}
+
HalResult<milliseconds> HalController::performEffect(
Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
hal_fn<milliseconds> performEffectFn = [&](std::shared_ptr<HalWrapper> hal) {
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index 6faab38..3d20fa1 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -205,6 +205,17 @@
mSupportedPrimitives);
}
+HalResult<float> AidlHalWrapper::getResonantFrequency() {
+ std::lock_guard<std::mutex> lock(mResonantFrequencyMutex);
+ return loadCached<float>(std::bind(&AidlHalWrapper::getResonantFrequencyInternal, this),
+ mResonantFrequency);
+}
+
+HalResult<float> AidlHalWrapper::getQFactor() {
+ std::lock_guard<std::mutex> lock(mQFactorMutex);
+ return loadCached<float>(std::bind(&AidlHalWrapper::getQFactorInternal, this), mQFactor);
+}
+
HalResult<milliseconds> AidlHalWrapper::performEffect(
Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
HalResult<Capabilities> capabilities = getCapabilities();
@@ -283,6 +294,18 @@
return HalResult<std::vector<CompositePrimitive>>::fromStatus(result, supportedPrimitives);
}
+HalResult<float> AidlHalWrapper::getResonantFrequencyInternal() {
+ float f0 = 0;
+ auto result = getHal()->getResonantFrequency(&f0);
+ return HalResult<float>::fromStatus(result, f0);
+}
+
+HalResult<float> AidlHalWrapper::getQFactorInternal() {
+ float qFactor = 0;
+ auto result = getHal()->getQFactor(&qFactor);
+ return HalResult<float>::fromStatus(result, qFactor);
+}
+
sp<Aidl::IVibrator> AidlHalWrapper::getHal() {
std::lock_guard<std::mutex> lock(mHandleMutex);
return mHandle;
@@ -366,6 +389,18 @@
}
template <typename I>
+HalResult<float> HidlHalWrapper<I>::getResonantFrequency() {
+ ALOGV("Skipped getResonantFrequency because Vibrator HAL AIDL is not available");
+ return HalResult<float>::unsupported();
+}
+
+template <typename I>
+HalResult<float> HidlHalWrapper<I>::getQFactor() {
+ ALOGV("Skipped getQFactor because Vibrator HAL AIDL is not available");
+ return HalResult<float>::unsupported();
+}
+
+template <typename I>
HalResult<std::chrono::milliseconds> HidlHalWrapper<I>::performComposedEffect(
const std::vector<CompositeEffect>&, const std::function<void()>&) {
ALOGV("Skipped composed effect because Vibrator HAL AIDL is not available");
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalController.h b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
index 16d571d..14ec7b2 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalController.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
@@ -73,6 +73,9 @@
HalResult<std::vector<hardware::vibrator::CompositePrimitive>> getSupportedPrimitives()
final override;
+ HalResult<float> getResonantFrequency() final override;
+ HalResult<float> getQFactor() final override;
+
HalResult<std::chrono::milliseconds> performEffect(
hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
const std::function<void()>& completionCallback) final override;
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index e22ad34..039a2d9 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -185,6 +185,9 @@
virtual HalResult<std::vector<hardware::vibrator::CompositePrimitive>>
getSupportedPrimitives() = 0;
+ virtual HalResult<float> getResonantFrequency() = 0;
+ virtual HalResult<float> getQFactor() = 0;
+
virtual HalResult<std::chrono::milliseconds> performEffect(
hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
const std::function<void()>& completionCallback) = 0;
@@ -232,6 +235,9 @@
HalResult<std::vector<hardware::vibrator::CompositePrimitive>> getSupportedPrimitives()
override final;
+ HalResult<float> getResonantFrequency() override final;
+ HalResult<float> getQFactor() override final;
+
HalResult<std::chrono::milliseconds> performEffect(
hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
const std::function<void()>& completionCallback) override final;
@@ -246,6 +252,8 @@
std::mutex mCapabilitiesMutex;
std::mutex mSupportedEffectsMutex;
std::mutex mSupportedPrimitivesMutex;
+ std::mutex mResonantFrequencyMutex;
+ std::mutex mQFactorMutex;
sp<hardware::vibrator::IVibrator> mHandle GUARDED_BY(mHandleMutex);
std::optional<Capabilities> mCapabilities GUARDED_BY(mCapabilitiesMutex);
std::optional<std::vector<hardware::vibrator::Effect>> mSupportedEffects
@@ -254,6 +262,8 @@
GUARDED_BY(mSupportedPrimitivesMutex);
std::vector<std::optional<std::chrono::milliseconds>> mPrimitiveDurations
GUARDED_BY(mSupportedPrimitivesMutex);
+ std::optional<float> mResonantFrequency GUARDED_BY(mResonantFrequencyMutex);
+ std::optional<float> mQFactor GUARDED_BY(mQFactorMutex);
// Loads and caches from IVibrator.
HalResult<std::chrono::milliseconds> getPrimitiveDuration(
@@ -263,6 +273,10 @@
HalResult<Capabilities> getCapabilitiesInternal();
HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffectsInternal();
HalResult<std::vector<hardware::vibrator::CompositePrimitive>> getSupportedPrimitivesInternal();
+
+ HalResult<float> getResonantFrequencyInternal();
+ HalResult<float> getQFactorInternal();
+
sp<hardware::vibrator::IVibrator> getHal();
};
@@ -293,6 +307,9 @@
HalResult<std::vector<hardware::vibrator::CompositePrimitive>> getSupportedPrimitives()
override final;
+ HalResult<float> getResonantFrequency() override final;
+ HalResult<float> getQFactor() override final;
+
HalResult<std::chrono::milliseconds> performComposedEffect(
const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
const std::function<void()>& completionCallback) override final;
diff --git a/services/vibratorservice/test/VibratorHalControllerTest.cpp b/services/vibratorservice/test/VibratorHalControllerTest.cpp
index c4b39ed..0c39247 100644
--- a/services/vibratorservice/test/VibratorHalControllerTest.cpp
+++ b/services/vibratorservice/test/VibratorHalControllerTest.cpp
@@ -67,6 +67,10 @@
MOCK_METHOD(vibrator::HalResult<std::vector<Effect>>, getSupportedEffects, (), (override));
MOCK_METHOD(vibrator::HalResult<std::vector<CompositePrimitive>>, getSupportedPrimitives, (),
(override));
+
+ MOCK_METHOD(vibrator::HalResult<float>, getResonantFrequency, (), (override));
+ MOCK_METHOD(vibrator::HalResult<float>, getQFactor, (), (override));
+
MOCK_METHOD(vibrator::HalResult<milliseconds>, performEffect,
(Effect effect, EffectStrength strength,
const std::function<void()>& completionCallback),
@@ -106,6 +110,8 @@
vibrator::HalResult<vibrator::Capabilities> capabilitiesResult,
vibrator::HalResult<std::vector<Effect>> effectsResult,
vibrator::HalResult<std::vector<CompositePrimitive>> primitivesResult,
+ vibrator::HalResult<float> resonantFrequencyResult,
+ vibrator::HalResult<float> qFactorResult,
vibrator::HalResult<milliseconds> durationResult) {
EXPECT_CALL(*mMockHal.get(), ping())
.Times(Exactly(cardinality))
@@ -138,6 +144,12 @@
EXPECT_CALL(*mMockHal.get(), getSupportedPrimitives())
.Times(Exactly(cardinality))
.WillRepeatedly(Return(primitivesResult));
+ EXPECT_CALL(*mMockHal.get(), getResonantFrequency())
+ .Times(Exactly(cardinality))
+ .WillRepeatedly(Return(resonantFrequencyResult));
+ EXPECT_CALL(*mMockHal.get(), getQFactor())
+ .Times(Exactly(cardinality))
+ .WillRepeatedly(Return(qFactorResult));
EXPECT_CALL(*mMockHal.get(), performEffect(Eq(Effect::CLICK), Eq(EffectStrength::LIGHT), _))
.Times(Exactly(cardinality))
.WillRepeatedly(Return(durationResult));
@@ -147,7 +159,7 @@
if (cardinality > 1) {
// One reconnection call after each failure.
- EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(12 * cardinality));
+ EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(14 * cardinality));
}
}
};
@@ -164,23 +176,21 @@
}
TEST_F(VibratorHalControllerTest, TestApiCallsAreForwardedToHal) {
- std::vector<Effect> effects;
- effects.push_back(Effect::CLICK);
- effects.push_back(Effect::TICK);
- std::vector<CompositePrimitive> primitives;
- primitives.push_back(CompositePrimitive::CLICK);
- primitives.push_back(CompositePrimitive::THUD);
- std::vector<CompositeEffect> compositeEffects;
- compositeEffects.push_back(
- vibrator::TestFactory::createCompositeEffect(CompositePrimitive::SPIN, 100ms, 0.5f));
- compositeEffects.push_back(
- vibrator::TestFactory::createCompositeEffect(CompositePrimitive::THUD, 1000ms, 1.0f));
+ std::vector<Effect> effects = {Effect::CLICK, Effect::TICK};
+ std::vector<CompositePrimitive> primitives = {CompositePrimitive::CLICK,
+ CompositePrimitive::THUD};
+ constexpr float F0 = 123.f;
+ constexpr float Q_FACTOR = 12.f;
+ const std::vector<CompositeEffect> compositeEffects =
+ {vibrator::TestFactory::createCompositeEffect(CompositePrimitive::SPIN, 100ms, 0.5f),
+ vibrator::TestFactory::createCompositeEffect(CompositePrimitive::THUD, 1000ms, 1.0f)};
setHalExpectations(/* cardinality= */ 1, compositeEffects, vibrator::HalResult<void>::ok(),
vibrator::HalResult<vibrator::Capabilities>::ok(
vibrator::Capabilities::ON_CALLBACK),
vibrator::HalResult<std::vector<Effect>>::ok(effects),
vibrator::HalResult<std::vector<CompositePrimitive>>::ok(primitives),
+ vibrator::HalResult<float>::ok(F0), vibrator::HalResult<float>::ok(Q_FACTOR),
vibrator::HalResult<milliseconds>::ok(100ms));
ASSERT_TRUE(mController->ping().isOk());
@@ -203,6 +213,14 @@
ASSERT_TRUE(getSupportedPrimitivesResult.isOk());
ASSERT_EQ(primitives, getSupportedPrimitivesResult.value());
+ auto getResonantFrequencyResult = mController->getResonantFrequency();
+ ASSERT_TRUE(getResonantFrequencyResult.isOk());
+ ASSERT_EQ(F0, getResonantFrequencyResult.value());
+
+ auto getQFactorResult = mController->getQFactor();
+ ASSERT_TRUE(getQFactorResult.isOk());
+ ASSERT_EQ(Q_FACTOR, getQFactorResult.value());
+
auto performEffectResult =
mController->performEffect(Effect::CLICK, EffectStrength::LIGHT, []() {});
ASSERT_TRUE(performEffectResult.isOk());
@@ -222,6 +240,8 @@
vibrator::HalResult<vibrator::Capabilities>::unsupported(),
vibrator::HalResult<std::vector<Effect>>::unsupported(),
vibrator::HalResult<std::vector<CompositePrimitive>>::unsupported(),
+ vibrator::HalResult<float>::unsupported(),
+ vibrator::HalResult<float>::unsupported(),
vibrator::HalResult<milliseconds>::unsupported());
ASSERT_EQ(0, mConnectCounter);
@@ -237,6 +257,8 @@
ASSERT_TRUE(mController->getCapabilities().isUnsupported());
ASSERT_TRUE(mController->getSupportedEffects().isUnsupported());
ASSERT_TRUE(mController->getSupportedPrimitives().isUnsupported());
+ ASSERT_TRUE(mController->getResonantFrequency().isUnsupported());
+ ASSERT_TRUE(mController->getQFactor().isUnsupported());
ASSERT_TRUE(mController->performEffect(Effect::CLICK, EffectStrength::LIGHT, []() {})
.isUnsupported());
ASSERT_TRUE(mController->performComposedEffect(std::vector<CompositeEffect>(), []() {})
@@ -251,6 +273,8 @@
vibrator::HalResult<vibrator::Capabilities>::failed("message"),
vibrator::HalResult<std::vector<Effect>>::failed("message"),
vibrator::HalResult<std::vector<CompositePrimitive>>::failed("message"),
+ vibrator::HalResult<float>::failed("message"),
+ vibrator::HalResult<float>::failed("message"),
vibrator::HalResult<milliseconds>::failed("message"));
ASSERT_EQ(0, mConnectCounter);
@@ -265,6 +289,8 @@
ASSERT_TRUE(mController->getCapabilities().isFailed());
ASSERT_TRUE(mController->getSupportedEffects().isFailed());
ASSERT_TRUE(mController->getSupportedPrimitives().isFailed());
+ ASSERT_TRUE(mController->getResonantFrequency().isFailed());
+ ASSERT_TRUE(mController->getQFactor().isFailed());
ASSERT_TRUE(
mController->performEffect(Effect::CLICK, EffectStrength::LIGHT, []() {}).isFailed());
ASSERT_TRUE(
@@ -327,13 +353,15 @@
ASSERT_TRUE(mController->getCapabilities().isUnsupported());
ASSERT_TRUE(mController->getSupportedEffects().isUnsupported());
ASSERT_TRUE(mController->getSupportedPrimitives().isUnsupported());
+ ASSERT_TRUE(mController->getResonantFrequency().isUnsupported());
+ ASSERT_TRUE(mController->getQFactor().isUnsupported());
ASSERT_TRUE(mController->performEffect(Effect::CLICK, EffectStrength::LIGHT, []() {})
.isUnsupported());
ASSERT_TRUE(mController->performComposedEffect(std::vector<CompositeEffect>(), []() {})
.isUnsupported());
// One connection attempt per api call.
- ASSERT_EQ(13, mConnectCounter);
+ ASSERT_EQ(15, mConnectCounter);
}
TEST_F(VibratorHalControllerTest, TestScheduledCallbackSurvivesReconnection) {
diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
index 8b5caa5..5d77595 100644
--- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -413,6 +413,82 @@
ASSERT_EQ(supportedPrimitives, result.value());
}
+TEST_F(VibratorHalWrapperAidlTest, TestGetResonantFrequencyDoesNotCacheFailedResult) {
+ constexpr float F0 = 123.f;
+ EXPECT_CALL(*mMockHal.get(), getResonantFrequency(_))
+ .Times(Exactly(3))
+ .WillOnce(
+ Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(F0), Return(Status())));
+
+ ASSERT_TRUE(mWrapper->getResonantFrequency().isUnsupported());
+ ASSERT_TRUE(mWrapper->getResonantFrequency().isFailed());
+
+ auto result = mWrapper->getResonantFrequency();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(F0, result.value());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestGetResonantFrequencyCachesResult) {
+ constexpr float F0 = 123.f;
+ EXPECT_CALL(*mMockHal.get(), getResonantFrequency(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(F0), Return(Status())));
+
+ std::vector<std::thread> threads;
+ for (int i = 0; i < 10; i++) {
+ threads.push_back(std::thread([&]() {
+ auto result = mWrapper->getResonantFrequency();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(F0, result.value());
+ }));
+ }
+ std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+ auto result = mWrapper->getResonantFrequency();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(F0, result.value());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestGetQFactorDoesNotCacheFailedResult) {
+ constexpr float Q_FACTOR = 123.f;
+ EXPECT_CALL(*mMockHal.get(), getQFactor(_))
+ .Times(Exactly(3))
+ .WillOnce(
+ Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(Q_FACTOR), Return(Status())));
+
+ ASSERT_TRUE(mWrapper->getQFactor().isUnsupported());
+ ASSERT_TRUE(mWrapper->getQFactor().isFailed());
+
+ auto result = mWrapper->getQFactor();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(Q_FACTOR, result.value());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestGetQFactorCachesResult) {
+ constexpr float Q_FACTOR = 123.f;
+ EXPECT_CALL(*mMockHal.get(), getQFactor(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(Q_FACTOR), Return(Status())));
+
+ std::vector<std::thread> threads;
+ for (int i = 0; i < 10; i++) {
+ threads.push_back(std::thread([&]() {
+ auto result = mWrapper->getQFactor();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(Q_FACTOR, result.value());
+ }));
+ }
+ std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+ auto result = mWrapper->getQFactor();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(Q_FACTOR, result.value());
+}
+
TEST_F(VibratorHalWrapperAidlTest, TestPerformEffectWithCallbackSupport) {
{
InSequence seq;