idlcli: vibrator: Add Blocking Options

Test: Manually on Pixel CS40L25 and DRV2624 Targets
Signed-off-by: Harpreet \"Eli\" Sangha <eliptus@google.com>
Change-Id: I3fbe889b82e80c48cc1a4ffd16f2efe0aa4672c5
diff --git a/cmds/idlcli/vibrator/CommandOn.cpp b/cmds/idlcli/vibrator/CommandOn.cpp
index 4e7e493..8212fc1 100644
--- a/cmds/idlcli/vibrator/CommandOn.cpp
+++ b/cmds/idlcli/vibrator/CommandOn.cpp
@@ -13,9 +13,14 @@
  * limitations under the License.
  */
 
+#include <thread>
+
 #include "utils.h"
 #include "vibrator.h"
 
+using std::chrono::milliseconds;
+using std::this_thread::sleep_for;
+
 namespace android {
 namespace idlcli {
 
@@ -26,16 +31,28 @@
 class CommandOn : public Command {
     std::string getDescription() const override { return "Turn on vibrator."; }
 
-    std::string getUsageSummary() const override { return "<duration>"; }
+    std::string getUsageSummary() const override { return "[options] <duration>"; }
 
     UsageDetails getUsageDetails() const override {
         UsageDetails details{
+                {"-b", {"Block for duration of vibration."}},
                 {"<duration>", {"In milliseconds."}},
         };
         return details;
     }
 
     Status doArgs(Args &args) override {
+        while (args.get<std::string>().value_or("").find("-") == 0) {
+            auto opt = *args.pop<std::string>();
+            if (opt == "--") {
+                break;
+            } else if (opt == "-b") {
+                mBlocking = true;
+            } else {
+                std::cerr << "Invalid Option '" << opt << "'!" << std::endl;
+                return USAGE;
+            }
+        }
         if (auto duration = args.pop<decltype(mDuration)>()) {
             mDuration = *duration;
         } else {
@@ -52,9 +69,21 @@
     Status doMain(Args && /*args*/) override {
         std::string statusStr;
         Status ret;
+        std::shared_ptr<VibratorCallback> callback;
 
         if (auto hal = getHal<aidl::IVibrator>()) {
-            auto status = hal->call(&aidl::IVibrator::on, mDuration, nullptr);
+            ABinderProcess_setThreadPoolMaxThreadCount(1);
+            ABinderProcess_startThreadPool();
+
+            int32_t cap;
+            hal->call(&aidl::IVibrator::getCapabilities, &cap);
+
+            if (mBlocking && (cap & aidl::IVibrator::CAP_ON_CALLBACK)) {
+                callback = ndk::SharedRefBase::make<VibratorCallback>();
+            }
+
+            auto status = hal->call(&aidl::IVibrator::on, mDuration, callback);
+
             statusStr = status.getDescription();
             ret = status.isOk() ? OK : ERROR;
         } else if (auto hal = getHal<V1_0::IVibrator>()) {
@@ -65,11 +94,20 @@
             return UNAVAILABLE;
         }
 
+        if (ret == OK && mBlocking) {
+            if (callback) {
+                callback->waitForComplete();
+            } else {
+                sleep_for(milliseconds(mDuration));
+            }
+        }
+
         std::cout << "Status: " << statusStr << std::endl;
 
         return ret;
     }
 
+    bool mBlocking;
     uint32_t mDuration;
 };