Implement PWLE support

Implement support to new API method composePwle and related frequency
control getters.

Bug: 167947076
Test: libvibratorservice_test
Change-Id: I6f47ea771a19b1ae46370c5d82671f6420e39f8b
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index 3ebf9b6..1010aa5 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -26,10 +26,12 @@
 #include <vibratorservice/VibratorCallbackScheduler.h>
 #include <vibratorservice/VibratorHalWrapper.h>
 
+using android::hardware::vibrator::Braking;
 using android::hardware::vibrator::CompositeEffect;
 using android::hardware::vibrator::CompositePrimitive;
 using android::hardware::vibrator::Effect;
 using android::hardware::vibrator::EffectStrength;
+using android::hardware::vibrator::PrimitivePwle;
 
 using std::chrono::milliseconds;
 
@@ -46,20 +48,6 @@
 // -------------------------------------------------------------------------------------------------
 
 template <class T>
-HalResult<T> loadCached(const std::function<HalResult<T>()>& loadFn, std::optional<T>& cache) {
-    if (cache.has_value()) {
-        // Return copy of cached value.
-        return HalResult<T>::ok(*cache);
-    }
-    HalResult<T> ret = loadFn();
-    if (ret.isOk()) {
-        // Cache copy of returned value.
-        cache.emplace(ret.value());
-    }
-    return ret;
-}
-
-template <class T>
 bool isStaticCastValid(Effect effect) {
     T castEffect = static_cast<T>(effect);
     auto iter = hardware::hidl_enum_range<T>();
@@ -141,15 +129,39 @@
     if (mInfoCache.mSupportedEffects.isFailed()) {
         mInfoCache.mSupportedEffects = getSupportedEffectsInternal();
     }
+    if (mInfoCache.mSupportedBraking.isFailed()) {
+        mInfoCache.mSupportedBraking = getSupportedBrakingInternal();
+    }
+    if (mInfoCache.mMinFrequency.isFailed()) {
+        mInfoCache.mMinFrequency = getMinFrequencyInternal();
+    }
     if (mInfoCache.mResonantFrequency.isFailed()) {
         mInfoCache.mResonantFrequency = getResonantFrequencyInternal();
     }
+    if (mInfoCache.mFrequencyResolution.isFailed()) {
+        mInfoCache.mFrequencyResolution = getFrequencyResolutionInternal();
+    }
     if (mInfoCache.mQFactor.isFailed()) {
         mInfoCache.mQFactor = getQFactorInternal();
     }
+    if (mInfoCache.mMaxAmplitudes.isFailed()) {
+        mInfoCache.mMaxAmplitudes = getMaxAmplitudesInternal();
+    }
     return mInfoCache.get();
 }
 
