/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "persistable_bundle_utils.h" #include "pwle_v2_utils.h" #include "test_utils.h" using aidl::android::hardware::vibrator::ActivePwle; using aidl::android::hardware::vibrator::BnVibratorCallback; using aidl::android::hardware::vibrator::Braking; using aidl::android::hardware::vibrator::BrakingPwle; 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::IVibratorManager; using aidl::android::hardware::vibrator::PrimitivePwle; using aidl::android::hardware::vibrator::PwleV2Primitive; using aidl::android::hardware::vibrator::VendorEffect; using aidl::android::os::PersistableBundle; using std::chrono::high_resolution_clock; using namespace ::std::chrono_literals; namespace pwle_v2_utils = aidl::android::hardware::vibrator::testing::pwlev2; const std::vector kEffects{ndk::enum_range().begin(), ndk::enum_range().end()}; const std::vector kEffectStrengths{ndk::enum_range().begin(), ndk::enum_range().end()}; const std::vector kInvalidEffects = { static_cast(static_cast(kEffects.front()) - 1), static_cast(static_cast(kEffects.back()) + 1), }; const std::vector kInvalidEffectStrengths = { static_cast(static_cast(kEffectStrengths.front()) - 1), static_cast(static_cast(kEffectStrengths.back()) + 1), }; const std::vector kCompositePrimitives{ ndk::enum_range().begin(), ndk::enum_range().end()}; const std::vector kRequiredPrimitives = { CompositePrimitive::CLICK, CompositePrimitive::LIGHT_TICK, CompositePrimitive::QUICK_RISE, CompositePrimitive::SLOW_RISE, CompositePrimitive::QUICK_FALL, }; const std::vector kInvalidPrimitives = { static_cast(static_cast(kCompositePrimitives.front()) - 1), static_cast(static_cast(kCompositePrimitives.back()) + 1), }; // Timeout to wait for vibration callback completion. static constexpr std::chrono::milliseconds VIBRATION_CALLBACK_TIMEOUT = 100ms; static constexpr int32_t VENDOR_EFFECTS_MIN_VERSION = 3; static constexpr int32_t PWLE_V2_MIN_VERSION = 3; static std::vector findVibratorManagerNames() { std::vector names; constexpr auto callback = [](const char* instance, void* context) { auto fullName = std::string(IVibratorManager::descriptor) + "/" + instance; static_cast*>(context)->emplace_back(fullName); }; AServiceManager_forEachDeclaredInstance(IVibratorManager::descriptor, static_cast(&names), callback); return names; } static std::vector findUnmanagedVibratorNames() { std::vector names; constexpr auto callback = [](const char* instance, void* context) { auto fullName = std::string(IVibrator::descriptor) + "/" + instance; static_cast*>(context)->emplace_back(fullName); }; AServiceManager_forEachDeclaredInstance(IVibrator::descriptor, static_cast(&names), callback); return names; } class CompletionCallback : public BnVibratorCallback { public: CompletionCallback(const std::function &callback) : mCallback(callback) {} ndk::ScopedAStatus onComplete() override { mCallback(); return ndk::ScopedAStatus::ok(); } private: std::function mCallback; }; class VibratorAidl : public testing::TestWithParam> { public: virtual void SetUp() override { int32_t managerIdx = std::get<0>(GetParam()); int32_t vibratorId = std::get<1>(GetParam()); if (managerIdx < 0) { // Testing a unmanaged vibrator, using vibratorId as index from registered HALs std::vector vibratorNames = findUnmanagedVibratorNames(); ASSERT_LT(vibratorId, vibratorNames.size()); vibrator = IVibrator::fromBinder(ndk::SpAIBinder( AServiceManager_waitForService(vibratorNames[vibratorId].c_str()))); } else { // Testing a managed vibrator, using vibratorId to retrieve it from the manager std::vector managerNames = findVibratorManagerNames(); ASSERT_LT(managerIdx, managerNames.size()); auto vibratorManager = IVibratorManager::fromBinder(ndk::SpAIBinder( AServiceManager_waitForService(managerNames[managerIdx].c_str()))); EXPECT_OK(vibratorManager->getVibrator(vibratorId, &vibrator)) << "\n For vibrator id: " << vibratorId; } ASSERT_NE(vibrator, nullptr); EXPECT_OK(vibrator->getInterfaceVersion(&version)); EXPECT_OK(vibrator->getCapabilities(&capabilities)); } virtual void TearDown() override { // Reset vibrator state between tests. EXPECT_OK(vibrator->off()); } std::shared_ptr vibrator; int32_t version; int32_t capabilities; }; static float getResonantFrequencyHz(const std::shared_ptr& vibrator, int32_t capabilities) { float resonantFrequencyHz; ndk::ScopedAStatus status = vibrator->getResonantFrequency(&resonantFrequencyHz); if (capabilities & IVibrator::CAP_GET_RESONANT_FREQUENCY) { EXPECT_OK(std::move(status)); EXPECT_GT(resonantFrequencyHz, 0); } else { EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)); } return resonantFrequencyHz; } static bool shouldValidateLegacyFrequencyControlResult(int32_t capabilities, int32_t version, ndk::ScopedAStatus& status) { bool hasFrequencyControl = capabilities & IVibrator::CAP_FREQUENCY_CONTROL; // Legacy frequency control APIs deprecated with PWLE V2 feature. bool isDeprecated = version >= PWLE_V2_MIN_VERSION; bool isUnknownOrUnsupported = status.getExceptionCode() == EX_UNSUPPORTED_OPERATION || status.getStatus() == STATUS_UNKNOWN_TRANSACTION; // Validate if older HAL or if result is provided, even after deprecation. return hasFrequencyControl && (!isDeprecated || !isUnknownOrUnsupported); } static float getFrequencyResolutionHz(const std::shared_ptr& vibrator, int32_t capabilities, int32_t version) { float freqResolutionHz = -1; ndk::ScopedAStatus status = vibrator->getFrequencyResolution(&freqResolutionHz); if (shouldValidateLegacyFrequencyControlResult(capabilities, version, status)) { EXPECT_OK(std::move(status)); EXPECT_GT(freqResolutionHz, 0); } else { EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)); } return freqResolutionHz; } static float getFrequencyMinimumHz(const std::shared_ptr& vibrator, int32_t capabilities, int32_t version) { float freqMinimumHz; ndk::ScopedAStatus status = vibrator->getFrequencyMinimum(&freqMinimumHz); if (shouldValidateLegacyFrequencyControlResult(capabilities, version, status)) { EXPECT_OK(std::move(status)); float resonantFrequencyHz = getResonantFrequencyHz(vibrator, capabilities); EXPECT_GT(freqMinimumHz, 0); EXPECT_LE(freqMinimumHz, resonantFrequencyHz); } else { EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)); } return freqMinimumHz; } static float getFrequencyMaximumHz(const std::shared_ptr& vibrator, int32_t capabilities, int32_t version) { std::vector bandwidthAmplitudeMap; ndk::ScopedAStatus status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap); if (shouldValidateLegacyFrequencyControlResult(capabilities, version, status)) { EXPECT_OK(std::move(status)); } else { EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)); } float freqMaximumHz = ((bandwidthAmplitudeMap.size() - 1) * getFrequencyResolutionHz(vibrator, capabilities, version)) + getFrequencyMinimumHz(vibrator, capabilities, version); return freqMaximumHz; } static float getAmplitudeMin() { return 0.0; } static float getAmplitudeMax() { return 1.0; } static ActivePwle composeValidActivePwle(const std::shared_ptr& vibrator, int32_t capabilities, int32_t version) { float frequencyHz; if (capabilities & IVibrator::CAP_GET_RESONANT_FREQUENCY) { frequencyHz = getResonantFrequencyHz(vibrator, capabilities); } else if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) { if (version < PWLE_V2_MIN_VERSION) { frequencyHz = getFrequencyMinimumHz(vibrator, capabilities, version); } else { frequencyHz = pwle_v2_utils::getPwleV2FrequencyMinHz(vibrator); } } else { frequencyHz = 150.0; // default value commonly used } ActivePwle active; active.startAmplitude = (getAmplitudeMin() + getAmplitudeMax()) / 2; active.startFrequency = frequencyHz; active.endAmplitude = (getAmplitudeMin() + getAmplitudeMax()) / 2; active.endFrequency = frequencyHz; vibrator->getPwlePrimitiveDurationMax(&(active.duration)); return active; } TEST_P(VibratorAidl, OnThenOffBeforeTimeout) { EXPECT_OK(vibrator->on(2000, nullptr /*callback*/)); sleep(1); EXPECT_OK(vibrator->off()); } TEST_P(VibratorAidl, OnWithCallback) { if (!(capabilities & IVibrator::CAP_ON_CALLBACK)) return; std::promise completionPromise; std::future completionFuture{completionPromise.get_future()}; auto callback = ndk::SharedRefBase::make( [&completionPromise] { completionPromise.set_value(); }); uint32_t durationMs = 250; auto timeout = std::chrono::milliseconds(durationMs) + VIBRATION_CALLBACK_TIMEOUT; EXPECT_OK(vibrator->on(durationMs, callback)); EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready); EXPECT_OK(vibrator->off()); } TEST_P(VibratorAidl, OnCallbackNotSupported) { if (!(capabilities & IVibrator::CAP_ON_CALLBACK)) { auto callback = ndk::SharedRefBase::make([] {}); EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->on(250, callback)); } } TEST_P(VibratorAidl, ValidateEffect) { std::vector supported; EXPECT_OK(vibrator->getSupportedEffects(&supported)); for (Effect effect : kEffects) { bool isEffectSupported = std::find(supported.begin(), supported.end(), effect) != supported.end(); for (EffectStrength strength : kEffectStrengths) { int32_t lengthMs = 0; ndk::ScopedAStatus status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs); if (isEffectSupported) { EXPECT_OK(std::move(status)) << "\n For effect: " << toString(effect) << " " << toString(strength); EXPECT_GT(lengthMs, 0); usleep(lengthMs * 1000); EXPECT_OK(vibrator->off()); } else { EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)) << "\n For effect: " << toString(effect) << " " << toString(strength); } } } } TEST_P(VibratorAidl, ValidateEffectWithCallback) { if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK)) return; std::vector supported; EXPECT_OK(vibrator->getSupportedEffects(&supported)); for (Effect effect : kEffects) { bool isEffectSupported = std::find(supported.begin(), supported.end(), effect) != supported.end(); for (EffectStrength strength : kEffectStrengths) { std::promise completionPromise; std::future completionFuture{completionPromise.get_future()}; auto callback = ndk::SharedRefBase::make( [&completionPromise] { completionPromise.set_value(); }); int lengthMs = 0; ndk::ScopedAStatus status = vibrator->perform(effect, strength, callback, &lengthMs); if (isEffectSupported) { EXPECT_OK(std::move(status)) << "\n For effect: " << toString(effect) << " " << toString(strength); EXPECT_GT(lengthMs, 0); } else { EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)) << "\n For effect: " << toString(effect) << " " << toString(strength); } if (lengthMs <= 0) continue; auto timeout = std::chrono::milliseconds(lengthMs) + VIBRATION_CALLBACK_TIMEOUT; EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready); EXPECT_OK(vibrator->off()); } } } TEST_P(VibratorAidl, ValidateEffectWithCallbackNotSupported) { if (capabilities & IVibrator::CAP_PERFORM_CALLBACK) return; for (Effect effect : kEffects) { for (EffectStrength strength : kEffectStrengths) { auto callback = ndk::SharedRefBase::make([] {}); int lengthMs; EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->perform(effect, strength, callback, &lengthMs)) << "\n For effect: " << toString(effect) << " " << toString(strength); } } } TEST_P(VibratorAidl, InvalidEffectsUnsupported) { for (Effect effect : kInvalidEffects) { for (EffectStrength strength : kEffectStrengths) { int32_t lengthMs; EXPECT_UNKNOWN_OR_UNSUPPORTED( vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs)) << "\n For effect: " << toString(effect) << " " << toString(strength); } } for (Effect effect : kEffects) { for (EffectStrength strength : kInvalidEffectStrengths) { int32_t lengthMs; EXPECT_UNKNOWN_OR_UNSUPPORTED( vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs)) << "\n For effect: " << toString(effect) << " " << toString(strength); } } } TEST_P(VibratorAidl, PerformVendorEffectSupported) { if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) return; float scale = 0.0f; float vendorScale = 0.0f; for (EffectStrength strength : kEffectStrengths) { PersistableBundle vendorData; ::aidl::android::hardware::vibrator::testing::fillBasicData(&vendorData); PersistableBundle nestedData; ::aidl::android::hardware::vibrator::testing::fillBasicData(&nestedData); vendorData.putPersistableBundle("test_nested_bundle", nestedData); VendorEffect effect; effect.vendorData = vendorData; effect.strength = strength; effect.scale = scale; effect.vendorScale = vendorScale; scale += 0.5f; vendorScale += 0.2f; auto callback = ndk::SharedRefBase::make([] {}); ndk::ScopedAStatus status = vibrator->performVendorEffect(effect, callback); // No expectations on the actual status, the effect might be refused with illegal argument // or the vendor might return a service-specific error code. EXPECT_TRUE(status.getExceptionCode() != EX_UNSUPPORTED_OPERATION && status.getStatus() != STATUS_UNKNOWN_TRANSACTION) << status << "\n For vendor effect with strength" << toString(strength) << " and scale " << effect.scale; if (status.isOk()) { // Generic vendor data should not trigger vibrations, but if it does trigger one // then we make sure the vibrator is reset by triggering off(). EXPECT_OK(vibrator->off()); } } } TEST_P(VibratorAidl, PerformVendorEffectStability) { if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) return; // Run some iterations of performVendorEffect with randomized vendor data to check basic // stability of the implementation. uint8_t iterations = 200; for (EffectStrength strength : kEffectStrengths) { float scale = 0.5f; float vendorScale = 0.2f; for (uint8_t i = 0; i < iterations; i++) { PersistableBundle vendorData; ::aidl::android::hardware::vibrator::testing::fillRandomData(&vendorData); VendorEffect effect; effect.vendorData = vendorData; effect.strength = strength; effect.scale = scale; effect.vendorScale = vendorScale; scale *= 2; vendorScale *= 1.5f; auto callback = ndk::SharedRefBase::make([] {}); ndk::ScopedAStatus status = vibrator->performVendorEffect(effect, callback); // No expectations on the actual status, the effect might be refused with illegal // argument or the vendor might return a service-specific error code. EXPECT_TRUE(status.getExceptionCode() != EX_UNSUPPORTED_OPERATION && status.getStatus() != STATUS_UNKNOWN_TRANSACTION) << status << "\n For random vendor effect with strength " << toString(strength) << " and scale " << effect.scale; if (status.isOk()) { // Random vendor data should not trigger vibrations, but if it does trigger one // then we make sure the vibrator is reset by triggering off(). EXPECT_OK(vibrator->off()); } } } } TEST_P(VibratorAidl, PerformVendorEffectEmptyVendorData) { if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) return; for (EffectStrength strength : kEffectStrengths) { VendorEffect effect; effect.strength = strength; effect.scale = 1.0f; effect.vendorScale = 1.0f; ndk::ScopedAStatus status = vibrator->performVendorEffect(effect, nullptr /*callback*/); EXPECT_TRUE(status.getExceptionCode() == EX_SERVICE_SPECIFIC) << status << "\n For vendor effect with strength " << toString(strength) << " and scale " << effect.scale; } } TEST_P(VibratorAidl, PerformVendorEffectInvalidScale) { if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) return; VendorEffect effect; effect.strength = EffectStrength::MEDIUM; effect.scale = -1.0f; effect.vendorScale = 1.0f; EXPECT_ILLEGAL_ARGUMENT(vibrator->performVendorEffect(effect, nullptr /*callback*/)); effect.scale = 1.0f; effect.vendorScale = -1.0f; EXPECT_ILLEGAL_ARGUMENT(vibrator->performVendorEffect(effect, nullptr /*callback*/)); } TEST_P(VibratorAidl, PerformVendorEffectUnsupported) { if (version < VENDOR_EFFECTS_MIN_VERSION) { EXPECT_EQ(capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS, 0) << "Vibrator version " << version << " should not report vendor effects capability"; } if (capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) return; for (EffectStrength strength : kEffectStrengths) { VendorEffect effect; effect.strength = strength; effect.scale = 1.0f; effect.vendorScale = 1.0f; EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->performVendorEffect(effect, nullptr /*callback*/)) << "\n For vendor effect with strength " << toString(strength); } } TEST_P(VibratorAidl, ChangeVibrationAmplitude) { if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) { EXPECT_OK(vibrator->setAmplitude(0.1f)); EXPECT_OK(vibrator->on(2000, nullptr /*callback*/)); EXPECT_OK(vibrator->setAmplitude(0.5f)); sleep(1); EXPECT_OK(vibrator->setAmplitude(1.0f)); sleep(1); EXPECT_OK(vibrator->off()); } } TEST_P(VibratorAidl, AmplitudeOutsideRangeFails) { if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) { EXPECT_ILLEGAL_ARGUMENT(vibrator->setAmplitude(-1)); EXPECT_ILLEGAL_ARGUMENT(vibrator->setAmplitude(0)); EXPECT_ILLEGAL_ARGUMENT(vibrator->setAmplitude(1.1)); } } TEST_P(VibratorAidl, AmplitudeReturnsUnsupportedMatchingCapabilities) { if ((capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) == 0) { EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->setAmplitude(1)); } } TEST_P(VibratorAidl, ChangeVibrationExternalControl) { if (capabilities & IVibrator::CAP_EXTERNAL_CONTROL) { EXPECT_OK(vibrator->setExternalControl(true)); sleep(1); EXPECT_OK(vibrator->setExternalControl(false)); sleep(1); } } TEST_P(VibratorAidl, ExternalAmplitudeControl) { const bool supportsExternalAmplitudeControl = (capabilities & IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) > 0; if (capabilities & IVibrator::CAP_EXTERNAL_CONTROL) { EXPECT_OK(vibrator->setExternalControl(true)); if (supportsExternalAmplitudeControl) { EXPECT_OK(vibrator->setAmplitude(0.5)); } else { EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->setAmplitude(0.5)); } EXPECT_OK(vibrator->setExternalControl(false)); } else { EXPECT_FALSE(supportsExternalAmplitudeControl); } } TEST_P(VibratorAidl, ExternalControlUnsupportedMatchingCapabilities) { if ((capabilities & IVibrator::CAP_EXTERNAL_CONTROL) == 0) { EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->setExternalControl(true)); } } TEST_P(VibratorAidl, GetSupportedPrimitives) { if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { std::vector supported; EXPECT_OK(vibrator->getSupportedPrimitives(&supported)); for (CompositePrimitive primitive : kCompositePrimitives) { bool isPrimitiveSupported = std::find(supported.begin(), supported.end(), primitive) != supported.end(); bool isPrimitiveRequired = std::find(kRequiredPrimitives.begin(), kRequiredPrimitives.end(), primitive) != kRequiredPrimitives.end(); EXPECT_TRUE(isPrimitiveSupported || !isPrimitiveRequired) << toString(primitive); } } } TEST_P(VibratorAidl, GetPrimitiveDuration) { if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { std::vector supported; EXPECT_OK(vibrator->getSupportedPrimitives(&supported)); for (CompositePrimitive primitive : kCompositePrimitives) { bool isPrimitiveSupported = std::find(supported.begin(), supported.end(), primitive) != supported.end(); int32_t duration; if (isPrimitiveSupported) { EXPECT_OK(vibrator->getPrimitiveDuration(primitive, &duration)) << "\n For primitive: " << toString(primitive) << " " << duration; if (primitive != CompositePrimitive::NOOP) { ASSERT_GT(duration, 0) << "\n For primitive: " << toString(primitive) << " " << duration; } } else { EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->getPrimitiveDuration(primitive, &duration)) << "\n For primitive: " << toString(primitive); } } } } TEST_P(VibratorAidl, ComposeValidPrimitives) { if (!(capabilities & IVibrator::CAP_COMPOSE_EFFECTS)) { GTEST_SKIP() << "CAP_COMPOSE_EFFECTS not supported"; } std::vector supported; int32_t maxDelay, maxSize; EXPECT_OK(vibrator->getSupportedPrimitives(&supported)); EXPECT_OK(vibrator->getCompositionDelayMax(&maxDelay)); EXPECT_OK(vibrator->getCompositionSizeMax(&maxSize)); std::vector composite; for (int i = 0; i < supported.size(); i++) { CompositePrimitive primitive = supported[i]; float t = static_cast(i + 1) / supported.size(); CompositeEffect effect; effect.delayMs = maxDelay * t; effect.primitive = primitive; effect.scale = t; if (composite.size() == maxSize) { break; } } if (composite.size() != 0) { EXPECT_OK(vibrator->compose(composite, nullptr)); EXPECT_OK(vibrator->off()); } } TEST_P(VibratorAidl, ComposeUnsupportedPrimitives) { if (!(capabilities & IVibrator::CAP_COMPOSE_EFFECTS)) { GTEST_SKIP() << "CAP_COMPOSE_EFFECTS not supported"; } std::vector unsupported(kInvalidPrimitives); std::vector supported; EXPECT_OK(vibrator->getSupportedPrimitives(&supported)); for (CompositePrimitive primitive : kCompositePrimitives) { bool isPrimitiveSupported = std::find(supported.begin(), supported.end(), primitive) != supported.end(); if (!isPrimitiveSupported) { unsupported.push_back(primitive); } } for (CompositePrimitive primitive : unsupported) { std::vector composite(1); for (CompositeEffect& effect : composite) { effect.delayMs = 0; effect.primitive = primitive; effect.scale = 1.0f; } EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->compose(composite, nullptr)); } } TEST_P(VibratorAidl, ComposeScaleBoundary) { if (!(capabilities & IVibrator::CAP_COMPOSE_EFFECTS)) { GTEST_SKIP() << "CAP_COMPOSE_EFFECTS not supported"; } std::vector composite(1); CompositeEffect& effect = composite[0]; effect.delayMs = 0; effect.primitive = CompositePrimitive::CLICK; effect.scale = std::nextafter(0.0f, -1.0f); EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr)); effect.scale = 0.0f; EXPECT_OK(vibrator->compose(composite, nullptr)); EXPECT_OK(vibrator->off()); effect.scale = 1.0f; EXPECT_OK(vibrator->compose(composite, nullptr)); EXPECT_OK(vibrator->off()); effect.scale = std::nextafter(1.0f, 2.0f); EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr)); } TEST_P(VibratorAidl, ComposeDelayBoundary) { if (!(capabilities & IVibrator::CAP_COMPOSE_EFFECTS)) { GTEST_SKIP() << "CAP_COMPOSE_EFFECTS not supported"; } int32_t maxDelay; EXPECT_OK(vibrator->getCompositionDelayMax(&maxDelay)); std::vector composite(1); CompositeEffect& effect = composite[0]; effect.primitive = CompositePrimitive::CLICK; effect.scale = 1.0f; effect.delayMs = 0; EXPECT_OK(vibrator->compose(composite, nullptr)); EXPECT_OK(vibrator->off()); effect.delayMs = 1; EXPECT_OK(vibrator->compose(composite, nullptr)); EXPECT_OK(vibrator->off()); effect.delayMs = maxDelay; EXPECT_OK(vibrator->compose(composite, nullptr)); EXPECT_OK(vibrator->off()); effect.delayMs = maxDelay + 1; EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr)); } TEST_P(VibratorAidl, ComposeSizeBoundary) { if (!(capabilities & IVibrator::CAP_COMPOSE_EFFECTS)) { GTEST_SKIP() << "CAP_COMPOSE_EFFECTS not supported"; } int32_t maxSize; EXPECT_OK(vibrator->getCompositionSizeMax(&maxSize)); std::vector composite(maxSize); CompositeEffect effect; effect.delayMs = 1; effect.primitive = CompositePrimitive::CLICK; effect.scale = 1.0f; std::fill(composite.begin(), composite.end(), effect); EXPECT_OK(vibrator->compose(composite, nullptr)); EXPECT_OK(vibrator->off()); composite.emplace_back(effect); EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr)); } TEST_P(VibratorAidl, ComposeCallback) { if (!(capabilities & IVibrator::CAP_COMPOSE_EFFECTS)) { GTEST_SKIP() << "CAP_COMPOSE_EFFECTS not supported"; } std::vector supported; EXPECT_OK(vibrator->getSupportedPrimitives(&supported)); for (CompositePrimitive primitive : supported) { if (primitive == CompositePrimitive::NOOP) { continue; } std::promise completionPromise; std::future completionFuture{completionPromise.get_future()}; auto callback = ndk::SharedRefBase::make( [&completionPromise] { completionPromise.set_value(); }); CompositeEffect effect; std::vector composite; int32_t durationMs; std::chrono::milliseconds duration; std::chrono::time_point start, end; std::chrono::milliseconds elapsed; effect.delayMs = 0; effect.primitive = primitive; effect.scale = 1.0f; composite.emplace_back(effect); EXPECT_OK(vibrator->getPrimitiveDuration(primitive, &durationMs)) << "\n For primitive: " << toString(primitive); duration = std::chrono::milliseconds(durationMs); start = high_resolution_clock::now(); EXPECT_OK(vibrator->compose(composite, callback)) << "\n For primitive: " << toString(primitive); EXPECT_EQ(completionFuture.wait_for(duration + VIBRATION_CALLBACK_TIMEOUT), std::future_status::ready) << "\n For primitive: " << toString(primitive); end = high_resolution_clock::now(); elapsed = std::chrono::duration_cast(end - start); EXPECT_GE(elapsed.count(), duration.count()) << "\n For primitive: " << toString(primitive); EXPECT_OK(vibrator->off()) << "\n For primitive: " << toString(primitive); } } TEST_P(VibratorAidl, AlwaysOn) { if (capabilities & IVibrator::CAP_ALWAYS_ON_CONTROL) { std::vector supported; EXPECT_OK(vibrator->getSupportedAlwaysOnEffects(&supported)); for (Effect effect : kEffects) { bool isEffectSupported = std::find(supported.begin(), supported.end(), effect) != supported.end(); for (EffectStrength strength : kEffectStrengths) { ndk::ScopedAStatus status = vibrator->alwaysOnEnable(0, effect, strength); if (isEffectSupported) { EXPECT_OK(std::move(status)) << "\n For effect: " << toString(effect) << " " << toString(strength); } else { EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)) << "\n For effect: " << toString(effect) << " " << toString(strength); } } } EXPECT_OK(vibrator->alwaysOnDisable(0)); } } TEST_P(VibratorAidl, GetResonantFrequency) { getResonantFrequencyHz(vibrator, capabilities); } TEST_P(VibratorAidl, GetQFactor) { float qFactor; ndk::ScopedAStatus status = vibrator->getQFactor(&qFactor); if (capabilities & IVibrator::CAP_GET_Q_FACTOR) { EXPECT_OK(std::move(status)); ASSERT_GT(qFactor, 0); } else { EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)); } } TEST_P(VibratorAidl, GetFrequencyResolution) { getFrequencyResolutionHz(vibrator, capabilities, version); } TEST_P(VibratorAidl, GetFrequencyMinimum) { getFrequencyMinimumHz(vibrator, capabilities, version); } TEST_P(VibratorAidl, GetBandwidthAmplitudeMap) { std::vector bandwidthAmplitudeMap; ndk::ScopedAStatus status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap); if (shouldValidateLegacyFrequencyControlResult(capabilities, version, status)) { EXPECT_OK(std::move(status)); ASSERT_FALSE(bandwidthAmplitudeMap.empty()); int minMapSize = (getResonantFrequencyHz(vibrator, capabilities) - getFrequencyMinimumHz(vibrator, capabilities, version)) / getFrequencyResolutionHz(vibrator, capabilities, version); ASSERT_GT(bandwidthAmplitudeMap.size(), minMapSize); for (float e : bandwidthAmplitudeMap) { ASSERT_GE(e, 0.0); ASSERT_LE(e, 1.0); } } else { EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)); } } TEST_P(VibratorAidl, GetPwlePrimitiveDurationMax) { int32_t durationMs; ndk::ScopedAStatus status = vibrator->getPwlePrimitiveDurationMax(&durationMs); if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) { EXPECT_OK(std::move(status)); ASSERT_NE(durationMs, 0); } else { EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)); } } TEST_P(VibratorAidl, GetPwleCompositionSizeMax) { int32_t maxSize; ndk::ScopedAStatus status = vibrator->getPwleCompositionSizeMax(&maxSize); if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) { EXPECT_OK(std::move(status)); ASSERT_NE(maxSize, 0); } else { EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)); } } TEST_P(VibratorAidl, GetSupportedBraking) { std::vector supported; ndk::ScopedAStatus status = vibrator->getSupportedBraking(&supported); if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) { bool isDefaultNoneSupported = std::find(supported.begin(), supported.end(), Braking::NONE) != supported.end(); EXPECT_OK(std::move(status)); ASSERT_TRUE(isDefaultNoneSupported); } else { EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)); } } TEST_P(VibratorAidl, ComposeValidPwle) { if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) { ActivePwle firstActive = composeValidActivePwle(vibrator, capabilities, version); std::vector supported; EXPECT_OK(vibrator->getSupportedBraking(&supported)); bool isClabSupported = std::find(supported.begin(), supported.end(), Braking::CLAB) != supported.end(); BrakingPwle firstBraking; firstBraking.braking = isClabSupported ? Braking::CLAB : Braking::NONE; firstBraking.duration = 100; ActivePwle secondActive = composeValidActivePwle(vibrator, capabilities, version); if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) { float minFrequencyHz = getFrequencyMinimumHz(vibrator, capabilities, version); float maxFrequencyHz = getFrequencyMaximumHz(vibrator, capabilities, version); float freqResolutionHz = getFrequencyResolutionHz(vibrator, capabilities, version); // As of API 16 these APIs are deprecated and no longer required to be implemented // with frequency control capability. if (minFrequencyHz >= 0 && maxFrequencyHz >= 0 && freqResolutionHz >= 0) { secondActive.startFrequency = minFrequencyHz + (freqResolutionHz / 2.0f); secondActive.endFrequency = maxFrequencyHz - (freqResolutionHz / 3.0f); } } BrakingPwle secondBraking; secondBraking.braking = Braking::NONE; secondBraking.duration = 10; std::vector pwleQueue = {firstActive, firstBraking, secondActive, secondBraking}; EXPECT_OK(vibrator->composePwle(pwleQueue, nullptr)); EXPECT_OK(vibrator->off()); } } TEST_P(VibratorAidl, ComposeValidPwleWithCallback) { if (!((capabilities & IVibrator::CAP_ON_CALLBACK) && (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS))) return; std::promise completionPromise; std::future completionFuture{completionPromise.get_future()}; auto callback = ndk::SharedRefBase::make( [&completionPromise] { completionPromise.set_value(); }); int32_t segmentDurationMaxMs; vibrator->getPwlePrimitiveDurationMax(&segmentDurationMaxMs); uint32_t durationMs = segmentDurationMaxMs * 2 + 100; // Sum of 2 active and 1 braking below auto timeout = std::chrono::milliseconds(durationMs) + VIBRATION_CALLBACK_TIMEOUT; ActivePwle active = composeValidActivePwle(vibrator, capabilities, version); std::vector supported; EXPECT_OK(vibrator->getSupportedBraking(&supported)); bool isClabSupported = std::find(supported.begin(), supported.end(), Braking::CLAB) != supported.end(); BrakingPwle braking; braking.braking = isClabSupported ? Braking::CLAB : Braking::NONE; braking.duration = 100; std::vector pwleQueue = {active, braking, active}; EXPECT_OK(vibrator->composePwle(pwleQueue, callback)); EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready); EXPECT_OK(vibrator->off()); } TEST_P(VibratorAidl, ComposePwleSegmentBoundary) { if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) { std::vector pwleQueue; // test empty queue EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueue, nullptr)); ActivePwle active = composeValidActivePwle(vibrator, capabilities, version); PrimitivePwle pwle; pwle = active; int segmentCountMax; vibrator->getPwleCompositionSizeMax(&segmentCountMax); // Create PWLE queue with more segments than allowed for (int i = 0; i < segmentCountMax + 10; i++) { pwleQueue.emplace_back(std::move(pwle)); } EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueue, nullptr)); } } TEST_P(VibratorAidl, ComposePwleAmplitudeParameterBoundary) { if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) { ActivePwle active = composeValidActivePwle(vibrator, capabilities, version); active.startAmplitude = getAmplitudeMax() + 1.0; // Amplitude greater than allowed active.endAmplitude = getAmplitudeMax() + 1.0; // Amplitude greater than allowed std::vector pwleQueueGreater = {active}; EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueGreater, nullptr)); active.startAmplitude = getAmplitudeMin() - 1.0; // Amplitude less than allowed active.endAmplitude = getAmplitudeMin() - 1.0; // Amplitude less than allowed std::vector pwleQueueLess = {active}; EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueLess, nullptr)); } } TEST_P(VibratorAidl, ComposePwleFrequencyParameterBoundary) { if ((capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) && (capabilities & IVibrator::CAP_FREQUENCY_CONTROL)) { float freqMinimumHz = getFrequencyMinimumHz(vibrator, capabilities, version); float freqMaximumHz = getFrequencyMaximumHz(vibrator, capabilities, version); float freqResolutionHz = getFrequencyResolutionHz(vibrator, capabilities, version); // As of API 16 these APIs are deprecated and no longer required to be implemented with // frequency control capability. if (freqMinimumHz < 0 || freqMaximumHz < 0 || freqResolutionHz < 0) { GTEST_SKIP() << "PWLE V1 is not supported, skipping test"; return; } ActivePwle active = composeValidActivePwle(vibrator, capabilities, version); active.startFrequency = freqMaximumHz + freqResolutionHz; // Frequency greater than allowed active.endFrequency = freqMaximumHz + freqResolutionHz; // Frequency greater than allowed std::vector pwleQueueGreater = {active}; EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueGreater, nullptr)); active.startFrequency = freqMinimumHz - freqResolutionHz; // Frequency less than allowed active.endFrequency = freqMinimumHz - freqResolutionHz; // Frequency less than allowed std::vector pwleQueueLess = {active}; EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueLess, nullptr)); } } TEST_P(VibratorAidl, ComposePwleSegmentDurationBoundary) { if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) { ActivePwle active = composeValidActivePwle(vibrator, capabilities, version); int32_t segmentDurationMaxMs; vibrator->getPwlePrimitiveDurationMax(&segmentDurationMaxMs); active.duration = segmentDurationMaxMs + 10; // Segment duration greater than allowed std::vector pwleQueue = {active}; EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueue, nullptr)); } } TEST_P(VibratorAidl, FrequencyToOutputAccelerationMapHasValidFrequencyRange) { if (version < PWLE_V2_MIN_VERSION || !(capabilities & IVibrator::CAP_FREQUENCY_CONTROL)) { GTEST_SKIP() << "Frequency control is not supported, skipping test"; return; } std::vector frequencyToOutputAccelerationMap; ndk::ScopedAStatus status = vibrator->getFrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap); EXPECT_OK(std::move(status)); ASSERT_FALSE(frequencyToOutputAccelerationMap.empty()); auto sharpnessRange = pwle_v2_utils::getPwleV2SharpnessRange(vibrator, frequencyToOutputAccelerationMap); // Validate the curve provides a usable sharpness range, which is a range of frequencies // that are supported by the device. ASSERT_TRUE(sharpnessRange.first >= 0); // Validate that the sharpness range is a valid interval, not a single point. ASSERT_TRUE(sharpnessRange.first < sharpnessRange.second); } TEST_P(VibratorAidl, FrequencyToOutputAccelerationMapUnsupported) { if ((capabilities & IVibrator::CAP_FREQUENCY_CONTROL)) return; std::vector frequencyToOutputAccelerationMap; EXPECT_UNKNOWN_OR_UNSUPPORTED( vibrator->getFrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap)); } TEST_P(VibratorAidl, GetPwleV2PrimitiveDurationMaxMillis) { if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) { GTEST_SKIP() << "PWLE V2 not supported, skipping test"; return; } int32_t durationMs; ndk::ScopedAStatus status = vibrator->getPwleV2PrimitiveDurationMaxMillis(&durationMs); EXPECT_OK(std::move(status)); ASSERT_GT(durationMs, 0); // Ensure greater than zero ASSERT_GE(durationMs, pwle_v2_utils::COMPOSE_PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS); } TEST_P(VibratorAidl, GetPwleV2CompositionSizeMax) { if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) { GTEST_SKIP() << "PWLE V2 not supported, skipping test"; return; } int32_t maxSize; ndk::ScopedAStatus status = vibrator->getPwleV2CompositionSizeMax(&maxSize); EXPECT_OK(std::move(status)); ASSERT_GT(maxSize, 0); // Ensure greater than zero ASSERT_GE(maxSize, pwle_v2_utils::COMPOSE_PWLE_V2_MIN_REQUIRED_SIZE); } TEST_P(VibratorAidl, GetPwleV2PrimitiveDurationMinMillis) { if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) { GTEST_SKIP() << "PWLE V2 not supported, skipping test"; return; } int32_t durationMs; ndk::ScopedAStatus status = vibrator->getPwleV2PrimitiveDurationMinMillis(&durationMs); EXPECT_OK(std::move(status)); ASSERT_GT(durationMs, 0); // Ensure greater than zero ASSERT_LE(durationMs, pwle_v2_utils::COMPOSE_PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS); } TEST_P(VibratorAidl, ValidatePwleV2DependencyOnFrequencyControl) { if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) { GTEST_SKIP() << "PWLE V2 not supported, skipping test"; return; } // Check if frequency control is supported bool hasFrequencyControl = (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) != 0; ASSERT_TRUE(hasFrequencyControl) << "Frequency control MUST be supported when PWLE V2 is."; } TEST_P(VibratorAidl, ComposeValidPwleV2Effect) { if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) { GTEST_SKIP() << "PWLE V2 not supported, skipping test"; return; } EXPECT_OK(vibrator->composePwleV2(pwle_v2_utils::composeValidPwleV2Effect(vibrator), nullptr)); EXPECT_OK(vibrator->off()); } TEST_P(VibratorAidl, ComposePwleV2Unsupported) { if (version < PWLE_V2_MIN_VERSION) { EXPECT_EQ(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2, 0) << "Vibrator version " << version << " should not report PWLE V2 capability."; } if ((capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) return; CompositePwleV2 composite; composite.pwlePrimitives.emplace_back(/*amplitude=*/1.0f, /*frequencyHz=*/100.0f, /*timeMillis=*/50); EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->composePwleV2(composite, nullptr)); } TEST_P(VibratorAidl, ComposeValidPwleV2EffectWithCallback) { if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) { GTEST_SKIP() << "PWLE V2 not supported, skipping test"; return; } std::promise completionPromise; std::future completionFuture{completionPromise.get_future()}; auto callback = ndk::SharedRefBase::make( [&completionPromise] { completionPromise.set_value(); }); int32_t minDuration; EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDuration)); auto timeout = std::chrono::milliseconds(minDuration) + VIBRATION_CALLBACK_TIMEOUT; float minFrequency = pwle_v2_utils::getPwleV2FrequencyMinHz(vibrator); CompositePwleV2 composite; composite.pwlePrimitives.emplace_back(/*amplitude=*/0.5, minFrequency, minDuration); EXPECT_OK(vibrator->composePwleV2(composite, callback)); EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready); EXPECT_OK(vibrator->off()); } TEST_P(VibratorAidl, composePwleV2EffectWithTooManyPoints) { if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) { GTEST_SKIP() << "PWLE V2 not supported, skipping test"; return; } EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2( pwle_v2_utils::composePwleV2EffectWithTooManyPoints(vibrator), nullptr)); } TEST_P(VibratorAidl, composeInvalidPwleV2Effect) { if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) { GTEST_SKIP() << "PWLE V2 not supported, skipping test"; return; } // Retrieve min and max durations int32_t minDurationMs, maxDurationMs; EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDurationMs)); EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMaxMillis(&maxDurationMs)); CompositePwleV2 composePwle; // Negative amplitude composePwle.pwlePrimitives.push_back( PwleV2Primitive(/*amplitude=*/-0.8f, /*frequency=*/100, minDurationMs)); EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr)) << "Composing PWLE V2 effect with negative amplitude should fail"; composePwle.pwlePrimitives.clear(); // Amplitude exceeding 1.0 composePwle.pwlePrimitives.push_back( PwleV2Primitive(/*amplitude=*/1.2f, /*frequency=*/100, minDurationMs)); EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr)) << "Composing PWLE V2 effect with amplitude greater than 1.0 should fail"; composePwle.pwlePrimitives.clear(); // Duration exceeding maximum composePwle.pwlePrimitives.push_back( PwleV2Primitive(/*amplitude=*/0.2f, /*frequency=*/100, maxDurationMs + 10)); EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr)) << "Composing PWLE V2 effect with duration exceeding maximum should fail"; composePwle.pwlePrimitives.clear(); // Negative duration composePwle.pwlePrimitives.push_back( PwleV2Primitive(/*amplitude=*/0.2f, /*frequency=*/100, /*time=*/-1)); EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr)) << "Composing PWLE V2 effect with negative duration should fail"; composePwle.pwlePrimitives.clear(); // Frequency below minimum float minFrequency = pwle_v2_utils::getPwleV2FrequencyMinHz(vibrator); composePwle.pwlePrimitives.push_back( PwleV2Primitive(/*amplitude=*/0.2f, minFrequency - 1, minDurationMs)); EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr)) << "Composing PWLE V2 effect with frequency below minimum should fail"; composePwle.pwlePrimitives.clear(); // Frequency above maximum float maxFrequency = pwle_v2_utils::getPwleV2FrequencyMaxHz(vibrator); composePwle.pwlePrimitives.push_back( PwleV2Primitive(/*amplitude=*/0.2f, maxFrequency + 1, minDurationMs)); EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr)) << "Composing PWLE V2 effect with frequency above maximum should fail"; } std::vector> GenerateVibratorMapping() { std::vector> tuples; std::vector managerNames = findVibratorManagerNames(); std::vector vibratorIds; for (int i = 0; i < managerNames.size(); i++) { auto vibratorManager = IVibratorManager::fromBinder( ndk::SpAIBinder(AServiceManager_waitForService(managerNames[i].c_str()))); if (vibratorManager->getVibratorIds(&vibratorIds).isOk()) { for (int32_t vibratorId : vibratorIds) { tuples.emplace_back(i, vibratorId); } } } std::vector vibratorNames = findUnmanagedVibratorNames(); for (int i = 0; i < vibratorNames.size(); i++) { tuples.emplace_back(-1, i); } return tuples; } std::string PrintGeneratedTest(const testing::TestParamInfo &info) { const auto &[managerIdx, vibratorId] = info.param; if (managerIdx < 0) { return std::string("TOP_LEVEL_VIBRATOR_") + std::to_string(vibratorId); } return std::string("MANAGER_") + std::to_string(managerIdx) + "_VIBRATOR_ID_" + std::to_string(vibratorId); } GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VibratorAidl); INSTANTIATE_TEST_SUITE_P(Vibrator, VibratorAidl, testing::ValuesIn(GenerateVibratorMapping()), PrintGeneratedTest); int main(int argc, char **argv) { // Random values are used in the implementation. std::srand(std::time(nullptr)); ::testing::InitGoogleTest(&argc, argv); ABinderProcess_setThreadPoolMaxThreadCount(1); ABinderProcess_startThreadPool(); return RUN_ALL_TESTS(); }