Merge "Add amplitude control to vibrator HAL"
diff --git a/vibrator/1.0/Android.mk b/vibrator/1.0/Android.mk
index 4e1ba6a..d921a7e 100644
--- a/vibrator/1.0/Android.mk
+++ b/vibrator/1.0/Android.mk
@@ -17,6 +17,25 @@
 
 
 #
+# Build types.hal (Effect)
+#
+GEN := $(intermediates)/android/hardware/vibrator/V1_0/Effect.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vibrator@1.0::types.Effect
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
 # Build types.hal (Status)
 #
 GEN := $(intermediates)/android/hardware/vibrator/V1_0/Status.java
@@ -73,6 +92,25 @@
 
 
 #
+# Build types.hal (Effect)
+#
+GEN := $(intermediates)/android/hardware/vibrator/V1_0/Effect.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vibrator@1.0::types.Effect
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
 # Build types.hal (Status)
 #
 GEN := $(intermediates)/android/hardware/vibrator/V1_0/Status.java
@@ -114,5 +152,39 @@
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
 
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.vibrator@1.0-java-constants
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(local-generated-sources-dir)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+#
+GEN := $(intermediates)/android/hardware/vibrator/V1_0/Constants.java
+$(GEN): $(HIDL)
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/IVibrator.hal
+
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava-constants \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.vibrator@1.0
+
+$(GEN):
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+# Avoid dependency cycle of framework.jar -> this-library -> framework.jar
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/vibrator/1.0/IVibrator.hal b/vibrator/1.0/IVibrator.hal
index 0a4ffca..757ad0d 100644
--- a/vibrator/1.0/IVibrator.hal
+++ b/vibrator/1.0/IVibrator.hal
@@ -17,7 +17,8 @@
 package android.hardware.vibrator@1.0;
 
 interface IVibrator {
-  /** Turn on vibrator
+  /**
+   * Turn on vibrator
    *
    * This function must only be called after the previous timeout has expired or
    * was canceled (through off()).
@@ -26,10 +27,46 @@
    */
   on(uint32_t timeoutMs) generates (Status vibratorOnRet);
 
-  /** Turn off vibrator
+  /**
+   * Turn off vibrator
    *
    * Cancel a previously-started vibration, if any.
    * @return vibratorOffRet whether vibrator command was successful or not.
    */
   off() generates (Status vibratorOffRet);
+
+  /**
+   * Returns whether the vibrator supports changes to its vibrational amplitude.
+   */
+  supportsAmplitudeControl() generates (bool supports);
+
+  /**
+   * 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.
+   * @return status Whether the command was successful or not. Must return
+   *                Status::UNSUPPORTED_OPERATION if setting the amplitude is
+   *                not supported by the device.
+   */
+  setAmplitude(uint8_t amplitude) generates (Status status);
+
+  /**
+   * Fire off a predefined haptic event.
+   *
+   * @param event The type of haptic event to trigger.
+   * @return status Whether the effect was successfully performed or not. Must
+   *                return Status::UNSUPPORTED_OPERATION is the effect is not
+   *                supported.
+   * @return lengthMs 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. Should be a
+   *                  positive, non-zero value if the returned status is
+   *                  Status::OK, and set to 0 otherwise.
+   */
+  perform(Effect effect, EffectStrength strength) generates (Status status, uint32_t lengthMs);
 };
diff --git a/vibrator/1.0/default/Vibrator.cpp b/vibrator/1.0/default/Vibrator.cpp
index 8c82bcd..19cf3dc 100644
--- a/vibrator/1.0/default/Vibrator.cpp
+++ b/vibrator/1.0/default/Vibrator.cpp
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "VibratorService"
 
+#include <inttypes.h>
+
 #include <log/log.h>
 
 #include <hardware/hardware.h>
@@ -36,7 +38,7 @@
     int32_t ret = mDevice->vibrator_on(mDevice, timeout_ms);
     if (ret != 0) {
         ALOGE("on command failed : %s", strerror(-ret));
-        return Status::ERR;
+        return Status::UNKNOWN_ERROR;
     }
     return Status::OK;
 }
@@ -45,11 +47,24 @@
     int32_t ret = mDevice->vibrator_off(mDevice);
     if (ret != 0) {
         ALOGE("off command failed : %s", strerror(-ret));
-        return Status::ERR;
+        return Status::UNKNOWN_ERROR;
     }
     return Status::OK;
 }
 