+HalResult<milliseconds> HalWrapper::performComposedEffect(const std::vector<CompositeEffect>&,
+                                                          const std::function<void()>&) {
+    ALOGV("Skipped performComposedEffect because it's not available in Vibrator HAL");
+    return HalResult<milliseconds>::unsupported();
+}
+
+HalResult<void> HalWrapper::performPwleEffect(const std::vector<PrimitivePwle>&,
+                                              const std::function<void()>&) {
+    ALOGV("Skipped performPwleEffect because it's not available in Vibrator HAL");
+    return HalResult<void>::unsupported();
+}
+
 HalResult<Capabilities> HalWrapper::getCapabilities() {
     std::lock_guard<std::mutex> lock(mInfoMutex);
     if (mInfoCache.mCapabilities.isFailed()) {
@@ -178,6 +190,11 @@
     return HalResult<std::vector<Effect>>::unsupported();
 }
 
+HalResult<std::vector<Braking>> HalWrapper::getSupportedBrakingInternal() {
+    ALOGV("Skipped getSupportedBraking because it's not available in Vibrator HAL");
+    return HalResult<std::vector<Braking>>::unsupported();
+}
+
 HalResult<std::vector<CompositePrimitive>> HalWrapper::getSupportedPrimitivesInternal() {
     ALOGV("Skipped getSupportedPrimitives because it's not available in Vibrator HAL");
     return HalResult<std::vector<CompositePrimitive>>::unsupported();
@@ -189,16 +206,31 @@
     return HalResult<std::vector<milliseconds>>::unsupported();
 }
 
+HalResult<float> HalWrapper::getMinFrequencyInternal() {
+    ALOGV("Skipped getMinFrequency because it's not available in Vibrator HAL");
+    return HalResult<float>::unsupported();
+}
+
 HalResult<float> HalWrapper::getResonantFrequencyInternal() {
     ALOGV("Skipped getResonantFrequency because it's not available in Vibrator HAL");
     return HalResult<float>::unsupported();
 }
 
+HalResult<float> HalWrapper::getFrequencyResolutionInternal() {
+    ALOGV("Skipped getFrequencyResolution because it's not available in Vibrator HAL");
+    return HalResult<float>::unsupported();
+}
+
 HalResult<float> HalWrapper::getQFactorInternal() {
     ALOGV("Skipped getQFactor because it's not available in Vibrator HAL");
     return HalResult<float>::unsupported();
 }
 
+HalResult<std::vector<float>> HalWrapper::getMaxAmplitudesInternal() {
+    ALOGV("Skipped getMaxAmplitudes because it's not available in Vibrator HAL");
+    return HalResult<std::vector<float>>::unsupported();
+}
+
 // -------------------------------------------------------------------------------------------------
 
 HalResult<void> AidlHalWrapper::ping() {
@@ -272,14 +304,14 @@
 }
 
 HalResult<milliseconds> AidlHalWrapper::performComposedEffect(
-        const std::vector<CompositeEffect>& primitiveEffects,
+        const std::vector<CompositeEffect>& primitives,
         const std::function<void()>& completionCallback) {
     // This method should always support callbacks, so no need to double check.
     auto cb = new HalCallbackWrapper(completionCallback);
 
     auto durations = getPrimitiveDurations().valueOr({});
     milliseconds duration(0);
-    for (const auto& effect : primitiveEffects) {
+    for (const auto& effect : primitives) {
         auto primitiveIdx = static_cast<size_t>(effect.primitive);
         if (primitiveIdx < durations.size()) {
             duration += durations[primitiveIdx];
@@ -290,7 +322,14 @@
         duration += milliseconds(effect.delayMs);
     }
 
-    return HalResult<milliseconds>::fromStatus(getHal()->compose(primitiveEffects, cb), duration);
+    return HalResult<milliseconds>::fromStatus(getHal()->compose(primitives, cb), duration);
+}
+
+HalResult<void> AidlHalWrapper::performPwleEffect(const std::vector<PrimitivePwle>& primitives,
+                                                  const std::function<void()>& completionCallback) {
+    // This method should always support callbacks, so no need to double check.
+    auto cb = new HalCallbackWrapper(completionCallback);
+    return HalResult<void>::fromStatus(getHal()->composePwle(primitives, cb));
 }
 
 HalResult<Capabilities> AidlHalWrapper::getCapabilitiesInternal() {
@@ -305,6 +344,12 @@
     return HalResult<std::vector<Effect>>::fromStatus(result, supportedEffects);
 }
 
+HalResult<std::vector<Braking>> AidlHalWrapper::getSupportedBrakingInternal() {
+    std::vector<Braking> supportedBraking;
+    auto result = getHal()->getSupportedBraking(&supportedBraking);
+    return HalResult<std::vector<Braking>>::fromStatus(result, supportedBraking);
+}
+
 HalResult<std::vector<CompositePrimitive>> AidlHalWrapper::getSupportedPrimitivesInternal() {
     std::vector<CompositePrimitive> supportedPrimitives;
     auto result = getHal()->getSupportedPrimitives(&supportedPrimitives);
@@ -335,18 +380,36 @@
     return HalResult<std::vector<milliseconds>>::ok(durations);
 }
 
+HalResult<float> AidlHalWrapper::getMinFrequencyInternal() {
+    float minFrequency = 0;
+    auto result = getHal()->getFrequencyMinimum(&minFrequency);
+    return HalResult<float>::fromStatus(result, minFrequency);
+}
+
 HalResult<float> AidlHalWrapper::getResonantFrequencyInternal() {
     float f0 = 0;
     auto result = getHal()->getResonantFrequency(&f0);
     return HalResult<float>::fromStatus(result, f0);
 }
 
+HalResult<float> AidlHalWrapper::getFrequencyResolutionInternal() {
+    float frequencyResolution = 0;
+    auto result = getHal()->getFrequencyResolution(&frequencyResolution);
+    return HalResult<float>::fromStatus(result, frequencyResolution);
+}
+
 HalResult<float> AidlHalWrapper::getQFactorInternal() {
     float qFactor = 0;
     auto result = getHal()->getQFactor(&qFactor);
     return HalResult<float>::fromStatus(result, qFactor);
 }
 
+HalResult<std::vector<float>> AidlHalWrapper::getMaxAmplitudesInternal() {
+    std::vector<float> amplitudes;
+    auto result = getHal()->getBandwidthAmplitudeMap(&amplitudes);
+    return HalResult<std::vector<float>>::fromStatus(result, amplitudes);
+}
+
 sp<Aidl::IVibrator> AidlHalWrapper::getHal() {
     std::lock_guard<std::mutex> lock(mHandleMutex);
     return mHandle;
@@ -412,13 +475,6 @@
 }
 
 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");
-    return HalResult<std::chrono::milliseconds>::unsupported();
-}
-
-template <typename I>
 HalResult<Capabilities> HidlHalWrapper<I>::getCapabilitiesInternal() {
     hardware::Return<bool> result = getHal()->supportsAmplitudeControl();
     Capabilities capabilities =
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index 3a90ce3..8720d9d 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -148,7 +148,8 @@
     EXTERNAL_CONTROL = hardware::vibrator::IVibrator::CAP_EXTERNAL_CONTROL,
     EXTERNAL_AMPLITUDE_CONTROL = hardware::vibrator::IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL,
     COMPOSE_EFFECTS = hardware::vibrator::IVibrator::CAP_COMPOSE_EFFECTS,
-    ALWAYS_ON_CONTROL = hardware::vibrator::IVibrator::CAP_ALWAYS_ON_CONTROL
+    COMPOSE_PWLE_EFFECTS = hardware::vibrator::IVibrator::CAP_COMPOSE_PWLE_EFFECTS,
+    ALWAYS_ON_CONTROL = hardware::vibrator::IVibrator::CAP_ALWAYS_ON_CONTROL,
 };
 
 inline Capabilities operator|(Capabilities lhs, Capabilities rhs) {
@@ -175,26 +176,36 @@
 public:
     const HalResult<Capabilities> capabilities;
     const HalResult<std::vector<hardware::vibrator::Effect>> supportedEffects;
+    const HalResult<std::vector<hardware::vibrator::Braking>> supportedBraking;
     const HalResult<std::vector<hardware::vibrator::CompositePrimitive>> supportedPrimitives;
     const HalResult<std::vector<std::chrono::milliseconds>> primitiveDurations;
+    const HalResult<float> minFrequency;
     const HalResult<float> resonantFrequency;
+    const HalResult<float> frequencyResolution;
     const HalResult<float> qFactor;
+    const HalResult<std::vector<float>> maxAmplitudes;
 
     bool checkAndLogFailure(const char*) const {
         return capabilities.checkAndLogFailure("getCapabilities") ||
                 supportedEffects.checkAndLogFailure("getSupportedEffects") ||
+                supportedBraking.checkAndLogFailure("getSupportedBraking") ||
                 supportedPrimitives.checkAndLogFailure("getSupportedPrimitives") ||
                 primitiveDurations.checkAndLogFailure("getPrimitiveDuration") ||
+                minFrequency.checkAndLogFailure("getMinFrequency") ||
                 resonantFrequency.checkAndLogFailure("getResonantFrequency") ||
-                qFactor.checkAndLogFailure("getQFactor");
+                frequencyResolution.checkAndLogFailure("getFrequencyResolution") ||
+                qFactor.checkAndLogFailure("getQFactor") ||
+                maxAmplitudes.checkAndLogFailure("getMaxAmplitudes");
     }
 };
 
 class InfoCache {
 public:
     Info get() {
-        return {mCapabilities,       mSupportedEffects,  mSupportedPrimitives,
-                mPrimitiveDurations, mResonantFrequency, mQFactor};
+        return {mCapabilities,        mSupportedEffects,    mSupportedBraking,
+                mSupportedPrimitives, mPrimitiveDurations,  mMinFrequency,
+                mResonantFrequency,   mFrequencyResolution, mQFactor,
+                mMaxAmplitudes};
     }
 
 private:
@@ -202,12 +213,17 @@
     HalResult<Capabilities> mCapabilities = HalResult<Capabilities>::failed(MSG);
     HalResult<std::vector<hardware::vibrator::Effect>> mSupportedEffects =
             HalResult<std::vector<hardware::vibrator::Effect>>::failed(MSG);
+    HalResult<std::vector<hardware::vibrator::Braking>> mSupportedBraking =
+            HalResult<std::vector<hardware::vibrator::Braking>>::failed(MSG);
     HalResult<std::vector<hardware::vibrator::CompositePrimitive>> mSupportedPrimitives =
             HalResult<std::vector<hardware::vibrator::CompositePrimitive>>::failed(MSG);
     HalResult<std::vector<std::chrono::milliseconds>> mPrimitiveDurations =
             HalResult<std::vector<std::chrono::milliseconds>>::failed(MSG);
+    HalResult<float> mMinFrequency = HalResult<float>::failed(MSG);
     HalResult<float> mResonantFrequency = HalResult<float>::failed(MSG);
+    HalResult<float> mFrequencyResolution = HalResult<float>::failed(MSG);
     HalResult<float> mQFactor = HalResult<float>::failed(MSG);
+    HalResult<std::vector<float>> mMaxAmplitudes = HalResult<std::vector<float>>::failed(MSG);
 
     friend class HalWrapper;
 };
@@ -243,8 +259,12 @@
             const std::function<void()>& completionCallback) = 0;
 
     virtual HalResult<std::chrono::milliseconds> performComposedEffect(
-            const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
-            const std::function<void()>& completionCallback) = 0;
+            const std::vector<hardware::vibrator::CompositeEffect>& primitives,
+            const std::function<void()>& completionCallback);
+
+    virtual HalResult<void> performPwleEffect(
+            const std::vector<hardware::vibrator::PrimitivePwle>& primitives,
+            const std::function<void()>& completionCallback);
 
 protected:
     // Shared pointer to allow CallbackScheduler to outlive this wrapper.
