vibrator: add getSupportedEffects

It's a real gap in this interface, since we need to call perform to
understand if an effect is supported.

Bug: 141828236
Test: atest VtsHalVibratorTargetTest
Change-Id: Iffbd9c0acf5e4c368767c7718025a4aef8f44ce3
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
index b2008f4..d21274b 100644
--- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
@@ -74,6 +74,14 @@
     int perform(in Effect effect, in EffectStrength strength, in IVibratorCallback callback);
 
     /**
+     * List supported effects.
+     *
+     * Return the effects which are supported (an effect is expected to be supported at every
+     * strength level.
+     */
+    Effect[] getSupportedEffects();
+
+    /**
      * Sets the motor's vibrational amplitude.
      *
      * Changes the force being produced by the underlying motor.
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index cdf8e09..2aec8c5 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -78,6 +78,11 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect>* _aidl_return) {
+    *_aidl_return = {Effect::CLICK, Effect::TICK};
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus Vibrator::setAmplitude(int32_t amplitude) {
     LOG(INFO) << "Vibrator set amplitude: " << amplitude;
     if (amplitude <= 0 || amplitude > 255) {
diff --git a/vibrator/aidl/default/Vibrator.h b/vibrator/aidl/default/Vibrator.h
index 77e96e3..14e7292 100644
--- a/vibrator/aidl/default/Vibrator.h
+++ b/vibrator/aidl/default/Vibrator.h
@@ -31,6 +31,7 @@
     ndk::ScopedAStatus perform(Effect effect, EffectStrength strength,
                                const std::shared_ptr<IVibratorCallback>& callback,
                                int32_t* _aidl_return) override;
+    ndk::ScopedAStatus getSupportedEffects(std::vector<Effect>* _aidl_return) override;
     ndk::ScopedAStatus setAmplitude(int32_t amplitude) override;
     ndk::ScopedAStatus setExternalControl(bool enabled) override;
 };
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index 33bcaf5..b0e6c72 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -32,6 +32,7 @@
 using android::hardware::vibrator::EffectStrength;
 using android::hardware::vibrator::IVibrator;
 
+// TODO(b/143992652): autogenerate
 const std::vector<Effect> kEffects = {
         Effect::CLICK,       Effect::DOUBLE_CLICK, Effect::TICK,        Effect::THUD,
         Effect::POP,         Effect::HEAVY_CLICK,  Effect::RINGTONE_1,  Effect::RINGTONE_2,
@@ -40,6 +41,7 @@
         Effect::RINGTONE_11, Effect::RINGTONE_12,  Effect::RINGTONE_13, Effect::RINGTONE_14,
         Effect::RINGTONE_15, Effect::TEXTURE_TICK};
 
+// TODO(b/143992652): autogenerate
 const std::vector<EffectStrength> kEffectStrengths = {EffectStrength::LIGHT, EffectStrength::MEDIUM,
                                                       EffectStrength::STRONG};
 
@@ -105,15 +107,22 @@
 }
 
 TEST_P(VibratorAidl, ValidateEffect) {
+    std::vector<Effect> supported;
+    ASSERT_TRUE(vibrator->getSupportedEffects(&supported).isOk());
+
     for (Effect effect : kEffects) {
+        bool isEffectSupported =
+                std::find(supported.begin(), supported.end(), effect) != supported.end();
+
         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()) {
+
+            if (isEffectSupported) {
+                EXPECT_TRUE(status.isOk());
                 EXPECT_GT(lengthMs, 0);
             } else {
+                EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
                 EXPECT_EQ(lengthMs, 0);
             }
         }
@@ -123,16 +132,29 @@
 TEST_P(VibratorAidl, ValidateEffectWithCallback) {
     if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK)) return;
 
+    std::vector<Effect> supported;
+    ASSERT_TRUE(vibrator->getSupportedEffects(&supported).isOk());
+
     for (Effect effect : kEffects) {
+        bool isEffectSupported =
+                std::find(supported.begin(), supported.end(), effect) != supported.end();
+
         for (EffectStrength strength : kEffectStrengths) {
             std::promise<void> completionPromise;
             std::future<void> completionFuture{completionPromise.get_future()};
             sp<CompletionCallback> callback =
                     new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
-            int lengthMs;
+            int lengthMs = 0;
             Status status = vibrator->perform(effect, strength, callback, &lengthMs);
-            EXPECT_TRUE(status.isOk() ||
-                        status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION);
+
+            if (isEffectSupported) {
+                EXPECT_TRUE(status.isOk());
+                EXPECT_GT(lengthMs, 0);
+            } else {
+                EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+                EXPECT_EQ(lengthMs, 0);
+            }
+
             if (!status.isOk()) continue;
 
             std::chrono::milliseconds timeout{lengthMs * 2};