| /* | |
| * Copyright (C) 2020 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. | |
| */ | |
| #define LOG_TAG "VibratorHalWrapperAidlTest" | |
| #include <aidl/android/hardware/vibrator/IVibrator.h> | |
| #include <android/persistable_bundle_aidl.h> | |
| #include <gmock/gmock.h> | |
| #include <gtest/gtest.h> | |
| #include <utils/Log.h> | |
| #include <thread> | |
| #include <vibratorservice/VibratorCallbackScheduler.h> | |
| #include <vibratorservice/VibratorHalWrapper.h> | |
| #include "test_mocks.h" | |
| #include "test_utils.h" | |
| using aidl::android::hardware::vibrator::Braking; | |
| using aidl::android::hardware::vibrator::CompositeEffect; | |
| using aidl::android::hardware::vibrator::CompositePrimitive; | |
| using aidl::android::hardware::vibrator::CompositePwleV2; | |
| using aidl::android::hardware::vibrator::Effect; | |
| using aidl::android::hardware::vibrator::EffectStrength; | |
| using aidl::android::hardware::vibrator::FrequencyAccelerationMapEntry; | |
| using aidl::android::hardware::vibrator::IVibrator; | |
| using aidl::android::hardware::vibrator::IVibratorCallback; | |
| using aidl::android::hardware::vibrator::PrimitivePwle; | |
| using aidl::android::hardware::vibrator::PwleV2Primitive; | |
| using aidl::android::hardware::vibrator::VendorEffect; | |
| using aidl::android::os::PersistableBundle; | |
| using namespace android; | |
| using namespace std::chrono_literals; | |
| using namespace testing; | |
| // ------------------------------------------------------------------------------------------------- | |
| class VibratorHalWrapperAidlTest : public Test { | |
| public: | |
| void SetUp() override { | |
| mMockHal = ndk::SharedRefBase::make<StrictMock<vibrator::MockIVibrator>>(); | |
| mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>(); | |
| mWrapper = std::make_unique<vibrator::AidlHalWrapper>(mMockScheduler, mMockHal); | |
| ASSERT_NE(mWrapper, nullptr); | |
| } | |
| protected: | |
| std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr; | |
| std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr; | |
| std::shared_ptr<StrictMock<vibrator::MockIVibrator>> mMockHal = nullptr; | |
| }; | |
| // ------------------------------------------------------------------------------------------------- | |
| TEST_F(VibratorHalWrapperAidlTest, TestOnWithCallbackSupport) { | |
| { | |
| InSequence seq; | |
| EXPECT_CALL(*mMockHal.get(), getCapabilities(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), on(Eq(10), _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(WithArg<1>(vibrator::TriggerCallback()), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), on(Eq(100), _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION))); | |
| EXPECT_CALL(*mMockHal.get(), on(Eq(1000), _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))); | |
| } | |
| std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>(); | |
| auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get()); | |
| ASSERT_TRUE(mWrapper->on(10ms, callback).isOk()); | |
| ASSERT_EQ(1, *callbackCounter.get()); | |
| ASSERT_TRUE(mWrapper->on(100ms, callback).isUnsupported()); | |
| // Callback not triggered for unsupported | |
| ASSERT_EQ(1, *callbackCounter.get()); | |
| ASSERT_TRUE(mWrapper->on(1000ms, callback).isFailed()); | |
| // Callback not triggered on failure | |
| ASSERT_EQ(1, *callbackCounter.get()); | |
| } | |
| TEST_F(VibratorHalWrapperAidlTest, TestOnWithoutCallbackSupport) { | |
| { | |
| InSequence seq; | |
| EXPECT_CALL(*mMockHal.get(), getCapabilities(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<0>(IVibrator::CAP_COMPOSE_EFFECTS), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), on(Eq(10), _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::ok())); | |
| EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms))) | |
| .Times(Exactly(1)) | |
| .WillOnce(vibrator::TriggerSchedulerCallback()); | |
| EXPECT_CALL(*mMockHal.get(), on(Eq(11), _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION))); | |
| EXPECT_CALL(*mMockHal.get(), on(Eq(12), _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))); | |
| } | |
| std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>(); | |
| auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get()); | |
| ASSERT_TRUE(mWrapper->on(10ms, callback).isOk()); | |
| ASSERT_EQ(1, *callbackCounter.get()); | |
| ASSERT_TRUE(mWrapper->on(11ms, callback).isUnsupported()); | |
| ASSERT_TRUE(mWrapper->on(12ms, callback).isFailed()); | |
| // Callback not triggered for unsupported and on failure | |
| ASSERT_EQ(1, *callbackCounter.get()); | |
| } | |
| TEST_F(VibratorHalWrapperAidlTest, TestOff) { | |
| EXPECT_CALL(*mMockHal.get(), off()) | |
| .Times(Exactly(3)) | |
| .WillOnce(Return(ndk::ScopedAStatus::ok())) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION))) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))); | |
| ASSERT_TRUE(mWrapper->off().isOk()); | |
| ASSERT_TRUE(mWrapper->off().isUnsupported()); | |
| ASSERT_TRUE(mWrapper->off().isFailed()); | |
| } | |
| TEST_F(VibratorHalWrapperAidlTest, TestSetAmplitude) { | |
| { | |
| InSequence seq; | |
| EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(0.1f))) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::ok())); | |
| EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(0.2f))) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION))); | |
| EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(0.5f))) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))); | |
| } | |
| ASSERT_TRUE(mWrapper->setAmplitude(0.1f).isOk()); | |
| ASSERT_TRUE(mWrapper->setAmplitude(0.2f).isUnsupported()); | |
| ASSERT_TRUE(mWrapper->setAmplitude(0.5f).isFailed()); | |
| } | |
| TEST_F(VibratorHalWrapperAidlTest, TestSetExternalControl) { | |
| { | |
| InSequence seq; | |
| EXPECT_CALL(*mMockHal.get(), setExternalControl(Eq(true))) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::ok())); | |
| EXPECT_CALL(*mMockHal.get(), setExternalControl(Eq(false))) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION))) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))); | |
| } | |
| ASSERT_TRUE(mWrapper->setExternalControl(true).isOk()); | |
| ASSERT_TRUE(mWrapper->setExternalControl(false).isUnsupported()); | |
| ASSERT_TRUE(mWrapper->setExternalControl(false).isFailed()); | |
| } | |
| TEST_F(VibratorHalWrapperAidlTest, TestAlwaysOnEnable) { | |
| { | |
| InSequence seq; | |
| EXPECT_CALL(*mMockHal.get(), | |
| alwaysOnEnable(Eq(1), Eq(Effect::CLICK), Eq(EffectStrength::LIGHT))) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::ok())); | |
| EXPECT_CALL(*mMockHal.get(), | |
| alwaysOnEnable(Eq(2), Eq(Effect::TICK), Eq(EffectStrength::MEDIUM))) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION))); | |
| EXPECT_CALL(*mMockHal.get(), | |
| alwaysOnEnable(Eq(3), Eq(Effect::POP), Eq(EffectStrength::STRONG))) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))); | |
| } | |
| auto result = mWrapper->alwaysOnEnable(1, Effect::CLICK, EffectStrength::LIGHT); | |
| ASSERT_TRUE(result.isOk()); | |
| result = mWrapper->alwaysOnEnable(2, Effect::TICK, EffectStrength::MEDIUM); | |
| ASSERT_TRUE(result.isUnsupported()); | |
| result = mWrapper->alwaysOnEnable(3, Effect::POP, EffectStrength::STRONG); | |
| ASSERT_TRUE(result.isFailed()); | |
| } | |
| TEST_F(VibratorHalWrapperAidlTest, TestAlwaysOnDisable) { | |
| { | |
| InSequence seq; | |
| EXPECT_CALL(*mMockHal.get(), alwaysOnDisable(Eq(1))) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::ok())); | |
| EXPECT_CALL(*mMockHal.get(), alwaysOnDisable(Eq(2))) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION))); | |
| EXPECT_CALL(*mMockHal.get(), alwaysOnDisable(Eq(3))) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))); | |
| } | |
| ASSERT_TRUE(mWrapper->alwaysOnDisable(1).isOk()); | |
| ASSERT_TRUE(mWrapper->alwaysOnDisable(2).isUnsupported()); | |
| ASSERT_TRUE(mWrapper->alwaysOnDisable(3).isFailed()); | |
| } | |
| 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; | |
| constexpr int32_t COMPOSITION_SIZE_MAX = 10; | |
| constexpr int32_t PWLE_SIZE_MAX = 20; | |
| constexpr int32_t PRIMITIVE_DELAY_MAX = 100; | |
| constexpr int32_t PWLE_DURATION_MAX = 200; | |
| constexpr int32_t PWLE_V2_COMPOSITION_SIZE_MAX = 16; | |
| constexpr int32_t PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS = 20; | |
| constexpr int32_t PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS = 1000; | |
| 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<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap{ | |
| FrequencyAccelerationMapEntry(/*frequency=*/30.0f, | |
| /*maxOutputAcceleration=*/0.2), | |
| FrequencyAccelerationMapEntry(/*frequency=*/60.0f, | |
| /*maxOutputAcceleration=*/0.8)}; | |
| std::vector<std::chrono::milliseconds> primitiveDurations; | |
| constexpr auto primitiveRange = ndk::enum_range<CompositePrimitive>(); | |
| constexpr auto primitiveCount = std::distance(primitiveRange.begin(), primitiveRange.end()); | |
| primitiveDurations.resize(primitiveCount); | |
| primitiveDurations[static_cast<size_t>(CompositePrimitive::CLICK)] = 10ms; | |
| EXPECT_CALL(*mMockHal.get(), getCapabilities(_)) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce(DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getSupportedEffects(_)) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce(DoAll(SetArgPointee<0>(supportedEffects), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getSupportedBraking(_)) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce(DoAll(SetArgPointee<0>(supportedBraking), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getSupportedPrimitives(_)) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce( | |
| DoAll(SetArgPointee<0>(supportedPrimitives), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::CLICK), _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<1>(10), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getCompositionSizeMax(_)) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce(DoAll(SetArgPointee<0>(COMPOSITION_SIZE_MAX), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getCompositionDelayMax(_)) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce( | |
| DoAll(SetArgPointee<0>(PRIMITIVE_DELAY_MAX), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getPwlePrimitiveDurationMax(_)) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce(DoAll(SetArgPointee<0>(PWLE_DURATION_MAX), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getPwleCompositionSizeMax(_)) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce(DoAll(SetArgPointee<0>(PWLE_SIZE_MAX), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getFrequencyMinimum(_)) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce(DoAll(SetArgPointee<0>(F_MIN), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getResonantFrequency(_)) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce(DoAll(SetArgPointee<0>(F0), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getFrequencyResolution(_)) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce(DoAll(SetArgPointee<0>(F_RESOLUTION), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getQFactor(_)) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce(DoAll(SetArgPointee<0>(Q_FACTOR), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getBandwidthAmplitudeMap(_)) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce(DoAll(SetArgPointee<0>(amplitudes), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getPwleV2CompositionSizeMax(_)) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_COMPOSITION_SIZE_MAX), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getPwleV2PrimitiveDurationMinMillis(_)) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getPwleV2PrimitiveDurationMaxMillis(_)) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getFrequencyToOutputAccelerationMap(_)) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce(DoAll(SetArgPointee<0>(frequencyToOutputAccelerationMap), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| 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.primitiveDelayMax.isFailed()); | |
| ASSERT_TRUE(failed.pwlePrimitiveDurationMax.isFailed()); | |
| ASSERT_TRUE(failed.compositionSizeMax.isFailed()); | |
| ASSERT_TRUE(failed.pwleSizeMax.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()); | |
| ASSERT_TRUE(failed.maxEnvelopeEffectSize.isFailed()); | |
| ASSERT_TRUE(failed.minEnvelopeEffectControlPointDuration.isFailed()); | |
| ASSERT_TRUE(failed.maxEnvelopeEffectControlPointDuration.isFailed()); | |
| ASSERT_TRUE(failed.frequencyToOutputAccelerationMap.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(std::chrono::milliseconds(PRIMITIVE_DELAY_MAX), successful.primitiveDelayMax.value()); | |
| ASSERT_EQ(std::chrono::milliseconds(PWLE_DURATION_MAX), | |
| successful.pwlePrimitiveDurationMax.value()); | |
| ASSERT_EQ(COMPOSITION_SIZE_MAX, successful.compositionSizeMax.value()); | |
| ASSERT_EQ(PWLE_SIZE_MAX, successful.pwleSizeMax.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()); | |
| ASSERT_EQ(PWLE_V2_COMPOSITION_SIZE_MAX, successful.maxEnvelopeEffectSize.value()); | |
| ASSERT_EQ(std::chrono::milliseconds(PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS), | |
| successful.minEnvelopeEffectControlPointDuration.value()); | |
| ASSERT_EQ(std::chrono::milliseconds(PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS), | |
| successful.maxEnvelopeEffectControlPointDuration.value()); | |
| ASSERT_EQ(frequencyToOutputAccelerationMap, | |
| successful.frequencyToOutputAccelerationMap.value()); | |
| } | |
| TEST_F(VibratorHalWrapperAidlTest, TestGetInfoCachesResult) { | |
| constexpr float F_MIN = 100.f; | |
| constexpr float F0 = 123.f; | |
| constexpr int32_t COMPOSITION_SIZE_MAX = 10; | |
| constexpr int32_t PWLE_SIZE_MAX = 20; | |
| constexpr int32_t PRIMITIVE_DELAY_MAX = 100; | |
| constexpr int32_t PWLE_DURATION_MAX = 200; | |
| constexpr int32_t PWLE_V2_COMPOSITION_SIZE_MAX = 16; | |
| constexpr int32_t PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS = 20; | |
| constexpr int32_t PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS = 1000; | |
| std::vector<Effect> supportedEffects = {Effect::CLICK, Effect::TICK}; | |
| std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap{ | |
| FrequencyAccelerationMapEntry(/*frequency=*/30.0f, | |
| /*maxOutputAcceleration=*/0.2), | |
| FrequencyAccelerationMapEntry(/*frequency=*/60.0f, | |
| /*maxOutputAcceleration=*/0.8)}; | |
| EXPECT_CALL(*mMockHal.get(), getCapabilities(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getSupportedEffects(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<0>(supportedEffects), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getQFactor(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION))); | |
| EXPECT_CALL(*mMockHal.get(), getSupportedPrimitives(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION))); | |
| EXPECT_CALL(*mMockHal.get(), getCompositionSizeMax(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<0>(COMPOSITION_SIZE_MAX), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getCompositionDelayMax(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce( | |
| DoAll(SetArgPointee<0>(PRIMITIVE_DELAY_MAX), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getPwlePrimitiveDurationMax(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<0>(PWLE_DURATION_MAX), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getPwleCompositionSizeMax(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<0>(PWLE_SIZE_MAX), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getFrequencyMinimum(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<0>(F_MIN), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getResonantFrequency(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<0>(F0), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getFrequencyResolution(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION))); | |
| EXPECT_CALL(*mMockHal.get(), getBandwidthAmplitudeMap(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION))); | |
| EXPECT_CALL(*mMockHal.get(), getSupportedBraking(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION))); | |
| EXPECT_CALL(*mMockHal.get(), getPwleV2CompositionSizeMax(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_COMPOSITION_SIZE_MAX), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getPwleV2PrimitiveDurationMinMillis(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getPwleV2PrimitiveDurationMaxMillis(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getFrequencyToOutputAccelerationMap(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<0>(frequencyToOutputAccelerationMap), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| std::vector<std::thread> threads; | |
| for (int i = 0; i < 10; i++) { | |
| threads.push_back( | |
| std::thread([&]() { ASSERT_TRUE(mWrapper->getInfo().capabilities.isOk()); })); | |
| } | |
| std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); }); | |
| 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(std::chrono::milliseconds(PRIMITIVE_DELAY_MAX), info.primitiveDelayMax.value()); | |
| ASSERT_EQ(std::chrono::milliseconds(PWLE_DURATION_MAX), info.pwlePrimitiveDurationMax.value()); | |
| ASSERT_EQ(COMPOSITION_SIZE_MAX, info.compositionSizeMax.value()); | |
| ASSERT_EQ(PWLE_SIZE_MAX, info.pwleSizeMax.value()); | |
| 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()); | |
| ASSERT_EQ(PWLE_V2_COMPOSITION_SIZE_MAX, info.maxEnvelopeEffectSize.value()); | |
| ASSERT_EQ(std::chrono::milliseconds(PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS), | |
| info.minEnvelopeEffectControlPointDuration.value()); | |
| ASSERT_EQ(std::chrono::milliseconds(PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS), | |
| info.maxEnvelopeEffectControlPointDuration.value()); | |
| ASSERT_EQ(frequencyToOutputAccelerationMap, info.frequencyToOutputAccelerationMap.value()); | |
| } | |
| TEST_F(VibratorHalWrapperAidlTest, TestPerformEffectWithCallbackSupport) { | |
| { | |
| InSequence seq; | |
| EXPECT_CALL(*mMockHal.get(), getCapabilities(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<0>(IVibrator::CAP_PERFORM_CALLBACK), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::CLICK), Eq(EffectStrength::LIGHT), _, _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<3>(1000), WithArg<2>(vibrator::TriggerCallback()), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::POP), Eq(EffectStrength::MEDIUM), _, _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION))); | |
| EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::THUD), Eq(EffectStrength::STRONG), _, _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))); | |
| } | |
| std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>(); | |
| auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get()); | |
| auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback); | |
| ASSERT_TRUE(result.isOk()); | |
| ASSERT_EQ(1000ms, result.value()); | |
| ASSERT_EQ(1, *callbackCounter.get()); | |
| result = mWrapper->performEffect(Effect::POP, EffectStrength::MEDIUM, callback); | |
| ASSERT_TRUE(result.isUnsupported()); | |
| // Callback not triggered for unsupported | |
| ASSERT_EQ(1, *callbackCounter.get()); | |
| result = mWrapper->performEffect(Effect::THUD, EffectStrength::STRONG, callback); | |
| ASSERT_TRUE(result.isFailed()); | |
| // Callback not triggered on failure | |
| ASSERT_EQ(1, *callbackCounter.get()); | |
| } | |
| TEST_F(VibratorHalWrapperAidlTest, TestPerformEffectWithoutCallbackSupport) { | |
| { | |
| InSequence seq; | |
| EXPECT_CALL(*mMockHal.get(), getCapabilities(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::CLICK), Eq(EffectStrength::LIGHT), _, _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<3>(10), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms))) | |
| .Times(Exactly(1)) | |
| .WillOnce(vibrator::TriggerSchedulerCallback()); | |
| EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::POP), Eq(EffectStrength::MEDIUM), _, _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION))); | |
| EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::THUD), Eq(EffectStrength::STRONG), _, _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))); | |
| } | |
| std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>(); | |
| auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get()); | |
| auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback); | |
| ASSERT_TRUE(result.isOk()); | |
| ASSERT_EQ(10ms, result.value()); | |
| ASSERT_EQ(1, *callbackCounter.get()); | |
| result = mWrapper->performEffect(Effect::POP, EffectStrength::MEDIUM, callback); | |
| ASSERT_TRUE(result.isUnsupported()); | |
| result = mWrapper->performEffect(Effect::THUD, EffectStrength::STRONG, callback); | |
| ASSERT_TRUE(result.isFailed()); | |
| // Callback not triggered for unsupported and on failure | |
| ASSERT_EQ(1, *callbackCounter.get()); | |
| } | |
| TEST_F(VibratorHalWrapperAidlTest, TestPerformVendorEffect) { | |
| PersistableBundle vendorData; | |
| vendorData.putInt("key", 1); | |
| VendorEffect vendorEffect; | |
| vendorEffect.vendorData = vendorData; | |
| vendorEffect.strength = EffectStrength::MEDIUM; | |
| vendorEffect.scale = 0.5f; | |
| { | |
| InSequence seq; | |
| EXPECT_CALL(*mMockHal.get(), performVendorEffect(_, _)) | |
| .Times(Exactly(3)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION))) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce(DoAll(WithArg<1>(vibrator::TriggerCallback()), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| } | |
| std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>(); | |
| auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get()); | |
| auto result = mWrapper->performVendorEffect(vendorEffect, callback); | |
| ASSERT_TRUE(result.isUnsupported()); | |
| // Callback not triggered on failure | |
| ASSERT_EQ(0, *callbackCounter.get()); | |
| result = mWrapper->performVendorEffect(vendorEffect, callback); | |
| ASSERT_TRUE(result.isFailed()); | |
| // Callback not triggered for unsupported | |
| ASSERT_EQ(0, *callbackCounter.get()); | |
| result = mWrapper->performVendorEffect(vendorEffect, callback); | |
| ASSERT_TRUE(result.isOk()); | |
| ASSERT_EQ(1, *callbackCounter.get()); | |
| } | |
| TEST_F(VibratorHalWrapperAidlTest, TestPerformComposedEffect) { | |
| std::vector<CompositePrimitive> supportedPrimitives = {CompositePrimitive::CLICK, | |
| CompositePrimitive::SPIN, | |
| CompositePrimitive::THUD}; | |
| std::vector<CompositeEffect> emptyEffects, singleEffect, multipleEffects; | |
| singleEffect.push_back( | |
| vibrator::TestFactory::createCompositeEffect(CompositePrimitive::CLICK, 10ms, 0.0f)); | |
| multipleEffects.push_back( | |
| vibrator::TestFactory::createCompositeEffect(CompositePrimitive::SPIN, 100ms, 0.5f)); | |
| multipleEffects.push_back( | |
| vibrator::TestFactory::createCompositeEffect(CompositePrimitive::THUD, 1000ms, 1.0f)); | |
| { | |
| InSequence seq; | |
| EXPECT_CALL(*mMockHal.get(), getSupportedPrimitives(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<0>(supportedPrimitives), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::CLICK), _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<1>(1), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::SPIN), _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<1>(2), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::THUD), _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<1>(3), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), compose(Eq(emptyEffects), _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(WithArg<1>(vibrator::TriggerCallback()), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), compose(Eq(singleEffect), _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION))); | |
| EXPECT_CALL(*mMockHal.get(), compose(Eq(multipleEffects), _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))); | |
| } | |
| std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>(); | |
| auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get()); | |
| auto result = mWrapper->performComposedEffect(emptyEffects, callback); | |
| ASSERT_TRUE(result.isOk()); | |
| ASSERT_EQ(0ms, result.value()); | |
| ASSERT_EQ(1, *callbackCounter.get()); | |
| result = mWrapper->performComposedEffect(singleEffect, callback); | |
| ASSERT_TRUE(result.isUnsupported()); | |
| // Callback not triggered for unsupported | |
| ASSERT_EQ(1, *callbackCounter.get()); | |
| result = mWrapper->performComposedEffect(multipleEffects, callback); | |
| ASSERT_TRUE(result.isFailed()); | |
| // Callback not triggered on failure | |
| ASSERT_EQ(1, *callbackCounter.get()); | |
| } | |
| TEST_F(VibratorHalWrapperAidlTest, TestPerformComposedCachesPrimitiveDurationsAndIgnoresFailures) { | |
| std::vector<CompositePrimitive> supportedPrimitives = {CompositePrimitive::SPIN, | |
| CompositePrimitive::THUD}; | |
| std::vector<CompositeEffect> multipleEffects; | |
| multipleEffects.push_back( | |
| vibrator::TestFactory::createCompositeEffect(CompositePrimitive::SPIN, 10ms, 0.5f)); | |
| multipleEffects.push_back( | |
| vibrator::TestFactory::createCompositeEffect(CompositePrimitive::THUD, 100ms, 1.0f)); | |
| { | |
| InSequence seq; | |
| EXPECT_CALL(*mMockHal.get(), getSupportedPrimitives(_)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<0>(supportedPrimitives), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::SPIN), _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<1>(2), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::THUD), _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))); | |
| EXPECT_CALL(*mMockHal.get(), compose(Eq(multipleEffects), _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(WithArg<1>(vibrator::TriggerCallback()), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::SPIN), _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<1>(2), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::THUD), _)) | |
| .Times(Exactly(1)) | |
| .WillOnce(DoAll(SetArgPointee<1>(2), Return(ndk::ScopedAStatus::ok()))); | |
| EXPECT_CALL(*mMockHal.get(), compose(Eq(multipleEffects), _)) | |
| .Times(Exactly(2)) | |
| // ndk::ScopedAStatus::ok() cannot be copy-constructed so can't use WillRepeatedly | |
| .WillOnce(DoAll(WithArg<1>(vibrator::TriggerCallback()), | |
| Return(ndk::ScopedAStatus::ok()))) | |
| .WillOnce(DoAll(WithArg<1>(vibrator::TriggerCallback()), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| } | |
| std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>(); | |
| auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get()); | |
| auto result = mWrapper->performComposedEffect(multipleEffects, callback); | |
| ASSERT_TRUE(result.isOk()); | |
| ASSERT_EQ(112ms, result.value()); // Failed primitive durations counted as 1. | |
| ASSERT_EQ(1, *callbackCounter.get()); | |
| result = mWrapper->performComposedEffect(multipleEffects, callback); | |
| ASSERT_TRUE(result.isOk()); | |
| ASSERT_EQ(114ms, result.value()); // Second fetch succeeds and returns primitive duration. | |
| ASSERT_EQ(2, *callbackCounter.get()); | |
| result = mWrapper->performComposedEffect(multipleEffects, callback); | |
| ASSERT_TRUE(result.isOk()); | |
| 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)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION))); | |
| EXPECT_CALL(*mMockHal.get(), composePwle(Eq(multiplePrimitives), _)) | |
| .Times(Exactly(2)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce(DoAll(WithArg<1>(vibrator::TriggerCallback()), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| } | |
| 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()); | |
| } | |
| TEST_F(VibratorHalWrapperAidlTest, TestComposePwleV2) { | |
| CompositePwleV2 composite; | |
| composite.pwlePrimitives = { | |
| PwleV2Primitive(/*amplitude=*/0.2, /*frequency=*/50, /*time=*/100), | |
| PwleV2Primitive(/*amplitude=*/0.5, /*frequency=*/150, /*time=*/100), | |
| PwleV2Primitive(/*amplitude=*/0.8, /*frequency=*/250, /*time=*/100), | |
| }; | |
| { | |
| InSequence seq; | |
| EXPECT_CALL(*mMockHal.get(), composePwleV2(_, _)) | |
| .Times(Exactly(3)) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION))) | |
| .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) | |
| .WillOnce(DoAll(WithArg<1>(vibrator::TriggerCallback()), | |
| Return(ndk::ScopedAStatus::ok()))); | |
| } | |
| std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>(); | |
| auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get()); | |
| auto result = mWrapper->composePwleV2(composite, callback); | |
| ASSERT_TRUE(result.isUnsupported()); | |
| // Callback not triggered on failure | |
| ASSERT_EQ(0, *callbackCounter.get()); | |
| result = mWrapper->composePwleV2(composite, callback); | |
| ASSERT_TRUE(result.isFailed()); | |
| // Callback not triggered for unsupported | |
| ASSERT_EQ(0, *callbackCounter.get()); | |
| result = mWrapper->composePwleV2(composite, callback); | |
| ASSERT_TRUE(result.isOk()); | |
| ASSERT_EQ(1, *callbackCounter.get()); | |
| } |