Create CallbackScheduler for Vibrator HAL callbacks
This scheduler keeps a single thread looping and executing callbacks
after a delay. This mechanism is used to simulate the callbacks that
some Vibrator HALs do not support.
Bug: 153418251
Test: atest libvibratorservice_test
Change-Id: If19481dfe2eca662d33738a11257bd4509fe81ca
diff --git a/services/vibratorservice/Android.bp b/services/vibratorservice/Android.bp
index b4342bd..e3c254d 100644
--- a/services/vibratorservice/Android.bp
+++ b/services/vibratorservice/Android.bp
@@ -16,6 +16,7 @@
name: "libvibratorservice",
srcs: [
+ "VibratorCallbackScheduler.cpp",
"VibratorHalWrapper.cpp",
],
diff --git a/services/vibratorservice/VibratorCallbackScheduler.cpp b/services/vibratorservice/VibratorCallbackScheduler.cpp
new file mode 100644
index 0000000..3f8cd67
--- /dev/null
+++ b/services/vibratorservice/VibratorCallbackScheduler.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <chrono>
+#include <thread>
+
+#include <vibratorservice/VibratorCallbackScheduler.h>
+
+namespace android {
+
+namespace vibrator {
+
+// -------------------------------------------------------------------------------------------------
+
+bool DelayedCallback::isExpired() const {
+ return mExpiration <= std::chrono::steady_clock::now();
+}
+
+DelayedCallback::Timestamp DelayedCallback::getExpiration() const {
+ return mExpiration;
+}
+
+void DelayedCallback::run() const {
+ mCallback();
+}
+
+bool DelayedCallback::operator<(const DelayedCallback& other) const {
+ return mExpiration < other.mExpiration;
+}
+
+bool DelayedCallback::operator>(const DelayedCallback& other) const {
+ return mExpiration > other.mExpiration;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+CallbackScheduler::~CallbackScheduler() {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mFinished = true;
+ }
+ mCondition.notify_all();
+ if (mCallbackThread && mCallbackThread->joinable()) {
+ mCallbackThread->join();
+ }
+}
+
+void CallbackScheduler::schedule(std::function<void()> callback, std::chrono::milliseconds delay) {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mCallbackThread == nullptr) {
+ mCallbackThread = std::make_unique<std::thread>(&CallbackScheduler::loop, this);
+ }
+ mQueue.emplace(DelayedCallback(callback, delay));
+ }
+ mCondition.notify_all();
+}
+
+void CallbackScheduler::loop() {
+ while (true) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mFinished) {
+ // Destructor was called, so let the callback thread die.
+ break;
+ }
+ while (!mQueue.empty() && mQueue.top().isExpired()) {
+ mQueue.top().run();
+ mQueue.pop();
+ }
+ if (mQueue.empty()) {
+ // Wait until a new callback is scheduled.
+ mCondition.wait(mMutex);
+ } else {
+ // Wait until next callback expires, or a new one is scheduled.
+ mCondition.wait_until(mMutex, mQueue.top().getExpiration());
+ }
+ }
+}
+
+// -------------------------------------------------------------------------------------------------
+
+}; // namespace vibrator
+
+}; // namespace android
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index db27bd9..1420bf5 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -23,6 +23,7 @@
#include <utils/Log.h>
+#include <vibratorservice/VibratorCallbackScheduler.h>
#include <vibratorservice/VibratorHalWrapper.h>
using android::hardware::vibrator::CompositeEffect;
@@ -46,10 +47,12 @@
template <class T>
HalResult<T> loadCached(const std::function<HalResult<T>()>& loadFn, std::optional<T>& cache) {
if (cache.has_value()) {
- return HalResult<T>::ok(cache.value());
+ // Return copy of cached value.
+ return HalResult<T>::ok(*cache);
}
HalResult<T> ret = loadFn();
if (ret.isOk()) {
+ // Cache copy of returned value.
cache.emplace(ret.value());
}
return ret;
@@ -62,27 +65,6 @@
return castEffect >= *iter.begin() && castEffect <= *std::prev(iter.end());
}
-template <class I, class T>
-using perform_fn = hardware::Return<void> (I::*)(T, V1_0::EffectStrength,
- V1_0::IVibrator::perform_cb);
-
-template <class I, class T>
-HalResult<milliseconds> perform(perform_fn<I, T> performFn, sp<I> handle, T effect,
- EffectStrength strength) {
- V1_0::Status status;
- int32_t lengthMs;
- V1_0::IVibrator::perform_cb effectCallback = [&status, &lengthMs](V1_0::Status retStatus,
- uint32_t retLengthMs) {
- status = retStatus;
- lengthMs = retLengthMs;
- };
-
- V1_0::EffectStrength effectStrength = static_cast<V1_0::EffectStrength>(strength);
- auto result = std::invoke(performFn, handle, effect, effectStrength, effectCallback);
-
- return HalResult<milliseconds>::fromReturn(result, status, milliseconds(lengthMs));
-}
-
// -------------------------------------------------------------------------------------------------
template <typename T>
@@ -179,7 +161,7 @@
class HalCallbackWrapper : public Aidl::BnVibratorCallback {
public:
- HalCallbackWrapper(const std::function<void()>& completionCallback)
+ HalCallbackWrapper(std::function<void()> completionCallback)
: mCompletionCallback(completionCallback) {}
binder::Status onComplete() override {
@@ -200,8 +182,17 @@
HalResult<void> AidlHalWrapper::on(milliseconds timeout,
const std::function<void()>& completionCallback) {
- auto cb = new HalCallbackWrapper(completionCallback);
- return HalResult<void>::fromStatus(mHandle->on(timeout.count(), cb));
+ HalResult<Capabilities> capabilities = getCapabilities();
+ bool supportsCallback = capabilities.isOk() &&
+ static_cast<int32_t>(capabilities.value() & Capabilities::ON_CALLBACK);
+ auto cb = supportsCallback ? new HalCallbackWrapper(completionCallback) : nullptr;
+
+ auto ret = HalResult<void>::fromStatus(mHandle->on(timeout.count(), cb));
+ if (!supportsCallback && ret.isOk()) {
+ mCallbackScheduler->schedule(completionCallback, timeout);
+ }
+
+ return ret;
}
HalResult<void> AidlHalWrapper::off() {
@@ -227,39 +218,56 @@
HalResult<Capabilities> AidlHalWrapper::getCapabilities() {
std::lock_guard<std::mutex> lock(mCapabilitiesMutex);
- static auto loadFn = [this]() {
- int32_t capabilities = 0;
- auto result = mHandle->getCapabilities(&capabilities);
- return HalResult<Capabilities>::fromStatus(result, static_cast<Capabilities>(capabilities));
- };
- return loadCached<Capabilities>(loadFn, mCapabilities);
+ return loadCached<Capabilities>(std::bind(&AidlHalWrapper::getCapabilitiesInternal, this),
+ mCapabilities);
}
HalResult<std::vector<Effect>> AidlHalWrapper::getSupportedEffects() {
std::lock_guard<std::mutex> lock(mSupportedEffectsMutex);
- static auto loadFn = [this]() {
- std::vector<Effect> supportedEffects;
- auto result = mHandle->getSupportedEffects(&supportedEffects);
- return HalResult<std::vector<Effect>>::fromStatus(result, supportedEffects);
- };
- return loadCached<std::vector<Effect>>(loadFn, mSupportedEffects);
+ return loadCached<std::vector<Effect>>(std::bind(&AidlHalWrapper::getSupportedEffectsInternal,
+ this),
+ mSupportedEffects);
}
HalResult<milliseconds> AidlHalWrapper::performEffect(
Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+ HalResult<Capabilities> capabilities = getCapabilities();
+ bool supportsCallback = capabilities.isOk() &&
+ static_cast<int32_t>(capabilities.value() & Capabilities::PERFORM_CALLBACK);
+ auto cb = supportsCallback ? new HalCallbackWrapper(completionCallback) : nullptr;
+
int32_t lengthMs;
- auto cb = new HalCallbackWrapper(completionCallback);
auto result = mHandle->perform(effect, strength, cb, &lengthMs);
- return HalResult<milliseconds>::fromStatus(result, milliseconds(lengthMs));
+ milliseconds length = milliseconds(lengthMs);
+
+ auto ret = HalResult<milliseconds>::fromStatus(result, length);
+ if (!supportsCallback && ret.isOk()) {
+ mCallbackScheduler->schedule(completionCallback, length);
+ }
+
+ return ret;
}
HalResult<void> AidlHalWrapper::performComposedEffect(
const std::vector<CompositeEffect>& primitiveEffects,
const std::function<void()>& completionCallback) {
+ // This method should always support callbacks, so no need to double check.
auto cb = new HalCallbackWrapper(completionCallback);
return HalResult<void>::fromStatus(mHandle->compose(primitiveEffects, cb));
}
+HalResult<Capabilities> AidlHalWrapper::getCapabilitiesInternal() {
+ int32_t capabilities = 0;
+ auto result = mHandle->getCapabilities(&capabilities);
+ return HalResult<Capabilities>::fromStatus(result, static_cast<Capabilities>(capabilities));
+}
+
+HalResult<std::vector<Effect>> AidlHalWrapper::getSupportedEffectsInternal() {
+ std::vector<Effect> supportedEffects;
+ auto result = mHandle->getSupportedEffects(&supportedEffects);
+ return HalResult<std::vector<Effect>>::fromStatus(result, supportedEffects);
+}
+
// -------------------------------------------------------------------------------------------------
HalResult<void> HidlHalWrapperV1_0::ping() {
@@ -267,10 +275,14 @@
return HalResult<void>::fromReturn(result);
}
-HalResult<void> HidlHalWrapperV1_0::on(milliseconds timeout, const std::function<void()>&) {
+HalResult<void> HidlHalWrapperV1_0::on(milliseconds timeout,
+ const std::function<void()>& completionCallback) {
auto result = mHandleV1_0->on(timeout.count());
- auto status = result.withDefault(V1_0::Status::UNKNOWN_ERROR);
- return HalResult<void>::fromStatus(status);
+ auto ret = HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
+ if (ret.isOk()) {
+ mCallbackScheduler->schedule(completionCallback, timeout);
+ }
+ return ret;
}
HalResult<void> HidlHalWrapperV1_0::off() {
@@ -309,11 +321,10 @@
return HalResult<std::vector<Effect>>::unsupported();
}
-HalResult<milliseconds> HidlHalWrapperV1_0::performEffect(Effect effect, EffectStrength strength,
- const std::function<void()>&) {
+HalResult<milliseconds> HidlHalWrapperV1_0::performEffect(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
if (isStaticCastValid<V1_0::Effect>(effect)) {
- V1_0::Effect e = static_cast<V1_0::Effect>(effect);
- return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength);
+ return performInternalV1_0(effect, strength, completionCallback);
}
ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
@@ -334,17 +345,44 @@
return HalResult<Capabilities>::fromReturn(result, capabilities);
}
+template <class I, class T>
+HalResult<milliseconds> HidlHalWrapperV1_0::performInternal(
+ perform_fn<I, T> performFn, sp<I> handle, T effect, EffectStrength strength,
+ const std::function<void()>& completionCallback) {
+ V1_0::Status status;
+ int32_t lengthMs;
+ auto effectCallback = [&status, &lengthMs](V1_0::Status retStatus, uint32_t retLengthMs) {
+ status = retStatus;
+ lengthMs = retLengthMs;
+ };
+
+ V1_0::EffectStrength effectStrength = static_cast<V1_0::EffectStrength>(strength);
+ auto result = std::invoke(performFn, handle, effect, effectStrength, effectCallback);
+ milliseconds length = milliseconds(lengthMs);
+
+ auto ret = HalResult<milliseconds>::fromReturn(result, status, length);
+ if (ret.isOk()) {
+ mCallbackScheduler->schedule(completionCallback, length);
+ }
+
+ return ret;
+}
+
+HalResult<milliseconds> HidlHalWrapperV1_0::performInternalV1_0(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+ V1_0::Effect e = static_cast<V1_0::Effect>(effect);
+ return performInternal(&V1_0::IVibrator::perform, mHandleV1_0, e, strength, completionCallback);
+}
+
// -------------------------------------------------------------------------------------------------
-HalResult<milliseconds> HidlHalWrapperV1_1::performEffect(Effect effect, EffectStrength strength,
- const std::function<void()>&) {
+HalResult<milliseconds> HidlHalWrapperV1_1::performEffect(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
if (isStaticCastValid<V1_0::Effect>(effect)) {
- V1_0::Effect e = static_cast<V1_0::Effect>(effect);
- return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength);
+ return performInternalV1_0(effect, strength, completionCallback);
}
if (isStaticCastValid<V1_1::Effect_1_1>(effect)) {
- V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect);
- return perform(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength);
+ return performInternalV1_1(effect, strength, completionCallback);
}
ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
@@ -352,21 +390,25 @@
return HalResult<milliseconds>::unsupported();
}
+HalResult<milliseconds> HidlHalWrapperV1_1::performInternalV1_1(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+ V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect);
+ return performInternal(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength,
+ completionCallback);
+}
+
// -------------------------------------------------------------------------------------------------
-HalResult<milliseconds> HidlHalWrapperV1_2::performEffect(Effect effect, EffectStrength strength,
- const std::function<void()>&) {
+HalResult<milliseconds> HidlHalWrapperV1_2::performEffect(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
if (isStaticCastValid<V1_0::Effect>(effect)) {
- V1_0::Effect e = static_cast<V1_0::Effect>(effect);
- return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength);
+ return performInternalV1_0(effect, strength, completionCallback);
}
if (isStaticCastValid<V1_1::Effect_1_1>(effect)) {
- V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect);
- return perform(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength);
+ return performInternalV1_1(effect, strength, completionCallback);
}
if (isStaticCastValid<V1_2::Effect>(effect)) {
- V1_2::Effect e = static_cast<V1_2::Effect>(effect);
- return perform(&V1_2::IVibrator::perform_1_2, mHandleV1_2, e, strength);
+ return performInternalV1_2(effect, strength, completionCallback);
}
ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
@@ -374,6 +416,13 @@
return HalResult<milliseconds>::unsupported();
}
+HalResult<milliseconds> HidlHalWrapperV1_2::performInternalV1_2(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+ V1_2::Effect e = static_cast<V1_2::Effect>(effect);
+ return performInternal(&V1_2::IVibrator::perform_1_2, mHandleV1_2, e, strength,
+ completionCallback);
+}
+
// -------------------------------------------------------------------------------------------------
HalResult<void> HidlHalWrapperV1_3::setExternalControl(bool enabled) {
@@ -381,23 +430,19 @@
return HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
}
-HalResult<milliseconds> HidlHalWrapperV1_3::performEffect(Effect effect, EffectStrength strength,
- const std::function<void()>&) {
+HalResult<milliseconds> HidlHalWrapperV1_3::performEffect(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
if (isStaticCastValid<V1_0::Effect>(effect)) {
- V1_0::Effect e = static_cast<V1_0::Effect>(effect);
- return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength);
+ return performInternalV1_0(effect, strength, completionCallback);
}
if (isStaticCastValid<V1_1::Effect_1_1>(effect)) {
- V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect);
- return perform(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength);
+ return performInternalV1_1(effect, strength, completionCallback);
}
if (isStaticCastValid<V1_2::Effect>(effect)) {
- V1_2::Effect e = static_cast<V1_2::Effect>(effect);
- return perform(&V1_2::IVibrator::perform_1_2, mHandleV1_2, e, strength);
+ return performInternalV1_2(effect, strength, completionCallback);
}
if (isStaticCastValid<V1_3::Effect>(effect)) {
- V1_3::Effect e = static_cast<V1_3::Effect>(effect);
- return perform(&V1_3::IVibrator::perform_1_3, mHandleV1_3, e, strength);
+ return performInternalV1_3(effect, strength, completionCallback);
}
ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
@@ -418,6 +463,13 @@
return HalResult<Capabilities>::fromReturn(result, capabilities);
}
+HalResult<milliseconds> HidlHalWrapperV1_3::performInternalV1_3(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+ V1_3::Effect e = static_cast<V1_3::Effect>(effect);
+ return performInternal(&V1_3::IVibrator::perform_1_3, mHandleV1_3, e, strength,
+ completionCallback);
+}
+
// -------------------------------------------------------------------------------------------------
}; // namespace vibrator
diff --git a/services/vibratorservice/include/vibratorservice/VibratorCallbackScheduler.h b/services/vibratorservice/include/vibratorservice/VibratorCallbackScheduler.h
new file mode 100644
index 0000000..2c194b5
--- /dev/null
+++ b/services/vibratorservice/include/vibratorservice/VibratorCallbackScheduler.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_VIBRATOR_CALLBACK_SCHEDULER_H
+#define ANDROID_VIBRATOR_CALLBACK_SCHEDULER_H
+
+#include <android-base/thread_annotations.h>
+#include <chrono>
+#include <condition_variable>
+#include <queue>
+#include <thread>
+
+namespace android {
+
+namespace vibrator {
+
+// Wrapper for a callback to be executed after a delay.
+class DelayedCallback {
+public:
+ using Timestamp = std::chrono::time_point<std::chrono::steady_clock>;
+
+ DelayedCallback(std::function<void()> callback, std::chrono::milliseconds delay)
+ : mCallback(callback), mExpiration(std::chrono::steady_clock::now() + delay) {}
+ ~DelayedCallback() = default;
+
+ void run() const;
+ bool isExpired() const;
+ Timestamp getExpiration() const;
+
+ // Compare by expiration time, where A < B when A expires first.
+ bool operator<(const DelayedCallback& other) const;
+ bool operator>(const DelayedCallback& other) const;
+
+private:
+ std::function<void()> mCallback;
+ Timestamp mExpiration;
+};
+
+// Schedules callbacks to be executed after a delay.
+class CallbackScheduler {
+public:
+ CallbackScheduler() : mCallbackThread(nullptr), mFinished(false) {}
+ virtual ~CallbackScheduler();
+
+ virtual void schedule(std::function<void()> callback, std::chrono::milliseconds delay);
+
+private:
+ std::condition_variable_any mCondition;
+ std::mutex mMutex;
+
+ // Lazily instantiated only at the first time this scheduler is used.
+ std::unique_ptr<std::thread> mCallbackThread;
+
+ // Used to quit the callback thread when this instance is being destroyed.
+ bool mFinished GUARDED_BY(mMutex);
+
+ // Priority queue with reverse comparator, so tasks that expire first will be on top.
+ std::priority_queue<DelayedCallback, std::vector<DelayedCallback>,
+ std::greater<DelayedCallback>>
+ mQueue GUARDED_BY(mMutex);
+
+ void loop();
+};
+
+}; // namespace vibrator
+
+}; // namespace android
+
+#endif // ANDROID_VIBRATOR_CALLBACK_SCHEDULER_H
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index 1a1f64b..0f9aacb 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -21,6 +21,8 @@
#include <android/hardware/vibrator/1.3/IVibrator.h>
#include <android/hardware/vibrator/IVibrator.h>
+#include <vibratorservice/VibratorCallbackScheduler.h>
+
namespace android {
namespace vibrator {
@@ -46,7 +48,7 @@
hardware::vibrator::V1_0::Status status, T data);
// This will throw std::bad_optional_access if this result is not ok.
- T value() const { return mValue.value(); }
+ const T& value() const { return mValue.value(); }
bool isOk() const { return !mUnsupported && mValue.has_value(); }
bool isFailed() const { return !mUnsupported && !mValue.has_value(); }
bool isUnsupported() const { return mUnsupported; }
@@ -122,6 +124,8 @@
// Wrapper for Vibrator HAL handlers.
class HalWrapper {
public:
+ explicit HalWrapper(std::shared_ptr<CallbackScheduler> scheduler)
+ : mCallbackScheduler(std::move(scheduler)) {}
virtual ~HalWrapper() = default;
virtual HalResult<void> ping() = 0;
@@ -147,13 +151,19 @@
virtual HalResult<void> performComposedEffect(
const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
const std::function<void()>& completionCallback) = 0;
+
+protected:
+ // Shared pointer to allow CallbackScheduler to outlive this wrapper.
+ const std::shared_ptr<CallbackScheduler> mCallbackScheduler;
};
// Wrapper for the AIDL Vibrator HAL.
class AidlHalWrapper : public HalWrapper {
public:
- explicit AidlHalWrapper(sp<hardware::vibrator::IVibrator> handle)
- : mHandle(std::move(handle)) {}
+ AidlHalWrapper(std::shared_ptr<CallbackScheduler> scheduler,
+ sp<hardware::vibrator::IVibrator> handle)
+ : HalWrapper(std::move(scheduler)), mHandle(std::move(handle)) {}
+ virtual ~AidlHalWrapper() = default;
virtual HalResult<void> ping() override;
@@ -186,13 +196,19 @@
std::optional<Capabilities> mCapabilities GUARDED_BY(mCapabilitiesMutex);
std::optional<std::vector<hardware::vibrator::Effect>> mSupportedEffects
GUARDED_BY(mSupportedEffectsMutex);
+
+ // Loads directly from IVibrator handle, skipping caches.
+ HalResult<Capabilities> getCapabilitiesInternal();
+ HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffectsInternal();
};
// Wrapper for the HDIL Vibrator HAL v1.0.
class HidlHalWrapperV1_0 : public HalWrapper {
public:
- explicit HidlHalWrapperV1_0(sp<hardware::vibrator::V1_0::IVibrator> handle)
- : mHandleV1_0(std::move(handle)) {}
+ HidlHalWrapperV1_0(std::shared_ptr<CallbackScheduler> scheduler,
+ sp<hardware::vibrator::V1_0::IVibrator> handle)
+ : HalWrapper(std::move(scheduler)), mHandleV1_0(std::move(handle)) {}
+ virtual ~HidlHalWrapperV1_0() = default;
virtual HalResult<void> ping() override;
@@ -225,14 +241,31 @@
// Loads directly from IVibrator handle, skipping the mCapabilities cache.
virtual HalResult<Capabilities> getCapabilitiesInternal();
+
+ template <class I, class T>
+ using perform_fn =
+ hardware::Return<void> (I::*)(T, hardware::vibrator::V1_0::EffectStrength,
+ hardware::vibrator::V1_0::IVibrator::perform_cb);
+
+ template <class I, class T>
+ HalResult<std::chrono::milliseconds> performInternal(
+ perform_fn<I, T> performFn, sp<I> handle, T effect,
+ hardware::vibrator::EffectStrength strength,
+ const std::function<void()>& completionCallback);
+
+ HalResult<std::chrono::milliseconds> performInternalV1_0(
+ hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+ const std::function<void()>& completionCallback);
};
// Wrapper for the HDIL Vibrator HAL v1.1.
class HidlHalWrapperV1_1 : public HidlHalWrapperV1_0 {
public:
- explicit HidlHalWrapperV1_1(sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
- : HidlHalWrapperV1_0(handleV1_0),
+ HidlHalWrapperV1_1(std::shared_ptr<CallbackScheduler> scheduler,
+ sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
+ : HidlHalWrapperV1_0(std::move(scheduler), handleV1_0),
mHandleV1_1(hardware::vibrator::V1_1::IVibrator::castFrom(handleV1_0)) {}
+ virtual ~HidlHalWrapperV1_1() = default;
virtual HalResult<std::chrono::milliseconds> performEffect(
hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
@@ -240,14 +273,20 @@
protected:
const sp<hardware::vibrator::V1_1::IVibrator> mHandleV1_1;
+
+ HalResult<std::chrono::milliseconds> performInternalV1_1(
+ hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+ const std::function<void()>& completionCallback);
};
// Wrapper for the HDIL Vibrator HAL v1.2.
class HidlHalWrapperV1_2 : public HidlHalWrapperV1_1 {
public:
- explicit HidlHalWrapperV1_2(sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
- : HidlHalWrapperV1_1(handleV1_0),
+ HidlHalWrapperV1_2(std::shared_ptr<CallbackScheduler> scheduler,
+ sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
+ : HidlHalWrapperV1_1(std::move(scheduler), handleV1_0),
mHandleV1_2(hardware::vibrator::V1_2::IVibrator::castFrom(handleV1_0)) {}
+ virtual ~HidlHalWrapperV1_2() = default;
virtual HalResult<std::chrono::milliseconds> performEffect(
hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
@@ -255,14 +294,20 @@
protected:
const sp<hardware::vibrator::V1_2::IVibrator> mHandleV1_2;
+
+ HalResult<std::chrono::milliseconds> performInternalV1_2(
+ hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+ const std::function<void()>& completionCallback);
};
// Wrapper for the HDIL Vibrator HAL v1.3.
class HidlHalWrapperV1_3 : public HidlHalWrapperV1_2 {
public:
- explicit HidlHalWrapperV1_3(sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
- : HidlHalWrapperV1_2(handleV1_0),
+ HidlHalWrapperV1_3(std::shared_ptr<CallbackScheduler> scheduler,
+ sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
+ : HidlHalWrapperV1_2(std::move(scheduler), handleV1_0),
mHandleV1_3(hardware::vibrator::V1_3::IVibrator::castFrom(handleV1_0)) {}
+ virtual ~HidlHalWrapperV1_3() = default;
virtual HalResult<void> setExternalControl(bool enabled) override;
@@ -274,6 +319,9 @@
const sp<hardware::vibrator::V1_3::IVibrator> mHandleV1_3;
virtual HalResult<Capabilities> getCapabilitiesInternal() override;
+ HalResult<std::chrono::milliseconds> performInternalV1_3(
+ hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+ const std::function<void()>& completionCallback);
};
// -------------------------------------------------------------------------------------------------
diff --git a/services/vibratorservice/test/Android.bp b/services/vibratorservice/test/Android.bp
index 7c038e9..fa399ad 100644
--- a/services/vibratorservice/test/Android.bp
+++ b/services/vibratorservice/test/Android.bp
@@ -16,6 +16,7 @@
name: "libvibratorservice_test",
test_suites: ["device-tests"],
srcs: [
+ "VibratorCallbackSchedulerTest.cpp",
"VibratorHalWrapperAidlTest.cpp",
"VibratorHalWrapperHidlV1_0Test.cpp",
"VibratorHalWrapperHidlV1_1Test.cpp",
diff --git a/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp b/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp
new file mode 100644
index 0000000..aaeb8f9
--- /dev/null
+++ b/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VibratorHalWrapperAidlTest"
+
+#include <android-base/thread_annotations.h>
+#include <android/hardware/vibrator/IVibrator.h>
+#include <condition_variable>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utils/Log.h>
+#include <thread>
+
+#include <vibratorservice/VibratorCallbackScheduler.h>
+
+using std::chrono::milliseconds;
+using std::chrono::steady_clock;
+using std::chrono::time_point;
+
+using namespace android;
+using namespace std::chrono_literals;
+using namespace testing;
+
+// -------------------------------------------------------------------------------------------------
+
+class VibratorCallbackSchedulerTest : public Test {
+public:
+ void SetUp() override {
+ mScheduler = std::make_unique<vibrator::CallbackScheduler>();
+ std::lock_guard<std::mutex> lock(mMutex);
+ mExpiredCallbacks.clear();
+ }
+
+protected:
+ std::mutex mMutex;
+ std::condition_variable_any mCondition;
+ std::unique_ptr<vibrator::CallbackScheduler> mScheduler = nullptr;
+ std::vector<int32_t> mExpiredCallbacks GUARDED_BY(mMutex);
+
+ std::function<void()> createCallback(int32_t id) {
+ return [=]() {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mExpiredCallbacks.push_back(id);
+ }
+ mCondition.notify_all();
+ };
+ }
+
+ std::vector<int32_t> getExpiredCallbacks() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return std::vector<int32_t>(mExpiredCallbacks);
+ }
+
+ bool waitForCallbacks(uint32_t callbackCount, milliseconds timeout) {
+ time_point<steady_clock> expiration = steady_clock::now() + timeout;
+ while (steady_clock::now() < expiration) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (callbackCount <= mExpiredCallbacks.size()) {
+ return true;
+ }
+ mCondition.wait_until(mMutex, expiration);
+ }
+ return false;
+ }
+};
+
+// -------------------------------------------------------------------------------------------------
+
+TEST_F(VibratorCallbackSchedulerTest, TestScheduleRunsOnlyAfterDelay) {
+ mScheduler->schedule(createCallback(1), 15ms);
+
+ // Not triggered before delay.
+ ASSERT_FALSE(waitForCallbacks(1, 10ms));
+ ASSERT_TRUE(getExpiredCallbacks().empty());
+
+ ASSERT_TRUE(waitForCallbacks(1, 10ms));
+ ASSERT_THAT(getExpiredCallbacks(), ElementsAre(1));
+}
+
+TEST_F(VibratorCallbackSchedulerTest, TestScheduleMultipleCallbacksRunsInDelayOrder) {
+ mScheduler->schedule(createCallback(1), 10ms);
+ mScheduler->schedule(createCallback(2), 5ms);
+ mScheduler->schedule(createCallback(3), 1ms);
+
+ ASSERT_TRUE(waitForCallbacks(3, 15ms));
+ ASSERT_THAT(getExpiredCallbacks(), ElementsAre(3, 2, 1));
+}
+
+TEST_F(VibratorCallbackSchedulerTest, TestScheduleInParallelRunsInDelayOrder) {
+ std::vector<std::thread> threads;
+ for (int i = 0; i < 5; i++) {
+ threads.push_back(std::thread(
+ [=]() { mScheduler->schedule(createCallback(i), milliseconds(10 + 2 * i)); }));
+ }
+ std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+ ASSERT_TRUE(waitForCallbacks(5, 25ms));
+ ASSERT_THAT(getExpiredCallbacks(), ElementsAre(0, 1, 2, 3, 4));
+}
+
+TEST_F(VibratorCallbackSchedulerTest, TestDestructorDropsPendingCallbacksAndKillsThread) {
+ mScheduler->schedule(createCallback(1), 5ms);
+ mScheduler.reset(nullptr);
+
+ // Should time out waiting for callback to run.
+ ASSERT_FALSE(waitForCallbacks(1, 10ms));
+ ASSERT_TRUE(getExpiredCallbacks().empty());
+}
diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
index 6db449a..0f2d7bc 100644
--- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -24,6 +24,7 @@
#include <utils/Log.h>
#include <thread>
+#include <vibratorservice/VibratorCallbackScheduler.h>
#include <vibratorservice/VibratorHalWrapper.h>
#include "test_utils.h"
@@ -88,11 +89,13 @@
void SetUp() override {
mMockBinder = new StrictMock<MockBinder>();
mMockHal = new StrictMock<MockIVibrator>();
- mWrapper = std::make_unique<vibrator::AidlHalWrapper>(mMockHal);
+ mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
+ mWrapper = std::make_unique<vibrator::AidlHalWrapper>(mMockScheduler, mMockHal);
ASSERT_NE(mWrapper, nullptr);
}
protected:
+ std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
sp<StrictMock<MockIVibrator>> mMockHal = nullptr;
sp<StrictMock<MockBinder>> mMockBinder = nullptr;
@@ -124,9 +127,13 @@
ASSERT_TRUE(mWrapper->ping().isFailed());
}
-TEST_F(VibratorHalWrapperAidlTest, TestOn) {
+TEST_F(VibratorHalWrapperAidlTest, TestOnWithCallbackSupport) {
{
InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), Return(Status())));
EXPECT_CALL(*mMockHal.get(), on(Eq(10), _))
.Times(Exactly(1))
.WillRepeatedly(DoAll(TriggerCallbackInArg1(), Return(Status())));
@@ -146,11 +153,46 @@
ASSERT_EQ(1, *callbackCounter.get());
ASSERT_TRUE(mWrapper->on(100ms, callback).isUnsupported());
- // Callback not triggered
+ // Callback not triggered for unsupported
ASSERT_EQ(1, *callbackCounter.get());
ASSERT_TRUE(mWrapper->on(1000ms, callback).isFailed());
- // Callback not triggered
+ // Callback not triggered on failure
+ ASSERT_EQ(1, *callbackCounter.get());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestOnWithoutCallbackSupport) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ DoAll(SetArgPointee<0>(IVibrator::CAP_COMPOSE_EFFECTS), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), on(Eq(10), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(Status()));
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+ EXPECT_CALL(*mMockHal.get(), on(Eq(11), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(
+ Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ EXPECT_CALL(*mMockHal.get(), on(Eq(12), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
+ }
+
+ std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+ auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+ ASSERT_TRUE(mWrapper->on(10ms, callback).isOk());
+ ASSERT_EQ(1, *callbackCounter.get());
+
+ ASSERT_TRUE(mWrapper->on(11ms, callback).isUnsupported());
+ ASSERT_TRUE(mWrapper->on(12ms, callback).isFailed());
+
+ // Callback not triggered for unsupported and on failure
ASSERT_EQ(1, *callbackCounter.get());
}
@@ -274,6 +316,10 @@
}));
}
std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+ auto result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(vibrator::Capabilities::ON_CALLBACK, result.value());
}
TEST_F(VibratorHalWrapperAidlTest, TestGetSupportedEffectsDoesNotCacheFailedResult) {
@@ -314,11 +360,19 @@
}));
}
std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+ auto result = mWrapper->getSupportedEffects();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(supportedEffects, result.value());
}
-TEST_F(VibratorHalWrapperAidlTest, TestPerformEffect) {
+TEST_F(VibratorHalWrapperAidlTest, TestPerformEffectWithCallbackSupport) {
{
InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ DoAll(SetArgPointee<0>(IVibrator::CAP_PERFORM_CALLBACK), Return(Status())));
EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::CLICK), Eq(EffectStrength::LIGHT), _, _))
.Times(Exactly(1))
.WillRepeatedly(
@@ -342,12 +396,52 @@
result = mWrapper->performEffect(Effect::POP, EffectStrength::MEDIUM, callback);
ASSERT_TRUE(result.isUnsupported());
- // Callback not triggered
+ // Callback not triggered for unsupported
ASSERT_EQ(1, *callbackCounter.get());
result = mWrapper->performEffect(Effect::THUD, EffectStrength::STRONG, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
+ // Callback not triggered on failure
+ ASSERT_EQ(1, *callbackCounter.get());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestPerformEffectWithoutCallbackSupport) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::CLICK), Eq(EffectStrength::LIGHT), _, _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(10), Return(Status())));
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+ EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::POP), Eq(EffectStrength::MEDIUM), _, _))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(
+ Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::THUD), Eq(EffectStrength::STRONG), _, _))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
+ }
+
+ std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+ auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+ auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
+
+ result = mWrapper->performEffect(Effect::POP, EffectStrength::MEDIUM, callback);
+ ASSERT_TRUE(result.isUnsupported());
+
+ result = mWrapper->performEffect(Effect::THUD, EffectStrength::STRONG, callback);
+ ASSERT_TRUE(result.isFailed());
+
+ // Callback not triggered for unsupported and on failure
ASSERT_EQ(1, *callbackCounter.get());
}
@@ -383,11 +477,11 @@
result = mWrapper->performComposedEffect(singleEffect, callback);
ASSERT_TRUE(result.isUnsupported());
- // Callback not triggered
+ // Callback not triggered for unsupported
ASSERT_EQ(1, *callbackCounter.get());
result = mWrapper->performComposedEffect(multipleEffects, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
+ // Callback not triggered on failure
ASSERT_EQ(1, *callbackCounter.get());
}
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
index 7f1016f..7eb4059 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
@@ -24,6 +24,7 @@
#include <utils/Log.h>
#include <thread>
+#include <vibratorservice/VibratorCallbackScheduler.h>
#include <vibratorservice/VibratorHalWrapper.h>
#include "test_utils.h"
@@ -59,11 +60,13 @@
public:
void SetUp() override {
mMockHal = new StrictMock<MockIVibratorV1_0>();
- mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_0>(mMockHal);
+ mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
+ mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_0>(mMockScheduler, mMockHal);
ASSERT_NE(mWrapper, nullptr);
}
protected:
+ std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
sp<StrictMock<MockIVibratorV1_0>> mMockHal = nullptr;
};
@@ -89,17 +92,20 @@
.Times(Exactly(1))
.WillRepeatedly(
[](uint32_t) { return hardware::Return<V1_0::Status>(V1_0::Status::OK); });
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(1ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(10))))
.Times(Exactly(1))
.WillRepeatedly([](uint32_t) {
return hardware::Return<V1_0::Status>(V1_0::Status::UNSUPPORTED_OPERATION);
});
- EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(100))))
+ EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(11))))
.Times(Exactly(1))
.WillRepeatedly([](uint32_t) {
return hardware::Return<V1_0::Status>(V1_0::Status::BAD_VALUE);
});
- EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(1000))))
+ EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(12))))
.Times(Exactly(1))
.WillRepeatedly([](uint32_t) {
return hardware::Return<V1_0::Status>(hardware::Status::fromExceptionCode(-1));
@@ -110,20 +116,14 @@
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
ASSERT_TRUE(mWrapper->on(1ms, callback).isOk());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(1, *callbackCounter.get());
ASSERT_TRUE(mWrapper->on(10ms, callback).isUnsupported());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_TRUE(mWrapper->on(11ms, callback).isFailed());
+ ASSERT_TRUE(mWrapper->on(12ms, callback).isFailed());
- ASSERT_TRUE(mWrapper->on(100ms, callback).isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
-
- ASSERT_TRUE(mWrapper->on(1000ms, callback).isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
+ // Callback not triggered for unsupported and on failure
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_0Test, TestOff) {
@@ -226,6 +226,10 @@
}));
}
std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+ auto result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
}
TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetSupportedEffectsUnsupported) {
@@ -240,9 +244,12 @@
.Times(Exactly(1))
.WillRepeatedly(
[](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_0::perform_cb cb) {
- cb(V1_0::Status::OK, 100);
+ cb(V1_0::Status::OK, 10);
return hardware::Return<void>();
});
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
EXPECT_CALL(*mMockHal.get(),
perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::MEDIUM), _))
.Times(Exactly(1))
@@ -269,24 +276,20 @@
auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(100ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
result = mWrapper->performEffect(Effect::CLICK, EffectStrength::MEDIUM, callback);
ASSERT_TRUE(result.isUnsupported());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
result = mWrapper->performEffect(Effect::CLICK, EffectStrength::STRONG, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
result = mWrapper->performEffect(Effect::CLICK, EffectStrength::STRONG, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
+
+ // Callback not triggered for unsupported and on failure
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformEffectUnsupported) {
@@ -295,6 +298,7 @@
// Using TICK that is only available in v1.1
auto result = mWrapper->performEffect(Effect::TICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isUnsupported());
+ // No callback is triggered.
ASSERT_EQ(0, *callbackCounter.get());
}
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_1Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_1Test.cpp
index d0531e6..d887efc 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_1Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_1Test.cpp
@@ -23,6 +23,7 @@
#include <utils/Log.h>
+#include <vibratorservice/VibratorCallbackScheduler.h>
#include <vibratorservice/VibratorHalWrapper.h>
#include "test_utils.h"
@@ -58,11 +59,13 @@
public:
void SetUp() override {
mMockHal = new StrictMock<MockIVibratorV1_1>();
- mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_1>(mMockHal);
+ mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
+ mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_1>(mMockScheduler, mMockHal);
ASSERT_NE(mWrapper, nullptr);
}
protected:
+ std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
sp<StrictMock<MockIVibratorV1_1>> mMockHal = nullptr;
};
@@ -70,23 +73,28 @@
// -------------------------------------------------------------------------------------------------
TEST_F(VibratorHalWrapperHidlV1_1Test, TestPerformEffectV1_0) {
- EXPECT_CALL(*mMockHal.get(),
- perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_1::perform_cb cb) {
- cb(V1_0::Status::OK, 100);
- return hardware::Return<void>();
- });
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(),
+ perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_1::perform_cb cb) {
+ cb(V1_0::Status::OK, 10);
+ return hardware::Return<void>();
+ });
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+ }
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(100ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_1Test, TestPerformEffectV1_1) {
@@ -100,6 +108,9 @@
cb(V1_0::Status::OK, 10);
return hardware::Return<void>();
});
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
EXPECT_CALL(*mMockHal.get(),
perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::MEDIUM), _))
.Times(Exactly(1))
@@ -128,23 +139,19 @@
auto result = mWrapper->performEffect(Effect::TICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
ASSERT_EQ(10ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(1, *callbackCounter.get());
result = mWrapper->performEffect(Effect::TICK, EffectStrength::MEDIUM, callback);
ASSERT_TRUE(result.isUnsupported());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
result = mWrapper->performEffect(Effect::TICK, EffectStrength::STRONG, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
result = mWrapper->performEffect(Effect::TICK, EffectStrength::STRONG, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
+
+ // Callback not triggered for unsupported and on failure
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_1Test, TestPerformEffectUnsupported) {
@@ -153,5 +160,6 @@
// Using THUD that is only available in v1.2
auto result = mWrapper->performEffect(Effect::THUD, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isUnsupported());
+ // No callback is triggered.
ASSERT_EQ(0, *callbackCounter.get());
}
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_2Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_2Test.cpp
index 5d2c269..26d9350 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_2Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_2Test.cpp
@@ -23,6 +23,7 @@
#include <utils/Log.h>
+#include <vibratorservice/VibratorCallbackScheduler.h>
#include <vibratorservice/VibratorHalWrapper.h>
#include "test_utils.h"
@@ -61,11 +62,13 @@
public:
void SetUp() override {
mMockHal = new StrictMock<MockIVibratorV1_2>();
- mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_2>(mMockHal);
+ mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
+ mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_2>(mMockScheduler, mMockHal);
ASSERT_NE(mWrapper, nullptr);
}
protected:
+ std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
sp<StrictMock<MockIVibratorV1_2>> mMockHal = nullptr;
};
@@ -73,43 +76,53 @@
// -------------------------------------------------------------------------------------------------
TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectV1_0) {
- EXPECT_CALL(*mMockHal.get(),
- perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb cb) {
- cb(V1_0::Status::OK, 100);
- return hardware::Return<void>();
- });
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(),
+ perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb cb) {
+ cb(V1_0::Status::OK, 10);
+ return hardware::Return<void>();
+ });
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+ }
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(100ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectV1_1) {
- EXPECT_CALL(*mMockHal.get(),
- perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_1::Effect_1_1, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb cb) {
- cb(V1_0::Status::OK, 100);
- return hardware::Return<void>();
- });
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(),
+ perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::LIGHT), _))
+ .Times(Exactly(1))
+ .WillRepeatedly([](V1_1::Effect_1_1, V1_0::EffectStrength,
+ MockIVibratorV1_2::perform_cb cb) {
+ cb(V1_0::Status::OK, 10);
+ return hardware::Return<void>();
+ });
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+ }
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
auto result = mWrapper->performEffect(Effect::TICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(100ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectV1_2) {
@@ -120,9 +133,12 @@
.Times(Exactly(1))
.WillRepeatedly(
[](V1_2::Effect, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb cb) {
- cb(V1_0::Status::OK, 100);
+ cb(V1_0::Status::OK, 10);
return hardware::Return<void>();
});
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
EXPECT_CALL(*mMockHal.get(),
perform_1_2(Eq(V1_2::Effect::THUD), Eq(V1_0::EffectStrength::MEDIUM), _))
.Times(Exactly(1))
@@ -149,24 +165,20 @@
auto result = mWrapper->performEffect(Effect::THUD, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(100ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
result = mWrapper->performEffect(Effect::THUD, EffectStrength::MEDIUM, callback);
ASSERT_TRUE(result.isUnsupported());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
result = mWrapper->performEffect(Effect::THUD, EffectStrength::STRONG, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
result = mWrapper->performEffect(Effect::THUD, EffectStrength::STRONG, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
+
+ // Callback not triggered for unsupported and on failure
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectUnsupported) {
@@ -175,5 +187,6 @@
// Using TEXTURE_TICK that is only available in v1.3
auto result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isUnsupported());
+ // No callback is triggered.
ASSERT_EQ(0, *callbackCounter.get());
}
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp
index a799257..5de6257 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp
@@ -24,6 +24,7 @@
#include <utils/Log.h>
#include <thread>
+#include <vibratorservice/VibratorCallbackScheduler.h>
#include <vibratorservice/VibratorHalWrapper.h>
#include "test_utils.h"
@@ -68,11 +69,13 @@
public:
void SetUp() override {
mMockHal = new StrictMock<MockIVibratorV1_3>();
- mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_3>(mMockHal);
+ mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
+ mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_3>(mMockScheduler, mMockHal);
ASSERT_NE(mWrapper, nullptr);
}
protected:
+ std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
sp<StrictMock<MockIVibratorV1_3>> mMockHal = nullptr;
};
@@ -210,6 +213,10 @@
}));
}
std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+ auto result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
}
TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetCapabilitiesDoesNotCacheFailedResult) {
@@ -258,63 +265,78 @@
}
TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_0) {
- EXPECT_CALL(*mMockHal.get(),
- perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
- cb(V1_0::Status::OK, 100);
- return hardware::Return<void>();
- });
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(),
+ perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
+ cb(V1_0::Status::OK, 10);
+ return hardware::Return<void>();
+ });
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+ }
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(100ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_1) {
- EXPECT_CALL(*mMockHal.get(),
- perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_1::Effect_1_1, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
- cb(V1_0::Status::OK, 100);
- return hardware::Return<void>();
- });
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(),
+ perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::LIGHT), _))
+ .Times(Exactly(1))
+ .WillRepeatedly([](V1_1::Effect_1_1, V1_0::EffectStrength,
+ MockIVibratorV1_3::perform_cb cb) {
+ cb(V1_0::Status::OK, 10);
+ return hardware::Return<void>();
+ });
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+ }
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
auto result = mWrapper->performEffect(Effect::TICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(100ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_2) {
- EXPECT_CALL(*mMockHal.get(),
- perform_1_2(Eq(V1_2::Effect::THUD), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_2::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
- cb(V1_0::Status::OK, 100);
- return hardware::Return<void>();
- });
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(),
+ perform_1_2(Eq(V1_2::Effect::THUD), Eq(V1_0::EffectStrength::LIGHT), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ [](V1_2::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
+ cb(V1_0::Status::OK, 10);
+ return hardware::Return<void>();
+ });
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+ }
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
auto result = mWrapper->performEffect(Effect::THUD, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(100ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_3) {
@@ -328,6 +350,9 @@
cb(V1_0::Status::OK, 10);
return hardware::Return<void>();
});
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
EXPECT_CALL(*mMockHal.get(),
perform_1_3(Eq(V1_3::Effect::TEXTURE_TICK), Eq(V1_0::EffectStrength::MEDIUM),
_))
@@ -357,21 +382,17 @@
auto result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
ASSERT_EQ(10ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(1, *callbackCounter.get());
result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::MEDIUM, callback);
ASSERT_TRUE(result.isUnsupported());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::STRONG, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::STRONG, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
+
+ // Callback not triggered for unsupported and on failure
+ ASSERT_EQ(1, *callbackCounter.get());
}
diff --git a/services/vibratorservice/test/test_utils.h b/services/vibratorservice/test/test_utils.h
index fc9b364..8d0b22e 100644
--- a/services/vibratorservice/test/test_utils.h
+++ b/services/vibratorservice/test/test_utils.h
@@ -28,6 +28,20 @@
using ::android::hardware::vibrator::CompositeEffect;
using ::android::hardware::vibrator::CompositePrimitive;
+// -------------------------------------------------------------------------------------------------
+
+class MockCallbackScheduler : public vibrator::CallbackScheduler {
+public:
+ MOCK_METHOD(void, schedule, (std::function<void()> callback, std::chrono::milliseconds delay),
+ (override));
+};
+
+ACTION(TriggerSchedulerCallback) {
+ arg0();
+}
+
+// -------------------------------------------------------------------------------------------------
+
class TestFactory {
public:
static CompositeEffect createCompositeEffect(CompositePrimitive primitive,
@@ -48,6 +62,8 @@
~TestFactory() = delete;
};
+// -------------------------------------------------------------------------------------------------
+
} // namespace vibrator
} // namespace android