@@ -257,12 +277,16 @@
     // Request vibrator info to HAL skipping cache.
     virtual HalResult<Capabilities> getCapabilitiesInternal() = 0;
     virtual HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffectsInternal();
+    virtual HalResult<std::vector<hardware::vibrator::Braking>> getSupportedBrakingInternal();
     virtual HalResult<std::vector<hardware::vibrator::CompositePrimitive>>
     getSupportedPrimitivesInternal();
     virtual HalResult<std::vector<std::chrono::milliseconds>> getPrimitiveDurationsInternal(
             const std::vector<hardware::vibrator::CompositePrimitive>& supportedPrimitives);
+    virtual HalResult<float> getMinFrequencyInternal();
     virtual HalResult<float> getResonantFrequencyInternal();
+    virtual HalResult<float> getFrequencyResolutionInternal();
     virtual HalResult<float> getQFactorInternal();
+    virtual HalResult<std::vector<float>> getMaxAmplitudesInternal();
 
 private:
     std::mutex mInfoMutex;
@@ -303,19 +327,28 @@
             const std::function<void()>& completionCallback) override final;
 
     HalResult<std::chrono::milliseconds> performComposedEffect(
-            const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
+            const std::vector<hardware::vibrator::CompositeEffect>& primitives,
+            const std::function<void()>& completionCallback) override final;
+
+    HalResult<void> performPwleEffect(
+            const std::vector<hardware::vibrator::PrimitivePwle>& primitives,
             const std::function<void()>& completionCallback) override final;
 
 protected:
     HalResult<Capabilities> getCapabilitiesInternal() override final;
     HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffectsInternal() override final;
