Loading vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl +5 −0 Original line number Diff line number Diff line Loading @@ -49,4 +49,9 @@ enum CompositePrimitive { * A haptic effect that simulates quick downwards movement with gravity. */ QUICK_FALL, /** * This very short effect should produce a light crisp sensation intended * to be used repetitively for dynamic feedback. */ LIGHT_TICK, } vibrator/aidl/android/hardware/vibrator/IVibrator.aidl +20 −1 Original line number Diff line number Diff line Loading @@ -157,13 +157,32 @@ interface IVibrator { */ int getCompositionSizeMax(); /** * List of supported effect primitive. * * Return the effect primitives which are supported by the compose API. * Implementations are expected to support all primitives of the interface * version that they implement. */ CompositePrimitive[] getSupportedPrimitives(); /** * Retrieve effect primitive's duration in milliseconds. * * Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS). * * @return Best effort estimation of effect primitive's duration. * @param primitive Effect primitive being queried. */ int getPrimitiveDuration(CompositePrimitive primitive); /** * Fire off a string of effect primitives, combined to perform richer effects. * * Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS). * * Doing this operation while the vibrator is already on is undefined behavior. Clients should * explicitly call off. * explicitly call off. IVibratorCallback.onComplete() support is required for this API. * * @param composite Array of composition parameters. */ Loading vibrator/aidl/default/Vibrator.cpp +21 −1 Original line number Diff line number Diff line Loading @@ -113,6 +113,26 @@ ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t* maxSize) { return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive>* supported) { *supported = { CompositePrimitive::NOOP, CompositePrimitive::CLICK, CompositePrimitive::THUD, CompositePrimitive::SPIN, CompositePrimitive::QUICK_RISE, CompositePrimitive::SLOW_RISE, CompositePrimitive::QUICK_FALL, CompositePrimitive::LIGHT_TICK, }; return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive, int32_t* durationMs) { if (primitive != CompositePrimitive::NOOP) { *durationMs = 100; } else { *durationMs = 0; } return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& composite, const std::shared_ptr<IVibratorCallback>& callback) { if (composite.size() > kComposeSizeMax) { Loading @@ -127,7 +147,7 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& composi return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } if (e.primitive < CompositePrimitive::NOOP || e.primitive > CompositePrimitive::QUICK_FALL) { e.primitive > CompositePrimitive::LIGHT_TICK) { return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } } Loading vibrator/aidl/default/include/vibrator-impl/Vibrator.h +3 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,9 @@ class Vibrator : public BnVibrator { ndk::ScopedAStatus setExternalControl(bool enabled) override; ndk::ScopedAStatus getCompositionDelayMax(int32_t* maxDelayMs); ndk::ScopedAStatus getCompositionSizeMax(int32_t* maxSize); ndk::ScopedAStatus getSupportedPrimitives(std::vector<CompositePrimitive>* supported) override; ndk::ScopedAStatus getPrimitiveDuration(CompositePrimitive primitive, int32_t* durationMs) override; ndk::ScopedAStatus compose(const std::vector<CompositeEffect>& composite, const std::shared_ptr<IVibratorCallback>& callback) override; ndk::ScopedAStatus getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return) override; Loading vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp +47 −0 Original line number Diff line number Diff line Loading @@ -261,6 +261,29 @@ TEST_P(VibratorAidl, ExternalControlUnsupportedMatchingCapabilities) { } } TEST_P(VibratorAidl, GetSupportedPrimitives) { if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { std::vector<CompositePrimitive> supported; EXPECT_EQ(Status::EX_NONE, vibrator->getSupportedPrimitives(&supported).exceptionCode()); std::sort(supported.begin(), supported.end()); EXPECT_EQ(kCompositePrimitives, supported); } } TEST_P(VibratorAidl, GetPrimitiveDuration) { if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { int32_t duration; for (auto primitive : kCompositePrimitives) { EXPECT_EQ(Status::EX_NONE, vibrator->getPrimitiveDuration(primitive, &duration).exceptionCode()); } } } TEST_P(VibratorAidl, ComposeValidPrimitives) { if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { int32_t maxDelay, maxSize; Loading Loading @@ -357,6 +380,30 @@ TEST_P(VibratorAidl, CompseSizeBoundary) { } } TEST_P(VibratorAidl, ComposeCallback) { if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { std::promise<void> completionPromise; std::future<void> completionFuture{completionPromise.get_future()}; sp<CompletionCallback> callback = new CompletionCallback([&completionPromise] { completionPromise.set_value(); }); CompositePrimitive primitive = CompositePrimitive::CLICK; CompositeEffect effect; std::vector<CompositeEffect> composite; int32_t duration; effect.delayMs = 0; effect.primitive = primitive; effect.scale = 1.0f; composite.emplace_back(effect); EXPECT_EQ(Status::EX_NONE, vibrator->getPrimitiveDuration(primitive, &duration).exceptionCode()); EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, callback).exceptionCode()); EXPECT_EQ(completionFuture.wait_for(std::chrono::milliseconds(duration * 2)), std::future_status::ready); } } TEST_P(VibratorAidl, AlwaysOn) { if (capabilities & IVibrator::CAP_ALWAYS_ON_CONTROL) { std::vector<Effect> supported; Loading Loading
vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl +5 −0 Original line number Diff line number Diff line Loading @@ -49,4 +49,9 @@ enum CompositePrimitive { * A haptic effect that simulates quick downwards movement with gravity. */ QUICK_FALL, /** * This very short effect should produce a light crisp sensation intended * to be used repetitively for dynamic feedback. */ LIGHT_TICK, }
vibrator/aidl/android/hardware/vibrator/IVibrator.aidl +20 −1 Original line number Diff line number Diff line Loading @@ -157,13 +157,32 @@ interface IVibrator { */ int getCompositionSizeMax(); /** * List of supported effect primitive. * * Return the effect primitives which are supported by the compose API. * Implementations are expected to support all primitives of the interface * version that they implement. */ CompositePrimitive[] getSupportedPrimitives(); /** * Retrieve effect primitive's duration in milliseconds. * * Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS). * * @return Best effort estimation of effect primitive's duration. * @param primitive Effect primitive being queried. */ int getPrimitiveDuration(CompositePrimitive primitive); /** * Fire off a string of effect primitives, combined to perform richer effects. * * Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS). * * Doing this operation while the vibrator is already on is undefined behavior. Clients should * explicitly call off. * explicitly call off. IVibratorCallback.onComplete() support is required for this API. * * @param composite Array of composition parameters. */ Loading
vibrator/aidl/default/Vibrator.cpp +21 −1 Original line number Diff line number Diff line Loading @@ -113,6 +113,26 @@ ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t* maxSize) { return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive>* supported) { *supported = { CompositePrimitive::NOOP, CompositePrimitive::CLICK, CompositePrimitive::THUD, CompositePrimitive::SPIN, CompositePrimitive::QUICK_RISE, CompositePrimitive::SLOW_RISE, CompositePrimitive::QUICK_FALL, CompositePrimitive::LIGHT_TICK, }; return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive, int32_t* durationMs) { if (primitive != CompositePrimitive::NOOP) { *durationMs = 100; } else { *durationMs = 0; } return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& composite, const std::shared_ptr<IVibratorCallback>& callback) { if (composite.size() > kComposeSizeMax) { Loading @@ -127,7 +147,7 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& composi return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } if (e.primitive < CompositePrimitive::NOOP || e.primitive > CompositePrimitive::QUICK_FALL) { e.primitive > CompositePrimitive::LIGHT_TICK) { return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } } Loading
vibrator/aidl/default/include/vibrator-impl/Vibrator.h +3 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,9 @@ class Vibrator : public BnVibrator { ndk::ScopedAStatus setExternalControl(bool enabled) override; ndk::ScopedAStatus getCompositionDelayMax(int32_t* maxDelayMs); ndk::ScopedAStatus getCompositionSizeMax(int32_t* maxSize); ndk::ScopedAStatus getSupportedPrimitives(std::vector<CompositePrimitive>* supported) override; ndk::ScopedAStatus getPrimitiveDuration(CompositePrimitive primitive, int32_t* durationMs) override; ndk::ScopedAStatus compose(const std::vector<CompositeEffect>& composite, const std::shared_ptr<IVibratorCallback>& callback) override; ndk::ScopedAStatus getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return) override; Loading
vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp +47 −0 Original line number Diff line number Diff line Loading @@ -261,6 +261,29 @@ TEST_P(VibratorAidl, ExternalControlUnsupportedMatchingCapabilities) { } } TEST_P(VibratorAidl, GetSupportedPrimitives) { if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { std::vector<CompositePrimitive> supported; EXPECT_EQ(Status::EX_NONE, vibrator->getSupportedPrimitives(&supported).exceptionCode()); std::sort(supported.begin(), supported.end()); EXPECT_EQ(kCompositePrimitives, supported); } } TEST_P(VibratorAidl, GetPrimitiveDuration) { if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { int32_t duration; for (auto primitive : kCompositePrimitives) { EXPECT_EQ(Status::EX_NONE, vibrator->getPrimitiveDuration(primitive, &duration).exceptionCode()); } } } TEST_P(VibratorAidl, ComposeValidPrimitives) { if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { int32_t maxDelay, maxSize; Loading Loading @@ -357,6 +380,30 @@ TEST_P(VibratorAidl, CompseSizeBoundary) { } } TEST_P(VibratorAidl, ComposeCallback) { if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { std::promise<void> completionPromise; std::future<void> completionFuture{completionPromise.get_future()}; sp<CompletionCallback> callback = new CompletionCallback([&completionPromise] { completionPromise.set_value(); }); CompositePrimitive primitive = CompositePrimitive::CLICK; CompositeEffect effect; std::vector<CompositeEffect> composite; int32_t duration; effect.delayMs = 0; effect.primitive = primitive; effect.scale = 1.0f; composite.emplace_back(effect); EXPECT_EQ(Status::EX_NONE, vibrator->getPrimitiveDuration(primitive, &duration).exceptionCode()); EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, callback).exceptionCode()); EXPECT_EQ(completionFuture.wait_for(std::chrono::milliseconds(duration * 2)), std::future_status::ready); } } TEST_P(VibratorAidl, AlwaysOn) { if (capabilities & IVibrator::CAP_ALWAYS_ON_CONTROL) { std::vector<Effect> supported; Loading