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;