+    HalResult<std::vector<hardware::vibrator::Braking>> getSupportedBrakingInternal()
+            override final;
     HalResult<std::vector<hardware::vibrator::CompositePrimitive>> getSupportedPrimitivesInternal()
             override final;
     HalResult<std::vector<std::chrono::milliseconds>> getPrimitiveDurationsInternal(
             const std::vector<hardware::vibrator::CompositePrimitive>& supportedPrimitives)
             override final;
+    HalResult<float> getMinFrequencyInternal() override final;
     HalResult<float> getResonantFrequencyInternal() override final;
+    HalResult<float> getFrequencyResolutionInternal() override final;
     HalResult<float> getQFactorInternal() override final;
+    HalResult<std::vector<float>> getMaxAmplitudesInternal() override final;
 
 private:
     const std::function<HalResult<sp<hardware::vibrator::IVibrator>>()> mReconnectFn;
@@ -347,10 +380,6 @@
                                    hardware::vibrator::EffectStrength strength) override final;
     HalResult<void> alwaysOnDisable(int32_t id) override final;
 
-    HalResult<std::chrono::milliseconds> performComposedEffect(
-            const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
-            const std::function<void()>& completionCallback) override final;
-
 protected:
     std::mutex mHandleMutex;
     sp<I> mHandle GUARDED_BY(mHandleMutex);
diff --git a/services/vibratorservice/test/VibratorHalControllerTest.cpp b/services/vibratorservice/test/VibratorHalControllerTest.cpp
index c0185de..279496a 100644
--- a/services/vibratorservice/test/VibratorHalControllerTest.cpp
+++ b/services/vibratorservice/test/VibratorHalControllerTest.cpp
@@ -31,8 +31,6 @@
 
 #include "test_utils.h"
 
-using android::hardware::vibrator::CompositeEffect;
-using android::hardware::vibrator::CompositePrimitive;
 using android::hardware::vibrator::Effect;
 using android::hardware::vibrator::EffectStrength;
 
@@ -71,10 +69,6 @@
                 (Effect effect, EffectStrength strength,
                  const std::function<void()>& completionCallback),
                 (override));
-    MOCK_METHOD(vibrator::HalResult<milliseconds>, performComposedEffect,
-                (const std::vector<CompositeEffect>& primitiveEffects,
-                 const std::function<void()>& completionCallback),
-                (override));
     MOCK_METHOD(vibrator::HalResult<vibrator::Capabilities>, getCapabilitiesInternal, (),
                 (override));
 
diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
index b9e8d8d..d1db82b 100644
--- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -76,20 +76,19 @@
     MOCK_METHOD(Status, compose,
                 (const std::vector<CompositeEffect>& e, const sp<IVibratorCallback>& cb),
                 (override));
+    MOCK_METHOD(Status, composePwle,
+                (const std::vector<PrimitivePwle>& e, const sp<IVibratorCallback>& cb), (override));
     MOCK_METHOD(Status, getSupportedAlwaysOnEffects, (std::vector<Effect> * ret), (override));
     MOCK_METHOD(Status, alwaysOnEnable, (int32_t id, Effect e, EffectStrength s), (override));
     MOCK_METHOD(Status, alwaysOnDisable, (int32_t id), (override));
     MOCK_METHOD(Status, getQFactor, (float * ret), (override));
     MOCK_METHOD(Status, getResonantFrequency, (float * ret), (override));
