idlcli: Support AIDL Vibrator

Test: Manual Invocation
Change-Id: Ic9c1152e26e4185cb81f6a96bb7afa6377b854ef
Signed-off-by: Harpreet \"Eli\" Sangha <eliptus@google.com>
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index 40b8dc7..bb92fd3 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -20,9 +20,11 @@
         "android.hardware.vibrator@1.2",
         "android.hardware.vibrator@1.3",
         "libbase",
+        "libbinder",
         "libhidlbase",
         "liblog",
         "libutils",
+        "vintf-vibrator-cpp",
     ],
     cflags: [
         "-DLOG_TAG=\"idlcli\"",
@@ -34,6 +36,7 @@
     defaults: ["idlcli-defaults"],
     srcs: [
         "CommandVibrator.cpp",
+        "vibrator/CommandGetCapabilities.cpp",
         "vibrator/CommandOff.cpp",
         "vibrator/CommandOn.cpp",
         "vibrator/CommandPerform.cpp",
diff --git a/cmds/idlcli/vibrator.h b/cmds/idlcli/vibrator.h
index bcb207b..2f11923 100644
--- a/cmds/idlcli/vibrator.h
+++ b/cmds/idlcli/vibrator.h
@@ -18,6 +18,8 @@
 #define FRAMEWORK_NATIVE_CMDS_IDLCLI_VIBRATOR_H_
 
 #include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <android/hardware/vibrator/IVibrator.h>
+#include <binder/IServiceManager.h>
 
 #include "utils.h"
 
@@ -31,9 +33,25 @@
 
 // Creates a Return<R> with STATUS::EX_NULL_POINTER.
 template <class R>
-inline Return<R> NullptrStatus() {
+inline R NullptrStatus() {
     using ::android::hardware::Status;
-    return Return<R>{Status::fromExceptionCode(Status::EX_NULL_POINTER)};
+    return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+}
+
+template <>
+inline binder::Status NullptrStatus() {
+    using binder::Status;
+    return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+}
+
+template <typename I>
+inline sp<I> getService() {
+    return I::getService();
+}
+
+template <>
+inline sp<hardware::vibrator::IVibrator> getService() {
+    return waitForVintfService<hardware::vibrator::IVibrator>();
 }
 
 template <typename I>
@@ -42,12 +60,12 @@
     static std::unique_ptr<HalWrapper> Create() {
         // Assume that if getService returns a nullptr, HAL is not available on the
         // device.
-        auto hal = I::getService();
+        auto hal = getService<I>();
         return hal ? std::unique_ptr<HalWrapper>(new HalWrapper(std::move(hal))) : nullptr;
     }
 
     template <class R, class... Args0, class... Args1>
-    Return<R> call(Return<R> (I::*fn)(Args0...), Args1&&... args1) {
+    R call(R (I::*fn)(Args0...), Args1&&... args1) {
         return (*mHal.*fn)(std::forward<Args1>(args1)...);
     }
 
@@ -65,7 +83,7 @@
 }
 
 template <class R, class I, class... Args0, class... Args1>
-Return<R> halCall(Return<R> (I::*fn)(Args0...), Args1&&... args1) {
+R halCall(R (I::*fn)(Args0...), Args1&&... args1) {
     auto hal = getHal<I>();
     return hal ? hal->call(fn, std::forward<Args1>(args1)...) : NullptrStatus<R>();
 }
@@ -77,6 +95,7 @@
 namespace V1_1 = ::android::hardware::vibrator::V1_1;
 namespace V1_2 = ::android::hardware::vibrator::V1_2;
 namespace V1_3 = ::android::hardware::vibrator::V1_3;
+namespace aidl = ::android::hardware::vibrator;
 
 } // namespace vibrator
 } // namespace idlcli
diff --git a/cmds/idlcli/vibrator/CommandGetCapabilities.cpp b/cmds/idlcli/vibrator/CommandGetCapabilities.cpp
new file mode 100644
index 0000000..30d8587
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetCapabilities.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetCapabilities : public Command {
+    std::string getDescription() const override { return "Retrieves vibrator capabilities."; }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        int32_t cap;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getCapabilities, &cap);
+            statusStr = status.toString8();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Capabilities: " << std::bitset<32>(cap) << std::endl;
+
+        return ret;
+    }
+};
+
+static const auto Command =
+        CommandRegistry<CommandVibrator>::Register<CommandGetCapabilities>("getCapabilities");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandOff.cpp b/cmds/idlcli/vibrator/CommandOff.cpp
index a674f01..53fada0 100644
--- a/cmds/idlcli/vibrator/CommandOff.cpp
+++ b/cmds/idlcli/vibrator/CommandOff.cpp
@@ -42,15 +42,24 @@
     }
 
     Status doMain(Args && /*args*/) override {
-        auto ret = halCall(&V1_0::IVibrator::off);
+        std::string statusStr;
+        Status ret;
 
-        if (!ret.isOk()) {
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::off);
+            statusStr = status.toString8();
+            ret = status.isOk() ? OK : ERROR;
+        } else if (auto hal = getHal<V1_0::IVibrator>()) {
+            auto status = hal->call(&V1_0::IVibrator::off);
+            statusStr = toString(status);
+            ret = status.isOk() && status == V1_0::Status::OK ? OK : ERROR;
+        } else {
             return UNAVAILABLE;
         }
 
