From d44007e625728e459772a6d5c806a5162fec362c Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 24 Oct 2019 18:12:46 -0700 Subject: [PATCH] Vibrator: Stable AIDL interface. This is from running: hidl2aidl android.hardware.vibrator@1.4 and then making several small modifications. Bug: 141828236 Test: dumpsys on cf Change-Id: I612e903c1e3f63f0470f8e5c827345c5b67d5645 --- .../compatibility_matrix.current.xml | 7 + vibrator/staidl/Android.bp | 14 ++ .../android/hardware/vibrator/Effect.aidl | 86 +++++++ .../hardware/vibrator/EffectStrength.aidl | 25 ++ .../android/hardware/vibrator/IVibrator.aidl | 101 ++++++++ .../hardware/vibrator/IVibratorCallback.aidl | 22 ++ vibrator/staidl/default/Android.bp | 13 ++ vibrator/staidl/default/Vibrator.cpp | 97 ++++++++ vibrator/staidl/default/Vibrator.h | 41 ++++ vibrator/staidl/default/main.cpp | 35 +++ vibrator/staidl/default/vibrator-default.rc | 4 + vibrator/staidl/default/vibrator-default.xml | 6 + vibrator/staidl/vts/Android.bp | 17 ++ .../staidl/vts/VtsHalVibratorTargetTest.cpp | 218 ++++++++++++++++++ 14 files changed, 686 insertions(+) create mode 100644 vibrator/staidl/Android.bp create mode 100644 vibrator/staidl/android/hardware/vibrator/Effect.aidl create mode 100644 vibrator/staidl/android/hardware/vibrator/EffectStrength.aidl create mode 100644 vibrator/staidl/android/hardware/vibrator/IVibrator.aidl create mode 100644 vibrator/staidl/android/hardware/vibrator/IVibratorCallback.aidl create mode 100644 vibrator/staidl/default/Android.bp create mode 100644 vibrator/staidl/default/Vibrator.cpp create mode 100644 vibrator/staidl/default/Vibrator.h create mode 100644 vibrator/staidl/default/main.cpp create mode 100644 vibrator/staidl/default/vibrator-default.rc create mode 100644 vibrator/staidl/default/vibrator-default.xml create mode 100644 vibrator/staidl/vts/Android.bp create mode 100644 vibrator/staidl/vts/VtsHalVibratorTargetTest.cpp diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index e6b70d8b27..9d68264cda 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -465,6 +465,13 @@ default + + android.hardware.vibrator + + IVibrator + default + + android.hardware.vibrator 1.0-4 diff --git a/vibrator/staidl/Android.bp b/vibrator/staidl/Android.bp new file mode 100644 index 0000000000..18468efb0b --- /dev/null +++ b/vibrator/staidl/Android.bp @@ -0,0 +1,14 @@ +aidl_interface { + name: "vintf-vibrator", + vendor_available: true, + srcs: [ + "android/hardware/vibrator/*.aidl", + ], + stability: "vintf", + backend: { + java: { + enabled: false, + }, + }, +} + diff --git a/vibrator/staidl/android/hardware/vibrator/Effect.aidl b/vibrator/staidl/android/hardware/vibrator/Effect.aidl new file mode 100644 index 0000000000..c60bfe98dc --- /dev/null +++ b/vibrator/staidl/android/hardware/vibrator/Effect.aidl @@ -0,0 +1,86 @@ +/* + * 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. + */ + +package android.hardware.vibrator; + +@VintfStability +@Backing(type="int") +enum Effect { + /** + * A single click effect. + * + * This effect should produce a sharp, crisp click sensation. + */ + CLICK, + /** + * A double click effect. + * + * This effect should produce two sequential sharp, crisp click sensations with a minimal + * amount of time between them. + */ + DOUBLE_CLICK, + /** + * A tick effect. + * + * This effect should produce a soft, short sensation, like the tick of a clock. + */ + TICK, + /** + * A thud effect. + * + * This effect should solid feeling bump, like the depression of a heavy mechanical button. + */ + THUD, + /** + * A pop effect. + * + * A short, quick burst effect. + */ + POP, + /** + * A heavy click effect. + * + * This should produce a sharp striking sensation, like a click but stronger. + */ + HEAVY_CLICK, + /** + * Ringtone patterns. They may correspond with the device's ringtone audio, or may just be a + * pattern that can be played as a ringtone with any audio, depending on the device. + */ + RINGTONE_1, + RINGTONE_2, + RINGTONE_3, + RINGTONE_4, + RINGTONE_5, + RINGTONE_6, + RINGTONE_7, + RINGTONE_8, + RINGTONE_9, + RINGTONE_10, + RINGTONE_11, + RINGTONE_12, + RINGTONE_13, + RINGTONE_14, + RINGTONE_15, + /** + * A soft tick effect meant to be played as a texture. + * + * A soft, short sensation like the tick of a clock. Unlike regular effects, texture effects + * are expected to be played multiple times in quick succession, replicating a specific + * texture to the user as a form of haptic feedback. + */ + TEXTURE_TICK, +} diff --git a/vibrator/staidl/android/hardware/vibrator/EffectStrength.aidl b/vibrator/staidl/android/hardware/vibrator/EffectStrength.aidl new file mode 100644 index 0000000000..66f70e57f3 --- /dev/null +++ b/vibrator/staidl/android/hardware/vibrator/EffectStrength.aidl @@ -0,0 +1,25 @@ +/* + * 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. + */ + +package android.hardware.vibrator; + +@VintfStability +@Backing(type="byte") +enum EffectStrength { + LIGHT, + MEDIUM, + STRONG, +} diff --git a/vibrator/staidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/staidl/android/hardware/vibrator/IVibrator.aidl new file mode 100644 index 0000000000..b2008f4be6 --- /dev/null +++ b/vibrator/staidl/android/hardware/vibrator/IVibrator.aidl @@ -0,0 +1,101 @@ +/* + * 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. + */ + +package android.hardware.vibrator; + +import android.hardware.vibrator.IVibratorCallback; +import android.hardware.vibrator.Effect; +import android.hardware.vibrator.EffectStrength; + +@VintfStability +interface IVibrator { + /** + * Whether on w/ IVibratorCallback can be used w/ 'on' function + */ + const int CAP_ON_CALLBACK = 1 << 0; + /** + * Whether on w/ IVibratorCallback can be used w/ 'perform' function + */ + const int CAP_PERFORM_CALLBACK = 1 << 1; + /** + * Whether setAmplitude is supported. + */ + const int CAP_AMPLITUDE_CONTROL = 1 << 2; + /** + * Whether setExternalControl is supported. + */ + const int CAP_EXTERNAL_CONTROL = 1 << 3; + + /** + * Determine capabilities of the vibrator HAL (CAP_* values) + */ + int getCapabilities(); + + /** + * Turn off vibrator + * + * Cancel a previously-started vibration, if any. + */ + void off(); + + /** + * Turn on vibrator + * + * This function must only be called after the previous timeout has expired or + * was canceled (through off()). + * @param timeoutMs number of milliseconds to vibrate. + * @param callback A callback used to inform Frameworks of state change, if supported. + */ + void on(in int timeoutMs, in IVibratorCallback callback); + + /** + * Fire off a predefined haptic event. + * + * @param effect The type of haptic event to trigger. + * @param strength The intensity of haptic event to trigger. + * @param callback A callback used to inform Frameworks of state change, if supported. + * @return The length of time the event is expected to take in + * milliseconds. This doesn't need to be perfectly accurate, but should be a reasonable + * approximation. + */ + int perform(in Effect effect, in EffectStrength strength, in IVibratorCallback callback); + + /** + * Sets the motor's vibrational amplitude. + * + * Changes the force being produced by the underlying motor. + * + * @param amplitude The unitless force setting. Note that this number must + * be between 1 and 255, inclusive. If the motor does not + * have exactly 255 steps, it must do it's best to map it + * onto the number of steps it does have. + */ + void setAmplitude(in int amplitude); + + /** + * Enables/disables control override of vibrator to audio. + * + * When this API is set, the vibrator control should be ceded to audio system + * for haptic audio. While this is enabled, issuing of other commands to control + * the vibrator is unsupported and the resulting behavior is undefined. Amplitude + * control may or may not be supported and is reflected in the return value of + * supportsAmplitudeControl() while this is enabled. When this is disabled, the + * vibrator should resume to an off state. + * + * @param enabled Whether external control should be enabled or disabled. + */ + void setExternalControl(in boolean enabled); +} diff --git a/vibrator/staidl/android/hardware/vibrator/IVibratorCallback.aidl b/vibrator/staidl/android/hardware/vibrator/IVibratorCallback.aidl new file mode 100644 index 0000000000..43859de5d5 --- /dev/null +++ b/vibrator/staidl/android/hardware/vibrator/IVibratorCallback.aidl @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package android.hardware.vibrator; + +@VintfStability +interface IVibratorCallback { + oneway void onComplete(); +} diff --git a/vibrator/staidl/default/Android.bp b/vibrator/staidl/default/Android.bp new file mode 100644 index 0000000000..f3998872b2 --- /dev/null +++ b/vibrator/staidl/default/Android.bp @@ -0,0 +1,13 @@ +cc_binary { + name: "android.hardware.vibrator-service.example", + relative_install_path: "hw", + init_rc: ["vibrator-default.rc"], + vintf_fragments: ["vibrator-default.xml"], + vendor: true, + shared_libs: [ + "libbase", + "libbinder_ndk", + "vintf-vibrator-ndk_platform", + ], + srcs: ["main.cpp", "Vibrator.cpp"], +} diff --git a/vibrator/staidl/default/Vibrator.cpp b/vibrator/staidl/default/Vibrator.cpp new file mode 100644 index 0000000000..cdf8e0963b --- /dev/null +++ b/vibrator/staidl/default/Vibrator.cpp @@ -0,0 +1,97 @@ +/* + * 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 "Vibrator.h" + +#include +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace vibrator { + +ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) { + LOG(INFO) << "Vibrator reporting capabilities"; + *_aidl_return = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK | + IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::off() { + LOG(INFO) << "Vibrator off"; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs, + const std::shared_ptr& callback) { + LOG(INFO) << "Vibrator on for timeoutMs: " << timeoutMs; + if (callback != nullptr) { + std::thread([=] { + LOG(INFO) << "Starting on on another thread"; + usleep(timeoutMs * 1000); + LOG(INFO) << "Notifying on complete"; + callback->onComplete(); + }).detach(); + } + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength, + const std::shared_ptr& callback, + int32_t* _aidl_return) { + LOG(INFO) << "Vibrator perform"; + + if (effect != Effect::CLICK && effect != Effect::TICK) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + } + if (strength != EffectStrength::LIGHT && strength != EffectStrength::MEDIUM && + strength != EffectStrength::STRONG) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + } + + constexpr size_t kEffectMillis = 100; + + if (callback != nullptr) { + std::thread([=] { + LOG(INFO) << "Starting perform on another thread"; + usleep(kEffectMillis * 1000); + LOG(INFO) << "Notifying perform complete"; + callback->onComplete(); + }).detach(); + } + + *_aidl_return = kEffectMillis; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::setAmplitude(int32_t amplitude) { + LOG(INFO) << "Vibrator set amplitude: " << amplitude; + if (amplitude <= 0 || amplitude > 255) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT)); + } + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) { + LOG(INFO) << "Vibrator set external control: " << enabled; + return ndk::ScopedAStatus::ok(); +} + +} // namespace vibrator +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/vibrator/staidl/default/Vibrator.h b/vibrator/staidl/default/Vibrator.h new file mode 100644 index 0000000000..77e96e3e4d --- /dev/null +++ b/vibrator/staidl/default/Vibrator.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace vibrator { + +class Vibrator : public BnVibrator { + ndk::ScopedAStatus getCapabilities(int32_t* _aidl_return) override; + ndk::ScopedAStatus off() override; + ndk::ScopedAStatus on(int32_t timeoutMs, + const std::shared_ptr& callback) override; + ndk::ScopedAStatus perform(Effect effect, EffectStrength strength, + const std::shared_ptr& callback, + int32_t* _aidl_return) override; + ndk::ScopedAStatus setAmplitude(int32_t amplitude) override; + ndk::ScopedAStatus setExternalControl(bool enabled) override; +}; + +} // namespace vibrator +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/vibrator/staidl/default/main.cpp b/vibrator/staidl/default/main.cpp new file mode 100644 index 0000000000..d1619ff314 --- /dev/null +++ b/vibrator/staidl/default/main.cpp @@ -0,0 +1,35 @@ +/* + * 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 "Vibrator.h" + +#include +#include +#include + +using aidl::android::hardware::vibrator::Vibrator; + +int main() { + ABinderProcess_setThreadPoolMaxThreadCount(0); + std::shared_ptr vib = ndk::SharedRefBase::make(); + + const std::string instance = std::string() + Vibrator::descriptor + "/default"; + binder_status_t status = AServiceManager_addService(vib->asBinder().get(), instance.c_str()); + CHECK(status == STATUS_OK); + + ABinderProcess_joinThreadPool(); + return EXIT_FAILURE; // should not reach +} diff --git a/vibrator/staidl/default/vibrator-default.rc b/vibrator/staidl/default/vibrator-default.rc new file mode 100644 index 0000000000..d17f4683c3 --- /dev/null +++ b/vibrator/staidl/default/vibrator-default.rc @@ -0,0 +1,4 @@ +service vendor.vibrator-default /vendor/bin/hw/android.hardware.vibrator-service.example + class hal + user system + group system diff --git a/vibrator/staidl/default/vibrator-default.xml b/vibrator/staidl/default/vibrator-default.xml new file mode 100644 index 0000000000..49b11ec8da --- /dev/null +++ b/vibrator/staidl/default/vibrator-default.xml @@ -0,0 +1,6 @@ + + + android.hardware.vibrator + IVibrator/default + + diff --git a/vibrator/staidl/vts/Android.bp b/vibrator/staidl/vts/Android.bp new file mode 100644 index 0000000000..20d53c7bcf --- /dev/null +++ b/vibrator/staidl/vts/Android.bp @@ -0,0 +1,17 @@ +cc_test { + name: "VtsHalVibratorTargetTest", + defaults: [ + "VtsHalTargetTestDefaults", + "use_libaidlvintf_gtest_helper_static", + ], + srcs: ["VtsHalVibratorTargetTest.cpp"], + shared_libs: [ + "libbinder", + ], + static_libs: [ + "vintf-vibrator-cpp", + ], + test_suites: [ + "vts-core", + ], +} diff --git a/vibrator/staidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/staidl/vts/VtsHalVibratorTargetTest.cpp new file mode 100644 index 0000000000..33bcaf5c9a --- /dev/null +++ b/vibrator/staidl/vts/VtsHalVibratorTargetTest.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +#include +#include +#include +#include + +#include + +using android::ProcessState; +using android::sp; +using android::String16; +using android::binder::Status; +using android::hardware::vibrator::BnVibratorCallback; +using android::hardware::vibrator::Effect; +using android::hardware::vibrator::EffectStrength; +using android::hardware::vibrator::IVibrator; + +const std::vector kEffects = { + Effect::CLICK, Effect::DOUBLE_CLICK, Effect::TICK, Effect::THUD, + Effect::POP, Effect::HEAVY_CLICK, Effect::RINGTONE_1, Effect::RINGTONE_2, + Effect::RINGTONE_3, Effect::RINGTONE_4, Effect::RINGTONE_5, Effect::RINGTONE_6, + Effect::RINGTONE_7, Effect::RINGTONE_8, Effect::RINGTONE_9, Effect::RINGTONE_10, + Effect::RINGTONE_11, Effect::RINGTONE_12, Effect::RINGTONE_13, Effect::RINGTONE_14, + Effect::RINGTONE_15, Effect::TEXTURE_TICK}; + +const std::vector kEffectStrengths = {EffectStrength::LIGHT, EffectStrength::MEDIUM, + EffectStrength::STRONG}; + +const std::vector kInvalidEffects = { + static_cast(static_cast(*kEffects.begin()) - 1), + static_cast(static_cast(*kEffects.end()) + 1), +}; + +const std::vector kInvalidEffectStrengths = { + static_cast(static_cast(*kEffectStrengths.begin()) - 1), + static_cast(static_cast(*kEffectStrengths.end()) + 1), +}; + +class CompletionCallback : public BnVibratorCallback { + public: + CompletionCallback(const std::function& callback) : mCallback(callback) {} + Status onComplete() override { + mCallback(); + return Status::ok(); + } + + private: + std::function mCallback; +}; + +class VibratorAidl : public testing::TestWithParam { + public: + virtual void SetUp() override { + vibrator = android::waitForDeclaredService(String16(GetParam().c_str())); + ASSERT_NE(vibrator, nullptr); + ASSERT_TRUE(vibrator->getCapabilities(&capabilities).isOk()); + } + + sp vibrator; + int32_t capabilities; +}; + +TEST_P(VibratorAidl, OnThenOffBeforeTimeout) { + EXPECT_TRUE(vibrator->on(2000, nullptr /*callback*/).isOk()); + sleep(1); + EXPECT_TRUE(vibrator->off().isOk()); +} + +TEST_P(VibratorAidl, OnWithCallback) { + if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK)) return; + + std::promise completionPromise; + std::future completionFuture{completionPromise.get_future()}; + sp callback = + new CompletionCallback([&completionPromise] { completionPromise.set_value(); }); + uint32_t durationMs = 250; + std::chrono::milliseconds timeout{durationMs * 2}; + EXPECT_TRUE(vibrator->on(durationMs, callback).isOk()); + EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready); + EXPECT_TRUE(vibrator->off().isOk()); +} + +TEST_P(VibratorAidl, OnCallbackNotSupported) { + if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK)) { + sp callback = new CompletionCallback([] {}); + EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, vibrator->on(250, callback).exceptionCode()); + } +} + +TEST_P(VibratorAidl, ValidateEffect) { + for (Effect effect : kEffects) { + for (EffectStrength strength : kEffectStrengths) { + int32_t lengthMs = 0; + Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs); + EXPECT_TRUE(status.isOk() || + status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION); + if (status.isOk()) { + EXPECT_GT(lengthMs, 0); + } else { + EXPECT_EQ(lengthMs, 0); + } + } + } +} + +TEST_P(VibratorAidl, ValidateEffectWithCallback) { + if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK)) return; + + for (Effect effect : kEffects) { + for (EffectStrength strength : kEffectStrengths) { + std::promise completionPromise; + std::future completionFuture{completionPromise.get_future()}; + sp callback = + new CompletionCallback([&completionPromise] { completionPromise.set_value(); }); + int lengthMs; + Status status = vibrator->perform(effect, strength, callback, &lengthMs); + EXPECT_TRUE(status.isOk() || + status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION); + if (!status.isOk()) continue; + + std::chrono::milliseconds timeout{lengthMs * 2}; + EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready); + } + } +} + +TEST_P(VibratorAidl, ValidateEffectWithCallbackNotSupported) { + if (capabilities & IVibrator::CAP_PERFORM_CALLBACK) return; + + for (Effect effect : kEffects) { + for (EffectStrength strength : kEffectStrengths) { + sp callback = new CompletionCallback([] {}); + int lengthMs; + Status status = vibrator->perform(effect, strength, callback, &lengthMs); + EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode()); + EXPECT_EQ(lengthMs, 0); + } + } +} + +TEST_P(VibratorAidl, InvalidEffectsUnsupported) { + for (Effect effect : kInvalidEffects) { + for (EffectStrength strength : kInvalidEffectStrengths) { + int32_t lengthMs; + Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs); + EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION); + } + } +} + +TEST_P(VibratorAidl, ChangeVibrationAmplitude) { + if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) { + EXPECT_TRUE(vibrator->setAmplitude(1).isOk()); + EXPECT_TRUE(vibrator->on(2000, nullptr /*callback*/).isOk()); + EXPECT_TRUE(vibrator->setAmplitude(128).isOk()); + sleep(1); + EXPECT_TRUE(vibrator->setAmplitude(255).isOk()); + sleep(1); + } +} + +TEST_P(VibratorAidl, AmplitudeOutsideRangeFails) { + if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) { + EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(-1).exceptionCode()); + EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(0).exceptionCode()); + EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(256).exceptionCode()); + } +} + +TEST_P(VibratorAidl, AmplitudeReturnsUnsupportedMatchingCapabilities) { + if ((capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) == 0) { + EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, vibrator->setAmplitude(1).exceptionCode()); + } +} + +TEST_P(VibratorAidl, ChangeVibrationExternalControl) { + if (capabilities & IVibrator::CAP_EXTERNAL_CONTROL) { + EXPECT_TRUE(vibrator->setExternalControl(true).isOk()); + sleep(1); + EXPECT_TRUE(vibrator->setExternalControl(false).isOk()); + sleep(1); + } +} + +TEST_P(VibratorAidl, ExternalControlUnsupportedMatchingCapabilities) { + if ((capabilities & IVibrator::CAP_EXTERNAL_CONTROL) == 0) { + EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, + vibrator->setExternalControl(true).exceptionCode()); + } +} + +INSTANTIATE_TEST_SUITE_P(, VibratorAidl, + testing::ValuesIn(android::getAidlHalInstanceNames(IVibrator::descriptor)), + android::PrintInstanceNameToString); + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + ProcessState::self()->setThreadPoolMaxThreadCount(1); + ProcessState::self()->startThreadPool(); + return RUN_ALL_TESTS(); +}