-    MOCK_METHOD(Status, getFrequencyResolution, (float *freqResolutionHz), (override));
-    MOCK_METHOD(Status, getFrequencyMinimum, (float *freqMinimumHz), (override));
+    MOCK_METHOD(Status, getFrequencyResolution, (float* ret), (override));
+    MOCK_METHOD(Status, getFrequencyMinimum, (float* ret), (override));
     MOCK_METHOD(Status, getBandwidthAmplitudeMap, (std::vector<float> * ret), (override));
-    MOCK_METHOD(Status, getPwlePrimitiveDurationMax, (int32_t *durationMs), (override));
-    MOCK_METHOD(Status, getPwleCompositionSizeMax, (int32_t *maxSize), (override));
+    MOCK_METHOD(Status, getPwlePrimitiveDurationMax, (int32_t * ret), (override));
+    MOCK_METHOD(Status, getPwleCompositionSizeMax, (int32_t * ret), (override));
     MOCK_METHOD(Status, getSupportedBraking, (std::vector<Braking> * ret), (override));
-    MOCK_METHOD(Status, composePwle,
-                (const std::vector<PrimitivePwle>& e, const sp<IVibratorCallback>& cb),
-                (override));
     MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
     MOCK_METHOD(std::string, getInterfaceHash, (), (override));
     MOCK_METHOD(IBinder*, onAsBinder, (), (override));
@@ -301,10 +300,14 @@
 }
 
 TEST_F(VibratorHalWrapperAidlTest, TestGetInfoDoesNotCacheFailedResult) {
+    constexpr float F_MIN = 100.f;
     constexpr float F0 = 123.f;
+    constexpr float F_RESOLUTION = 0.5f;
     constexpr float Q_FACTOR = 123.f;
     std::vector<Effect> supportedEffects = {Effect::CLICK, Effect::TICK};
     std::vector<CompositePrimitive> supportedPrimitives = {CompositePrimitive::CLICK};
+    std::vector<Braking> supportedBraking = {Braking::CLAB};
+    std::vector<float> amplitudes = {0.f, 1.f, 0.f};
 
     std::vector<std::chrono::milliseconds> primitiveDurations;
     constexpr auto primitiveRange = enum_range<CompositePrimitive>();
@@ -320,6 +323,10 @@
             .Times(Exactly(2))
             .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
             .WillRepeatedly(DoAll(SetArgPointee<0>(supportedEffects), Return(Status())));
+    EXPECT_CALL(*mMockHal.get(), getSupportedBraking(_))
+            .Times(Exactly(2))
+            .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+            .WillRepeatedly(DoAll(SetArgPointee<0>(supportedBraking), Return(Status())));
     EXPECT_CALL(*mMockHal.get(), getSupportedPrimitives(_))
             .Times(Exactly(2))
             .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
@@ -327,33 +334,54 @@
     EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::CLICK), _))
             .Times(Exactly(1))
             .WillRepeatedly(DoAll(SetArgPointee<1>(10), Return(Status())));
+    EXPECT_CALL(*mMockHal.get(), getFrequencyMinimum(_))
+            .Times(Exactly(2))
+            .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+            .WillRepeatedly(DoAll(SetArgPointee<0>(F_MIN), Return(Status())));
     EXPECT_CALL(*mMockHal.get(), getResonantFrequency(_))
             .Times(Exactly(2))
             .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
             .WillRepeatedly(DoAll(SetArgPointee<0>(F0), Return(Status())));
+    EXPECT_CALL(*mMockHal.get(), getFrequencyResolution(_))
+            .Times(Exactly(2))
+            .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+            .WillRepeatedly(DoAll(SetArgPointee<0>(F_RESOLUTION), Return(Status())));
     EXPECT_CALL(*mMockHal.get(), getQFactor(_))
             .Times(Exactly(2))
             .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
             .WillRepeatedly(DoAll(SetArgPointee<0>(Q_FACTOR), Return(Status())));
+    EXPECT_CALL(*mMockHal.get(), getBandwidthAmplitudeMap(_))
+            .Times(Exactly(2))
+            .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+            .WillRepeatedly(DoAll(SetArgPointee<0>(amplitudes), Return(Status())));
 
     vibrator::Info failed = mWrapper->getInfo();
     ASSERT_TRUE(failed.capabilities.isFailed());
     ASSERT_TRUE(failed.supportedEffects.isFailed());
+    ASSERT_TRUE(failed.supportedBraking.isFailed());
     ASSERT_TRUE(failed.supportedPrimitives.isFailed());
     ASSERT_TRUE(failed.primitiveDurations.isFailed());
+    ASSERT_TRUE(failed.minFrequency.isFailed());
     ASSERT_TRUE(failed.resonantFrequency.isFailed());
+    ASSERT_TRUE(failed.frequencyResolution.isFailed());
     ASSERT_TRUE(failed.qFactor.isFailed());
+    ASSERT_TRUE(failed.maxAmplitudes.isFailed());
 
     vibrator::Info successful = mWrapper->getInfo();
     ASSERT_EQ(vibrator::Capabilities::ON_CALLBACK, successful.capabilities.value());
     ASSERT_EQ(supportedEffects, successful.supportedEffects.value());