-        std::cout << "Status: " << toString(ret) << std::endl;
+        std::cout << "Status: " << statusStr << std::endl;
 
-        return ret == V1_0::Status::OK ? OK : ERROR;
+        return ret;
     }
 };
 
diff --git a/cmds/idlcli/vibrator/CommandOn.cpp b/cmds/idlcli/vibrator/CommandOn.cpp
index 2164b7d..ccb3c19 100644
--- a/cmds/idlcli/vibrator/CommandOn.cpp
+++ b/cmds/idlcli/vibrator/CommandOn.cpp
@@ -50,15 +50,24 @@
     }
 
     Status doMain(Args && /*args*/) override {
-        auto ret = halCall(&V1_0::IVibrator::on, mDuration);
+        std::string statusStr;
+        Status ret;
 
-        if (!ret.isOk()) {
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::on, mDuration, nullptr);
+            statusStr = status.toString8();
+            ret = status.isOk() ? OK : ERROR;
+        } else if (auto hal = getHal<V1_0::IVibrator>()) {
+            auto status = hal->call(&V1_0::IVibrator::on, mDuration);
+            statusStr = toString(status);
+            ret = status.isOk() && status == V1_0::Status::OK ? OK : ERROR;
+        } else {
             return UNAVAILABLE;
         }
 
-        std::cout << "Status: " << toString(ret) << std::endl;
+        std::cout << "Status: " << statusStr << std::endl;
 
-        return ret == V1_0::Status::OK ? OK : ERROR;
+        return ret;
     }
 
     uint32_t mDuration;
diff --git a/cmds/idlcli/vibrator/CommandPerform.cpp b/cmds/idlcli/vibrator/CommandPerform.cpp
index 688cbd8..58d4e0a 100644
--- a/cmds/idlcli/vibrator/CommandPerform.cpp
+++ b/cmds/idlcli/vibrator/CommandPerform.cpp
@@ -23,6 +23,34 @@
 
 namespace vibrator {
 
+/*
+ * The following static asserts are only relevant here because the argument
+ * parser uses a single implementation for determining the string names.
+ */
+static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
+              static_cast<uint8_t>(aidl::EffectStrength::LIGHT));
+static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) ==
+              static_cast<uint8_t>(aidl::EffectStrength::MEDIUM));
+static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) ==
+              static_cast<uint8_t>(aidl::EffectStrength::STRONG));
+static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) ==
+              static_cast<uint8_t>(aidl::Effect::CLICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) ==
+              static_cast<uint8_t>(aidl::Effect::DOUBLE_CLICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) == static_cast<uint8_t>(aidl::Effect::TICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) == static_cast<uint8_t>(aidl::Effect::THUD));
+static_assert(static_cast<uint8_t>(V1_3::Effect::POP) == static_cast<uint8_t>(aidl::Effect::POP));
+static_assert(static_cast<uint8_t>(V1_3::Effect::HEAVY_CLICK) ==
+              static_cast<uint8_t>(aidl::Effect::HEAVY_CLICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_1) ==
+              static_cast<uint8_t>(aidl::Effect::RINGTONE_1));
+static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_2) ==
+              static_cast<uint8_t>(aidl::Effect::RINGTONE_2));
+static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) ==
+              static_cast<uint8_t>(aidl::Effect::RINGTONE_15));
+static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
+              static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
+
 using V1_0::EffectStrength;
 using V1_3::Effect;
 
