Add new TEXTURE_TICK constant.

Unlike TICK, this is specifically meant to be called repeatedly in
reaction to small movements in order to replicate a specific texture.

Bug: 111461797
Test: VTS
Change-Id: If21687b5fed5f578a638017abc9ce479a122612d
diff --git a/current.txt b/current.txt
index 88d2e11..b91f3f9 100644
--- a/current.txt
+++ b/current.txt
@@ -544,7 +544,8 @@
 61bc302e7c974c59b25898c585c6e9685e8a81021b1bed3eedf5224198f2785a android.hardware.usb@1.2::IUsb
 46996cd2a1c66261a75a1f6ecada77eeb5861eb264fa39b996548fe0a7f22dd3 android.hardware.usb@1.2::IUsbCallback
 3bbaa8cbc5d6b1da21f5509b2b641e05fc7eeca1354751eb1bb3cf37f89aa32f android.hardware.usb@1.2::types
-92c1a726c80970d623b891f7c2f9a989a40a15ee1244092b49f4eb6adcdce4e9 android.hardware.vibrator@1.3::IVibrator
+0f7ff73793548d5154014059b7e0fe9ef6355d32218ace157954d02055f5248b android.hardware.vibrator@1.3::IVibrator
+2e313dc27a1327a29862ab3e085917f75c9e996f7c8df5a0ce37b9a0ed076b80 android.hardware.vibrator@1.3::types
 f19832856a3f53ced5ef91d3cc630a57fb7f4d4ce15f364dbed09099b89f6830 android.hardware.wifi@1.3::IWifi
 7c6799c19bfdb3dec016b751556fe246cf7d37191ee7bb82a0091ab9fbf6f2fb android.hardware.wifi@1.3::IWifiChip
 3bef30e8b61ab050c0f6fd26572712be5ebb7707d624c9aa6c74bbb9d6a5b4a9 android.hardware.wifi@1.3::IWifiStaIface
diff --git a/vibrator/1.3/Android.bp b/vibrator/1.3/Android.bp
index 28370d6..a2ff784 100644
--- a/vibrator/1.3/Android.bp
+++ b/vibrator/1.3/Android.bp
@@ -8,6 +8,7 @@
     },
     srcs: [
         "IVibrator.hal",
+        "types.hal",
     ],
     interfaces: [
         "android.hardware.vibrator@1.0",
diff --git a/vibrator/1.3/IVibrator.hal b/vibrator/1.3/IVibrator.hal
index 01c2801..1c870ee 100644
--- a/vibrator/1.3/IVibrator.hal
+++ b/vibrator/1.3/IVibrator.hal
@@ -16,6 +16,7 @@
 
 package android.hardware.vibrator@1.3;
 
+import @1.0::EffectStrength;
 import @1.0::Status;
 import @1.2::IVibrator;
 
@@ -41,4 +42,18 @@
    *                not supported by the device.
    */
   setExternalControl(bool enabled) 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 if 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_1_3(Effect effect, EffectStrength strength)
+          generates (Status status, uint32_t lengthMs);
 };
diff --git a/vibrator/1.3/example/Vibrator.cpp b/vibrator/1.3/example/Vibrator.cpp
index bb9a057..eb50187 100644
--- a/vibrator/1.3/example/Vibrator.cpp
+++ b/vibrator/1.3/example/Vibrator.cpp
@@ -74,22 +74,9 @@
 
 // Methods from ::android::hardware::vibrator::V1_2::IVibrator follow.
 
-Return<void> Vibrator::perform_1_2(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
-    uint8_t amplitude;
-    uint32_t ms;
-    Status status;
-
-    ALOGI("Perform: Effect %s\n", effectToName(effect));
-
-    amplitude = strengthToAmplitude(strength);
-    setAmplitude(amplitude);
-
-    ms = effectToMs(effect);
-    status = activate(ms);
-
-    _hidl_cb(status, ms);
-
-    return Void();
+Return<void> Vibrator::perform_1_2(V1_2::Effect effect, EffectStrength strength,
+                                   perform_cb _hidl_cb) {
+    return perform_1_3(static_cast<V1_3::Effect>(effect), strength, _hidl_cb);
 }
 
 // Methods from ::android::hardware::vibrator::V1_3::IVibrator follow.
@@ -110,6 +97,24 @@
     }
 }
 
+Return<void> Vibrator::perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
+    uint8_t amplitude;
+    uint32_t ms;
+    Status status;
+
+    ALOGI("Perform: Effect %s\n", effectToName(effect));
+
+    amplitude = strengthToAmplitude(strength);
+    setAmplitude(amplitude);
+
+    ms = effectToMs(effect);
+    status = activate(ms);
+
+    _hidl_cb(status, ms);
+
+    return Void();
+}
+
 // Private methods follow.
 
 Status Vibrator::enable(bool enabled) {
@@ -184,6 +189,7 @@
         case Effect::DOUBLE_CLICK:
             return 15;
         case Effect::TICK:
+        case Effect::TEXTURE_TICK:
             return 5;
         case Effect::THUD:
             return 5;
diff --git a/vibrator/1.3/example/Vibrator.h b/vibrator/1.3/example/Vibrator.h
index a931b63..8cf0b1e 100644
--- a/vibrator/1.3/example/Vibrator.h
+++ b/vibrator/1.3/example/Vibrator.h
@@ -27,7 +27,6 @@
 
 using android::hardware::vibrator::V1_0::EffectStrength;
 using android::hardware::vibrator::V1_0::Status;
-using android::hardware::vibrator::V1_2::Effect;
 
 class Vibrator : public IVibrator {
   public:
@@ -46,11 +45,13 @@
                              perform_cb _hidl_cb) override;
 
     // Methods from ::android::hardware::vibrator::V1_2::IVibrator follow.
-    Return<void> perform_1_2(Effect effect, EffectStrength strength, perform_cb _hidl_cb) override;
+    Return<void> perform_1_2(V1_2::Effect effect, EffectStrength strength,
+                             perform_cb _hidl_cb) override;
 
     // Methods from ::android::hardware::vibrator::V1_3::IVibrator follow.
     Return<bool> supportsExternalControl() override;
     Return<Status> setExternalControl(bool enabled) override;
+    Return<void> perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) override;
 
   private:
     Status enable(bool enabled);