+    ASSERT_EQ(supportedBraking, successful.supportedBraking.value());
     ASSERT_EQ(supportedPrimitives, successful.supportedPrimitives.value());
     ASSERT_EQ(primitiveDurations, successful.primitiveDurations.value());
+    ASSERT_EQ(F_MIN, successful.minFrequency.value());
     ASSERT_EQ(F0, successful.resonantFrequency.value());
+    ASSERT_EQ(F_RESOLUTION, successful.frequencyResolution.value());
     ASSERT_EQ(Q_FACTOR, successful.qFactor.value());
+    ASSERT_EQ(amplitudes, successful.maxAmplitudes.value());
 }
 
-TEST_F(VibratorHalWrapperAidlTest, TestGetCapabilitiesCachesResult) {
+TEST_F(VibratorHalWrapperAidlTest, TestGetInfoCachesResult) {
+    constexpr float F_MIN = 100.f;
     constexpr float F0 = 123.f;
     std::vector<Effect> supportedEffects = {Effect::CLICK, Effect::TICK};
 
@@ -363,14 +391,29 @@
     EXPECT_CALL(*mMockHal.get(), getSupportedEffects(_))
             .Times(Exactly(1))
             .WillRepeatedly(DoAll(SetArgPointee<0>(supportedEffects), Return(Status())));
+    EXPECT_CALL(*mMockHal.get(), getQFactor(_))
+            .Times(Exactly(1))
+            .WillRepeatedly(
+                    Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
     EXPECT_CALL(*mMockHal.get(), getSupportedPrimitives(_))
             .Times(Exactly(1))
             .WillRepeatedly(
                     Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+    EXPECT_CALL(*mMockHal.get(), getFrequencyMinimum(_))
+            .Times(Exactly(1))
+            .WillRepeatedly(DoAll(SetArgPointee<0>(F_MIN), Return(Status())));
     EXPECT_CALL(*mMockHal.get(), getResonantFrequency(_))
             .Times(Exactly(1))
             .WillRepeatedly(DoAll(SetArgPointee<0>(F0), Return(Status())));
-    EXPECT_CALL(*mMockHal.get(), getQFactor(_))
+    EXPECT_CALL(*mMockHal.get(), getFrequencyResolution(_))
+            .Times(Exactly(1))
+            .WillRepeatedly(
+                    Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+    EXPECT_CALL(*mMockHal.get(), getBandwidthAmplitudeMap(_))
+            .Times(Exactly(1))
+            .WillRepeatedly(
+                    Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+    EXPECT_CALL(*mMockHal.get(), getSupportedBraking(_))
             .Times(Exactly(1))
             .WillRepeatedly(
                     Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
@@ -385,10 +428,14 @@
     vibrator::Info info = mWrapper->getInfo();
     ASSERT_EQ(vibrator::Capabilities::ON_CALLBACK, info.capabilities.value());
     ASSERT_EQ(supportedEffects, info.supportedEffects.value());
+    ASSERT_TRUE(info.supportedBraking.isUnsupported());
     ASSERT_TRUE(info.supportedPrimitives.isUnsupported());
     ASSERT_TRUE(info.primitiveDurations.isUnsupported());
+    ASSERT_EQ(F_MIN, info.minFrequency.value());
     ASSERT_EQ(F0, info.resonantFrequency.value());
+    ASSERT_TRUE(info.frequencyResolution.isUnsupported());
     ASSERT_TRUE(info.qFactor.isUnsupported());
+    ASSERT_TRUE(info.maxAmplitudes.isUnsupported());
 }
 
 TEST_F(VibratorHalWrapperAidlTest, TestPerformEffectWithCallbackSupport) {
@@ -581,3 +628,39 @@
     ASSERT_EQ(114ms, result.value()); // Cached durations not fetched again, same duration returned.
     ASSERT_EQ(3, *callbackCounter.get());
 }
+
+TEST_F(VibratorHalWrapperAidlTest, TestPerformPwleEffect) {
+    std::vector<PrimitivePwle> emptyPrimitives, multiplePrimitives;
+    multiplePrimitives.push_back(vibrator::TestFactory::createActivePwle(0, 1, 0, 1, 10ms));
+    multiplePrimitives.push_back(vibrator::TestFactory::createBrakingPwle(Braking::NONE, 100ms));
+
+    {
+        InSequence seq;
+        EXPECT_CALL(*mMockHal.get(), composePwle(Eq(emptyPrimitives), _))
+                .Times(Exactly(1))
+                .WillRepeatedly(Return(
+                        Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+        EXPECT_CALL(*mMockHal.get(), composePwle(Eq(multiplePrimitives), _))
+                .Times(Exactly(2))
+                .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+                .WillRepeatedly(DoAll(TriggerCallbackInArg1(), Return(Status())));
+        ;
+    }
+
+    std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+    auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+    auto result = mWrapper->performPwleEffect(emptyPrimitives, callback);
+    ASSERT_TRUE(result.isUnsupported());
+    // Callback not triggered on failure
+    ASSERT_EQ(0, *callbackCounter.get());
+
+    result = mWrapper->performPwleEffect(multiplePrimitives, callback);
+    ASSERT_TRUE(result.isFailed());
+    // Callback not triggered for unsupported
+    ASSERT_EQ(0, *callbackCounter.get());
+
+    result = mWrapper->performPwleEffect(multiplePrimitives, callback);
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(1, *callbackCounter.get());
+}
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
index 954477b..96b2582 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
@@ -31,11 +31,13 @@
 
 namespace V1_0 = android::hardware::vibrator::V1_0;
 
+using android::hardware::vibrator::Braking;
 using android::hardware::vibrator::CompositeEffect;
 using android::hardware::vibrator::CompositePrimitive;
 using android::hardware::vibrator::Effect;
 using android::hardware::vibrator::EffectStrength;
 using android::hardware::vibrator::IVibrator;
+using android::hardware::vibrator::PrimitivePwle;
 
 using namespace android;
 using namespace std::chrono_literals;
@@ -201,10 +203,14 @@
     vibrator::Info info = mWrapper->getInfo();
     ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, info.capabilities.value());
     ASSERT_TRUE(info.supportedEffects.isUnsupported());
+    ASSERT_TRUE(info.supportedBraking.isUnsupported());
     ASSERT_TRUE(info.supportedPrimitives.isUnsupported());
     ASSERT_TRUE(info.primitiveDurations.isUnsupported());
+    ASSERT_TRUE(info.minFrequency.isUnsupported());
     ASSERT_TRUE(info.resonantFrequency.isUnsupported());
+    ASSERT_TRUE(info.frequencyResolution.isUnsupported());
     ASSERT_TRUE(info.qFactor.isUnsupported());
+    ASSERT_TRUE(info.maxAmplitudes.isUnsupported());
 }
 
 TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetInfoWithoutAmplitudeControl) {
@@ -230,10 +236,14 @@
     vibrator::Info info = mWrapper->getInfo();
     ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, info.capabilities.value());
     ASSERT_TRUE(info.supportedEffects.isUnsupported());
+    ASSERT_TRUE(info.supportedBraking.isUnsupported());
     ASSERT_TRUE(info.supportedPrimitives.isUnsupported());
     ASSERT_TRUE(info.primitiveDurations.isUnsupported());
+    ASSERT_TRUE(info.minFrequency.isUnsupported());
     ASSERT_TRUE(info.resonantFrequency.isUnsupported());
+    ASSERT_TRUE(info.frequencyResolution.isUnsupported());
     ASSERT_TRUE(info.qFactor.isUnsupported());
+    ASSERT_TRUE(info.maxAmplitudes.isUnsupported());
 }
 
 TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformEffect) {
@@ -320,3 +330,18 @@
     // No callback is triggered.
     ASSERT_EQ(0, *callbackCounter.get());
 }
+
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformPwleEffectUnsupported) {
+    std::vector<PrimitivePwle> emptyPrimitives, multiplePrimitives;
+    multiplePrimitives.push_back(vibrator::TestFactory::createActivePwle(0, 1, 0, 1, 10ms));
+    multiplePrimitives.push_back(vibrator::TestFactory::createBrakingPwle(Braking::NONE, 100ms));
+
+    std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+    auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+    ASSERT_TRUE(mWrapper->performPwleEffect(emptyPrimitives, callback).isUnsupported());
+    ASSERT_TRUE(mWrapper->performPwleEffect(multiplePrimitives, callback).isUnsupported());
+
+    // No callback is triggered.
+    ASSERT_EQ(0, *callbackCounter.get());
+}
diff --git a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
index 406a470..3de1576 100644
--- a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
@@ -40,6 +40,8 @@
 using namespace android;
 using namespace testing;
 
+static const auto OFF_FN = [](std::shared_ptr<vibrator::HalWrapper> hal) { return hal->off(); };
+
 class MockBinder : public BBinder {
 public:
     MOCK_METHOD(status_t, linkToDeath,
@@ -70,20 +72,19 @@
     MOCK_METHOD(Status, compose,
                 (const std::vector<CompositeEffect>& e, const sp<IVibratorCallback>& cb),
                 (override));
+    MOCK_METHOD(Status, composePwle,
+                (const std::vector<PrimitivePwle>& e, const sp<IVibratorCallback>& cb), (override));
     MOCK_METHOD(Status, getSupportedAlwaysOnEffects, (std::vector<Effect> * ret), (override));
     MOCK_METHOD(Status, alwaysOnEnable, (int32_t id, Effect e, EffectStrength s), (override));
     MOCK_METHOD(Status, alwaysOnDisable, (int32_t id), (override));
     MOCK_METHOD(Status, getQFactor, (float * ret), (override));
     MOCK_METHOD(Status, getResonantFrequency, (float * ret), (override));
-    MOCK_METHOD(Status, getFrequencyResolution, (float *freqResolutionHz), (override));
-    MOCK_METHOD(Status, getFrequencyMinimum, (float *freqMinimumHz), (override));
+    MOCK_METHOD(Status, getFrequencyResolution, (float* ret), (override));
+    MOCK_METHOD(Status, getFrequencyMinimum, (float* ret), (override));
     MOCK_METHOD(Status, getBandwidthAmplitudeMap, (std::vector<float> * ret), (override));
-    MOCK_METHOD(Status, getPwlePrimitiveDurationMax, (int32_t *durationMs), (override));
-    MOCK_METHOD(Status, getPwleCompositionSizeMax, (int32_t *maxSize), (override));
+    MOCK_METHOD(Status, getPwlePrimitiveDurationMax, (int32_t * ret), (override));
+    MOCK_METHOD(Status, getPwleCompositionSizeMax, (int32_t * ret), (override));
     MOCK_METHOD(Status, getSupportedBraking, (std::vector<Braking> * ret), (override));
-    MOCK_METHOD(Status, composePwle,
-                (const std::vector<PrimitivePwle>& e, const sp<IVibratorCallback>& cb),
-                (override));
     MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
     MOCK_METHOD(std::string, getInterfaceHash, (), (override));
     MOCK_METHOD(IBinder*, onAsBinder, (), (override));
@@ -256,31 +257,11 @@
                             Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY))))
             .WillRepeatedly(DoAll(SetArgPointee<1>(mMockVibrator), Return(Status())));
 