@@ -62,38 +90,50 @@
     }
 
     Status doMain(Args && /*args*/) override {
-        Return<void> ret;
-        V1_0::Status status;
+        std::string statusStr;
         uint32_t lengthMs;
-        auto callback = [&status, &lengthMs](V1_0::Status retStatus, uint32_t retLengthMs) {
-            status = retStatus;
-            lengthMs = retLengthMs;
-        };
+        Status ret;
 
-        if (auto hal = getHal<V1_3::IVibrator>()) {
-            ret = hal->call(&V1_3::IVibrator::perform_1_3, static_cast<V1_3::Effect>(mEffect),
-                            mStrength, callback);
-        } else if (auto hal = getHal<V1_2::IVibrator>()) {
-            ret = hal->call(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(mEffect),
-                            mStrength, callback);
-        } else if (auto hal = getHal<V1_1::IVibrator>()) {
-            ret = hal->call(&V1_1::IVibrator::perform_1_1, static_cast<V1_1::Effect_1_1>(mEffect),
-                            mStrength, callback);
-        } else if (auto hal = getHal<V1_0::IVibrator>()) {
-            ret = hal->call(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(mEffect),
-                            mStrength, callback);
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            int32_t aidlLengthMs;
+            auto status =
+                    hal->call(&aidl::IVibrator::perform, static_cast<aidl::Effect>(mEffect),
+                              static_cast<aidl::EffectStrength>(mStrength), nullptr, &aidlLengthMs);
+            statusStr = status.toString8();
+            lengthMs = static_cast<uint32_t>(aidlLengthMs);
+            ret = status.isOk() ? OK : ERROR;
         } else {
-            ret = NullptrStatus<void>();
+            Return<void> hidlRet;
+            V1_0::Status status;
+            auto callback = [&status, &lengthMs](V1_0::Status retStatus, uint32_t retLengthMs) {
+                status = retStatus;
+                lengthMs = retLengthMs;
+            };
+
+            if (auto hal = getHal<V1_3::IVibrator>()) {
+                hidlRet = hal->call(&V1_3::IVibrator::perform_1_3,
+                                    static_cast<V1_3::Effect>(mEffect), mStrength, callback);
+            } else if (auto hal = getHal<V1_2::IVibrator>()) {
+                hidlRet = hal->call(&V1_2::IVibrator::perform_1_2,
+                                    static_cast<V1_2::Effect>(mEffect), mStrength, callback);
+            } else if (auto hal = getHal<V1_1::IVibrator>()) {
+                hidlRet = hal->call(&V1_1::IVibrator::perform_1_1,
+                                    static_cast<V1_1::Effect_1_1>(mEffect), mStrength, callback);
+            } else if (auto hal = getHal<V1_0::IVibrator>()) {
+                hidlRet = hal->call(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(mEffect),
+                                    mStrength, callback);
+            } else {
+                return UNAVAILABLE;
+            }
+
+            statusStr = toString(status);
+            ret = hidlRet.isOk() && status == V1_0::Status::OK ? OK : ERROR;
         }
 
-        if (!ret.isOk()) {
-            return UNAVAILABLE;
-        }
-
-        std::cout << "Status: " << toString(status) << std::endl;
+        std::cout << "Status: " << statusStr << std::endl;
         std::cout << "Length: " << lengthMs << std::endl;
 
-        return status == V1_0::Status::OK ? OK : ERROR;
+        return ret;
     }
 
     Effect mEffect;
diff --git a/cmds/idlcli/vibrator/CommandSetAmplitude.cpp b/cmds/idlcli/vibrator/CommandSetAmplitude.cpp
index 38a1dc2..6e2261f 100644
--- a/cmds/idlcli/vibrator/CommandSetAmplitude.cpp
+++ b/cmds/idlcli/vibrator/CommandSetAmplitude.cpp
@@ -50,15 +50,24 @@
     }
 
     Status doMain(Args && /*args*/) override {
-        auto ret = halCall(&V1_0::IVibrator::setAmplitude, mAmplitude);
+        std::string statusStr;
+        Status ret;
 
-        if (!ret.isOk()) {
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::setAmplitude, mAmplitude);
+            statusStr = status.toString8();
+            ret = status.isOk() ? OK : ERROR;
+        } else if (auto hal = getHal<V1_0::IVibrator>()) {
+            auto status = hal->call(&V1_0::IVibrator::setAmplitude, mAmplitude);
+            statusStr = toString(status);
+            ret = status.isOk() && status == V1_0::Status::OK ? OK : ERROR;
+        } else {
             return UNAVAILABLE;
         }
 
-        std::cout << "Status: " << toString(ret) << std::endl;
+        std::cout << "Status: " << statusStr << std::endl;
 
-        return ret == V1_0::Status::OK ? OK : ERROR;
+        return ret;
     }
 
     uint8_t mAmplitude;
diff --git a/cmds/idlcli/vibrator/CommandSetExternalControl.cpp b/cmds/idlcli/vibrator/CommandSetExternalControl.cpp
index 5fb1fac..5bc827e 100644
--- a/cmds/idlcli/vibrator/CommandSetExternalControl.cpp
+++ b/cmds/idlcli/vibrator/CommandSetExternalControl.cpp
@@ -48,15 +48,24 @@
     }
 
     Status doMain(Args && /*args*/) override {
-        auto ret = halCall(&V1_3::IVibrator::setExternalControl, mEnable);
+        std::string statusStr;
+        Status ret;
 
-        if (!ret.isOk()) {
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::setExternalControl, mEnable);
+            statusStr = status.toString8();
+            ret = status.isOk() ? OK : ERROR;
+        } else if (auto hal = getHal<V1_3::IVibrator>()) {
+            auto status = hal->call(&V1_3::IVibrator::setExternalControl, mEnable);
+            statusStr = toString(status);
+            ret = status.isOk() && status == V1_0::Status::OK ? OK : ERROR;
+        } else {
             return UNAVAILABLE;
         }
 
-        std::cout << "Status: " << toString(ret) << std::endl;
+        std::cout << "Status: " << statusStr << std::endl;
 
-        return ret == V1_0::Status::OK ? OK : ERROR;
+        return ret;
     }
 
     bool mEnable;