mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
Updating IVibrator.aidl to introduce APIs for PWLE V2 support. The updated interface now enables retrieval of minimum and maximum PWLE durations, maximum composition size, and facilitates the composition of PWLE effects using points. Bug: 347034419 Flag: EXEMPT HAL interface change Test: vts-tradefed run vts -m VtsHalVibratorTargetTest Change-Id: Id0a93e4f8678622bdb698cddc2b39f46e0283fdd
1249 lines
48 KiB
C++
1249 lines
48 KiB
C++
/*
|
|
* 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 <aidl/Gtest.h>
|
|
#include <aidl/Vintf.h>
|
|
#include <aidl/android/hardware/vibrator/BnVibratorCallback.h>
|
|
#include <aidl/android/hardware/vibrator/IVibrator.h>
|
|
#include <aidl/android/hardware/vibrator/IVibratorManager.h>
|
|
|
|
#include <android/binder_manager.h>
|
|
#include <android/binder_process.h>
|
|
#include <android/persistable_bundle_aidl.h>
|
|
|
|
#include <cmath>
|
|
#include <cstdlib>
|
|
#include <ctime>
|
|
#include <future>
|
|
#include <iomanip>
|
|
#include <iostream>
|
|
#include <random>
|
|
|
|
#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::Effect;
|
|
using aidl::android::hardware::vibrator::EffectStrength;
|
|
using aidl::android::hardware::vibrator::IVibrator;
|
|
using aidl::android::hardware::vibrator::IVibratorManager;
|
|
using aidl::android::hardware::vibrator::PrimitivePwle;
|
|
using aidl::android::hardware::vibrator::PwleV2OutputMapEntry;
|
|
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<Effect> kEffects{ndk::enum_range<Effect>().begin(),
|
|
ndk::enum_range<Effect>().end()};
|
|
const std::vector<EffectStrength> kEffectStrengths{ndk::enum_range<EffectStrength>().begin(),
|
|
ndk::enum_range<EffectStrength>().end()};
|
|
|
|
const std::vector<Effect> kInvalidEffects = {
|
|
static_cast<Effect>(static_cast<int32_t>(kEffects.front()) - 1),
|
|
static_cast<Effect>(static_cast<int32_t>(kEffects.back()) + 1),
|
|
};
|
|
|
|
const std::vector<EffectStrength> kInvalidEffectStrengths = {
|
|
static_cast<EffectStrength>(static_cast<int8_t>(kEffectStrengths.front()) - 1),
|
|
static_cast<EffectStrength>(static_cast<int8_t>(kEffectStrengths.back()) + 1),
|
|
};
|
|
|
|
const std::vector<CompositePrimitive> kCompositePrimitives{
|
|
ndk::enum_range<CompositePrimitive>().begin(), ndk::enum_range<CompositePrimitive>().end()};
|
|
|
|
const std::vector<CompositePrimitive> kRequiredPrimitives = {
|
|
CompositePrimitive::CLICK, CompositePrimitive::LIGHT_TICK,
|
|
CompositePrimitive::QUICK_RISE, CompositePrimitive::SLOW_RISE,
|
|
CompositePrimitive::QUICK_FALL,
|
|
};
|
|
|
|
const std::vector<CompositePrimitive> kInvalidPrimitives = {
|
|
static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.front()) - 1),
|
|
static_cast<CompositePrimitive>(static_cast<int32_t>(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 std::vector<std::string> findVibratorManagerNames() {
|
|
std::vector<std::string> names;
|
|
constexpr auto callback = [](const char* instance, void* context) {
|
|
auto fullName = std::string(IVibratorManager::descriptor) + "/" + instance;
|
|
static_cast<std::vector<std::string>*>(context)->emplace_back(fullName);
|
|
};
|
|
AServiceManager_forEachDeclaredInstance(IVibratorManager::descriptor,
|
|
static_cast<void*>(&names), callback);
|
|
return names;
|
|
}
|
|
|
|
static std::vector<std::string> findUnmanagedVibratorNames() {
|
|
std::vector<std::string> names;
|
|
constexpr auto callback = [](const char* instance, void* context) {
|
|
auto fullName = std::string(IVibrator::descriptor) + "/" + instance;
|
|
static_cast<std::vector<std::string>*>(context)->emplace_back(fullName);
|
|
};
|
|
AServiceManager_forEachDeclaredInstance(IVibrator::descriptor, static_cast<void*>(&names),
|
|
callback);
|
|
return names;
|
|
}
|
|
|
|
class CompletionCallback : public BnVibratorCallback {
|
|
public:
|
|
CompletionCallback(const std::function<void()> &callback) : mCallback(callback) {}
|
|
ndk::ScopedAStatus onComplete() override {
|
|
mCallback();
|
|
return ndk::ScopedAStatus::ok();
|
|
}
|
|
|
|
private:
|
|
std::function<void()> mCallback;
|
|
};
|
|
|
|
class VibratorAidl : public testing::TestWithParam<std::tuple<int32_t, int32_t>> {
|
|
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<std::string> 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<std::string> 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<IVibrator> vibrator;
|
|
int32_t version;
|
|
int32_t capabilities;
|
|
};
|
|
|
|
static float getResonantFrequencyHz(const std::shared_ptr<IVibrator>& 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 float getFrequencyResolutionHz(const std::shared_ptr<IVibrator>& vibrator,
|
|
int32_t capabilities) {
|
|
float freqResolutionHz;
|
|
ndk::ScopedAStatus status = vibrator->getFrequencyResolution(&freqResolutionHz);
|
|
if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
|
|
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<IVibrator>& vibrator,
|
|
int32_t capabilities) {
|
|
float freqMinimumHz;
|
|
ndk::ScopedAStatus status = vibrator->getFrequencyMinimum(&freqMinimumHz);
|
|
if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
|
|
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<IVibrator>& vibrator,
|
|
int32_t capabilities) {
|
|
std::vector<float> bandwidthAmplitudeMap;
|
|
ndk::ScopedAStatus status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
|
|
if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
|
|
EXPECT_OK(std::move(status));
|
|
} else {
|
|
EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
|
|
}
|
|
|
|
float freqMaximumHz = ((bandwidthAmplitudeMap.size() - 1) *
|
|
getFrequencyResolutionHz(vibrator, capabilities)) +
|
|
getFrequencyMinimumHz(vibrator, capabilities);
|
|
return freqMaximumHz;
|
|
}
|
|
|
|
static float getAmplitudeMin() {
|
|
return 0.0;
|
|
}
|
|
|
|
static float getAmplitudeMax() {
|
|
return 1.0;
|
|
}
|
|
|
|
static ActivePwle composeValidActivePwle(const std::shared_ptr<IVibrator>& vibrator,
|
|
int32_t capabilities) {
|
|
float frequencyHz;
|
|
if (capabilities & IVibrator::CAP_GET_RESONANT_FREQUENCY) {
|
|
frequencyHz = getResonantFrequencyHz(vibrator, capabilities);
|
|
} else if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
|
|
frequencyHz = getFrequencyMinimumHz(vibrator, capabilities);
|
|
} 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<void> completionPromise;
|
|
std::future<void> completionFuture{completionPromise.get_future()};
|
|
auto callback = ndk::SharedRefBase::make<CompletionCallback>(
|
|
[&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<CompletionCallback>([] {});
|
|
EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->on(250, callback));
|
|
}
|
|
}
|
|
|
|
TEST_P(VibratorAidl, ValidateEffect) {
|
|
std::vector<Effect> 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<Effect> 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<void> completionPromise;
|
|
std::future<void> completionFuture{completionPromise.get_future()};
|
|
auto callback = ndk::SharedRefBase::make<CompletionCallback>(
|
|
[&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<CompletionCallback>([] {});
|
|
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<CompletionCallback>([] {});
|
|
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<CompletionCallback>([] {});
|
|
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<CompositePrimitive> 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<CompositePrimitive> 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<CompositePrimitive> supported;
|
|
int32_t maxDelay, maxSize;
|
|
|
|
EXPECT_OK(vibrator->getSupportedPrimitives(&supported));
|
|
EXPECT_OK(vibrator->getCompositionDelayMax(&maxDelay));
|
|
EXPECT_OK(vibrator->getCompositionSizeMax(&maxSize));
|
|
|
|
std::vector<CompositeEffect> composite;
|
|
|
|
for (int i = 0; i < supported.size(); i++) {
|
|
CompositePrimitive primitive = supported[i];
|
|
float t = static_cast<float>(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<CompositePrimitive> unsupported(kInvalidPrimitives);
|
|
std::vector<CompositePrimitive> 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<CompositeEffect> 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<CompositeEffect> 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<CompositeEffect> 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<CompositeEffect> 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<CompositePrimitive> supported;
|
|
EXPECT_OK(vibrator->getSupportedPrimitives(&supported));
|
|
|
|
for (CompositePrimitive primitive : supported) {
|
|
if (primitive == CompositePrimitive::NOOP) {
|
|
continue;
|
|
}
|
|
|
|
std::promise<void> completionPromise;
|
|
std::future<void> completionFuture{completionPromise.get_future()};
|
|
auto callback = ndk::SharedRefBase::make<CompletionCallback>(
|
|
[&completionPromise] { completionPromise.set_value(); });
|
|
CompositeEffect effect;
|
|
std::vector<CompositeEffect> composite;
|
|
int32_t durationMs;
|
|
std::chrono::milliseconds duration;
|
|
std::chrono::time_point<high_resolution_clock> 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<std::chrono::milliseconds>(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<Effect> 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);
|
|
}
|
|
|
|
TEST_P(VibratorAidl, GetFrequencyMinimum) {
|
|
getFrequencyMinimumHz(vibrator, capabilities);
|
|
}
|
|
|
|
TEST_P(VibratorAidl, GetBandwidthAmplitudeMap) {
|
|
std::vector<float> bandwidthAmplitudeMap;
|
|
ndk::ScopedAStatus status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
|
|
if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
|
|
EXPECT_OK(std::move(status));
|
|
ASSERT_FALSE(bandwidthAmplitudeMap.empty());
|
|
|
|
int minMapSize = (getResonantFrequencyHz(vibrator, capabilities) -
|
|
getFrequencyMinimumHz(vibrator, capabilities)) /
|
|
getFrequencyResolutionHz(vibrator, capabilities);
|
|
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<Braking> 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);
|
|
|
|
std::vector<Braking> 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);
|
|
if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
|
|
float minFrequencyHz = getFrequencyMinimumHz(vibrator, capabilities);
|
|
float maxFrequencyHz = getFrequencyMaximumHz(vibrator, capabilities);
|
|
float freqResolutionHz = getFrequencyResolutionHz(vibrator, capabilities);
|
|
secondActive.startFrequency = minFrequencyHz + (freqResolutionHz / 2.0f);
|
|
secondActive.endFrequency = maxFrequencyHz - (freqResolutionHz / 3.0f);
|
|
}
|
|
BrakingPwle secondBraking;
|
|
secondBraking.braking = Braking::NONE;
|
|
secondBraking.duration = 10;
|
|
|
|
std::vector<PrimitivePwle> 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<void> completionPromise;
|
|
std::future<void> completionFuture{completionPromise.get_future()};
|
|
auto callback = ndk::SharedRefBase::make<CompletionCallback>(
|
|
[&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);
|
|
|
|
std::vector<Braking> 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<PrimitivePwle> 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<PrimitivePwle> pwleQueue;
|
|
// test empty queue
|
|
EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueue, nullptr));
|
|
|
|
ActivePwle active = composeValidActivePwle(vibrator, capabilities);
|
|
|
|
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);
|
|
active.startAmplitude = getAmplitudeMax() + 1.0; // Amplitude greater than allowed
|
|
active.endAmplitude = getAmplitudeMax() + 1.0; // Amplitude greater than allowed
|
|
|
|
std::vector<PrimitivePwle> 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<PrimitivePwle> 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);
|
|
float freqMaximumHz = getFrequencyMaximumHz(vibrator, capabilities);
|
|
float freqResolutionHz = getFrequencyResolutionHz(vibrator, capabilities);
|
|
|
|
ActivePwle active = composeValidActivePwle(vibrator, capabilities);
|
|
active.startFrequency =
|
|
freqMaximumHz + freqResolutionHz; // Frequency greater than allowed
|
|
active.endFrequency = freqMaximumHz + freqResolutionHz; // Frequency greater than allowed
|
|
|
|
std::vector<PrimitivePwle> 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<PrimitivePwle> 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);
|
|
|
|
int32_t segmentDurationMaxMs;
|
|
vibrator->getPwlePrimitiveDurationMax(&segmentDurationMaxMs);
|
|
active.duration = segmentDurationMaxMs + 10; // Segment duration greater than allowed
|
|
|
|
std::vector<PrimitivePwle> pwleQueue = {active};
|
|
|
|
EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueue, nullptr));
|
|
}
|
|
}
|
|
|
|
TEST_P(VibratorAidl, PwleV2FrequencyToOutputAccelerationMapHasValidFrequencyRange) {
|
|
std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap;
|
|
ndk::ScopedAStatus status =
|
|
vibrator->getPwleV2FrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap);
|
|
if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2) {
|
|
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);
|
|
} else {
|
|
EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
|
|
}
|
|
}
|
|
|
|
TEST_P(VibratorAidl, GetPwleV2PrimitiveDurationMaxMillis) {
|
|
int32_t durationMs;
|
|
ndk::ScopedAStatus status = vibrator->getPwleV2PrimitiveDurationMaxMillis(&durationMs);
|
|
if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2) {
|
|
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);
|
|
} else {
|
|
EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
|
|
}
|
|
}
|
|
|
|
TEST_P(VibratorAidl, GetPwleV2CompositionSizeMax) {
|
|
int32_t maxSize;
|
|
ndk::ScopedAStatus status = vibrator->getPwleV2CompositionSizeMax(&maxSize);
|
|
if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2) {
|
|
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);
|
|
} else {
|
|
EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
|
|
}
|
|
}
|
|
|
|
TEST_P(VibratorAidl, GetPwleV2PrimitiveDurationMinMillis) {
|
|
int32_t durationMs;
|
|
ndk::ScopedAStatus status = vibrator->getPwleV2PrimitiveDurationMinMillis(&durationMs);
|
|
if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2) {
|
|
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);
|
|
} else {
|
|
EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
|
|
}
|
|
}
|
|
|
|
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, ComposeValidPwleV2EffectWithCallback) {
|
|
if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
|
|
GTEST_SKIP() << "PWLE V2 not supported, skipping test";
|
|
return;
|
|
}
|
|
|
|
std::promise<void> completionPromise;
|
|
std::future<void> completionFuture{completionPromise.get_future()};
|
|
auto callback = ndk::SharedRefBase::make<CompletionCallback>(
|
|
[&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);
|
|
|
|
EXPECT_OK(vibrator->composePwleV2(
|
|
{PwleV2Primitive(/*amplitude=*/0.5, minFrequency, minDuration)}, 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));
|
|
|
|
std::vector<PwleV2Primitive> composePwle;
|
|
|
|
// Negative amplitude
|
|
composePwle.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.clear();
|
|
|
|
// Amplitude exceeding 1.0
|
|
composePwle.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.clear();
|
|
|
|
// Duration exceeding maximum
|
|
composePwle.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.clear();
|
|
|
|
// Negative duration
|
|
composePwle.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.clear();
|
|
|
|
// Frequency below minimum
|
|
float minFrequency = pwle_v2_utils::getPwleV2FrequencyMinHz(vibrator);
|
|
composePwle.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.clear();
|
|
|
|
// Frequency above maximum
|
|
float maxFrequency = pwle_v2_utils::getPwleV2FrequencyMaxHz(vibrator);
|
|
composePwle.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<std::tuple<int32_t, int32_t>> GenerateVibratorMapping() {
|
|
std::vector<std::tuple<int32_t, int32_t>> tuples;
|
|
|
|
std::vector<std::string> managerNames = findVibratorManagerNames();
|
|
std::vector<int32_t> 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<std::string> vibratorNames = findUnmanagedVibratorNames();
|
|
for (int i = 0; i < vibratorNames.size(); i++) {
|
|
tuples.emplace_back(-1, i);
|
|
}
|
|
|
|
return tuples;
|
|
}
|
|
|
|
std::string PrintGeneratedTest(const testing::TestParamInfo<VibratorAidl::ParamType> &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();
|
|
}
|