-    EXPECT_CALL(*mMockVibrator.get(), getCapabilities(_))
+    EXPECT_CALL(*mMockVibrator.get(), off())
             .Times(Exactly(3))
             .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
             .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
-            .WillRepeatedly(DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), Return(Status())));
-
-    EXPECT_CALL(*mMockVibrator.get(), getSupportedEffects(_))
-            .Times(Exactly(1))
-            .WillOnce(
-                    Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
-
-    EXPECT_CALL(*mMockVibrator.get(), getSupportedPrimitives(_))
-            .Times(Exactly(1))
-            .WillOnce(
-                    Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
-
-    EXPECT_CALL(*mMockVibrator.get(), getResonantFrequency(_))
-            .Times(Exactly(1))
-            .WillOnce(
-                    Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
-
-    EXPECT_CALL(*mMockVibrator.get(), getQFactor(_))
-            .Times(Exactly(1))
-            .WillOnce(
-                    Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+            .WillRepeatedly(Return(Status()));
 
     // Get vibrator controller is successful even if first getVibrator.
     auto result = mWrapper->getVibrator(kVibratorId);
@@ -290,10 +271,10 @@
     auto vibrator = result.value();
     // First getVibrator call fails.
     ASSERT_FALSE(vibrator->init());
-    // First and second getCapabilities calls fail, reload IVibrator with getVibrator.
-    ASSERT_TRUE(vibrator->getInfo().capabilities.isFailed());
-    // Third call to getCapabilities worked after IVibrator reloaded.
-    ASSERT_FALSE(vibrator->getInfo().capabilities.isFailed());
+    // First and second off() calls fail, reload IVibrator with getVibrator.
+    ASSERT_TRUE(vibrator->doWithRetry<void>(OFF_FN, "off").isFailed());
+    // Third call to off() worked after IVibrator reloaded.
+    ASSERT_TRUE(vibrator->doWithRetry<void>(OFF_FN, "off").isOk());
 }
 
 TEST_F(VibratorManagerHalWrapperAidlTest, TestPrepareSynced) {
diff --git a/services/vibratorservice/test/test_utils.h b/services/vibratorservice/test/test_utils.h
index 8d0b22e..1933a11 100644
--- a/services/vibratorservice/test/test_utils.h
+++ b/services/vibratorservice/test/test_utils.h
@@ -25,8 +25,12 @@
 
 namespace vibrator {
 
+using ::android::hardware::vibrator::ActivePwle;
+using ::android::hardware::vibrator::Braking;
+using ::android::hardware::vibrator::BrakingPwle;
 using ::android::hardware::vibrator::CompositeEffect;
 using ::android::hardware::vibrator::CompositePrimitive;
+using ::android::hardware::vibrator::PrimitivePwle;
 
 // -------------------------------------------------------------------------------------------------
 
@@ -53,6 +57,25 @@
         return effect;
     }
 
+    static PrimitivePwle createActivePwle(float startAmplitude, float startFrequency,
+                                          float endAmplitude, float endFrequency,
+                                          std::chrono::milliseconds duration) {
+        ActivePwle pwle;
+        pwle.startAmplitude = startAmplitude;
+        pwle.endAmplitude = endAmplitude;
+        pwle.startFrequency = startFrequency;
+        pwle.endFrequency = endFrequency;
+        pwle.duration = duration.count();
+        return pwle;
+    }
+
+    static PrimitivePwle createBrakingPwle(Braking braking, std::chrono::milliseconds duration) {
+        BrakingPwle pwle;
+        pwle.braking = braking;
+        pwle.duration = duration.count();
+        return pwle;
+    }
+
     static std::function<void()> createCountingCallback(int32_t* counter) {
         return [counter]() { *counter += 1; };
     }