+Return<bool> Vibrator::supportsAmplitudeControl()  {
+    return false;
+}
+
+Return<Status> Vibrator::setAmplitude(uint8_t) {
+    return Status::UNSUPPORTED_OPERATION;
+}
+
+Return<void> Vibrator::perform(Effect, EffectStrength, perform_cb _hidl_cb) {
+    _hidl_cb(Status::UNSUPPORTED_OPERATION, 0);
+    return Void();
+}
+
 IVibrator* HIDL_FETCH_IVibrator(const char * /*hal*/) {
     vibrator_device_t *vib_device;
     const hw_module_t *hw_module = nullptr;
diff --git a/vibrator/1.0/default/Vibrator.h b/vibrator/1.0/default/Vibrator.h
index 061b364..bea6ea8 100644
--- a/vibrator/1.0/default/Vibrator.h
+++ b/vibrator/1.0/default/Vibrator.h
@@ -26,23 +26,18 @@
 namespace V1_0 {
 namespace implementation {
 
-using ::android::hardware::vibrator::V1_0::IVibrator;
-using ::android::hardware::vibrator::V1_0::Status;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
 struct Vibrator : public IVibrator {
   Vibrator(vibrator_device_t *device);
 
   // Methods from ::android::hardware::vibrator::V1_0::IVibrator follow.
   Return<Status> on(uint32_t timeoutMs)  override;
   Return<Status> off()  override;
+  Return<bool> supportsAmplitudeControl() override;
+  Return<Status> setAmplitude(uint8_t amplitude) override;
+  Return<void> perform(Effect effect, EffectStrength strength, perform_cb _hidl_cb) override;
 
-  private:
-    vibrator_device_t    *mDevice;
+private:
+  vibrator_device_t    *mDevice;
 };
 
 extern "C" IVibrator* HIDL_FETCH_IVibrator(const char* name);
diff --git a/vibrator/1.0/types.hal b/vibrator/1.0/types.hal
index 8fc5683..a080c07 100644
--- a/vibrator/1.0/types.hal
+++ b/vibrator/1.0/types.hal
@@ -16,7 +16,33 @@
 
 package android.hardware.vibrator@1.0;
 
-enum Status: uint32_t {
-    OK             = 0,
-    ERR            = 1
+enum Status : uint32_t {
+    OK,
+    UNKNOWN_ERROR,
+    BAD_VALUE,
+    UNSUPPORTED_OPERATION
+};
+
+@export
+enum Effect : uint32_t {
+    /**
+     * 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
+};
+
+@export
+enum EffectStrength : uint8_t {
+    LIGHT,
+    MEDIUM,
+    STRONG
 };
diff --git a/vibrator/1.0/vts/functional/VtsHalVibratorV1_0TargetTest.cpp b/vibrator/1.0/vts/functional/VtsHalVibratorV1_0TargetTest.cpp
index a978f2c..f415ad5 100644
--- a/vibrator/1.0/vts/functional/VtsHalVibratorV1_0TargetTest.cpp
+++ b/vibrator/1.0/vts/functional/VtsHalVibratorV1_0TargetTest.cpp
@@ -22,6 +22,8 @@
 #include <VtsHalHidlTargetTestBase.h>
 #include <unistd.h>
 
+using ::android::hardware::vibrator::V1_0::Effect;
+using ::android::hardware::vibrator::V1_0::EffectStrength;
 using ::android::hardware::vibrator::V1_0::IVibrator;
 using ::android::hardware::vibrator::V1_0::Status;
 using ::android::hardware::Return;
@@ -50,12 +52,49 @@
  private:
 };
 
+static void validatePerformEffect(Status status, uint32_t lengthMs) {
+  ASSERT_TRUE(status == Status::OK || status == Status::UNSUPPORTED_OPERATION);
+  if (status == Status::OK) {
+      ASSERT_GT(lengthMs, static_cast<uint32_t>(0));
+  } else {
+      ASSERT_EQ(lengthMs, static_cast<uint32_t>(0));
+  }
+}
+
 TEST_F(VibratorHidlTest, OnThenOffBeforeTimeout) {
   EXPECT_EQ(Status::OK, vibrator->on(2000));
   sleep(1);
   EXPECT_EQ(Status::OK, vibrator->off());
 }
 
+TEST_F(VibratorHidlTest, PerformEffect) {
+  vibrator->perform(Effect::CLICK, EffectStrength::MEDIUM, validatePerformEffect);
+  vibrator->perform(Effect::DOUBLE_CLICK, EffectStrength::LIGHT, validatePerformEffect);
+}
+
+TEST_F(VibratorHidlTest, ChangeVibrationalAmplitude) {
+  if (vibrator->supportsAmplitudeControl()) {
+    EXPECT_EQ(Status::OK, vibrator->setAmplitude(1));
+    EXPECT_EQ(Status::OK, vibrator->on(2000));
+    EXPECT_EQ(Status::OK, vibrator->setAmplitude(128));
+    sleep(1);
+    EXPECT_EQ(Status::OK, vibrator->setAmplitude(255));
+    sleep(1);
+  }
+}
+
+TEST_F(VibratorHidlTest, AmplitudeOutsideRangeFails) {
+  if (vibrator->supportsAmplitudeControl()) {
+    EXPECT_EQ(Status::BAD_VALUE, vibrator->setAmplitude(0));
+  }
+}
+
+TEST_F(VibratorHidlTest, SetAmplitudeReturnUnsupportedOperationIfNotSupported) {
+  if (!vibrator->supportsAmplitudeControl()) {
+    EXPECT_EQ(Status::UNSUPPORTED_OPERATION, vibrator->setAmplitude(1));
+  }
+}
+
 int main(int argc, char **argv) {
   ::testing::AddGlobalTestEnvironment(new VibratorHidlEnvironment);
   ::testing::InitGoogleTest(&argc, argv);