diff --git a/vibrator/1.3/types.hal b/vibrator/1.3/types.hal
new file mode 100644
index 0000000..ceb62a5
--- /dev/null
+++ b/vibrator/1.3/types.hal
@@ -0,0 +1,30 @@
+/*
+ * 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@1.3;
+
+import @1.2::Effect;
+
+enum Effect : @1.2::Effect {
+     /**
+      * 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/1.3/vts/functional/VtsHalVibratorV1_3TargetTest.cpp b/vibrator/1.3/vts/functional/VtsHalVibratorV1_3TargetTest.cpp
index a67d1dc..818f9c7 100644
--- a/vibrator/1.3/vts/functional/VtsHalVibratorV1_3TargetTest.cpp
+++ b/vibrator/1.3/vts/functional/VtsHalVibratorV1_3TargetTest.cpp
@@ -24,9 +24,16 @@
 #include <unistd.h>
 
 using ::android::sp;
+using ::android::hardware::hidl_enum_range;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::vibrator::V1_0::EffectStrength;
 using ::android::hardware::vibrator::V1_0::Status;
+using ::android::hardware::vibrator::V1_3::Effect;
 using ::android::hardware::vibrator::V1_3::IVibrator;
 
+#define EXPECT_OK(ret) ASSERT_TRUE((ret).isOk())
+
 // Test environment for Vibrator HIDL HAL.
 class VibratorHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
    public:
@@ -71,6 +78,74 @@
     }
 }
 
+static void validatePerformEffectUnsupportedOperation(Status status, uint32_t lengthMs) {
+    ASSERT_EQ(Status::UNSUPPORTED_OPERATION, status);
+    ASSERT_EQ(static_cast<uint32_t>(0), lengthMs)
+            << "Effects that return UNSUPPORTED_OPERATION must have a duration of zero";
+}
+
+static void validatePerformEffect(Status status, uint32_t lengthMs) {
+    ASSERT_TRUE(status == Status::OK || status == Status::UNSUPPORTED_OPERATION);
+    if (status == Status::OK) {
+        ASSERT_LT(static_cast<uint32_t>(0), lengthMs)
+                << "Effects that return OK must return a positive duration";
+    } else {
+        validatePerformEffectUnsupportedOperation(status, lengthMs);
+    }
+}
+
+/*
+ * Test to make sure effects within the valid range return are either supported and return OK with
+ * a valid duration, or are unsupported and return UNSUPPORTED_OPERATION with a duration of 0.
+ */
+TEST_F(VibratorHidlTest_1_3, PerformEffect_1_3) {
+    for (const auto& effect : hidl_enum_range<Effect>()) {
+        for (const auto& strength : hidl_enum_range<EffectStrength>()) {
+            EXPECT_OK(vibrator->perform_1_3(effect, strength, validatePerformEffect));
+        }
+    }
+}
+
+/*
+ * Test to make sure effect values above the valid range are rejected.
+ */
+TEST_F(VibratorHidlTest_1_3, PerformEffect_1_3_BadEffects_AboveValidRange) {
+    Effect effect = *std::prev(hidl_enum_range<Effect>().end());
+    Effect badEffect = static_cast<Effect>(static_cast<int32_t>(effect) + 1);
+    EXPECT_OK(vibrator->perform_1_3(badEffect, EffectStrength::LIGHT,
+                                    validatePerformEffectUnsupportedOperation));
+}
+
+/*
+ * Test to make sure effect values below the valid range are rejected.
+ */
+TEST_F(VibratorHidlTest_1_3, PerformEffect_1_3_BadEffects_BelowValidRange) {
+    Effect effect = *hidl_enum_range<Effect>().begin();
+    Effect badEffect = static_cast<Effect>(static_cast<int32_t>(effect) - 1);
+    EXPECT_OK(vibrator->perform_1_3(badEffect, EffectStrength::LIGHT,
+                                    validatePerformEffectUnsupportedOperation));
+}
+
+/*
+ * Test to make sure strength values above the valid range are rejected.
+ */
+TEST_F(VibratorHidlTest_1_3, PerformEffect_1_3_BadStrength_AboveValidRange) {
+    EffectStrength strength = *std::prev(hidl_enum_range<EffectStrength>().end());
+    EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) + 1);
+    EXPECT_OK(vibrator->perform_1_3(Effect::THUD, badStrength,
+                                    validatePerformEffectUnsupportedOperation));
+}
+
+/*
+ * Test to make sure strength values below the valid range are rejected.
+ */
+TEST_F(VibratorHidlTest_1_3, PerformEffect_1_3_BadStrength_BelowValidRange) {
+    EffectStrength strength = *hidl_enum_range<EffectStrength>().begin();
+    EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) - 1);
+    EXPECT_OK(vibrator->perform_1_3(Effect::THUD, badStrength,
+                                    validatePerformEffectUnsupportedOperation));
+}
+
 int main(int argc, char** argv) {
     ::testing::AddGlobalTestEnvironment(VibratorHidlEnvironment::Instance());
     ::testing::InitGoogleTest(&argc, argv);