Return duration for composed effects.
Use IVibrator.getPrimitiveDuration to calculate the duration a composed
effect should have and return this result to the service.
Bug: 177807015
Test: atest libvibratorservice_test
Change-Id: I606fdb59818a13e138e1cde36172ea74050a8a75
diff --git a/services/vibratorservice/VibratorHalController.cpp b/services/vibratorservice/VibratorHalController.cpp
index bcd9957..537e49b 100644
--- a/services/vibratorservice/VibratorHalController.cpp
+++ b/services/vibratorservice/VibratorHalController.cpp
@@ -217,10 +217,10 @@
return apply(performEffectFn, "performEffect");
}
-HalResult<void> HalController::performComposedEffect(
+HalResult<milliseconds> HalController::performComposedEffect(
const std::vector<CompositeEffect>& primitiveEffects,
const std::function<void()>& completionCallback) {
- hal_fn<void> performComposedEffectFn = [&](std::shared_ptr<HalWrapper> hal) {
+ hal_fn<milliseconds> performComposedEffectFn = [&](std::shared_ptr<HalWrapper> hal) {
return hal->performComposedEffect(primitiveEffects, completionCallback);
};
return apply(performComposedEffectFn, "performComposedEffect");
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index 7fee82f..6faab38 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -224,12 +224,45 @@
return ret;
}
-HalResult<void> AidlHalWrapper::performComposedEffect(
+HalResult<milliseconds> 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(getHal()->compose(primitiveEffects, cb));
+ milliseconds duration(0);
+ for (const auto& effect : primitiveEffects) {
+ auto durationResult = getPrimitiveDuration(effect.primitive);
+ if (durationResult.isOk()) {
+ duration += durationResult.value();
+ }
+ duration += milliseconds(effect.delayMs);
+ }
+ return HalResult<milliseconds>::fromStatus(getHal()->compose(primitiveEffects, cb), duration);
+}
+
+HalResult<milliseconds> AidlHalWrapper::getPrimitiveDuration(CompositePrimitive primitive) {
+ std::lock_guard<std::mutex> lock(mSupportedPrimitivesMutex);
+ if (mPrimitiveDurations.empty()) {
+ constexpr auto primitiveRange = enum_range<CompositePrimitive>();
+ constexpr auto primitiveCount = std::distance(primitiveRange.begin(), primitiveRange.end());
+ mPrimitiveDurations.resize(primitiveCount);
+ }
+ auto primitiveIdx = static_cast<size_t>(primitive);
+ if (primitiveIdx >= mPrimitiveDurations.size()) {
+ // Safety check, should not happen if enum_range is correct.
+ return HalResult<milliseconds>::unsupported();
+ }
+ auto& cache = mPrimitiveDurations[primitiveIdx];
+ if (cache.has_value()) {
+ return HalResult<milliseconds>::ok(*cache);
+ }
+ int32_t duration;
+ auto result = getHal()->getPrimitiveDuration(primitive, &duration);
+ if (result.isOk()) {
+ // Cache copy of returned value.
+ cache.emplace(duration);
+ }
+ return HalResult<milliseconds>::fromStatus(result, milliseconds(duration));
}
HalResult<Capabilities> AidlHalWrapper::getCapabilitiesInternal() {
@@ -333,10 +366,10 @@
}
template <typename I>
-HalResult<void> HidlHalWrapper<I>::performComposedEffect(const std::vector<CompositeEffect>&,
- const std::function<void()>&) {
+HalResult<std::chrono::milliseconds> HidlHalWrapper<I>::performComposedEffect(
+ const std::vector<CompositeEffect>&, const std::function<void()>&) {
ALOGV("Skipped composed effect because Vibrator HAL AIDL is not available");
- return HalResult<void>::unsupported();
+ return HalResult<std::chrono::milliseconds>::unsupported();
}
template <typename I>
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalController.h b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
index c405545..16d571d 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalController.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
@@ -77,7 +77,7 @@
hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
const std::function<void()>& completionCallback) final override;
- HalResult<void> performComposedEffect(
+ HalResult<std::chrono::milliseconds> performComposedEffect(
const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
const std::function<void()>& completionCallback) final override;
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index 638b483..e22ad34 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -189,7 +189,7 @@
hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
const std::function<void()>& completionCallback) = 0;
- virtual HalResult<void> performComposedEffect(
+ virtual HalResult<std::chrono::milliseconds> performComposedEffect(
const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
const std::function<void()>& completionCallback) = 0;
@@ -236,7 +236,7 @@
hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
const std::function<void()>& completionCallback) override final;
- HalResult<void> performComposedEffect(
+ HalResult<std::chrono::milliseconds> performComposedEffect(
const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
const std::function<void()>& completionCallback) override final;
@@ -252,6 +252,12 @@
GUARDED_BY(mSupportedEffectsMutex);
std::optional<std::vector<hardware::vibrator::CompositePrimitive>> mSupportedPrimitives
GUARDED_BY(mSupportedPrimitivesMutex);
+ std::vector<std::optional<std::chrono::milliseconds>> mPrimitiveDurations
+ GUARDED_BY(mSupportedPrimitivesMutex);
+
+ // Loads and caches from IVibrator.
+ HalResult<std::chrono::milliseconds> getPrimitiveDuration(
+ hardware::vibrator::CompositePrimitive primitive);
// Loads directly from IVibrator handle, skipping caches.
HalResult<Capabilities> getCapabilitiesInternal();
@@ -287,7 +293,7 @@
HalResult<std::vector<hardware::vibrator::CompositePrimitive>> getSupportedPrimitives()
override final;
- HalResult<void> performComposedEffect(
+ HalResult<std::chrono::milliseconds> performComposedEffect(
const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
const std::function<void()>& completionCallback) override final;
diff --git a/services/vibratorservice/test/VibratorHalControllerTest.cpp b/services/vibratorservice/test/VibratorHalControllerTest.cpp
index 2d9d0d6..c4b39ed 100644
--- a/services/vibratorservice/test/VibratorHalControllerTest.cpp
+++ b/services/vibratorservice/test/VibratorHalControllerTest.cpp
@@ -71,7 +71,7 @@
(Effect effect, EffectStrength strength,
const std::function<void()>& completionCallback),
(override));
- MOCK_METHOD(vibrator::HalResult<void>, performComposedEffect,
+ MOCK_METHOD(vibrator::HalResult<milliseconds>, performComposedEffect,
(const std::vector<CompositeEffect>& primitiveEffects,
const std::function<void()>& completionCallback),
(override));
@@ -143,7 +143,7 @@
.WillRepeatedly(Return(durationResult));
EXPECT_CALL(*mMockHal.get(), performComposedEffect(Eq(compositeEffects), _))
.Times(Exactly(cardinality))
- .WillRepeatedly(Return(voidResult));
+ .WillRepeatedly(Return(durationResult));
if (cardinality > 1) {
// One reconnection call after each failure.
@@ -208,7 +208,10 @@
ASSERT_TRUE(performEffectResult.isOk());
ASSERT_EQ(100ms, performEffectResult.value());
- ASSERT_TRUE(mController->performComposedEffect(compositeEffects, []() {}).isOk());
+ auto performComposedEffectResult =
+ mController->performComposedEffect(compositeEffects, []() {});
+ ASSERT_TRUE(performComposedEffectResult.isOk());
+ ASSERT_EQ(100ms, performComposedEffectResult.value());
ASSERT_EQ(1, mConnectCounter);
}
diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
index 96b76ba..a34cc7c 100644
--- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -504,10 +504,21 @@
EXPECT_CALL(*mMockHal.get(), compose(Eq(emptyEffects), _))
.Times(Exactly(1))
.WillRepeatedly(DoAll(TriggerCallbackInArg1(), Return(Status())));
+
+ EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::CLICK), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(1), Return(Status())));
EXPECT_CALL(*mMockHal.get(), compose(Eq(singleEffect), _))
.Times(Exactly(1))
.WillRepeatedly(Return(
Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+
+ EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::SPIN), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(2), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::THUD), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(3), Return(Status())));
EXPECT_CALL(*mMockHal.get(), compose(Eq(multipleEffects), _))
.Times(Exactly(1))
.WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
@@ -518,6 +529,7 @@
auto result = mWrapper->performComposedEffect(emptyEffects, callback);
ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(0ms, result.value());
ASSERT_EQ(1, *callbackCounter.get());
result = mWrapper->performComposedEffect(singleEffect, callback);
@@ -530,3 +542,40 @@
// Callback not triggered on failure
ASSERT_EQ(1, *callbackCounter.get());
}
+
+TEST_F(VibratorHalWrapperAidlTest, TestPerformComposedCachesPrimitiveDurationsAndIgnoresFailures) {
+ std::vector<CompositeEffect> multipleEffects;
+ multipleEffects.push_back(
+ vibrator::TestFactory::createCompositeEffect(CompositePrimitive::SPIN, 10ms, 0.5f));
+ multipleEffects.push_back(
+ vibrator::TestFactory::createCompositeEffect(CompositePrimitive::THUD, 100ms, 1.0f));
+
+ EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::SPIN), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(1), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::THUD), _))
+ .Times(Exactly(2))
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(2), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), compose(Eq(multipleEffects), _))
+ .Times(Exactly(3))
+ .WillRepeatedly(DoAll(TriggerCallbackInArg1(), Return(Status())));
+
+ std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+ auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+ auto result = mWrapper->performComposedEffect(multipleEffects, callback);
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(111ms, result.value()); // Failed primitive duration counted as 0.
+ ASSERT_EQ(1, *callbackCounter.get());
+
+ result = mWrapper->performComposedEffect(multipleEffects, callback);
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(113ms, result.value()); // Second fetch succeeds and returns primitive duration.
+ ASSERT_EQ(2, *callbackCounter.get());
+
+ result = mWrapper->performComposedEffect(multipleEffects, callback);
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(113ms, result.value()); // Cached durations not fetched again, same duration returned.
+ ASSERT_EQ(3, *callbackCounter.get());
+}