vibrator: Modify some delta and apply calibration fix

Reference the delta from the leading project.

Bug: 148918900
Test: manual haptics function check and logs
Change-Id: I777d3295a7a92e2ce8547b85886038cfbe32ac5a
Signed-off-by: chasewu <chasewu@google.com>
diff --git a/device-redfin.mk b/device-redfin.mk
index 2a6d20a..90c8b94 100644
--- a/device-redfin.mk
+++ b/device-redfin.mk
@@ -115,6 +115,20 @@
 PRODUCT_PACKAGES += \
     android.hardware.vibrator@1.3-service.redfin
 
+# DRV2624 Haptics Waveform
+PRODUCT_COPY_FILES += \
+    device/google/redfin/vibrator/drv2624/drv2624.bin:$(TARGET_COPY_OUT_VENDOR)/firmware/drv2624.bin
+
+# Vibrator HAL
+PRODUCT_PRODUCT_PROPERTIES +=\
+    ro.vibrator.hal.config.dynamic=1 \
+    ro.vibrator.hal.click.duration=8 \
+    ro.vibrator.hal.tick.duration=8 \
+    ro.vibrator.hal.heavyclick.duration=8 \
+    ro.vibrator.hal.long.voltage=161 \
+    ro.vibrator.hal.long.frequency.shift=0 \
+    ro.vibrator.hal.steady.shape=1
+
 # Dumpstate HAL
 PRODUCT_PACKAGES += \
     android.hardware.dumpstate@1.0-service.redfin
diff --git a/init.insmod.redfin.cfg b/init.insmod.redfin.cfg
index f57ad6c..ad77b2d 100644
--- a/init.insmod.redfin.cfg
+++ b/init.insmod.redfin.cfg
@@ -5,7 +5,7 @@
 #############################################
 
 # Load kernel modules
-modprobe|adsp_loader_dlkm.ko apr_dlkm.ko atomic64_test.ko bolero_cdc_dlkm.ko br_netfilter.ko hdmi_dlkm.ko lcd.ko lkdtm.ko llcc_perfmon.ko locktorture.ko machine_dlkm.ko mbhc_dlkm.ko native_dlkm.ko pinctrl_lpi_dlkm.ko platform_dlkm.ko q6_dlkm.ko q6_notifier_dlkm.ko q6_pdr_dlkm.ko rcutorture.ko rx_macro_dlkm.ko snd_event_dlkm.ko stub_dlkm.ko swr_ctrl_dlkm.ko swr_dlkm.ko test_user_copy.ko torture.ko tx_macro_dlkm.ko usf_dlkm.ko va_macro_dlkm.ko wcd938x_dlkm.ko wcd938x_slave_dlkm.ko wcd9xxx_dlkm.ko wcd_core_dlkm.ko wlan.ko wsa881x_dlkm.ko wsa_macro_dlkm.ko heatmap.ko sec_touch.ko
+modprobe|adsp_loader_dlkm.ko apr_dlkm.ko atomic64_test.ko bolero_cdc_dlkm.ko br_netfilter.ko hdmi_dlkm.ko lcd.ko lkdtm.ko llcc_perfmon.ko locktorture.ko machine_dlkm.ko mbhc_dlkm.ko native_dlkm.ko pinctrl_lpi_dlkm.ko platform_dlkm.ko q6_dlkm.ko q6_notifier_dlkm.ko q6_pdr_dlkm.ko rcutorture.ko rx_macro_dlkm.ko snd_event_dlkm.ko stub_dlkm.ko swr_ctrl_dlkm.ko swr_dlkm.ko test_user_copy.ko torture.ko tx_macro_dlkm.ko usf_dlkm.ko va_macro_dlkm.ko wcd938x_dlkm.ko wcd938x_slave_dlkm.ko wcd9xxx_dlkm.ko wcd_core_dlkm.ko wlan.ko wsa881x_dlkm.ko wsa_macro_dlkm.ko heatmap.ko sec_touch.ko drv2624.ko
 
 # All modules loaded
 setprop|vendor.all.modules.ready
diff --git a/vibrator/Android.bp b/vibrator/Android.bp
index 261a26c..c19ddbd 100644
--- a/vibrator/Android.bp
+++ b/vibrator/Android.bp
@@ -1,5 +1,5 @@
 //
-// Copyright (C) 2017 The Android Open Source Project
+// 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.
@@ -14,69 +14,18 @@
 // limitations under the License.
 
 cc_defaults {
-    name: "android.hardware.vibrator@1.3-defaults.redfin",
+    name: "PixelVibratorDefaultsRedfin",
     defaults: ["hidl_defaults"],
     relative_install_path: "hw",
-    shared_libs: [
-        "libhidlbase",
-        "libcutils",
-        "libhidltransport",
-        "liblog",
-        "libhwbinder",
-        "libutils",
-        "libhardware",
-        "android.hardware.vibrator@1.0",
-        "android.hardware.vibrator@1.1",
-        "android.hardware.vibrator@1.2",
-        "android.hardware.vibrator@1.3",
-    ],
-    proprietary: true,
-}
-
-cc_library {
-    name: "android.hardware.vibrator@1.3-impl.redfin",
-    defaults: ["android.hardware.vibrator@1.3-defaults.redfin"],
-    srcs: [
-        "Hardware.cpp",
-        "Vibrator.cpp",
-    ],
-}
-
-cc_binary {
-    name: "android.hardware.vibrator@1.3-service.redfin",
-    defaults: ["android.hardware.vibrator@1.3-defaults.redfin"],
-    init_rc: ["android.hardware.vibrator@1.3-service.redfin.rc"],
-    vintf_fragments: ["android.hardware.vibrator@1.3-service.redfin.xml"],
-    srcs: ["service.cpp"],
-    static_libs: ["android.hardware.vibrator@1.3-impl.redfin"],
-}
-
-cc_test {
-    name: "PtsVibratorHalRedfinTestSuite",
-    defaults: ["android.hardware.vibrator@1.3-defaults.redfin"],
-    srcs: [
-        "tests/main.cpp",
-        "tests/test-hwapi.cpp",
-        "tests/test-hwcal.cpp",
-        "tests/test-vibrator.cpp",
-    ],
     static_libs: [
-        "android.hardware.vibrator@1.3-impl.redfin",
-        "libgmock",
+        "PixelVibratorCommonRedfin",
     ],
     shared_libs: [
         "libbase",
+        "libhidlbase",
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libhardware",
     ],
-    test_suites: [
-        "general-tests",
-        "pts",
-    ],
-    multilib: {
-        lib32: {
-            suffix: "32",
-        },
-        lib64: {
-            suffix: "64",
-        },
-    },
 }
diff --git a/vibrator/AndroidTest.xml b/vibrator/AndroidTest.xml
deleted file mode 100644
index a6ddf6d..0000000
--- a/vibrator/AndroidTest.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-    Copyright (c) 2019 Google Inc.
-
-    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.
--->
-<configuration description="Runs PtsVibratorHalRedfinTestSuite.">
-    <option name="test-suite-tag" value="pts" />
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="append-bitness" value="true" />
-        <option name="cleanup" value="true" />
-        <option name="push" value="PtsVibratorHalRedfinTestSuite->/data/local/tmp/PtsVibratorHalRedfinTestSuite" />
-    </target_preparer>
-    <test class="com.android.tradefed.testtype.GTest" >
-        <option name="module-name" value="PtsVibratorHalRedfinTestSuite" />
-        <option name="native-test-device-path" value="/data/local/tmp" />
-    </test>
-</configuration>
diff --git a/vibrator/Hardware.cpp b/vibrator/Hardware.cpp
deleted file mode 100644
index 6f1d01d..0000000
--- a/vibrator/Hardware.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "android.hardware.vibrator@1.3-service.redfin"
-
-#include "Hardware.h"
-
-#include <log/log.h>
-
-#include <iostream>
-
-namespace android {
-namespace hardware {
-namespace vibrator {
-namespace V1_3 {
-namespace implementation {
-
-template <typename T>
-static void fileFromEnv(const char *env, T *outStream, std::string *outName = nullptr) {
-    auto file = std::getenv(env);
-    auto mode = std::is_base_of_v<std::ostream, T> ? std::ios_base::out : std::ios_base::in;
-
-    if (file == nullptr) {
-        ALOGE("Failed get env %s", env);
-        return;
-    }
-
-    if (outName != nullptr) {
-        *outName = std::string(file);
-    }
-
-    // Force 'in' mode to prevent file creation
-    outStream->open(file, mode | std::ios_base::in);
-    if (!*outStream) {
-        ALOGE("Failed to open %s:%s (%d): %s", env, file, errno, strerror(errno));
-    }
-}
-
-static auto pathsFromEnv(const char *env) {
-    std::map<std::string, std::ifstream> ret;
-    auto value = std::getenv(env);
-
-    if (value == nullptr) {
-        return ret;
-    }
-
-    std::istringstream paths{value};
-    std::string path;
-
-    while (paths >> path) {
-        ret[path].open(path);
-    }
-
-    return ret;
-}
-
-static std::string trim(const std::string &str, const std::string &whitespace = " \t") {
-    const auto str_begin = str.find_first_not_of(whitespace);
-    if (str_begin == std::string::npos) {
-        return "";
-    }
-
-    const auto str_end = str.find_last_not_of(whitespace);
-    const auto str_range = str_end - str_begin + 1;
-
-    return str.substr(str_begin, str_range);
-}
-
-template <typename T>
-static Enable_If_Iterable<T, true> unpack(std::istream &stream, T *value) {
-    for (auto &entry : *value) {
-        stream >> entry;
-    }
-}
-
-template <typename T>
-static Enable_If_Iterable<T, false> unpack(std::istream &stream, T *value) {
-    stream >> *value;
-}
-
-HwApi::HwApi() {
-    // ostreams below are required
-    fileFromEnv("F0_FILEPATH", &mF0, &mNames[&mF0]);
-    fileFromEnv("REDC_FILEPATH", &mRedc, &mNames[&mRedc]);
-    fileFromEnv("Q_FILEPATH", &mQ, &mNames[&mQ]);
-    fileFromEnv("ACTIVATE_PATH", &mActivate, &mNames[&mActivate]);
-    fileFromEnv("DURATION_PATH", &mDuration, &mNames[&mDuration]);
-    fileFromEnv("STATE_PATH", &mState, &mNames[&mState]);
-    fileFromEnv("EFFECT_DURATION_PATH", &mEffectDuration, &mNames[&mEffectDuration]);
-    fileFromEnv("EFFECT_INDEX_PATH", &mEffectIndex, &mNames[&mEffectIndex]);
-    fileFromEnv("EFFECT_QUEUE_PATH", &mEffectQueue, &mNames[&mEffectQueue]);
-    fileFromEnv("EFFECT_SCALE_PATH", &mEffectScale, &mNames[&mEffectScale]);
-    fileFromEnv("GLOBAL_SCALE_PATH", &mGlobalScale, &mNames[&mGlobalScale]);
-    fileFromEnv("ASP_ENABLE_PATH", &mAspEnable, &mNames[&mAspEnable]);
-    fileFromEnv("GPIO_FALL_INDEX", &mGpioFallIndex, &mNames[&mGpioFallIndex]);
-    fileFromEnv("GPIO_FALL_SCALE", &mGpioFallScale, &mNames[&mGpioFallScale]);
-    fileFromEnv("GPIO_RISE_INDEX", &mGpioRiseIndex, &mNames[&mGpioRiseIndex]);
-    fileFromEnv("GPIO_RISE_SCALE", &mGpioRiseScale, &mNames[&mGpioRiseScale]);
-}
-
-template <typename T>
-bool HwApi::has(T &stream) {
-    return !!stream;
-}
-
-template <typename T, typename U>
-bool HwApi::get(T *value, U &stream) {
-    bool ret;
-    stream.seekg(0);
-    stream >> *value;
-    if (!(ret = !!stream)) {
-        ALOGE("Failed to read %s (%d): %s", mNames[&stream].c_str(), errno, strerror(errno));
-    }
-    stream.clear();
-    return ret;
-}
-
-template <typename T, typename U>
-bool HwApi::set(const T &value, U &stream) {
-    bool ret;
-    stream << value << std::endl;
-    if (!(ret = !!stream)) {
-        ALOGE("Failed to write %s (%d): %s", mNames[&stream].c_str(), errno, strerror(errno));
-        stream.clear();
-    }
-    return ret;
-}
-
-void HwApi::debug(int fd) {
-    dprintf(fd, "Kernel:\n");
-
-    for (auto &entry : pathsFromEnv("HWAPI_DEBUG_PATHS")) {
-        auto &path = entry.first;
-        auto &stream = entry.second;
-        std::string line;
-
-        dprintf(fd, "  %s:\n", path.c_str());
-        while (std::getline(stream, line)) {
-            dprintf(fd, "    %s\n", line.c_str());
-        }
-    }
-}
-
-HwCal::HwCal() {
-    std::ifstream calfile;
-
-    fileFromEnv("CALIBRATION_FILEPATH", &calfile);
-
-    for (std::string line; std::getline(calfile, line);) {
-        if (line.empty() || line[0] == '#') {
-            continue;
-        }
-        std::istringstream is_line(line);
-        std::string key, value;
-        if (std::getline(is_line, key, ':') && std::getline(is_line, value)) {
-            mCalData[trim(key)] = trim(value);
-        }
-    }
-}
-
-template <typename T>
-bool HwCal::get(const char *key, T *value) {
-    auto it = mCalData.find(key);
-    if (it == mCalData.end()) {
-        ALOGE("Missing %s config!", key);
-        return false;
-    }
-    std::stringstream stream{it->second};
-    unpack(stream, value);
-    if (!stream || !stream.eof()) {
-        ALOGE("Invalid %s config!", key);
-        return false;
-    }
-    return true;
-}
-
-void HwCal::debug(int fd) {
-    std::ifstream stream;
-    std::string path;
-    std::string line;
-
-    dprintf(fd, "Persist:\n");
-
-    fileFromEnv("CALIBRATION_FILEPATH", &stream, &path);
-
-    dprintf(fd, "  %s:\n", path.c_str());
-    while (std::getline(stream, line)) {
-        dprintf(fd, "    %s\n", line.c_str());
-    }
-}
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace vibrator
-}  // namespace hardware
-}  // namespace android
diff --git a/vibrator/Hardware.h b/vibrator/Hardware.h
deleted file mode 100644
index 4b65f24..0000000
--- a/vibrator/Hardware.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * 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.
- */
-#ifndef ANDROID_HARDWARE_VIBRATOR_HARDWARE_H
-#define ANDROID_HARDWARE_VIBRATOR_HARDWARE_H
-
-#include "Vibrator.h"
-#include "utils.h"
-
-namespace android {
-namespace hardware {
-namespace vibrator {
-namespace V1_3 {
-namespace implementation {
-
-class HwApi : public Vibrator::HwApi {
-  public:
-    HwApi();
-    bool setF0(uint32_t value) override { return set(value, mF0); }
-    bool setRedc(uint32_t value) override { return set(value, mRedc); }
-    bool setQ(uint32_t value) override { return set(value, mQ); }
-    bool setActivate(bool value) override { return set(value, mActivate); }
-    bool setDuration(uint32_t value) override { return set(value, mDuration); }
-    bool getEffectDuration(uint32_t *value) override { return get(value, mEffectDuration); }
-    bool setEffectIndex(uint32_t value) override { return set(value, mEffectIndex); }
-    bool setEffectQueue(std::string value) override { return set(value, mEffectQueue); }
-    bool hasEffectScale() override { return has(mEffectScale); }
-    bool setEffectScale(uint32_t value) override { return set(value, mEffectScale); }
-    bool setGlobalScale(uint32_t value) override { return set(value, mGlobalScale); }
-    bool setState(bool value) override { return set(value, mState); }
-    bool hasAspEnable() override { return has(mAspEnable); }
-    bool getAspEnable(bool *value) override { return get(value, mAspEnable); }
-    bool setAspEnable(bool value) override { return set(value, mAspEnable); }
-    bool setGpioFallIndex(uint32_t value) override { return set(value, mGpioFallIndex); }
-    bool setGpioFallScale(uint32_t value) override { return set(value, mGpioFallScale); }
-    bool setGpioRiseIndex(uint32_t value) override { return set(value, mGpioRiseIndex); }
-    bool setGpioRiseScale(uint32_t value) override { return set(value, mGpioRiseScale); }
-    void debug(int fd) override;
-
-  private:
-    template <typename T>
-    bool has(T &stream);
-    template <typename T, typename U>
-    bool get(T *value, U &stream);
-    template <typename T, typename U>
-    bool set(const T &value, U &stream);
-
-  private:
-    std::map<void *, std::string> mNames;
-    std::ofstream mF0;
-    std::ofstream mRedc;
-    std::ofstream mQ;
-    std::ofstream mActivate;
-    std::ofstream mDuration;
-    std::ifstream mEffectDuration;
-    std::ofstream mEffectIndex;
-    std::ofstream mEffectQueue;
-    std::ofstream mEffectScale;
-    std::ofstream mGlobalScale;
-    std::ofstream mState;
-    std::fstream mAspEnable;
-    std::ofstream mGpioFallIndex;
-    std::ofstream mGpioFallScale;
-    std::ofstream mGpioRiseIndex;
-    std::ofstream mGpioRiseScale;
-};
-
-class HwCal : public Vibrator::HwCal {
-  private:
-    static constexpr char F0_CONFIG[] = "f0_measured";
-    static constexpr char REDC_CONFIG[] = "redc_measured";
-    static constexpr char Q_CONFIG[] = "q_measured";
-    static constexpr char Q_INDEX[] = "q_index";
-    static constexpr char VOLTAGES_CONFIG[] = "v_levels";
-
-    static constexpr uint32_t Q_FLOAT_TO_FIXED = 1 << 16;
-    static constexpr float Q_INDEX_TO_FLOAT = 1.5f;
-    static constexpr uint32_t Q_INDEX_TO_FIXED = Q_INDEX_TO_FLOAT * Q_FLOAT_TO_FIXED;
-    static constexpr uint32_t Q_INDEX_OFFSET = 2.0f * Q_FLOAT_TO_FIXED;
-
-    static constexpr uint32_t Q_DEFAULT = 15.5 * Q_FLOAT_TO_FIXED;
-    static constexpr std::array<uint32_t, 6> V_LEVELS_DEFAULT = {60, 70, 80, 90, 100, 76};
-
-  public:
-    HwCal();
-    bool getF0(uint32_t *value) override { return get(F0_CONFIG, value); }
-    bool getRedc(uint32_t *value) override { return get(REDC_CONFIG, value); }
-    bool getQ(uint32_t *value) override {
-        if (get(Q_CONFIG, value)) {
-            return true;
-        }
-        if (get(Q_INDEX, value)) {
-            *value = *value * Q_INDEX_TO_FIXED + Q_INDEX_OFFSET;
-            return true;
-        }
-        *value = Q_DEFAULT;
-        return true;
-    }
-    bool getVolLevels(std::array<uint32_t, 6> *value) override {
-        if (get(VOLTAGES_CONFIG, value)) {
-            return true;
-        }
-        *value = V_LEVELS_DEFAULT;
-        return true;
-    }
-    void debug(int fd) override;
-
-  private:
-    template <typename T>
-    bool get(const char *key, T *value);
-
-  private:
-    std::map<std::string, std::string> mCalData;
-};
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace vibrator
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_VIBRATOR_HARDWARE_H
diff --git a/vibrator/Vibrator.cpp b/vibrator/Vibrator.cpp
deleted file mode 100644
index 8bce7cc..0000000
--- a/vibrator/Vibrator.cpp
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#define LOG_TAG "android.hardware.vibrator@1.3-service.redfin"
-
-#include <log/log.h>
-
-#include <cutils/properties.h>
-#include <hardware/hardware.h>
-#include <hardware/vibrator.h>
-
-#include "Vibrator.h"
-
-#include <cinttypes>
-#include <cmath>
-#include <fstream>
-#include <iostream>
-
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
-#endif
-
-namespace android {
-namespace hardware {
-namespace vibrator {
-namespace V1_3 {
-namespace implementation {
-
-using Status = ::android::hardware::vibrator::V1_0::Status;
-using EffectStrength = ::android::hardware::vibrator::V1_0::EffectStrength;
-
-static constexpr uint32_t WAVEFORM_SIMPLE_EFFECT_INDEX = 2;
-
-static constexpr uint32_t WAVEFORM_TEXTURE_TICK_EFFECT_LEVEL = 0;
-
-static constexpr uint32_t WAVEFORM_TICK_EFFECT_LEVEL = 1;
-
-static constexpr uint32_t WAVEFORM_CLICK_EFFECT_LEVEL = 2;
-
-static constexpr uint32_t WAVEFORM_HEAVY_CLICK_EFFECT_LEVEL = 3;
-
-static constexpr uint32_t WAVEFORM_DOUBLE_CLICK_SILENCE_MS = 100;
-
-static constexpr uint32_t WAVEFORM_LONG_VIBRATION_EFFECT_INDEX = 0;
-
-static constexpr uint32_t WAVEFORM_TRIGGER_QUEUE_INDEX = 65534;
-
-static constexpr uint32_t VOLTAGE_GLOBAL_SCALE_LEVEL = 5;
-static constexpr uint8_t VOLTAGE_SCALE_MAX = 100;
-
-static constexpr int8_t MAX_COLD_START_LATENCY_MS = 6; // I2C Transaction + DSP Return-From-Standby
-static constexpr int8_t MAX_PAUSE_TIMING_ERROR_MS = 1; // ALERT Irq Handling
-
-static constexpr float AMP_ATTENUATE_STEP_SIZE = 0.125f;
-static constexpr float EFFECT_FREQUENCY_KHZ = 48.0f;
-
-static uint8_t amplitudeToScale(uint8_t amplitude, uint8_t maximum) {
-    return std::round((-20 * std::log10(amplitude / static_cast<float>(maximum))) /
-                      (AMP_ATTENUATE_STEP_SIZE));
-}
-
-Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal)
-    : mHwApi(std::move(hwapi)), mHwCal(std::move(hwcal)) {
-    uint32_t caldata;
-    uint32_t effectDuration;
-
-    if (!mHwApi->setState(true)) {
-        ALOGE("Failed to set state (%d): %s", errno, strerror(errno));
-    }
-
-    if (mHwCal->getF0(&caldata)) {
-        mHwApi->setF0(caldata);
-    }
-    if (mHwCal->getRedc(&caldata)) {
-        mHwApi->setRedc(caldata);
-    }
-    if (mHwCal->getQ(&caldata)) {
-        mHwApi->setQ(caldata);
-    }
-    mHwCal->getVolLevels(&mVolLevels);
-
-    mHwApi->setEffectIndex(WAVEFORM_SIMPLE_EFFECT_INDEX);
-    mHwApi->getEffectDuration(&effectDuration);
-
-    mSimpleEffectDuration = std::ceil(effectDuration / EFFECT_FREQUENCY_KHZ);
-
-    const uint32_t scaleFall =
-        amplitudeToScale(mVolLevels[WAVEFORM_CLICK_EFFECT_LEVEL], VOLTAGE_SCALE_MAX);
-    const uint32_t scaleRise =
-        amplitudeToScale(mVolLevels[WAVEFORM_HEAVY_CLICK_EFFECT_LEVEL], VOLTAGE_SCALE_MAX);
-
-    mHwApi->setGpioFallIndex(WAVEFORM_SIMPLE_EFFECT_INDEX);
-    mHwApi->setGpioFallScale(scaleFall);
-    mHwApi->setGpioRiseIndex(WAVEFORM_SIMPLE_EFFECT_INDEX);
-    mHwApi->setGpioRiseScale(scaleRise);
-}
-
-Return<Status> Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex) {
-    mHwApi->setEffectIndex(effectIndex);
-    mHwApi->setDuration(timeoutMs);
-    mHwApi->setActivate(1);
-
-    return Status::OK;
-}
-
-// Methods from ::android::hardware::vibrator::V1_1::IVibrator follow.
-Return<Status> Vibrator::on(uint32_t timeoutMs) {
-    if (MAX_COLD_START_LATENCY_MS <= UINT32_MAX - timeoutMs) {
-        timeoutMs += MAX_COLD_START_LATENCY_MS;
-    }
-    setGlobalAmplitude(true);
-    return on(timeoutMs, WAVEFORM_LONG_VIBRATION_EFFECT_INDEX);
-}
-
-Return<Status> Vibrator::off() {
-    setGlobalAmplitude(false);
-    if (!mHwApi->setActivate(0)) {
-        ALOGE("Failed to turn vibrator off (%d): %s", errno, strerror(errno));
-        return Status::UNKNOWN_ERROR;
-    }
-    return Status::OK;
-}
-
-Return<bool> Vibrator::supportsAmplitudeControl() {
-    return !isUnderExternalControl() && mHwApi->hasEffectScale();
-}
-
-Return<Status> Vibrator::setAmplitude(uint8_t amplitude) {
-    if (!amplitude) {
-        return Status::BAD_VALUE;
-    }
-
-    if (!isUnderExternalControl()) {
-        return setEffectAmplitude(amplitude, UINT8_MAX);
-    } else {
-        return Status::UNSUPPORTED_OPERATION;
-    }
-}
-
-Return<Status> Vibrator::setEffectAmplitude(uint8_t amplitude, uint8_t maximum) {
-    int32_t scale = amplitudeToScale(amplitude, maximum);
-
-    if (!mHwApi->setEffectScale(scale)) {
-        ALOGE("Failed to set effect amplitude (%d): %s", errno, strerror(errno));
-        return Status::UNKNOWN_ERROR;
-    }
-
-    return Status::OK;
-}
-
-Return<Status> Vibrator::setGlobalAmplitude(bool set) {
-    uint8_t amplitude = set ? mVolLevels[VOLTAGE_GLOBAL_SCALE_LEVEL] : VOLTAGE_SCALE_MAX;
-    int32_t scale = amplitudeToScale(amplitude, VOLTAGE_SCALE_MAX);
-
-    if (!mHwApi->setGlobalScale(scale)) {
-        ALOGE("Failed to set global amplitude (%d): %s", errno, strerror(errno));
-        return Status::UNKNOWN_ERROR;
-    }
-
-    return Status::OK;
-}
-
-// Methods from ::android::hardware::vibrator::V1_3::IVibrator follow.
-
-Return<bool> Vibrator::supportsExternalControl() {
-    return (mHwApi->hasAspEnable() ? true : false);
-}
-
-Return<Status> Vibrator::setExternalControl(bool enabled) {
-    setGlobalAmplitude(enabled);
-
-    if (!mHwApi->setAspEnable(enabled)) {
-        ALOGE("Failed to set external control (%d): %s", errno, strerror(errno));
-        return Status::UNKNOWN_ERROR;
-    }
-    return Status::OK;
-}
-
-bool Vibrator::isUnderExternalControl() {
-    bool isAspEnabled;
-    mHwApi->getAspEnable(&isAspEnabled);
-    return isAspEnabled;
-}
-
-// Methods from ::android.hidl.base::V1_0::IBase follow.
-
-Return<void> Vibrator::debug(const hidl_handle &handle,
-                             const hidl_vec<hidl_string> & /* options */) {
-    if (handle == nullptr || handle->numFds < 1 || handle->data[0] < 0) {
-        ALOGE("Called debug() with invalid fd.");
-        return Void();
-    }
-
-    int fd = handle->data[0];
-
-    dprintf(fd, "HIDL:\n");
-
-    dprintf(fd, "  Voltage Levels:");
-    for (auto v : mVolLevels) {
-        dprintf(fd, " %" PRIu32, v);
-    }
-    dprintf(fd, "\n");
-
-    dprintf(fd, "  Effect Duration: %" PRIu32 "\n", mSimpleEffectDuration);
-
-    dprintf(fd, "\n");
-
-    mHwApi->debug(fd);
-
-    dprintf(fd, "\n");
-
-    mHwCal->debug(fd);
-
-    fsync(fd);
-    return Void();
-}
-
-template <typename T>
-Return<void> Vibrator::performWrapper(T effect, EffectStrength strength, perform_cb _hidl_cb) {
-    auto validRange = hidl_enum_range<T>();
-    if (effect < *validRange.begin() || effect > *std::prev(validRange.end())) {
-        _hidl_cb(Status::UNSUPPORTED_OPERATION, 0);
-        return Void();
-    }
-    return performEffect(static_cast<Effect>(effect), strength, _hidl_cb);
-}
-
-Return<void> Vibrator::perform(V1_0::Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
-    return performWrapper(effect, strength, _hidl_cb);
-}
-
-Return<void> Vibrator::perform_1_1(V1_1::Effect_1_1 effect, EffectStrength strength,
-                                   perform_cb _hidl_cb) {
-    return performWrapper(effect, strength, _hidl_cb);
-}
-
-Return<void> Vibrator::perform_1_2(V1_2::Effect effect, EffectStrength strength,
-                                   perform_cb _hidl_cb) {
-    return performWrapper(effect, strength, _hidl_cb);
-}
-
-Return<void> Vibrator::perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
-    return performWrapper(effect, strength, _hidl_cb);
-}
-
-Return<Status> Vibrator::getSimpleDetails(Effect effect, EffectStrength strength,
-                                          uint32_t *outTimeMs, uint32_t *outVolLevel) {
-    uint32_t timeMs;
-    uint32_t volLevel;
-    uint32_t volIndex;
-    int8_t volOffset;
-
-    switch (strength) {
-        case EffectStrength::LIGHT:
-            volOffset = -1;
-            break;
-        case EffectStrength::MEDIUM:
-            volOffset = 0;
-            break;
-        case EffectStrength::STRONG:
-            volOffset = 1;
-            break;
-        default:
-            return Status::UNSUPPORTED_OPERATION;
-    }
-
-    switch (effect) {
-        case Effect::TEXTURE_TICK:
-            volIndex = WAVEFORM_TEXTURE_TICK_EFFECT_LEVEL;
-            volOffset = 0;
-            break;
-        case Effect::TICK:
-            volIndex = WAVEFORM_TICK_EFFECT_LEVEL;
-            volOffset = 0;
-            break;
-        case Effect::CLICK:
-            volIndex = WAVEFORM_CLICK_EFFECT_LEVEL;
-            break;
-        case Effect::HEAVY_CLICK:
-            volIndex = WAVEFORM_HEAVY_CLICK_EFFECT_LEVEL;
-            break;
-        default:
-            return Status::UNSUPPORTED_OPERATION;
-    }
-
-    volLevel = mVolLevels[volIndex + volOffset];
-    timeMs = mSimpleEffectDuration + MAX_COLD_START_LATENCY_MS;
-
-    *outTimeMs = timeMs;
-    *outVolLevel = volLevel;
-
-    return Status::OK;
-}
-
-Return<Status> Vibrator::getCompoundDetails(Effect effect, EffectStrength strength,
-                                            uint32_t *outTimeMs, uint32_t * /*outVolLevel*/,
-                                            std::string *outEffectQueue) {
-    Status status;
-    uint32_t timeMs;
-    std::ostringstream effectBuilder;
-    uint32_t thisTimeMs;
-    uint32_t thisVolLevel;
-
-    switch (effect) {
-        case Effect::DOUBLE_CLICK:
-            timeMs = 0;
-
-            status = getSimpleDetails(Effect::CLICK, strength, &thisTimeMs, &thisVolLevel);
-            if (status != Status::OK) {
-                return status;
-            }
-            effectBuilder << WAVEFORM_SIMPLE_EFFECT_INDEX << "." << thisVolLevel;
-            timeMs += thisTimeMs;
-
-            effectBuilder << ",";
-
-            effectBuilder << WAVEFORM_DOUBLE_CLICK_SILENCE_MS;
-            timeMs += WAVEFORM_DOUBLE_CLICK_SILENCE_MS + MAX_PAUSE_TIMING_ERROR_MS;
-
-            effectBuilder << ",";
-
-            status = getSimpleDetails(Effect::HEAVY_CLICK, strength, &thisTimeMs, &thisVolLevel);
-            if (status != Status::OK) {
-                return status;
-            }
-            effectBuilder << WAVEFORM_SIMPLE_EFFECT_INDEX << "." << thisVolLevel;
-            timeMs += thisTimeMs;
-
-            break;
-        default:
-            return Status::UNSUPPORTED_OPERATION;
-    }
-
-    *outTimeMs = timeMs;
-    *outEffectQueue = effectBuilder.str();
-
-    return Status::OK;
-}
-
-Return<Status> Vibrator::setEffectQueue(const std::string &effectQueue) {
-    if (!mHwApi->setEffectQueue(effectQueue)) {
-        ALOGE("Failed to write \"%s\" to effect queue (%d): %s", effectQueue.c_str(), errno,
-              strerror(errno));
-        return Status::UNKNOWN_ERROR;
-    }
-
-    return Status::OK;
-}
-
-Return<void> Vibrator::performEffect(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
-    Status status = Status::OK;
-    uint32_t timeMs = 0;
-    uint32_t effectIndex;
-    uint32_t volLevel;
-    std::string effectQueue;
-
-    switch (effect) {
-        case Effect::TEXTURE_TICK:
-            // fall-through
-        case Effect::TICK:
-            // fall-through
-        case Effect::CLICK:
-            // fall-through
-        case Effect::HEAVY_CLICK:
-            status = getSimpleDetails(effect, strength, &timeMs, &volLevel);
-            break;
-        case Effect::DOUBLE_CLICK:
-            status = getCompoundDetails(effect, strength, &timeMs, &volLevel, &effectQueue);
-            break;
-        default:
-            status = Status::UNSUPPORTED_OPERATION;
-            break;
-    }
-    if (status != Status::OK) {
-        goto exit;
-    }
-
-    if (!effectQueue.empty()) {
-        status = setEffectQueue(effectQueue);
-        if (status != Status::OK) {
-            goto exit;
-        }
-        effectIndex = WAVEFORM_TRIGGER_QUEUE_INDEX;
-    } else {
-        setEffectAmplitude(volLevel, VOLTAGE_SCALE_MAX);
-        effectIndex = WAVEFORM_SIMPLE_EFFECT_INDEX;
-    }
-
-    on(timeMs, effectIndex);
-
-exit:
-
-    _hidl_cb(status, timeMs);
-
-    return Void();
-}
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace vibrator
-}  // namespace hardware
-}  // namespace android
diff --git a/vibrator/Vibrator.h b/vibrator/Vibrator.h
deleted file mode 100644
index b204dae..0000000
--- a/vibrator/Vibrator.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-#ifndef ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
-#define ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
-
-#include <android/hardware/vibrator/1.3/IVibrator.h>
-#include <hidl/Status.h>
-
-#include <fstream>
-
-namespace android {
-namespace hardware {
-namespace vibrator {
-namespace V1_3 {
-namespace implementation {
-
-class Vibrator : public IVibrator {
-  public:
-    // APIs for interfacing with the kernel driver.
-    class HwApi {
-      public:
-        virtual ~HwApi() = default;
-        // Stores the LRA resonant frequency to be used for PWLE playback
-        // and click compensation.
-        virtual bool setF0(uint32_t value) = 0;
-        // Stores the LRA series resistance to be used for click
-        // compensation.
-        virtual bool setRedc(uint32_t value) = 0;
-        // Stores the LRA Q factor to be used for Q-dependent waveform
-        // selection.
-        virtual bool setQ(uint32_t value) = 0;
-        // Activates/deactivates the vibrator for durations specified by
-        // setDuration().
-        virtual bool setActivate(bool value) = 0;
-        // Specifies the vibration duration in milliseconds.
-        virtual bool setDuration(uint32_t value) = 0;
-        // Reports the duration of the waveform selected by
-        // setEffectIndex(), measured in 48-kHz periods.
-        virtual bool getEffectDuration(uint32_t *value) = 0;
-        // Selects the waveform associated with vibration calls from
-        // the Android vibrator HAL.
-        virtual bool setEffectIndex(uint32_t value) = 0;
-        // Specifies an array of waveforms, delays, and repetition markers to
-        // generate complex waveforms.
-        virtual bool setEffectQueue(std::string value) = 0;
-        // Reports whether setEffectScale() is supported.
-        virtual bool hasEffectScale() = 0;
-        // Indicates the number of 0.125-dB steps of attenuation to apply to
-        // waveforms triggered in response to vibration calls from the
-        // Android vibrator HAL.
-        virtual bool setEffectScale(uint32_t value) = 0;
-        // Indicates the number of 0.125-dB steps of attenuation to apply to
-        // any output waveform (additive to all other set*Scale()
-        // controls).
-        virtual bool setGlobalScale(uint32_t value) = 0;
-        // Specifies the active state of the vibrator
-        // (true = enabled, false= disabled).
-        virtual bool setState(bool value) = 0;
-        // Reports whether getAspEnable()/setAspEnable() is supported.
-        virtual bool hasAspEnable() = 0;
-        // Enables/disables ASP playback.
-        virtual bool getAspEnable(bool *value) = 0;
-        // Reports enabled/disabled state of ASP playback.
-        virtual bool setAspEnable(bool value) = 0;
-        // Selects the waveform associated with a GPIO1 falling edge.
-        virtual bool setGpioFallIndex(uint32_t value) = 0;
-        // Indicates the number of 0.125-dB steps of attenuation to apply to
-        // waveforms triggered in response to a GPIO1 falling edge.
-        virtual bool setGpioFallScale(uint32_t value) = 0;
-        // Selects the waveform associated with a GPIO1 rising edge.
-        virtual bool setGpioRiseIndex(uint32_t value) = 0;
-        // Indicates the number of 0.125-dB steps of attenuation to apply to
-        // waveforms triggered in response to a GPIO1 rising edge.
-        virtual bool setGpioRiseScale(uint32_t value) = 0;
-        // Emit diagnostic information to the given file.
-        virtual void debug(int fd) = 0;
-    };
-
-    // APIs for obtaining calibration/configuration data from persistent memory.
-    class HwCal {
-      public:
-        virtual ~HwCal() = default;
-        // Obtains the LRA resonant frequency to be used for PWLE playback
-        // and click compensation.
-        virtual bool getF0(uint32_t *value) = 0;
-        // Obtains the LRA series resistance to be used for click
-        // compensation.
-        virtual bool getRedc(uint32_t *value) = 0;
-        // Obtains the LRA Q factor to be used for Q-dependent waveform
-        // selection.
-        virtual bool getQ(uint32_t *value) = 0;
-        // Obtains the discreet voltage levels to be applied for the various
-        // waveforms, in units of 1%.
-        virtual bool getVolLevels(std::array<uint32_t, 6> *value) = 0;
-        // Emit diagnostic information to the given file.
-        virtual void debug(int fd) = 0;
-    };
-
-  public:
-    Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal);
-
-    // Methods from ::android::hardware::vibrator::V1_0::IVibrator follow.
-    using Status = ::android::hardware::vibrator::V1_0::Status;
-    Return<Status> on(uint32_t timeoutMs) override;
-    Return<Status> off() override;
-    Return<bool> supportsAmplitudeControl() override;
-    Return<Status> setAmplitude(uint8_t amplitude) override;
-
-    // Methods from ::android::hardware::vibrator::V1_3::IVibrator follow.
-    Return<bool> supportsExternalControl() override;
-    Return<Status> setExternalControl(bool enabled) override;
-
-    using EffectStrength = ::android::hardware::vibrator::V1_0::EffectStrength;
-    Return<void> perform(V1_0::Effect effect, EffectStrength strength,
-                         perform_cb _hidl_cb) override;
-    Return<void> perform_1_1(V1_1::Effect_1_1 effect, EffectStrength strength,
-                             perform_cb _hidl_cb) override;
-    Return<void> perform_1_2(V1_2::Effect effect, EffectStrength strength,
-                             perform_cb _hidl_cb) override;
-    Return<void> perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) override;
-
-    // Methods from ::android.hidl.base::V1_0::IBase follow.
-    Return<void> debug(const hidl_handle &handle, const hidl_vec<hidl_string> &options) override;
-
-  private:
-    Return<Status> on(uint32_t timeoutMs, uint32_t effectIndex);
-    template <typename T>
-    Return<void> performWrapper(T effect, EffectStrength strength, perform_cb _hidl_cb);
-    // set 'amplitude' based on an arbitrary scale determined by 'maximum'
-    Return<Status> setEffectAmplitude(uint8_t amplitude, uint8_t maximum);
-    Return<Status> setGlobalAmplitude(bool set);
-    // 'simple' effects are those precompiled and loaded into the controller
-    Return<Status> getSimpleDetails(Effect effect, EffectStrength strength, uint32_t *outTimeMs,
-                                    uint32_t *outVolLevel);
-    // 'compound' effects are those composed by stringing multiple 'simple' effects
-    Return<Status> getCompoundDetails(Effect effect, EffectStrength strength, uint32_t *outTimeMs,
-                                      uint32_t *outVolLevel, std::string *outEffectQueue);
-    Return<Status> setEffectQueue(const std::string &effectQueue);
-    Return<void> performEffect(Effect effect, EffectStrength strength, perform_cb _hidl_cb);
-    bool isUnderExternalControl();
-    std::unique_ptr<HwApi> mHwApi;
-    std::unique_ptr<HwCal> mHwCal;
-    std::array<uint32_t, 6> mVolLevels;
-    uint32_t mSimpleEffectDuration;
-};
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace vibrator
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
diff --git a/vibrator/android.hardware.vibrator@1.3-service.redfin.rc b/vibrator/android.hardware.vibrator@1.3-service.redfin.rc
deleted file mode 100644
index a609ab0..0000000
--- a/vibrator/android.hardware.vibrator@1.3-service.redfin.rc
+++ /dev/null
@@ -1,38 +0,0 @@
-service vendor.vibrator-1-3 /vendor/bin/hw/android.hardware.vibrator@1.3-service.redfin
-    class hal
-    user system
-    group system
-
-    setenv CALIBRATION_FILEPATH /mnt/vendor/persist/haptics/cs40l25a.cal
-
-    setenv F0_FILEPATH /sys/class/leds/vibrator/device/f0_stored
-    setenv REDC_FILEPATH /sys/class/leds/vibrator/device/redc_stored
-    setenv Q_FILEPATH /sys/class/leds/vibrator/device/q_stored
-    setenv ACTIVATE_PATH /sys/class/leds/vibrator/activate
-    setenv DURATION_PATH /sys/class/leds/vibrator/duration
-    setenv STATE_PATH /sys/class/leds/vibrator/state
-    setenv EFFECT_DURATION_PATH /sys/class/leds/vibrator/device/cp_trigger_duration
-    setenv EFFECT_INDEX_PATH /sys/class/leds/vibrator/device/cp_trigger_index
-    setenv EFFECT_QUEUE_PATH /sys/class/leds/vibrator/device/cp_trigger_queue
-    setenv EFFECT_SCALE_PATH /sys/class/leds/vibrator/device/cp_dig_scale
-    setenv GLOBAL_SCALE_PATH /sys/class/leds/vibrator/device/dig_scale
-    setenv ASP_ENABLE_PATH /sys/class/leds/vibrator/device/asp_enable
-    setenv GPIO_FALL_INDEX /sys/class/leds/vibrator/device/gpio1_fall_index
-    setenv GPIO_FALL_SCALE /sys/class/leds/vibrator/device/gpio1_fall_dig_scale
-    setenv GPIO_RISE_INDEX /sys/class/leds/vibrator/device/gpio1_rise_index
-    setenv GPIO_RISE_SCALE /sys/class/leds/vibrator/device/gpio1_rise_dig_scale
-
-    setenv HWAPI_DEBUG_PATHS "
-        /sys/class/leds/vibrator/device/asp_enable
-        /sys/class/leds/vibrator/device/f0_stored
-        /sys/class/leds/vibrator/device/fw_rev
-        /sys/class/leds/vibrator/device/gpio1_fall_dig_scale
-        /sys/class/leds/vibrator/device/gpio1_fall_index
-        /sys/class/leds/vibrator/device/gpio1_rise_dig_scale
-        /sys/class/leds/vibrator/device/gpio1_rise_index
-        /sys/class/leds/vibrator/device/heartbeat
-        /sys/class/leds/vibrator/device/num_waves
-        /sys/class/leds/vibrator/device/q_stored
-        /sys/class/leds/vibrator/device/redc_stored
-        /sys/class/leds/vibrator/state
-        "
diff --git a/vibrator/common/Android.bp b/vibrator/common/Android.bp
new file mode 100644
index 0000000..477aa05
--- /dev/null
+++ b/vibrator/common/Android.bp
@@ -0,0 +1,33 @@
+//
+// 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.
+
+cc_library {
+    name: "PixelVibratorCommonRedfin",
+    srcs: [
+        "HardwareBase.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+        "libutils",
+    ],
+    cflags: [
+        "-DATRACE_TAG=(ATRACE_TAG_VIBRATOR | ATRACE_TAG_HAL)",
+        "-DLOG_TAG=\"android.hardware.vibrator@1.x-common\"",
+    ],
+    export_include_dirs: ["."],
+    vendor_available: true,
+}
diff --git a/vibrator/common/HardwareBase.cpp b/vibrator/common/HardwareBase.cpp
new file mode 100644
index 0000000..f868b6a
--- /dev/null
+++ b/vibrator/common/HardwareBase.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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 "HardwareBase.h"
+
+#include <cutils/properties.h>
+#include <log/log.h>
+
+#include <fstream>
+#include <sstream>
+
+#include "utils.h"
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace common {
+namespace implementation {
+
+HwApiBase::HwApiBase() {
+    mPathPrefix = std::getenv("HWAPI_PATH_PREFIX") ?: "";
+    if (mPathPrefix.empty()) {
+        ALOGE("Failed get HWAPI path prefix!");
+    }
+}
+
+bool HwApiBase::has(const std::ios &stream) {
+    return !!stream;
+}
+
+void HwApiBase::debug(int fd) {
+    dprintf(fd, "Kernel:\n");
+
+    for (auto &entry : utils::pathsFromEnv("HWAPI_DEBUG_PATHS", mPathPrefix)) {
+        auto &path = entry.first;
+        auto &stream = entry.second;
+        std::string line;
+
+        dprintf(fd, "  %s:\n", path.c_str());
+        while (std::getline(stream, line)) {
+            dprintf(fd, "    %s\n", line.c_str());
+        }
+    }
+
+    mRecordsMutex.lock();
+    dprintf(fd, "  Records:\n");
+    for (auto &r : mRecords) {
+        if (r == nullptr) {
+            continue;
+        }
+        dprintf(fd, "    %s\n", r->toString(mNames).c_str());
+    }
+    mRecordsMutex.unlock();
+}
+
+HwCalBase::HwCalBase() {
+    std::ifstream calfile;
+    auto propertyPrefix = std::getenv("PROPERTY_PREFIX");
+
+    if (propertyPrefix != NULL) {
+        mPropertyPrefix = std::string(propertyPrefix);
+    } else {
+        ALOGE("Failed get property prefix!");
+    }
+
+    utils::fileFromEnv("CALIBRATION_FILEPATH", &calfile);
+
+    for (std::string line; std::getline(calfile, line);) {
+        if (line.empty() || line[0] == '#') {
+            continue;
+        }
+        std::istringstream is_line(line);
+        std::string key, value;
+        if (std::getline(is_line, key, ':') && std::getline(is_line, value)) {
+            mCalData[utils::trim(key)] = utils::trim(value);
+        }
+    }
+}
+
+void HwCalBase::debug(int fd) {
+    std::ifstream stream;
+    std::string path;
+    std::string line;
+    struct context {
+        HwCalBase *obj;
+        int fd;
+    } context{this, fd};
+
+    dprintf(fd, "Properties:\n");
+
+    property_list(
+        [](const char *key, const char *value, void *cookie) {
+            struct context *context = static_cast<struct context *>(cookie);
+            HwCalBase *obj = context->obj;
+            int fd = context->fd;
+            const std::string expect{obj->mPropertyPrefix};
+            const std::string actual{key, std::min(strlen(key), expect.size())};
+            if (actual == expect) {
+                dprintf(fd, "  %s:\n", key);
+                dprintf(fd, "    %s\n", value);
+            }
+        },
+        &context);
+
+    dprintf(fd, "\n");
+
+    dprintf(fd, "Persist:\n");
+
+    utils::fileFromEnv("CALIBRATION_FILEPATH", &stream, &path);
+
+    dprintf(fd, "  %s:\n", path.c_str());
+    while (std::getline(stream, line)) {
+        dprintf(fd, "    %s\n", line.c_str());
+    }
+}
+
+}  // namespace implementation
+}  // namespace common
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
diff --git a/vibrator/common/HardwareBase.h b/vibrator/common/HardwareBase.h
new file mode 100644
index 0000000..46aa839
--- /dev/null
+++ b/vibrator/common/HardwareBase.h
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ */
+#ifndef ANDROID_HARDWARE_VIBRATOR_HARDWARE_BASE_H
+#define ANDROID_HARDWARE_VIBRATOR_HARDWARE_BASE_H
+
+#include <android-base/unique_fd.h>
+#include <log/log.h>
+#include <sys/epoll.h>
+#include <utils/Trace.h>
+
+#include <list>
+#include <map>
+#include <sstream>
+#include <string>
+
+#include "utils.h"
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace common {
+namespace implementation {
+
+using base::unique_fd;
+
+class HwApiBase {
+  private:
+    using NamesMap = std::map<const std::ios *, std::string>;
+
+    class RecordInterface {
+      public:
+        virtual std::string toString(const NamesMap &names) = 0;
+        virtual ~RecordInterface() {}
+    };
+    template <typename T>
+    class Record : public RecordInterface {
+      public:
+        Record(const char *func, const T &value, const std::ios *stream)
+            : mFunc(func), mValue(value), mStream(stream) {}
+        std::string toString(const NamesMap &names) override;
+
+      private:
+        const char *mFunc;
+        const T mValue;
+        const std::ios *mStream;
+    };
+    using Records = std::list<std::unique_ptr<RecordInterface>>;
+
+    static constexpr uint32_t RECORDS_SIZE = 32;
+
+  public:
+    HwApiBase();
+    void debug(int fd);
+
+  protected:
+    template <typename T>
+    void open(const std::string &name, T *stream);
+    bool has(const std::ios &stream);
+    template <typename T>
+    bool get(T *value, std::istream *stream);
+    template <typename T>
+    bool set(const T &value, std::ostream *stream);
+    template <typename T>
+    bool poll(const T &value, std::istream *stream);
+    template <typename T>
+    void record(const char *func, const T &value, const std::ios *stream);
+
+  private:
+    std::string mPathPrefix;
+    NamesMap mNames;
+    Records mRecords{RECORDS_SIZE};
+    std::mutex mRecordsMutex;
+};
+
+#define HWAPI_RECORD(args...) HwApiBase::record(__FUNCTION__, ##args)
+
+template <typename T>
+void HwApiBase::open(const std::string &name, T *stream) {
+    mNames[stream] = name;
+    utils::openNoCreate(mPathPrefix + name, stream);
+}
+
+template <typename T>
+bool HwApiBase::get(T *value, std::istream *stream) {
+    ATRACE_NAME("HwApi::get");
+    bool ret;
+    stream->seekg(0);
+    *stream >> *value;
+    if (!(ret = !!*stream)) {
+        ALOGE("Failed to read %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno));
+    }
+    stream->clear();
+    HWAPI_RECORD(*value, stream);
+    return ret;
+}
+
+template <typename T>
+bool HwApiBase::set(const T &value, std::ostream *stream) {
+    ATRACE_NAME("HwApi::set");
+    using utils::operator<<;
+    bool ret;
+    *stream << value << std::endl;
+    if (!(ret = !!*stream)) {
+        ALOGE("Failed to write %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno));
+        stream->clear();
+    }
+    HWAPI_RECORD(value, stream);
+    return ret;
+}
+
+template <typename T>
+bool HwApiBase::poll(const T &value, std::istream *stream) {
+    ATRACE_NAME("HwApi::poll");
+    auto path = mPathPrefix + mNames[stream];
+    unique_fd fileFd{::open(path.c_str(), O_RDONLY)};
+    unique_fd epollFd{epoll_create(1)};
+    epoll_event event = {
+        .events = EPOLLPRI | EPOLLET,
+    };
+    T actual;
+    bool ret;
+
+    if (epoll_ctl(epollFd, EPOLL_CTL_ADD, fileFd, &event)) {
+        ALOGE("Failed to poll %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno));
+        return false;
+    }
+
+    while ((ret = get(&actual, stream)) && (actual != value)) {
+        epoll_wait(epollFd, &event, 1, -1);
+    }
+
+    HWAPI_RECORD(value, stream);
+    return ret;
+}
+
+template <typename T>
+void HwApiBase::record(const char *func, const T &value, const std::ios *stream) {
+    std::lock_guard<std::mutex> lock(mRecordsMutex);
+    mRecords.emplace_back(std::make_unique<Record<T>>(func, value, stream));
+    mRecords.pop_front();
+}
+
+template <typename T>
+std::string HwApiBase::Record<T>::toString(const NamesMap &names) {
+    using utils::operator<<;
+    std::stringstream ret;
+
+    ret << mFunc << " '" << names.at(mStream) << "' = '" << mValue << "'";
+
+    return ret.str();
+}
+
+class HwCalBase {
+  public:
+    HwCalBase();
+    void debug(int fd);
+
+  protected:
+    template <typename T>
+    bool getProperty(const char *key, T *value, const T defval);
+    template <typename T>
+    bool getPersist(const char *key, T *value);
+
+  private:
+    std::string mPropertyPrefix;
+    std::map<std::string, std::string> mCalData;
+};
+
+template <typename T>
+bool HwCalBase::getProperty(const char *key, T *outval, const T defval) {
+    ATRACE_NAME("HwCal::getProperty");
+    *outval = utils::getProperty(mPropertyPrefix + key, defval);
+    return true;
+}
+
+template <typename T>
+bool HwCalBase::getPersist(const char *key, T *value) {
+    ATRACE_NAME("HwCal::getPersist");
+    auto it = mCalData.find(key);
+    if (it == mCalData.end()) {
+        ALOGE("Missing %s config!", key);
+        return false;
+    }
+    std::stringstream stream{it->second};
+    utils::unpack(stream, value);
+    if (!stream || !stream.eof()) {
+        ALOGE("Invalid %s config!", key);
+        return false;
+    }
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace common
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_VIBRATOR_HARDWARE_BASE_H
diff --git a/vibrator/common/TEST_MAPPING b/vibrator/common/TEST_MAPPING
new file mode 100644
index 0000000..c0e8e98
--- /dev/null
+++ b/vibrator/common/TEST_MAPPING
@@ -0,0 +1,13 @@
+{
+  "postsubmit": [
+    {
+      "name": "VibratorHalIntegrationBenchmark"
+    },
+    {
+      "name": "VibratorHalIntegrationBenchmark",
+      "keywords": [
+        "primary-device"
+      ]
+    }
+  ]
+}
diff --git a/vibrator/common/bench/Android.bp b/vibrator/common/bench/Android.bp
new file mode 100644
index 0000000..8df1d8d
--- /dev/null
+++ b/vibrator/common/bench/Android.bp
@@ -0,0 +1,32 @@
+//
+// 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.
+
+cc_benchmark {
+    name: "VibratorHalIntegrationBenchmarkRedfin",
+    defaults: ["hidl_defaults"],
+    srcs: [
+        "benchmark.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.vibrator@1.0",
+        "android.hardware.vibrator@1.1",
+        "android.hardware.vibrator@1.2",
+        "android.hardware.vibrator@1.3",
+        "libhardware",
+        "libhidlbase",
+        "libutils",
+    ],
+    test_suites: ["device-tests"],
+}
diff --git a/vibrator/common/bench/benchmark.cpp b/vibrator/common/bench/benchmark.cpp
new file mode 100644
index 0000000..06013f9
--- /dev/null
+++ b/vibrator/common/bench/benchmark.cpp
@@ -0,0 +1,274 @@
+/*
+ * 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 "benchmark/benchmark.h"
+
+#include <android/hardware/vibrator/1.3/IVibrator.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_enum_range;
+using ::android::hardware::Return;
+using ::android::hardware::details::hidl_enum_values;
+using ::benchmark::Counter;
+using ::benchmark::Fixture;
+using ::benchmark::kMicrosecond;
+using ::benchmark::State;
+using ::benchmark::internal::Benchmark;
+using ::std::chrono::duration;
+using ::std::chrono::duration_cast;
+using ::std::chrono::high_resolution_clock;
+
+namespace V1_0 = ::android::hardware::vibrator::V1_0;
+namespace V1_1 = ::android::hardware::vibrator::V1_1;
+namespace V1_2 = ::android::hardware::vibrator::V1_2;
+namespace V1_3 = ::android::hardware::vibrator::V1_3;
+
+template <typename I>
+class VibratorBench : public Fixture {
+  public:
+    void SetUp(State & /*state*/) override { mVibrator = I::getService(); }
+
+    void TearDown(State & /*state*/) override {
+        if (!mVibrator) {
+            return;
+        }
+        mVibrator->off();
+    }
+
+    static void DefaultConfig(Benchmark *b) { b->Unit(kMicrosecond); }
+
+    static void DefaultArgs(Benchmark * /*b*/) {
+        // none
+    }
+
+  protected:
+    auto getOtherArg(const State &state, std::size_t index) const {
+        return state.range(index + 0);
+    }
+
+  protected:
+    sp<I> mVibrator;
+};
+
+enum class EmptyEnum : uint32_t;
+template <>
+inline constexpr std::array<EmptyEnum, 0> hidl_enum_values<EmptyEnum> = {};
+
+template <typename T, typename U>
+std::set<T> difference(const hidl_enum_range<T> &t, const hidl_enum_range<U> &u) {
+    class Compare {
+      public:
+        bool operator()(const T &a, const U &b) { return a < static_cast<T>(b); }
+        bool operator()(const U &a, const T &b) { return static_cast<T>(a) < b; }
+    };
+    std::set<T> ret;
+
+    std::set_difference(t.begin(), t.end(), u.begin(), u.end(),
+                        std::insert_iterator<decltype(ret)>(ret, ret.begin()), Compare());
+
+    return ret;
+}
+
+template <typename I, typename E1, typename E2 = EmptyEnum>
+class VibratorEffectsBench : public VibratorBench<I> {
+  public:
+    using Effect = E1;
+    using EffectStrength = V1_0::EffectStrength;
+    using Status = V1_0::Status;
+
+  public:
+    static void DefaultArgs(Benchmark *b) {
+        b->ArgNames({"Effect", "Strength"});
+        for (const auto &effect : difference(hidl_enum_range<E1>(), hidl_enum_range<E2>())) {
+            for (const auto &strength : hidl_enum_range<EffectStrength>()) {
+                b->Args({static_cast<long>(effect), static_cast<long>(strength)});
+            }
+        }
+    }
+
+    void performBench(State *state, Return<void> (I::*performApi)(Effect, EffectStrength,
+                                                                  typename I::perform_cb)) {
+        auto effect = getEffect(*state);
+        auto strength = getStrength(*state);
+        bool supported = true;
+
+        (*this->mVibrator.*performApi)(effect, strength, [&](Status status, uint32_t /*lengthMs*/) {
+            if (status == Status::UNSUPPORTED_OPERATION) {
+                supported = false;
+            }
+        });
+
+        if (!supported) {
+            return;
+        }
+
+        for (auto _ : *state) {
+            state->ResumeTiming();
+            (*this->mVibrator.*performApi)(effect, strength,
+                                           [](Status /*status*/, uint32_t /*lengthMs*/) {});
+            state->PauseTiming();
+            this->mVibrator->off();
+        }
+    }
+
+  protected:
+    auto getEffect(const State &state) const {
+        return static_cast<Effect>(this->getOtherArg(state, 0));
+    }
+
+    auto getStrength(const State &state) const {
+        return static_cast<EffectStrength>(this->getOtherArg(state, 1));
+    }
+};
+
+#define BENCHMARK_WRAPPER(fixt, test, code) \
+    BENCHMARK_DEFINE_F(fixt, test)          \
+    /* NOLINTNEXTLINE */                    \
+    (State & state) {                       \
+        if (!mVibrator) {                   \
+            return;                         \
+        }                                   \
+                                            \
+        code                                \
+    }                                       \
+    BENCHMARK_REGISTER_F(fixt, test)->Apply(fixt::DefaultConfig)->Apply(fixt::DefaultArgs)
+
+using VibratorBench_V1_0 = VibratorBench<V1_0::IVibrator>;
+
+BENCHMARK_WRAPPER(VibratorBench_V1_0, on, {
+    uint32_t ms = UINT32_MAX;
+
+    for (auto _ : state) {
+        state.ResumeTiming();
+        mVibrator->on(ms);
+        state.PauseTiming();
+        mVibrator->off();
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_0, off, {
+    uint32_t ms = UINT32_MAX;
+
+    for (auto _ : state) {
+        state.PauseTiming();
+        mVibrator->on(ms);
+        state.ResumeTiming();
+        mVibrator->off();
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_0, supportsAmplitudeControl, {
+    for (auto _ : state) {
+        mVibrator->supportsAmplitudeControl();
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_0, setAmplitude, {
+    uint8_t amplitude = UINT8_MAX;
+
+    if (!mVibrator->supportsAmplitudeControl()) {
+        return;
+    }
+
+    mVibrator->on(UINT32_MAX);
+
+    for (auto _ : state) {
+        mVibrator->setAmplitude(amplitude);
+    }
+
+    mVibrator->off();
+});
+
+using VibratorEffectsBench_V1_0 = VibratorEffectsBench<V1_0::IVibrator, V1_0::Effect>;
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_V1_0, perform,
+                  { performBench(&state, &V1_0::IVibrator::perform); });
+
+using VibratorEffectsBench_V1_1 =
+    VibratorEffectsBench<V1_1::IVibrator, V1_1::Effect_1_1, V1_0::Effect>;
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_V1_1, perform_1_1,
+                  { performBench(&state, &V1_1::IVibrator::perform_1_1); });
+
+using VibratorEffectsBench_V1_2 =
+    VibratorEffectsBench<V1_2::IVibrator, V1_2::Effect, V1_1::Effect_1_1>;
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_V1_2, perform_1_2,
+                  { performBench(&state, &V1_2::IVibrator::perform_1_2); });
+
+using VibratorBench_V1_3 = VibratorBench<V1_3::IVibrator>;
+
+BENCHMARK_WRAPPER(VibratorBench_V1_3, supportsExternalControl, {
+    for (auto _ : state) {
+        mVibrator->supportsExternalControl();
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalControl, {
+    bool enable = true;
+
+    if (!mVibrator->supportsExternalControl()) {
+        return;
+    }
+
+    for (auto _ : state) {
+        state.ResumeTiming();
+        mVibrator->setExternalControl(enable);
+        state.PauseTiming();
+        mVibrator->setExternalControl(false);
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_3, supportsExternalAmplitudeControl, {
+    if (!mVibrator->supportsExternalControl()) {
+        return;
+    }
+
+    mVibrator->setExternalControl(true);
+
+    for (auto _ : state) {
+        mVibrator->supportsAmplitudeControl();
+    }
+
+    mVibrator->setExternalControl(false);
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalAmplitude, {
+    uint8_t amplitude = UINT8_MAX;
+
+    if (!mVibrator->supportsExternalControl()) {
+        return;
+    }
+
+    mVibrator->setExternalControl(true);
+
+    if (!mVibrator->supportsAmplitudeControl()) {
+        return;
+    }
+
+    for (auto _ : state) {
+        mVibrator->setAmplitude(amplitude);
+    }
+
+    mVibrator->setExternalControl(false);
+});
+
+using VibratorEffectsBench_V1_3 = VibratorEffectsBench<V1_3::IVibrator, V1_3::Effect, V1_2::Effect>;
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_V1_3, perform_1_3,
+                  { performBench(&state, &V1_3::IVibrator::perform_1_3); });
+
+BENCHMARK_MAIN();
diff --git a/vibrator/common/utils.h b/vibrator/common/utils.h
new file mode 100644
index 0000000..2079256
--- /dev/null
+++ b/vibrator/common/utils.h
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+#ifndef ANDROID_HARDWARE_VIBRATOR_UTILS_H
+#define ANDROID_HARDWARE_VIBRATOR_UTILS_H
+
+#include <android-base/macros.h>
+#include <android-base/properties.h>
+#include <log/log.h>
+
+#include <fstream>
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace utils {
+
+template <typename T>
+class Is_Iterable {
+  private:
+    template <typename U>
+    static std::true_type test(typename U::iterator *u);
+
+    template <typename U>
+    static std::false_type test(U *u);
+
+  public:
+    static const bool value = decltype(test<T>(0))::value;
+};
+
+template <typename T, bool B>
+using Enable_If_Iterable = std::enable_if_t<Is_Iterable<T>::value == B>;
+
+template <typename T, typename U = void>
+using Enable_If_Signed = std::enable_if_t<std::is_signed_v<T>, U>;
+
+template <typename T, typename U = void>
+using Enable_If_Unsigned = std::enable_if_t<std::is_unsigned_v<T>, U>;
+
+// override for default behavior of printing as a character
+inline std::ostream &operator<<(std::ostream &stream, const int8_t value) {
+    return stream << +value;
+}
+// override for default behavior of printing as a character
+inline std::ostream &operator<<(std::ostream &stream, const uint8_t value) {
+    return stream << +value;
+}
+
+template <typename T>
+inline auto toUnderlying(const T value) {
+    return static_cast<std::underlying_type_t<T>>(value);
+}
+
+template <typename T>
+inline Enable_If_Iterable<T, true> unpack(std::istream &stream, T *value) {
+    for (auto &entry : *value) {
+        stream >> entry;
+    }
+}
+
+template <typename T>
+inline Enable_If_Iterable<T, false> unpack(std::istream &stream, T *value) {
+    stream >> *value;
+}
+
+template <>
+inline void unpack<std::string>(std::istream &stream, std::string *value) {
+    *value = std::string(std::istreambuf_iterator(stream), {});
+    stream.setstate(std::istream::eofbit);
+}
+
+template <typename T>
+inline Enable_If_Signed<T, T> getProperty(const std::string &key, const T def) {
+    return base::GetIntProperty(key, def);
+}
+
+template <typename T>
+inline Enable_If_Unsigned<T, T> getProperty(const std::string &key, const T def) {
+    return base::GetUintProperty(key, def);
+}
+
+template <>
+inline bool getProperty<bool>(const std::string &key, const bool def) {
+    return base::GetBoolProperty(key, def);
+}
+
+template <typename T>
+static void openNoCreate(const std::string &file, T *outStream) {
+    auto mode = std::is_base_of_v<std::ostream, T> ? std::ios_base::out : std::ios_base::in;
+
+    // Force 'in' mode to prevent file creation
+    outStream->open(file, mode | std::ios_base::in);
+    if (!*outStream) {
+        ALOGE("Failed to open %s (%d): %s", file.c_str(), errno, strerror(errno));
+    }
+}
+
+template <typename T>
+static void fileFromEnv(const char *env, T *outStream, std::string *outName = nullptr) {
+    auto file = std::getenv(env);
+
+    if (file == nullptr) {
+        ALOGE("Failed get env %s", env);
+        return;
+    }
+
+    if (outName != nullptr) {
+        *outName = std::string(file);
+    }
+
+    openNoCreate(file, outStream);
+}
+
+static ATTRIBUTE_UNUSED auto pathsFromEnv(const char *env, const std::string &prefix = "") {
+    std::map<std::string, std::ifstream> ret;
+    auto value = std::getenv(env);
+
+    if (value == nullptr) {
+        return ret;
+    }
+
+    std::istringstream paths{value};
+    std::string path;
+
+    while (paths >> path) {
+        ret[path].open(prefix + path);
+    }
+
+    return ret;
+}
+
+static ATTRIBUTE_UNUSED std::string trim(const std::string &str,
+                                         const std::string &whitespace = " \t") {
+    const auto str_begin = str.find_first_not_of(whitespace);
+    if (str_begin == std::string::npos) {
+        return "";
+    }
+
+    const auto str_end = str.find_last_not_of(whitespace);
+    const auto str_range = str_end - str_begin + 1;
+
+    return str.substr(str_begin, str_range);
+}
+
+}  // namespace utils
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_VIBRATOR_UTILS_H
diff --git a/vibrator/drv2624/Android.bp b/vibrator/drv2624/Android.bp
new file mode 100644
index 0000000..cf75650
--- /dev/null
+++ b/vibrator/drv2624/Android.bp
@@ -0,0 +1,55 @@
+//
+// Copyright (C) 2017 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.
+
+cc_defaults {
+    name: "android.hardware.vibrator@1.3-defaults.redfin",
+    defaults: ["PixelVibratorDefaultsRedfin"],
+    shared_libs: [
+        "android.hardware.vibrator@1.0",
+        "android.hardware.vibrator@1.1",
+        "android.hardware.vibrator@1.2",
+        "android.hardware.vibrator@1.3",
+    ],
+    cflags: [
+        "-DATRACE_TAG=(ATRACE_TAG_VIBRATOR | ATRACE_TAG_HAL)",
+        "-DLOG_TAG=\"android.hardware.vibrator@1.3-redfin\"",
+    ],
+}
+
+cc_defaults {
+    name: "VibratorHalDrv2624TestDefaultsRedfin",
+    defaults: ["android.hardware.vibrator@1.3-defaults.redfin"],
+    static_libs: ["android.hardware.vibrator@1.3-impl.redfin"],
+    test_suites: ["device-tests"],
+    require_root: true,
+}
+
+cc_library {
+    name: "android.hardware.vibrator@1.3-impl.redfin",
+    defaults: ["android.hardware.vibrator@1.3-defaults.redfin"],
+    srcs: ["Vibrator.cpp"],
+    export_include_dirs: ["."],
+    vendor_available: true,
+}
+
+cc_binary {
+    name: "android.hardware.vibrator@1.3-service.redfin",
+    defaults: ["android.hardware.vibrator@1.3-defaults.redfin"],
+    init_rc: ["android.hardware.vibrator@1.3-service.redfin.rc"],
+    vintf_fragments: ["android.hardware.vibrator@1.3-service.redfin.xml"],
+    srcs: ["service.cpp"],
+    static_libs: ["android.hardware.vibrator@1.3-impl.redfin"],
+    proprietary: true,
+}
diff --git a/vibrator/drv2624/Hardware.h b/vibrator/drv2624/Hardware.h
new file mode 100644
index 0000000..d43fa6d
--- /dev/null
+++ b/vibrator/drv2624/Hardware.h
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+#ifndef ANDROID_HARDWARE_VIBRATOR_HARDWARE_H
+#define ANDROID_HARDWARE_VIBRATOR_HARDWARE_H
+
+#include "HardwareBase.h"
+#include "Vibrator.h"
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+using common::implementation::HwApiBase;
+using common::implementation::HwCalBase;
+
+class HwApi : public Vibrator::HwApi, private HwApiBase {
+  public:
+    static std::unique_ptr<HwApi> Create() {
+        auto hwapi = std::unique_ptr<HwApi>(new HwApi());
+        // the following streams are required
+        if (!hwapi->mActivate.is_open() || !hwapi->mDuration.is_open() ||
+            !hwapi->mState.is_open()) {
+            return nullptr;
+        }
+        return hwapi;
+    }
+
+    bool setAutocal(std::string value) override { return set(value, &mAutocal); }
+    bool setOlLraPeriod(uint32_t value) override { return set(value, &mOlLraPeriod); }
+    bool setActivate(bool value) override { return set(value, &mActivate); }
+    bool setDuration(uint32_t value) override { return set(value, &mDuration); }
+    bool setState(bool value) override { return set(value, &mState); }
+    bool hasRtpInput() override { return has(mRtpInput); }
+    bool setRtpInput(int8_t value) override { return set(value, &mRtpInput); }
+    bool setMode(std::string value) override { return set(value, &mMode); }
+    bool setSequencer(std::string value) override { return set(value, &mSequencer); }
+    bool setScale(uint8_t value) override { return set(value, &mScale); }
+    bool setCtrlLoop(bool value) override { return set(value, &mCtrlLoop); }
+    bool setLpTriggerEffect(uint32_t value) override { return set(value, &mLpTrigger); }
+    bool setLraWaveShape(uint32_t value) override { return set(value, &mLraWaveShape); }
+    bool setOdClamp(uint32_t value) override { return set(value, &mOdClamp); }
+    void debug(int fd) override { HwApiBase::debug(fd); }
+
+  private:
+    HwApi() {
+        open("device/autocal", &mAutocal);
+        open("device/ol_lra_period", &mOlLraPeriod);
+        open("activate", &mActivate);
+        open("duration", &mDuration);
+        open("state", &mState);
+        open("device/rtp_input", &mRtpInput);
+        open("device/mode", &mMode);
+        open("device/set_sequencer", &mSequencer);
+        open("device/scale", &mScale);
+        open("device/ctrl_loop", &mCtrlLoop);
+        open("device/lp_trigger_effect", &mLpTrigger);
+        open("device/lra_wave_shape", &mLraWaveShape);
+        open("device/od_clamp", &mOdClamp);
+    }
+
+  private:
+    std::ofstream mAutocal;
+    std::ofstream mOlLraPeriod;
+    std::ofstream mActivate;
+    std::ofstream mDuration;
+    std::ofstream mState;
+    std::ofstream mRtpInput;
+    std::ofstream mMode;
+    std::ofstream mSequencer;
+    std::ofstream mScale;
+    std::ofstream mCtrlLoop;
+    std::ofstream mLpTrigger;
+    std::ofstream mLraWaveShape;
+    std::ofstream mOdClamp;
+};
+
+class HwCal : public Vibrator::HwCal, private HwCalBase {
+  private:
+    static constexpr char AUTOCAL_CONFIG[] = "autocal";
+    static constexpr char LRA_PERIOD_CONFIG[] = "lra_period";
+    static constexpr char EFFECT_COEFF_CONFIG[] = "haptic_coefficient";
+    static constexpr char STEADY_AMP_MAX_CONFIG[] = "vibration_amp_max";
+
+    static constexpr uint32_t WAVEFORM_CLICK_EFFECT_MS = 6;
+    static constexpr uint32_t WAVEFORM_TICK_EFFECT_MS = 2;
+    static constexpr uint32_t WAVEFORM_DOUBLE_CLICK_EFFECT_MS = 144;
+    static constexpr uint32_t WAVEFORM_HEAVY_CLICK_EFFECT_MS = 8;
+
+    static constexpr uint32_t DEFAULT_LRA_PERIOD = 262;
+    static constexpr uint32_t DEFAULT_FREQUENCY_SHIFT = 10;
+    static constexpr uint32_t DEFAULT_VOLTAGE_MAX = 107;  // 2.15V;
+
+  public:
+    HwCal() {}
+
+    bool getAutocal(std::string *value) override { return getPersist(AUTOCAL_CONFIG, value); }
+    bool getLraPeriod(uint32_t *value) override {
+        if (getPersist(LRA_PERIOD_CONFIG, value)) {
+            return true;
+        }
+        *value = DEFAULT_LRA_PERIOD;
+        return true;
+    }
+    bool getEffectCoeffs(std::array<float, 4> *value) override {
+        if (getPersist(EFFECT_COEFF_CONFIG, value)) {
+            return true;
+        }
+        return false;
+    }
+    bool getSteadyAmpMax(float *value) override {
+        if (getPersist(STEADY_AMP_MAX_CONFIG, value)) {
+            return true;
+        }
+        return false;
+    }
+    bool getCloseLoopThreshold(uint32_t *value) override {
+        return getProperty("closeloop.threshold", value, UINT32_MAX);
+        return true;
+    }
+    bool getDynamicConfig(bool *value) override {
+        return getProperty("config.dynamic", value, false);
+    }
+    bool getLongFrequencyShift(uint32_t *value) override {
+        return getProperty("long.frequency.shift", value, DEFAULT_FREQUENCY_SHIFT);
+    }
+    bool getShortVoltageMax(uint32_t *value) override {
+        return getProperty("short.voltage", value, DEFAULT_VOLTAGE_MAX);
+    }
+    bool getLongVoltageMax(uint32_t *value) override {
+        return getProperty("long.voltage", value, DEFAULT_VOLTAGE_MAX);
+    }
+    bool getClickDuration(uint32_t *value) override {
+        return getProperty("click.duration", value, WAVEFORM_CLICK_EFFECT_MS);
+    }
+    bool getTickDuration(uint32_t *value) override {
+        return getProperty("tick.duration", value, WAVEFORM_TICK_EFFECT_MS);
+    }
+    bool getDoubleClickDuration(uint32_t *value) override {
+        *value = WAVEFORM_DOUBLE_CLICK_EFFECT_MS;
+        return true;
+    }
+    bool getHeavyClickDuration(uint32_t *value) override {
+        return getProperty("heavyclick.duration", value, WAVEFORM_HEAVY_CLICK_EFFECT_MS);
+    }
+    bool getEffectShape(uint32_t *value) override {
+        return getProperty("effect.shape", value, UINT32_MAX);
+    }
+    bool getSteadyShape(uint32_t *value) override {
+        return getProperty("steady.shape", value, UINT32_MAX);
+    }
+    void debug(int fd) override { HwCalBase::debug(fd); }
+};
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_VIBRATOR_HARDWARE_H
diff --git a/vibrator/drv2624/TEST_MAPPING b/vibrator/drv2624/TEST_MAPPING
new file mode 100644
index 0000000..ec34f66
--- /dev/null
+++ b/vibrator/drv2624/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "VibratorHalDrv2624TestSuite"
+    }
+  ],
+  "postsubmit": [
+    {
+      "name": "VibratorHalDrv2624Benchmark",
+      "keywords": [
+        "primary-device"
+      ]
+    }
+  ]
+}
diff --git a/vibrator/drv2624/Vibrator.cpp b/vibrator/drv2624/Vibrator.cpp
new file mode 100644
index 0000000..02d786f
--- /dev/null
+++ b/vibrator/drv2624/Vibrator.cpp
@@ -0,0 +1,485 @@
+/*
+ * Copyright (C) 2017 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 "Vibrator.h"
+
+#include <cutils/properties.h>
+#include <hardware/hardware.h>
+#include <hardware/vibrator.h>
+#include <log/log.h>
+#include <utils/Trace.h>
+
+#include <cinttypes>
+#include <cmath>
+#include <fstream>
+#include <iostream>
+
+#include "utils.h"
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+static constexpr int8_t MAX_RTP_INPUT = 127;
+static constexpr int8_t MIN_RTP_INPUT = 0;
+
+static constexpr char RTP_MODE[] = "rtp";
+static constexpr char WAVEFORM_MODE[] = "waveform";
+
+// Use effect #1 in the waveform library for CLICK effect
+static constexpr char WAVEFORM_CLICK_EFFECT_SEQ[] = "1 0";
+
+// Use effect #2 in the waveform library for TICK effect
+static constexpr char WAVEFORM_TICK_EFFECT_SEQ[] = "2 0";
+
+// Use effect #3 in the waveform library for DOUBLE_CLICK effect
+static constexpr char WAVEFORM_DOUBLE_CLICK_EFFECT_SEQ[] = "3 0";
+
+// Use effect #4 in the waveform library for HEAVY_CLICK effect
+static constexpr char WAVEFORM_HEAVY_CLICK_EFFECT_SEQ[] = "4 0";
+
+// UT team design those target G values
+static constexpr std::array<float, 5> EFFECT_TARGET_G = {0.175, 0.325, 0.37, 0.475, 0.6};
+static constexpr std::array<float, 3> STEADY_TARGET_G = {1.38, 1.145, 0.905};
+
+#define FLOAT_EPS 1e-6
+
+static std::uint32_t freqPeriodFormula(std::uint32_t in) {
+    return 1000000000 / (24615 * in);
+}
+
+static std::uint32_t convertLevelsToOdClamp(float voltageLevel, uint32_t lraPeriod) {
+    float odClamp;
+
+    odClamp = voltageLevel /
+              ((21.32 / 1000.0) *
+               sqrt(1.0 - (static_cast<float>(freqPeriodFormula(lraPeriod)) * 8.0 / 10000.0)));
+
+    return round(odClamp);
+}
+
+static float targetGToVlevelsUnderLinearEquation(std::array<float, 4> inputCoeffs, float targetG) {
+    // Implement linear equation to get voltage levels, f(x) = ax + b
+    // 0 to 3.2 is our valid output
+    float outPutVal = 0.0f;
+    outPutVal = (targetG - inputCoeffs[1]) / inputCoeffs[0];
+    if ((outPutVal > FLOAT_EPS) && (outPutVal <= 3.2)) {
+        return outPutVal;
+    } else {
+        return 0.0f;
+    }
+}
+
+static float targetGToVlevelsUnderCubicEquation(std::array<float, 4> inputCoeffs, float targetG) {
+    // Implement cubic equation to get voltage levels, f(x) = ax^3 + bx^2 + cx + d
+    // 0 to 3.2 is our valid output
+    float AA = 0.0f, BB = 0.0f, CC = 0.0f, Delta = 0.0f;
+    float Y1 = 0.0f, Y2 = 0.0f, K = 0.0f, T = 0.0f, sita = 0.0f;
+    float outPutVal = 0.0f;
+    float oneHalf = 1.0 / 2.0, oneThird = 1.0 / 3.0;
+    float cosSita = 0.0f, sinSitaSqrt3 = 0.0f, sqrtA = 0.0f;
+
+    AA = inputCoeffs[1] * inputCoeffs[1] - 3.0 * inputCoeffs[0] * inputCoeffs[2];
+    BB = inputCoeffs[1] * inputCoeffs[2] - 9.0 * inputCoeffs[0] * (inputCoeffs[3] - targetG);
+    CC = inputCoeffs[2] * inputCoeffs[2] - 3.0 * inputCoeffs[1] * (inputCoeffs[3] - targetG);
+
+    Delta = BB * BB - 4.0 * AA * CC;
+
+    // There are four discriminants in Shengjin formula.
+    // https://zh.wikipedia.org/wiki/%E4%B8%89%E6%AC%A1%E6%96%B9%E7%A8%8B#%E7%9B%9B%E9%87%91%E5%85%AC%E5%BC%8F%E6%B3%95
+    if ((fabs(AA) <= FLOAT_EPS) && (fabs(BB) <= FLOAT_EPS)) {
+        // Case 1: A = B = 0
+        outPutVal = -inputCoeffs[1] / (3 * inputCoeffs[0]);
+        if ((outPutVal > FLOAT_EPS) && (outPutVal <= 3.2)) {
+            return outPutVal;
+        }
+        return 0.0f;
+    } else if (Delta > FLOAT_EPS) {
+        // Case 2: Delta > 0
+        Y1 = AA * inputCoeffs[1] + 3.0 * inputCoeffs[0] * (-BB + pow(Delta, oneHalf)) / 2.0;
+        Y2 = AA * inputCoeffs[1] + 3.0 * inputCoeffs[0] * (-BB - pow(Delta, oneHalf)) / 2.0;
+
+        if ((Y1 < -FLOAT_EPS) && (Y2 > FLOAT_EPS)) {
+            return (-inputCoeffs[1] + pow(-Y1, oneThird) - pow(Y2, oneThird)) /
+                   (3.0 * inputCoeffs[0]);
+        } else if ((Y1 > FLOAT_EPS) && (Y2 < -FLOAT_EPS)) {
+            return (-inputCoeffs[1] - pow(Y1, oneThird) + pow(-Y2, oneThird)) /
+                   (3.0 * inputCoeffs[0]);
+        } else if ((Y1 < -FLOAT_EPS) && (Y2 < -FLOAT_EPS)) {
+            return (-inputCoeffs[1] + pow(-Y1, oneThird) + pow(-Y2, oneThird)) /
+                   (3.0 * inputCoeffs[0]);
+        } else {
+            return (-inputCoeffs[1] - pow(Y1, oneThird) - pow(Y2, oneThird)) /
+                   (3.0 * inputCoeffs[0]);
+        }
+        return 0.0f;
+    } else if (Delta < -FLOAT_EPS) {
+        // Case 3: Delta < 0
+        T = (2 * AA * inputCoeffs[1] - 3 * inputCoeffs[0] * BB) / (2 * AA * sqrt(AA));
+        sita = acos(T);
+        cosSita = cos(sita / 3);
+        sinSitaSqrt3 = sqrt(3.0) * sin(sita / 3);
+        sqrtA = sqrt(AA);
+
+        outPutVal = (-inputCoeffs[1] - 2 * sqrtA * cosSita) / (3 * inputCoeffs[0]);
+        if ((outPutVal > FLOAT_EPS) && (outPutVal <= 3.2)) {
+            return outPutVal;
+        }
+        outPutVal = (-inputCoeffs[1] + sqrtA * (cosSita + sinSitaSqrt3)) / (3 * inputCoeffs[0]);
+        if ((outPutVal > FLOAT_EPS) && (outPutVal <= 3.2)) {
+            return outPutVal;
+        }
+        outPutVal = (-inputCoeffs[1] + sqrtA * (cosSita - sinSitaSqrt3)) / (3 * inputCoeffs[0]);
+        if ((outPutVal > FLOAT_EPS) && (outPutVal <= 3.2)) {
+            return outPutVal;
+        }
+        return 0.0f;
+    } else if (Delta <= FLOAT_EPS) {
+        // Case 4: Delta = 0
+        K = BB / AA;
+        outPutVal = (-inputCoeffs[1] / inputCoeffs[0] + K);
+        if ((outPutVal > FLOAT_EPS) && (outPutVal <= 3.2)) {
+            return outPutVal;
+        }
+        outPutVal = (-K / 2);
+        if ((outPutVal > FLOAT_EPS) && (outPutVal <= 3.2)) {
+            return outPutVal;
+        }
+        return 0.0f;
+    } else {
+        // Exception handling
+        return 0.0f;
+    }
+}
+
+using utils::toUnderlying;
+
+using Status = ::android::hardware::vibrator::V1_0::Status;
+using EffectStrength = ::android::hardware::vibrator::V1_0::EffectStrength;
+
+Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal)
+    : mHwApi(std::move(hwapi)), mHwCal(std::move(hwcal)) {
+    std::string autocal;
+    uint32_t lraPeriod = 0;
+    bool dynamicConfig = false;
+    bool hasEffectCoeffs = false;
+    std::array<float, 4> effectCoeffs = {0};
+
+    if (!mHwApi->setState(true)) {
+        ALOGE("Failed to set state (%d): %s", errno, strerror(errno));
+    }
+
+    if (mHwCal->getAutocal(&autocal)) {
+        mHwApi->setAutocal(autocal);
+    }
+    mHwCal->getLraPeriod(&lraPeriod);
+
+    mHwCal->getCloseLoopThreshold(&mCloseLoopThreshold);
+    mHwCal->getDynamicConfig(&dynamicConfig);
+
+    if (dynamicConfig) {
+        uint8_t i = 0;
+        float tempVolLevel = 0.0f;
+        float tempAmpMax = 0.0f;
+        uint32_t longFreqencyShift = 0;
+        uint32_t shortVoltageMax = 0, longVoltageMax = 0;
+        uint32_t shape = 0;
+
+        mHwCal->getLongFrequencyShift(&longFreqencyShift);
+        mHwCal->getShortVoltageMax(&shortVoltageMax);
+        mHwCal->getLongVoltageMax(&longVoltageMax);
+
+        hasEffectCoeffs = mHwCal->getEffectCoeffs(&effectCoeffs);
+        for (i = 0; i < 5; i++) {
+            if (hasEffectCoeffs) {
+                // Use linear approach to get the target voltage levels
+                if ((effectCoeffs[2] == 0) && (effectCoeffs[3] == 0)) {
+                    tempVolLevel =
+                        targetGToVlevelsUnderLinearEquation(effectCoeffs, EFFECT_TARGET_G[i]);
+                    mEffectTargetOdClamp[i] = convertLevelsToOdClamp(tempVolLevel, lraPeriod);
+                } else {
+                    // Use cubic approach to get the target voltage levels
+                    tempVolLevel =
+                        targetGToVlevelsUnderCubicEquation(effectCoeffs, EFFECT_TARGET_G[i]);
+                    mEffectTargetOdClamp[i] = convertLevelsToOdClamp(tempVolLevel, lraPeriod);
+                }
+            } else {
+                mEffectTargetOdClamp[i] = shortVoltageMax;
+            }
+        }
+        // Add a boundary protection for level 5 only, since
+        // some devices might not be able to reach the maximum target G
+        if ((mEffectTargetOdClamp[4] <= 0) || (mEffectTargetOdClamp[4] > 161)) {
+            mEffectTargetOdClamp[4] = shortVoltageMax;
+        }
+
+        mHwCal->getEffectShape(&shape);
+        mEffectConfig.reset(new VibrationConfig({
+            .shape = (shape == UINT32_MAX) ? WaveShape::SINE : static_cast<WaveShape>(shape),
+            .odClamp = &mEffectTargetOdClamp[0],
+            .olLraPeriod = lraPeriod,
+        }));
+
+        mSteadyTargetOdClamp = mHwCal->getSteadyAmpMax(&tempAmpMax)
+                                   ? round((STEADY_TARGET_G[0] / tempAmpMax) * longVoltageMax)
+                                   : longVoltageMax;
+        mHwCal->getSteadyShape(&shape);
+        mSteadyConfig.reset(new VibrationConfig({
+            .shape = (shape == UINT32_MAX) ? WaveShape::SQUARE : static_cast<WaveShape>(shape),
+            .odClamp = &mSteadyTargetOdClamp,
+            // 1. Change long lra period to frequency
+            // 2. Get frequency': subtract the frequency shift from the frequency
+            // 3. Get final long lra period after put the frequency' to formula
+            .olLraPeriod = freqPeriodFormula(freqPeriodFormula(lraPeriod) - longFreqencyShift),
+        }));
+    } else {
+        mHwApi->setOlLraPeriod(lraPeriod);
+    }
+
+    mHwCal->getClickDuration(&mClickDuration);
+    mHwCal->getTickDuration(&mTickDuration);
+    mHwCal->getDoubleClickDuration(&mDoubleClickDuration);
+    mHwCal->getHeavyClickDuration(&mHeavyClickDuration);
+
+    // This enables effect #1 from the waveform library to be triggered by SLPI
+    // while the AP is in suspend mode
+    if (!mHwApi->setLpTriggerEffect(1)) {
+        ALOGW("Failed to set LP trigger mode (%d): %s", errno, strerror(errno));
+    }
+}
+
+Return<Status> Vibrator::on(uint32_t timeoutMs, const char mode[],
+                            const std::unique_ptr<VibrationConfig> &config,
+                            const int8_t volOffset) {
+    LoopControl loopMode = LoopControl::OPEN;
+
+    // Open-loop mode is used for short click for over-drive
+    // Close-loop mode is used for long notification for stability
+    if (mode == RTP_MODE && timeoutMs > mCloseLoopThreshold) {
+        loopMode = LoopControl::CLOSE;
+    }
+
+    mHwApi->setCtrlLoop(toUnderlying(loopMode));
+    if (!mHwApi->setDuration(timeoutMs)) {
+        ALOGE("Failed to set duration (%d): %s", errno, strerror(errno));
+        return Status::UNKNOWN_ERROR;
+    }
+
+    mHwApi->setMode(mode);
+    if (config != nullptr) {
+        mHwApi->setLraWaveShape(toUnderlying(config->shape));
+        mHwApi->setOdClamp(config->odClamp[volOffset]);
+        mHwApi->setOlLraPeriod(config->olLraPeriod);
+    }
+
+    if (!mHwApi->setActivate(1)) {
+        ALOGE("Failed to activate (%d): %s", errno, strerror(errno));
+        return Status::UNKNOWN_ERROR;
+    }
+
+    return Status::OK;
+}
+
+// Methods from ::android::hardware::vibrator::V1_2::IVibrator follow.
+Return<Status> Vibrator::on(uint32_t timeoutMs) {
+    ATRACE_NAME("Vibrator::on");
+    return on(timeoutMs, RTP_MODE, mSteadyConfig, 0);
+}
+
+Return<Status> Vibrator::off() {
+    ATRACE_NAME("Vibrator::off");
+    if (!mHwApi->setActivate(0)) {
+        ALOGE("Failed to turn vibrator off (%d): %s", errno, strerror(errno));
+        return Status::UNKNOWN_ERROR;
+    }
+    return Status::OK;
+}
+
+Return<bool> Vibrator::supportsAmplitudeControl() {
+    ATRACE_NAME("Vibrator::supportsAmplitudeControl");
+    return (mHwApi->hasRtpInput() ? true : false);
+}
+
+Return<Status> Vibrator::setAmplitude(uint8_t amplitude) {
+    ATRACE_NAME("Vibrator::setAmplitude");
+    if (amplitude == 0) {
+        return Status::BAD_VALUE;
+    }
+
+    int32_t rtp_input =
+        std::round((amplitude - 1) / 254.0 * (MAX_RTP_INPUT - MIN_RTP_INPUT) + MIN_RTP_INPUT);
+
+    if (!mHwApi->setRtpInput(rtp_input)) {
+        ALOGE("Failed to set amplitude (%d): %s", errno, strerror(errno));
+        return Status::UNKNOWN_ERROR;
+    }
+
+    return Status::OK;
+}
+
+// Methods from ::android::hardware::vibrator::V1_3::IVibrator follow.
+
+Return<bool> Vibrator::supportsExternalControl() {
+    ATRACE_NAME("Vibrator::supportsExternalControl");
+    return false;
+}
+
+Return<Status> Vibrator::setExternalControl(bool enabled) {
+    ATRACE_NAME("Vibrator::setExternalControl");
+    ALOGE("Not support in DRV2624 solution, %d", enabled);
+    return Status::UNSUPPORTED_OPERATION;
+}
+
+// Methods from ::android.hidl.base::V1_0::IBase follow.
+
+Return<void> Vibrator::debug(const hidl_handle &handle,
+                             const hidl_vec<hidl_string> & /* options */) {
+    if (handle == nullptr || handle->numFds < 1 || handle->data[0] < 0) {
+        ALOGE("Called debug() with invalid fd.");
+        return Void();
+    }
+
+    int fd = handle->data[0];
+
+    dprintf(fd, "HIDL:\n");
+
+    dprintf(fd, "  Close Loop Thresh: %" PRIu32 "\n", mCloseLoopThreshold);
+    if (mSteadyConfig) {
+        dprintf(fd, "  Steady Shape: %" PRIu32 "\n", mSteadyConfig->shape);
+        dprintf(fd, "  Steady OD Clamp: %" PRIu32 "\n", mSteadyConfig->odClamp[0]);
+        dprintf(fd, "  Steady OL LRA Period: %" PRIu32 "\n", mSteadyConfig->olLraPeriod);
+    }
+    if (mEffectConfig) {
+        dprintf(fd, "  Effect Shape: %" PRIu32 "\n", mEffectConfig->shape);
+        dprintf(fd,
+                "  Effect OD Clamp: %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 "\n",
+                mEffectConfig->odClamp[0], mEffectConfig->odClamp[1], mEffectConfig->odClamp[2],
+                mEffectConfig->odClamp[3], mEffectConfig->odClamp[4]);
+        dprintf(fd, "  Effect OL LRA Period: %" PRIu32 "\n", mEffectConfig->olLraPeriod);
+    }
+    dprintf(fd, "  Click Duration: %" PRIu32 "\n", mClickDuration);
+    dprintf(fd, "  Tick Duration: %" PRIu32 "\n", mTickDuration);
+    dprintf(fd, "  Double Click Duration: %" PRIu32 "\n", mDoubleClickDuration);
+    dprintf(fd, "  Heavy Click Duration: %" PRIu32 "\n", mHeavyClickDuration);
+
+    dprintf(fd, "\n");
+
+    mHwApi->debug(fd);
+
+    dprintf(fd, "\n");
+
+    mHwCal->debug(fd);
+
+    fsync(fd);
+    return Void();
+}
+
+Return<void> Vibrator::perform(V1_0::Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
+    return performWrapper(effect, strength, _hidl_cb);
+}
+
+Return<void> Vibrator::perform_1_1(V1_1::Effect_1_1 effect, EffectStrength strength,
+                                   perform_cb _hidl_cb) {
+    return performWrapper(effect, strength, _hidl_cb);
+}
+
+Return<void> Vibrator::perform_1_2(V1_2::Effect effect, EffectStrength strength,
+                                   perform_cb _hidl_cb) {
+    return performWrapper(effect, strength, _hidl_cb);
+}
+
+Return<void> Vibrator::perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
+    return performWrapper(effect, strength, _hidl_cb);
+}
+
+template <typename T>
+Return<void> Vibrator::performWrapper(T effect, EffectStrength strength, perform_cb _hidl_cb) {
+    ATRACE_NAME("Vibrator::performWrapper");
+    auto validEffectRange = hidl_enum_range<T>();
+    if (effect < *validEffectRange.begin() || effect > *std::prev(validEffectRange.end())) {
+        _hidl_cb(Status::UNSUPPORTED_OPERATION, 0);
+        return Void();
+    }
+    auto validStrengthRange = hidl_enum_range<EffectStrength>();
+    if (strength < *validStrengthRange.begin() || strength > *std::prev(validStrengthRange.end())) {
+        _hidl_cb(Status::UNSUPPORTED_OPERATION, 0);
+        return Void();
+    }
+    return performEffect(static_cast<Effect>(effect), strength, _hidl_cb);
+}
+
+Return<void> Vibrator::performEffect(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
+    Status status = Status::OK;
+    uint32_t timeMS;
+    int8_t volOffset;
+
+    switch (strength) {
+        case EffectStrength::LIGHT:
+            volOffset = 0;
+            break;
+        case EffectStrength::MEDIUM:
+            volOffset = 1;
+            break;
+        case EffectStrength::STRONG:
+            volOffset = 1;
+            break;
+        default:
+            status = Status::UNSUPPORTED_OPERATION;
+            break;
+    }
+
+    switch (effect) {
+        case Effect::TEXTURE_TICK:
+            mHwApi->setSequencer(WAVEFORM_TICK_EFFECT_SEQ);
+            timeMS = mTickDuration;
+            volOffset = TEXTURE_TICK;
+            break;
+        case Effect::CLICK:
+            mHwApi->setSequencer(WAVEFORM_CLICK_EFFECT_SEQ);
+            timeMS = mClickDuration;
+            volOffset += CLICK;
+            break;
+        case Effect::DOUBLE_CLICK:
+            mHwApi->setSequencer(WAVEFORM_DOUBLE_CLICK_EFFECT_SEQ);
+            timeMS = mDoubleClickDuration;
+            volOffset += CLICK;
+            break;
+        case Effect::TICK:
+            mHwApi->setSequencer(WAVEFORM_TICK_EFFECT_SEQ);
+            timeMS = mTickDuration;
+            volOffset += TICK;
+            break;
+        case Effect::HEAVY_CLICK:
+            mHwApi->setSequencer(WAVEFORM_HEAVY_CLICK_EFFECT_SEQ);
+            timeMS = mHeavyClickDuration;
+            volOffset += HEAVY_CLICK;
+            break;
+        default:
+            _hidl_cb(Status::UNSUPPORTED_OPERATION, 0);
+            return Void();
+    }
+    on(timeMS, WAVEFORM_MODE, mEffectConfig, volOffset);
+    _hidl_cb(status, timeMS);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
diff --git a/vibrator/drv2624/Vibrator.h b/vibrator/drv2624/Vibrator.h
new file mode 100644
index 0000000..16cd8e8
--- /dev/null
+++ b/vibrator/drv2624/Vibrator.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+#ifndef ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
+#define ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
+
+#include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <hidl/Status.h>
+
+#include <fstream>
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+class Vibrator : public IVibrator {
+  public:
+    // APIs for interfacing with the kernel driver.
+    class HwApi {
+      public:
+        virtual ~HwApi() = default;
+        // Stores the COMP, BEMF, and GAIN calibration values to use.
+        //   <COMP> <BEMF> <GAIN>
+        virtual bool setAutocal(std::string value) = 0;
+        // Stores the open-loop LRA frequency to be used.
+        virtual bool setOlLraPeriod(uint32_t value) = 0;
+        // Activates/deactivates the vibrator for durations specified by
+        // setDuration().
+        virtual bool setActivate(bool value) = 0;
+        // Specifies the vibration duration in milliseconds.
+        virtual bool setDuration(uint32_t value) = 0;
+        // Specifies the active state of the vibrator
+        // (true = enabled, false = disabled).
+        virtual bool setState(bool value) = 0;
+        // Reports whether setRtpInput() is supported.
+        virtual bool hasRtpInput() = 0;
+        // Specifies the playback amplitude of the haptic waveforms in RTP mode.
+        // Negative numbers indicates braking.
+        virtual bool setRtpInput(int8_t value) = 0;
+        // Specifies the mode of operation.
+        //   rtp        - RTP Mode
+        //   waveform   - Waveform Sequencer Mode
+        //   diag       - Diagnostics Routine
+        //   autocal    - Automatic Level Calibration Routine
+        virtual bool setMode(std::string value) = 0;
+        // Specifies a waveform sequence in index-count pairs.
+        //   <index-1> <count-1> [<index-2> <cound-2> ...]
+        virtual bool setSequencer(std::string value) = 0;
+        // Specifies the scaling of effects in Waveform mode.
+        //   0 - 100%
+        //   1 - 75%
+        //   2 - 50%
+        //   3 - 25%
+        virtual bool setScale(uint8_t value) = 0;
+        // Selects either closed loop or open loop mode.
+        // (true = open, false = closed).
+        virtual bool setCtrlLoop(bool value) = 0;
+        // Specifies waveform index to be played in low-power trigger mode.
+        //   0  - Disabled
+        //   1+ - Waveform Index
+        virtual bool setLpTriggerEffect(uint32_t value) = 0;
+        // Specifies which shape to use for driving the LRA when in open loop
+        // mode.
+        //   0 - Square Wave
+        //   1 - Sine Wave
+        virtual bool setLraWaveShape(uint32_t value) = 0;
+        // Specifies the maximum voltage for automatic overdrive and automatic
+        // braking periods.
+        virtual bool setOdClamp(uint32_t value) = 0;
+        // Emit diagnostic information to the given file.
+        virtual void debug(int fd) = 0;
+    };
+
+    // APIs for obtaining calibration/configuration data from persistent memory.
+    class HwCal {
+      public:
+        virtual ~HwCal() = default;
+        // Obtains the COMP, BEMF, and GAIN calibration values to use.
+        virtual bool getAutocal(std::string *value) = 0;
+        // Obtains the open-loop LRA frequency to be used.
+        virtual bool getLraPeriod(uint32_t *value) = 0;
+        // Obtains the effect coeffs to calculate the target voltage
+        virtual bool getEffectCoeffs(std::array<float, 4> *value) = 0;
+        // Obtain the max steady G value
+        virtual bool getSteadyAmpMax(float *value) = 0;
+        // Obtains threshold in ms, above which close-loop should be used.
+        virtual bool getCloseLoopThreshold(uint32_t *value) = 0;
+        // Obtains dynamic/static configuration choice.
+        virtual bool getDynamicConfig(bool *value) = 0;
+        // Obtains LRA frequency shift for long (steady) vibrations.
+        virtual bool getLongFrequencyShift(uint32_t *value) = 0;
+        // Obtains maximum voltage for short (effect) vibrations
+        virtual bool getShortVoltageMax(uint32_t *value) = 0;
+        // Obtains maximum voltage for long (steady) vibrations
+        virtual bool getLongVoltageMax(uint32_t *value) = 0;
+        // Obtains the duration for the click effect
+        virtual bool getClickDuration(uint32_t *value) = 0;
+        // Obtains the duration for the tick effect
+        virtual bool getTickDuration(uint32_t *value) = 0;
+        // Obtains the duration for the double-click effect
+        virtual bool getDoubleClickDuration(uint32_t *value) = 0;
+        // Obtains the duration for the heavy-click effect
+        virtual bool getHeavyClickDuration(uint32_t *value) = 0;
+        // Obtains the wave shape for effect haptics
+        virtual bool getEffectShape(uint32_t *value) = 0;
+        // Obtains the wave shape for steady vibration
+        virtual bool getSteadyShape(uint32_t *value) = 0;
+        // Emit diagnostic information to the given file.
+        virtual void debug(int fd) = 0;
+    };
+
+  private:
+    enum class LoopControl : bool {
+        CLOSE = false,
+        OPEN = true,
+    };
+
+    enum class WaveShape : uint32_t {
+        SQUARE = 0,
+        SINE = 1,
+    };
+
+    struct VibrationConfig {
+        WaveShape shape;
+        uint32_t *odClamp;
+        uint32_t olLraPeriod;
+    };
+
+    enum OdClampOffset : uint32_t {
+        TEXTURE_TICK,
+        TICK,
+        CLICK,
+        HEAVY_CLICK,
+    };
+
+  public:
+    Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal);
+
+    // Methods from ::android::hardware::vibrator::V1_0::IVibrator follow.
+    using Status = ::android::hardware::vibrator::V1_0::Status;
+    Return<Status> on(uint32_t timeoutMs) override;
+    Return<Status> off() override;
+    Return<bool> supportsAmplitudeControl() override;
+    Return<Status> setAmplitude(uint8_t amplitude) override;
+
+    // Methods from ::android::hardware::vibrator::V1_3::IVibrator follow.
+    Return<bool> supportsExternalControl() override;
+    Return<Status> setExternalControl(bool enabled) override;
+
+    using EffectStrength = ::android::hardware::vibrator::V1_0::EffectStrength;
+    Return<void> perform(V1_0::Effect effect, EffectStrength strength,
+                         perform_cb _hidl_cb) override;
+    Return<void> perform_1_1(V1_1::Effect_1_1 effect, EffectStrength strength,
+                             perform_cb _hidl_cb) override;
+    Return<void> perform_1_2(V1_2::Effect effect, EffectStrength strength,
+                             perform_cb _hidl_cb) override;
+    Return<void> perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) override;
+
+    // Methods from ::android.hidl.base::V1_0::IBase follow.
+    Return<void> debug(const hidl_handle &handle, const hidl_vec<hidl_string> &options) override;
+
+  private:
+    Return<Status> on(uint32_t timeoutMs, const char mode[],
+                      const std::unique_ptr<VibrationConfig> &config, const int8_t volOffset);
+    template <typename T>
+    Return<void> performWrapper(T effect, EffectStrength strength, perform_cb _hidl_cb);
+    Return<void> performEffect(Effect effect, EffectStrength strength, perform_cb _hidl_cb);
+    std::unique_ptr<HwApi> mHwApi;
+    std::unique_ptr<HwCal> mHwCal;
+    uint32_t mCloseLoopThreshold;
+    std::unique_ptr<VibrationConfig> mSteadyConfig;
+    std::unique_ptr<VibrationConfig> mEffectConfig;
+    uint32_t mClickDuration;
+    uint32_t mTickDuration;
+    uint32_t mDoubleClickDuration;
+    uint32_t mHeavyClickDuration;
+    std::array<uint32_t, 5> mEffectTargetOdClamp;
+    uint32_t mSteadyTargetOdClamp;
+};
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
diff --git a/vibrator/drv2624/android.hardware.vibrator@1.3-service.redfin.rc b/vibrator/drv2624/android.hardware.vibrator@1.3-service.redfin.rc
new file mode 100644
index 0000000..02d6ea4
--- /dev/null
+++ b/vibrator/drv2624/android.hardware.vibrator@1.3-service.redfin.rc
@@ -0,0 +1,15 @@
+service vendor.vibrator-1-3 /vendor/bin/hw/android.hardware.vibrator@1.3-service.redfin
+    class hal
+    user system
+    group system
+
+    setenv PROPERTY_PREFIX ro.vibrator.hal.
+    setenv CALIBRATION_FILEPATH /mnt/vendor/persist/haptics/drv2624.cal
+
+    setenv HWAPI_PATH_PREFIX /sys/class/leds/vibrator/
+    setenv HWAPI_DEBUG_PATHS "
+        device/autocal
+        device/lp_trigger_effect
+        device/ol_lra_period
+        state
+        "
diff --git a/vibrator/android.hardware.vibrator@1.3-service.redfin.xml b/vibrator/drv2624/android.hardware.vibrator@1.3-service.redfin.xml
similarity index 100%
rename from vibrator/android.hardware.vibrator@1.3-service.redfin.xml
rename to vibrator/drv2624/android.hardware.vibrator@1.3-service.redfin.xml
diff --git a/vibrator/drv2624/bench/Android.bp b/vibrator/drv2624/bench/Android.bp
new file mode 100644
index 0000000..d7b63ef
--- /dev/null
+++ b/vibrator/drv2624/bench/Android.bp
@@ -0,0 +1,32 @@
+//
+// 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.
+
+cc_benchmark {
+    name: "VibratorHalDrv2624BenchmarkRedfin",
+    defaults: ["VibratorHalDrv2624TestDefaultsRedfin"],
+    srcs: [
+        "benchmark.cpp",
+    ],
+    static_libs: [
+        "libc++fs",
+    ],
+    shared_libs: [
+        "libbase",
+    ],
+    // TODO(b/135767253): Remove when fixed.
+    test_suites: ["device-tests"],
+    // TODO(b/142024316): Remove when fixed.
+    require_root: true,
+}
diff --git a/vibrator/drv2624/bench/benchmark.cpp b/vibrator/drv2624/bench/benchmark.cpp
new file mode 100644
index 0000000..e63da43
--- /dev/null
+++ b/vibrator/drv2624/bench/benchmark.cpp
@@ -0,0 +1,203 @@
+/* * 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 "benchmark/benchmark.h"
+
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <cutils/fs.h>
+
+#include "Hardware.h"
+#include "Vibrator.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_enum_range;
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+using ::android::base::SetProperty;
+using ::android::hardware::vibrator::V1_0::EffectStrength;
+using ::android::hardware::vibrator::V1_0::Status;
+
+class VibratorBench : public benchmark::Fixture {
+  private:
+    static constexpr const char *FILE_NAMES[]{
+        "device/autocal",
+        "device/ol_lra_period",
+        "activate",
+        "duration",
+        "state",
+        "device/rtp_input",
+        "device/mode",
+        "device/set_sequencer",
+        "device/scale",
+        "device/ctrl_loop",
+        "device/lp_trigger_effect",
+        "device/lra_wave_shape",
+        "device/od_clamp",
+    };
+    static constexpr char PROPERTY_PREFIX[] = "test.vibrator.hal.";
+
+  public:
+    void SetUp(::benchmark::State &state) override {
+        auto prefix = std::filesystem::path(mFilesDir.path) / "";
+
+        setenv("HWAPI_PATH_PREFIX", prefix.c_str(), true);
+
+        for (auto n : FILE_NAMES) {
+            const auto name = std::filesystem::path(n);
+            const auto path = std::filesystem::path(mFilesDir.path) / name;
+
+            fs_mkdirs(path.c_str(), S_IRWXU);
+            symlink("/dev/null", path.c_str());
+        }
+
+        setenv("PROPERTY_PREFIX", PROPERTY_PREFIX, true);
+
+        SetProperty(std::string() + PROPERTY_PREFIX + "config.dynamic", getDynamicConfig(state));
+
+        mVibrator = new Vibrator(HwApi::Create(), std::make_unique<HwCal>());
+    }
+
+    static void DefaultConfig(benchmark::internal::Benchmark *b) {
+        b->Unit(benchmark::kMicrosecond);
+    }
+
+    static void DefaultArgs(benchmark::internal::Benchmark *b) {
+        b->ArgNames({"DynamicConfig"});
+        b->Args({false});
+        b->Args({true});
+    }
+
+  protected:
+    std::string getDynamicConfig(const ::benchmark::State &state) const {
+        return std::to_string(state.range(0));
+    }
+
+    auto getOtherArg(const ::benchmark::State &state, std::size_t index) const {
+        return state.range(index + 1);
+    }
+
+  protected:
+    TemporaryDir mFilesDir;
+    sp<IVibrator> mVibrator;
+};
+
+#define BENCHMARK_WRAPPER(fixt, test, code)                           \
+    BENCHMARK_DEFINE_F(fixt, test)                                    \
+    /* NOLINTNEXTLINE */                                              \
+    (benchmark::State & state){code} BENCHMARK_REGISTER_F(fixt, test) \
+        ->Apply(fixt::DefaultConfig)                                  \
+        ->Apply(fixt::DefaultArgs)
+
+BENCHMARK_WRAPPER(VibratorBench, on, {
+    uint32_t duration = std::rand() ?: 1;
+
+    for (auto _ : state) {
+        mVibrator->on(duration);
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench, off, {
+    for (auto _ : state) {
+        mVibrator->off();
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench, supportsAmplitudeControl, {
+    for (auto _ : state) {
+        mVibrator->supportsAmplitudeControl();
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench, setAmplitude, {
+    uint8_t amplitude = std::rand() ?: 1;
+
+    for (auto _ : state) {
+        mVibrator->setAmplitude(amplitude);
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench, supportsExternalControl, {
+    for (auto _ : state) {
+        mVibrator->supportsExternalControl();
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench, setExternalControl_enable, {
+    for (auto _ : state) {
+        mVibrator->setExternalControl(true);
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench, setExternalControl_disable, {
+    for (auto _ : state) {
+        mVibrator->setExternalControl(false);
+    }
+});
+
+class VibratorEffectsBench : public VibratorBench {
+  public:
+    static void DefaultArgs(benchmark::internal::Benchmark *b) {
+        b->ArgNames({"DynamicConfig", "Effect", "Strength"});
+        for (const auto &dynamic : {false, true}) {
+            for (const auto &effect : hidl_enum_range<Effect>()) {
+                for (const auto &strength : hidl_enum_range<EffectStrength>()) {
+                    b->Args({dynamic, static_cast<long>(effect), static_cast<long>(strength)});
+                }
+            }
+        }
+    }
+
+  protected:
+    auto getEffect(const ::benchmark::State &state) const {
+        return static_cast<Effect>(getOtherArg(state, 0));
+    }
+
+    auto getStrength(const ::benchmark::State &state) const {
+        return static_cast<EffectStrength>(getOtherArg(state, 1));
+    }
+};
+
+BENCHMARK_WRAPPER(VibratorEffectsBench, perform_1_3, {
+    Effect effect = getEffect(state);
+    EffectStrength strength = getStrength(state);
+    bool supported = true;
+
+    mVibrator->perform_1_3(effect, strength, [&](Status status, uint32_t /*lengthMs*/) {
+        if (status == Status::UNSUPPORTED_OPERATION) {
+            supported = false;
+        }
+    });
+
+    if (!supported) {
+        return;
+    }
+
+    for (auto _ : state) {
+        mVibrator->perform_1_3(effect, strength, [](Status /*status*/, uint32_t /*lengthMs*/) {});
+    }
+});
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+
+BENCHMARK_MAIN();
diff --git a/vibrator/drv2624/drv2624.bin b/vibrator/drv2624/drv2624.bin
new file mode 100644
index 0000000..e6f896d
--- /dev/null
+++ b/vibrator/drv2624/drv2624.bin
Binary files differ
diff --git a/vibrator/service.cpp b/vibrator/drv2624/service.cpp
similarity index 80%
rename from vibrator/service.cpp
rename to vibrator/drv2624/service.cpp
index 32eec89..c0447a7 100644
--- a/vibrator/service.cpp
+++ b/vibrator/drv2624/service.cpp
@@ -13,8 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "android.hardware.vibrator@1.3-service.redfin"
 
+#include <android/hardware/vibrator/1.3/IVibrator.h>
 #include <hidl/HidlSupport.h>
 #include <hidl/HidlTransportSupport.h>
 #include <utils/Errors.h>
@@ -23,15 +23,24 @@
 #include "Hardware.h"
 #include "Vibrator.h"
 
+using android::OK;
+using android::sp;
+using android::status_t;
+using android::UNKNOWN_ERROR;
 using android::hardware::configureRpcThreadpool;
 using android::hardware::joinRpcThreadpool;
 using android::hardware::vibrator::V1_3::implementation::HwApi;
 using android::hardware::vibrator::V1_3::implementation::HwCal;
 using android::hardware::vibrator::V1_3::implementation::Vibrator;
-using namespace android;
 
 status_t registerVibratorService() {
-    sp<Vibrator> vibrator = new Vibrator(std::make_unique<HwApi>(), std::make_unique<HwCal>());
+    auto hwapi = HwApi::Create();
+
+    if (!hwapi) {
+        return UNKNOWN_ERROR;
+    }
+
+    sp<Vibrator> vibrator = new Vibrator(std::move(hwapi), std::make_unique<HwCal>());
 
     return vibrator->registerAsService();
 }
diff --git a/vibrator/drv2624/tests/Android.bp b/vibrator/drv2624/tests/Android.bp
new file mode 100644
index 0000000..2adfc84
--- /dev/null
+++ b/vibrator/drv2624/tests/Android.bp
@@ -0,0 +1,31 @@
+//
+// 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.
+
+cc_test {
+    name: "VibratorHalDrv2624TestSuiteRedfin",
+    defaults: ["VibratorHalDrv2624TestDefaultsRedfin"],
+    srcs: [
+        "test-hwapi.cpp",
+        "test-hwcal.cpp",
+        "test-vibrator.cpp",
+    ],
+    static_libs: [
+        "libc++fs",
+        "libgmock",
+    ],
+    shared_libs: [
+        "libbase",
+    ],
+}
diff --git a/vibrator/drv2624/tests/mocks.h b/vibrator/drv2624/tests/mocks.h
new file mode 100644
index 0000000..d4867df
--- /dev/null
+++ b/vibrator/drv2624/tests/mocks.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+#ifndef ANDROID_HARDWARE_VIBRATOR_TEST_MOCKS_H
+#define ANDROID_HARDWARE_VIBRATOR_TEST_MOCKS_H
+
+#include "Vibrator.h"
+
+class MockApi : public ::android::hardware::vibrator::V1_3::implementation::Vibrator::HwApi {
+  public:
+    MOCK_METHOD0(destructor, void());
+    MOCK_METHOD1(setAutocal, bool(std::string value));
+    MOCK_METHOD1(setOlLraPeriod, bool(uint32_t value));
+    MOCK_METHOD1(setActivate, bool(bool value));
+    MOCK_METHOD1(setDuration, bool(uint32_t value));
+    MOCK_METHOD1(setState, bool(bool value));
+    MOCK_METHOD0(hasRtpInput, bool());
+    MOCK_METHOD1(setRtpInput, bool(int8_t value));
+    MOCK_METHOD1(setMode, bool(std::string value));
+    MOCK_METHOD1(setSequencer, bool(std::string value));
+    MOCK_METHOD1(setScale, bool(uint8_t value));
+    MOCK_METHOD1(setCtrlLoop, bool(bool value));
+    MOCK_METHOD1(setLpTriggerEffect, bool(uint32_t value));
+    MOCK_METHOD1(setLraWaveShape, bool(uint32_t value));
+    MOCK_METHOD1(setOdClamp, bool(uint32_t value));
+    MOCK_METHOD1(debug, void(int fd));
+
+    ~MockApi() override { destructor(); };
+};
+
+class MockCal : public ::android::hardware::vibrator::V1_3::implementation::Vibrator::HwCal {
+  public:
+    MOCK_METHOD0(destructor, void());
+    MOCK_METHOD1(getAutocal, bool(std::string &value));  // NOLINT
+    MOCK_METHOD1(getLraPeriod, bool(uint32_t *value));
+    MOCK_METHOD1(getEffectCoeffs, bool(std::array<float, 4> *value));
+    MOCK_METHOD1(getSteadyAmpMax, bool(float *value));
+    MOCK_METHOD1(getCloseLoopThreshold, bool(uint32_t *value));
+    MOCK_METHOD1(getDynamicConfig, bool(bool *value));
+    MOCK_METHOD1(getLongFrequencyShift, bool(uint32_t *value));
+    MOCK_METHOD1(getShortVoltageMax, bool(uint32_t *value));
+    MOCK_METHOD1(getLongVoltageMax, bool(uint32_t *value));
+    MOCK_METHOD1(getClickDuration, bool(uint32_t *value));
+    MOCK_METHOD1(getTickDuration, bool(uint32_t *value));
+    MOCK_METHOD1(getDoubleClickDuration, bool(uint32_t *value));
+    MOCK_METHOD1(getHeavyClickDuration, bool(uint32_t *value));
+    MOCK_METHOD1(getEffectShape, bool(uint32_t *value));
+    MOCK_METHOD1(getSteadyShape, bool(uint32_t *value));
+    MOCK_METHOD1(debug, void(int fd));
+
+    ~MockCal() override { destructor(); };
+    // b/132668253: Workaround gMock Compilation Issue
+    bool getAutocal(std::string *value) { return getAutocal(*value); }
+};
+
+#endif  // ANDROID_HARDWARE_VIBRATOR_TEST_MOCKS_H
diff --git a/vibrator/drv2624/tests/test-hwapi.cpp b/vibrator/drv2624/tests/test-hwapi.cpp
new file mode 100644
index 0000000..fc57f85
--- /dev/null
+++ b/vibrator/drv2624/tests/test-hwapi.cpp
@@ -0,0 +1,401 @@
+/*
+ * 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 <android-base/file.h>
+#include <cutils/fs.h>
+#include <gtest/gtest.h>
+
+#include <cstdlib>
+#include <fstream>
+
+#include "Hardware.h"
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+using ::testing::Test;
+using ::testing::TestParamInfo;
+using ::testing::ValuesIn;
+using ::testing::WithParamInterface;
+
+class HwApiTest : public Test {
+  protected:
+    static constexpr const char *FILE_NAMES[]{
+        "device/autocal",
+        "device/ol_lra_period",
+        "activate",
+        "duration",
+        "state",
+        "device/rtp_input",
+        "device/mode",
+        "device/set_sequencer",
+        "device/scale",
+        "device/ctrl_loop",
+        "device/lp_trigger_effect",
+        "device/lra_wave_shape",
+        "device/od_clamp",
+    };
+
+    static constexpr const char *REQUIRED[]{
+        "activate",
+        "duration",
+        "state",
+    };
+
+  public:
+    void SetUp() override {
+        std::string prefix;
+        for (auto n : FILE_NAMES) {
+            auto name = std::filesystem::path(n);
+            auto path = std::filesystem::path(mFilesDir.path) / name;
+            fs_mkdirs(path.c_str(), S_IRWXU);
+            std::ofstream touch{path};
+            mFileMap[name] = path;
+        }
+        prefix = std::filesystem::path(mFilesDir.path) / "";
+        setenv("HWAPI_PATH_PREFIX", prefix.c_str(), true);
+        mHwApi = HwApi::Create();
+
+        for (auto n : REQUIRED) {
+            auto name = std::filesystem::path(n);
+            auto path = std::filesystem::path(mEmptyDir.path) / name;
+            fs_mkdirs(path.c_str(), S_IRWXU);
+            std::ofstream touch{path};
+        }
+        prefix = std::filesystem::path(mEmptyDir.path) / "";
+        setenv("HWAPI_PATH_PREFIX", prefix.c_str(), true);
+        mNoApi = HwApi::Create();
+    }
+
+    void TearDown() override { verifyContents(); }
+
+  protected:
+    // Set expected file content for a test.
+    template <typename T>
+    void expectContent(const std::string &name, const T &value) {
+        mExpectedContent[name] << value << std::endl;
+    }
+
+    // Set actual file content for an input test.
+    template <typename T>
+    void updateContent(const std::string &name, const T &value) {
+        std::ofstream(mFileMap[name]) << value << std::endl;
+    }
+
+    template <typename T>
+    void expectAndUpdateContent(const std::string &name, const T &value) {
+        expectContent(name, value);
+        updateContent(name, value);
+    }
+
+    // Compare all file contents against expected contents.
+    void verifyContents() {
+        for (auto &a : mFileMap) {
+            std::ifstream file{a.second};
+            std::string expect = mExpectedContent[a.first].str();
+            std::string actual = std::string(std::istreambuf_iterator<char>(file),
+                                             std::istreambuf_iterator<char>());
+            EXPECT_EQ(expect, actual) << a.first;
+        }
+    }
+
+    // TODO(eliptus): Determine how to induce errors in required files
+    static bool isRequired(const std::string &name) {
+        for (auto n : REQUIRED) {
+            if (std::string(n) == name) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    static auto ParamNameFixup(std::string str) {
+        std::replace(str.begin(), str.end(), '/', '_');
+        return str;
+    }
+
+  protected:
+    std::unique_ptr<Vibrator::HwApi> mHwApi;
+    std::unique_ptr<Vibrator::HwApi> mNoApi;
+    std::map<std::string, std::string> mFileMap;
+    TemporaryDir mFilesDir;
+    TemporaryDir mEmptyDir;
+    std::map<std::string, std::stringstream> mExpectedContent;
+};
+
+class CreateTest : public HwApiTest, public WithParamInterface<const char *> {
+  public:
+    void SetUp() override{};
+    void TearDown() override{};
+
+    static auto PrintParam(const TestParamInfo<CreateTest::ParamType> &info) {
+        return ParamNameFixup(info.param);
+    }
+    static auto &AllParams() { return FILE_NAMES; }
+};
+
+TEST_P(CreateTest, file_missing) {
+    auto skip = std::string(GetParam());
+    TemporaryDir dir;
+    std::unique_ptr<HwApi> hwapi;
+    std::string prefix;
+
+    for (auto n : FILE_NAMES) {
+        auto name = std::string(n);
+        auto path = std::string(dir.path) + "/" + name;
+        if (name == skip) {
+            continue;
+        }
+        fs_mkdirs(path.c_str(), S_IRWXU);
+        std::ofstream touch{path};
+    }
+
+    prefix = std::filesystem::path(dir.path) / "";
+    setenv("HWAPI_PATH_PREFIX", prefix.c_str(), true);
+    hwapi = HwApi::Create();
+    if (isRequired(skip)) {
+        EXPECT_EQ(nullptr, hwapi);
+    } else {
+        EXPECT_NE(nullptr, hwapi);
+    }
+}
+
+INSTANTIATE_TEST_CASE_P(HwApiTests, CreateTest, ValuesIn(CreateTest::AllParams()),
+                        CreateTest::PrintParam);
+
+template <typename T>
+class HwApiTypedTest : public HwApiTest,
+                       public WithParamInterface<std::tuple<std::string, std::function<T>>> {
+  public:
+    static auto PrintParam(const TestParamInfo<typename HwApiTypedTest::ParamType> &info) {
+        return ParamNameFixup(std::get<0>(info.param));
+    }
+    static auto MakeParam(std::string name, std::function<T> func) {
+        return std::make_tuple(name, func);
+    }
+};
+
+using HasTest = HwApiTypedTest<bool(Vibrator::HwApi &)>;
+
+TEST_P(HasTest, success_returnsTrue) {
+    auto param = GetParam();
+    auto func = std::get<1>(param);
+
+    EXPECT_TRUE(func(*mHwApi));
+}
+
+TEST_P(HasTest, success_returnsFalse) {
+    auto param = GetParam();
+    auto func = std::get<1>(param);
+
+    EXPECT_FALSE(func(*mNoApi));
+}
+
+INSTANTIATE_TEST_CASE_P(HwApiTests, HasTest,
+                        ValuesIn({
+                            HasTest::MakeParam("device/rtp_input", &Vibrator::HwApi::hasRtpInput),
+                        }),
+                        HasTest::PrintParam);
+
+using SetBoolTest = HwApiTypedTest<bool(Vibrator::HwApi &, bool)>;
+
+TEST_P(SetBoolTest, success_returnsTrue) {
+    auto param = GetParam();
+    auto name = std::get<0>(param);
+    auto func = std::get<1>(param);
+
+    expectContent(name, "1");
+
+    EXPECT_TRUE(func(*mHwApi, true));
+}
+
+TEST_P(SetBoolTest, success_returnsFalse) {
+    auto param = GetParam();
+    auto name = std::get<0>(param);
+    auto func = std::get<1>(param);
+
+    expectContent(name, "0");
+
+    EXPECT_TRUE(func(*mHwApi, false));
+}
+
+TEST_P(SetBoolTest, failure) {
+    auto param = GetParam();
+    auto name = std::get<0>(param);
+    auto func = std::get<1>(param);
+
+    if (isRequired(name)) {
+        GTEST_SKIP();
+    }
+
+    EXPECT_FALSE(func(*mNoApi, true));
+    EXPECT_FALSE(func(*mNoApi, false));
+}
+
+INSTANTIATE_TEST_CASE_P(HwApiTests, SetBoolTest,
+                        ValuesIn({
+                            SetBoolTest::MakeParam("activate", &Vibrator::HwApi::setActivate),
+                            SetBoolTest::MakeParam("state", &Vibrator::HwApi::setState),
+                            SetBoolTest::MakeParam("device/ctrl_loop",
+                                                   &Vibrator::HwApi::setCtrlLoop),
+                        }),
+                        SetBoolTest::PrintParam);
+
+using SetInt8Test = HwApiTypedTest<bool(Vibrator::HwApi &, int8_t)>;
+
+TEST_P(SetInt8Test, success) {
+    auto param = GetParam();
+    auto name = std::get<0>(param);
+    auto func = std::get<1>(param);
+    int8_t value = std::rand();
+
+    expectContent(name, +value);
+
+    EXPECT_TRUE(func(*mHwApi, value));
+}
+
+TEST_P(SetInt8Test, failure) {
+    auto param = GetParam();
+    auto name = std::get<0>(param);
+    auto func = std::get<1>(param);
+    int8_t value = std::rand();
+
+    if (isRequired(name)) {
+        GTEST_SKIP();
+    }
+
+    EXPECT_FALSE(func(*mNoApi, value));
+}
+
+INSTANTIATE_TEST_CASE_P(HwApiTests, SetInt8Test,
+                        ValuesIn({
+                            SetInt8Test::MakeParam("device/rtp_input",
+                                                   &Vibrator::HwApi::setRtpInput),
+                        }),
+                        SetInt8Test::PrintParam);
+
+using SetUint8Test = HwApiTypedTest<bool(Vibrator::HwApi &, uint8_t)>;
+
+TEST_P(SetUint8Test, success) {
+    auto param = GetParam();
+    auto name = std::get<0>(param);
+    auto func = std::get<1>(param);
+    uint8_t value = std::rand();
+
+    expectContent(name, +value);
+
+    EXPECT_TRUE(func(*mHwApi, value));
+}
+
+TEST_P(SetUint8Test, failure) {
+    auto param = GetParam();
+    auto name = std::get<0>(param);
+    auto func = std::get<1>(param);
+    uint8_t value = std::rand();
+
+    if (isRequired(name)) {
+        GTEST_SKIP();
+    }
+
+    EXPECT_FALSE(func(*mNoApi, value));
+}
+
+INSTANTIATE_TEST_CASE_P(HwApiTests, SetUint8Test,
+                        ValuesIn({
+                            SetUint8Test::MakeParam("device/scale", &Vibrator::HwApi::setScale),
+                        }),
+                        SetUint8Test::PrintParam);
+
+using SetUint32Test = HwApiTypedTest<bool(Vibrator::HwApi &, uint32_t)>;
+
+TEST_P(SetUint32Test, success) {
+    auto param = GetParam();
+    auto name = std::get<0>(param);
+    auto func = std::get<1>(param);
+    uint32_t value = std::rand();
+
+    expectContent(name, value);
+
+    EXPECT_TRUE(func(*mHwApi, value));
+}
+
+TEST_P(SetUint32Test, failure) {
+    auto param = GetParam();
+    auto name = std::get<0>(param);
+    auto func = std::get<1>(param);
+    uint32_t value = std::rand();
+
+    if (isRequired(name)) {
+        GTEST_SKIP();
+    }
+
+    EXPECT_FALSE(func(*mNoApi, value));
+}
+
+INSTANTIATE_TEST_CASE_P(
+    HwApiTests, SetUint32Test,
+    ValuesIn({
+        SetUint32Test::MakeParam("device/ol_lra_period", &Vibrator::HwApi::setOlLraPeriod),
+        SetUint32Test::MakeParam("duration", &Vibrator::HwApi::setDuration),
+        SetUint32Test::MakeParam("device/lp_trigger_effect", &Vibrator::HwApi::setLpTriggerEffect),
+        SetUint32Test::MakeParam("device/lra_wave_shape", &Vibrator::HwApi::setLraWaveShape),
+        SetUint32Test::MakeParam("device/od_clamp", &Vibrator::HwApi::setOdClamp),
+    }),
+    SetUint32Test::PrintParam);
+
+using SetStringTest = HwApiTypedTest<bool(Vibrator::HwApi &, std::string)>;
+
+TEST_P(SetStringTest, success) {
+    auto param = GetParam();
+    auto name = std::get<0>(param);
+    auto func = std::get<1>(param);
+    std::string value = TemporaryFile().path;
+
+    expectContent(name, value);
+
+    EXPECT_TRUE(func(*mHwApi, value));
+}
+
+TEST_P(SetStringTest, failure) {
+    auto param = GetParam();
+    auto name = std::get<0>(param);
+    auto func = std::get<1>(param);
+    std::string value = TemporaryFile().path;
+
+    if (isRequired(name)) {
+        GTEST_SKIP();
+    }
+
+    EXPECT_FALSE(func(*mNoApi, value));
+}
+
+INSTANTIATE_TEST_CASE_P(
+    HwApiTests, SetStringTest,
+    ValuesIn({
+        SetStringTest::MakeParam("device/autocal", &Vibrator::HwApi::setAutocal),
+        SetStringTest::MakeParam("device/mode", &Vibrator::HwApi::setMode),
+        SetStringTest::MakeParam("device/set_sequencer", &Vibrator::HwApi::setSequencer),
+    }),
+    SetStringTest::PrintParam);
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
diff --git a/vibrator/drv2624/tests/test-hwcal.cpp b/vibrator/drv2624/tests/test-hwcal.cpp
new file mode 100644
index 0000000..b95f943
--- /dev/null
+++ b/vibrator/drv2624/tests/test-hwcal.cpp
@@ -0,0 +1,396 @@
+/*
+ * 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 <android-base/file.h>
+#include <android-base/properties.h>
+#include <gtest/gtest.h>
+
+#include <fstream>
+
+#include "Hardware.h"
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+using ::android::base::SetProperty;
+using ::android::base::WaitForProperty;
+
+using ::testing::Test;
+
+class HwCalTest : public Test {
+  protected:
+    static constexpr char PROPERTY_PREFIX[] = "test.vibrator.hal.";
+
+    static constexpr uint32_t DEFAULT_LRA_PERIOD = 262;
+
+    static constexpr uint32_t DEFAULT_FREQUENCY_SHIFT = 10;
+    static constexpr uint32_t DEFAULT_VOLTAGE_MAX = 107;
+
+    static constexpr uint32_t DEFAULT_CLICK_DURATION_MS = 6;
+    static constexpr uint32_t DEFAULT_TICK_DURATION_MS = 2;
+    static constexpr uint32_t DEFAULT_DOUBLE_CLICK_DURATION_MS = 135;
+    static constexpr uint32_t DEFAULT_HEAVY_CLICK_DURATION_MS = 8;
+
+  public:
+    void SetUp() override {
+        setenv("PROPERTY_PREFIX", PROPERTY_PREFIX, true);
+        setenv("CALIBRATION_FILEPATH", mCalFile.path, true);
+    }
+
+  private:
+    template <typename T>
+    static void pack(std::ostream &stream, const T &value, std::string lpad, std::string rpad) {
+        stream << lpad << value << rpad;
+    }
+
+  protected:
+    void createHwCal() { mHwCal = std::make_unique<HwCal>(); }
+
+    template <typename T>
+    void write(const std::string key, const T &value, std::string lpad = " ",
+               std::string rpad = "") {
+        std::ofstream calfile{mCalFile.path, std::ios_base::app};
+        calfile << key << ":";
+        pack(calfile, value, lpad, rpad);
+        calfile << std::endl;
+    }
+
+    void unlink() { ::unlink(mCalFile.path); }
+
+  protected:
+    std::unique_ptr<Vibrator::HwCal> mHwCal;
+    TemporaryFile mCalFile;
+};
+
+TEST_F(HwCalTest, closeloop_present) {
+    std::string prefix{PROPERTY_PREFIX};
+    uint32_t expect = std::rand();
+    uint32_t actual = ~expect;
+
+    EXPECT_TRUE(SetProperty(prefix + "closeloop.threshold", std::to_string(expect)));
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getCloseLoopThreshold(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, closeloop_missing) {
+    std::string prefix{PROPERTY_PREFIX};
+    uint32_t expect = UINT32_MAX;
+    uint32_t actual = ~expect;
+
+    EXPECT_TRUE(SetProperty(prefix + "closeloop.threshold", std::string()));
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getCloseLoopThreshold(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, dynamicconfig_presentFalse) {
+    std::string prefix{PROPERTY_PREFIX};
+    bool expect = false;
+    bool actual = !expect;
+
+    EXPECT_TRUE(SetProperty(prefix + "config.dynamic", "0"));
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getDynamicConfig(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, dynamicconfig_presentTrue) {
+    std::string prefix{PROPERTY_PREFIX};
+    bool expect = true;
+    bool actual = !expect;
+
+    EXPECT_TRUE(SetProperty(prefix + "config.dynamic", "1"));
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getDynamicConfig(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, dynamicconfig_missing) {
+    std::string prefix{PROPERTY_PREFIX};
+    bool expect = false;
+    bool actual = !expect;
+
+    EXPECT_TRUE(SetProperty(prefix + "config.dynamic", std::string()));
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getDynamicConfig(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, freqshift_present) {
+    std::string prefix{PROPERTY_PREFIX};
+    uint32_t expect = std::rand();
+    uint32_t actual = ~expect;
+
+    EXPECT_TRUE(SetProperty(prefix + "long.frequency.shift", std::to_string(expect)));
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getLongFrequencyShift(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, freqshift_missing) {
+    std::string prefix{PROPERTY_PREFIX};
+    uint32_t expect = DEFAULT_FREQUENCY_SHIFT;
+    uint32_t actual = ~expect;
+
+    EXPECT_TRUE(SetProperty(prefix + "long.frequency.shift", std::string()));
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getLongFrequencyShift(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, shortvolt_present) {
+    std::string prefix{PROPERTY_PREFIX};
+    uint32_t expect = std::rand();
+    uint32_t actual = ~expect;
+
+    EXPECT_TRUE(SetProperty(prefix + "short.voltage", std::to_string(expect)));
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getShortVoltageMax(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, shortvolt_missing) {
+    std::string prefix{PROPERTY_PREFIX};
+    uint32_t expect = DEFAULT_VOLTAGE_MAX;
+    uint32_t actual = ~expect;
+
+    EXPECT_TRUE(SetProperty(prefix + "short.voltage", std::string()));
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getShortVoltageMax(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, longvolt_present) {
+    std::string prefix{PROPERTY_PREFIX};
+    uint32_t expect = std::rand();
+    uint32_t actual = ~expect;
+
+    EXPECT_TRUE(SetProperty(prefix + "long.voltage", std::to_string(expect)));
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getLongVoltageMax(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, longvolt_missing) {
+    std::string prefix{PROPERTY_PREFIX};
+    uint32_t expect = DEFAULT_VOLTAGE_MAX;
+    uint32_t actual = ~expect;
+
+    EXPECT_TRUE(SetProperty(prefix + "long.voltage", std::string()));
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getLongVoltageMax(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, click_present) {
+    std::string prefix{PROPERTY_PREFIX};
+    uint32_t expect = std::rand();
+    uint32_t actual = ~expect;
+
+    EXPECT_TRUE(SetProperty(prefix + "click.duration", std::to_string(expect)));
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getClickDuration(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, click_missing) {
+    std::string prefix{PROPERTY_PREFIX};
+    uint32_t expect = DEFAULT_CLICK_DURATION_MS;
+    uint32_t actual = ~expect;
+
+    EXPECT_TRUE(SetProperty(prefix + "click.duration", std::string()));
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getClickDuration(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, tick_present) {
+    std::string prefix{PROPERTY_PREFIX};
+    uint32_t expect = std::rand();
+    uint32_t actual = ~expect;
+
+    EXPECT_TRUE(SetProperty(prefix + "tick.duration", std::to_string(expect)));
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getTickDuration(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, tick_missing) {
+    std::string prefix{PROPERTY_PREFIX};
+    uint32_t expect = DEFAULT_TICK_DURATION_MS;
+    uint32_t actual = ~expect;
+
+    EXPECT_TRUE(SetProperty(prefix + "tick.duration", std::string()));
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getTickDuration(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, doubleclick) {
+    std::string prefix{PROPERTY_PREFIX};
+    uint32_t expect = DEFAULT_DOUBLE_CLICK_DURATION_MS;
+    uint32_t actual = ~expect;
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getDoubleClickDuration(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, heavyclick_present) {
+    std::string prefix{PROPERTY_PREFIX};
+    uint32_t expect = std::rand();
+    uint32_t actual = ~expect;
+
+    EXPECT_TRUE(SetProperty(prefix + "heavyclick.duration", std::to_string(expect)));
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getHeavyClickDuration(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, heavyclick_missing) {
+    std::string prefix{PROPERTY_PREFIX};
+    uint32_t expect = DEFAULT_HEAVY_CLICK_DURATION_MS;
+    uint32_t actual = ~expect;
+
+    EXPECT_TRUE(SetProperty(prefix + "heavyclick.duration", std::string()));
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getHeavyClickDuration(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, autocal_present) {
+    std::string expect = std::to_string(std::rand()) + " " + std::to_string(std::rand()) + " " +
+                         std::to_string(std::rand());
+    std::string actual = "";
+
+    write("autocal", expect);
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getAutocal(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, autocal_missing) {
+    std::string actual;
+
+    createHwCal();
+
+    EXPECT_FALSE(mHwCal->getAutocal(&actual));
+}
+
+TEST_F(HwCalTest, lra_period_present) {
+    uint32_t expect = std::rand();
+    uint32_t actual = ~expect;
+
+    write("lra_period", expect);
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getLraPeriod(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, lra_period_missing) {
+    uint32_t expect = DEFAULT_LRA_PERIOD;
+    uint32_t actual = ~expect;
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getLraPeriod(&actual));
+    EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, multiple) {
+    std::string autocalExpect = std::to_string(std::rand()) + " " + std::to_string(std::rand()) +
+                                " " + std::to_string(std::rand());
+    std::string autocalActual = "";
+    uint32_t lraPeriodExpect = std::rand();
+    uint32_t lraPeriodActual = ~lraPeriodExpect;
+
+    write("autocal", autocalExpect);
+    write("lra_period", lraPeriodExpect);
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getAutocal(&autocalActual));
+    EXPECT_EQ(autocalExpect, autocalActual);
+    EXPECT_TRUE(mHwCal->getLraPeriod(&lraPeriodActual));
+    EXPECT_EQ(lraPeriodExpect, lraPeriodActual);
+}
+
+TEST_F(HwCalTest, trimming) {
+    std::string autocalExpect = std::to_string(std::rand()) + " " + std::to_string(std::rand()) +
+                                " " + std::to_string(std::rand());
+    std::string autocalActual = "";
+    uint32_t lraPeriodExpect = std::rand();
+    uint32_t lraPeriodActual = ~lraPeriodExpect;
+
+    write("autocal", autocalExpect, " \t", "\t ");
+    write("lra_period", lraPeriodExpect, " \t", "\t ");
+
+    createHwCal();
+
+    EXPECT_TRUE(mHwCal->getAutocal(&autocalActual));
+    EXPECT_EQ(autocalExpect, autocalActual);
+    EXPECT_TRUE(mHwCal->getLraPeriod(&lraPeriodActual));
+    EXPECT_EQ(lraPeriodExpect, lraPeriodActual);
+}
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
diff --git a/vibrator/drv2624/tests/test-vibrator.cpp b/vibrator/drv2624/tests/test-vibrator.cpp
new file mode 100644
index 0000000..47bdfad
--- /dev/null
+++ b/vibrator/drv2624/tests/test-vibrator.cpp
@@ -0,0 +1,449 @@
+/*
+ * 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 <android-base/logging.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "Vibrator.h"
+#include "mocks.h"
+#include "types.h"
+#include "utils.h"
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+using ::android::hardware::vibrator::V1_0::EffectStrength;
+using ::android::hardware::vibrator::V1_0::Status;
+
+using ::testing::_;
+using ::testing::AnyNumber;
+using ::testing::AnyOf;
+using ::testing::Assign;
+using ::testing::Combine;
+using ::testing::DoAll;
+using ::testing::DoDefault;
+using ::testing::Exactly;
+using ::testing::ExpectationSet;
+using ::testing::Mock;
+using ::testing::Return;
+using ::testing::Sequence;
+using ::testing::SetArgPointee;
+using ::testing::SetArgReferee;
+using ::testing::Test;
+using ::testing::TestParamInfo;
+using ::testing::ValuesIn;
+using ::testing::WithParamInterface;
+
+// Constants With Prescribed Values
+
+static const std::map<EffectTuple, EffectSequence> EFFECT_SEQUENCES{
+    {{Effect::CLICK, EffectStrength::LIGHT}, {"1 0", 2}},
+    {{Effect::CLICK, EffectStrength::MEDIUM}, {"1 0", 0}},
+    {{Effect::CLICK, EffectStrength::STRONG}, {"1 0", 0}},
+    {{Effect::TICK, EffectStrength::LIGHT}, {"2 0", 2}},
+    {{Effect::TICK, EffectStrength::MEDIUM}, {"2 0", 0}},
+    {{Effect::TICK, EffectStrength::STRONG}, {"2 0", 0}},
+    {{Effect::DOUBLE_CLICK, EffectStrength::LIGHT}, {"3 0", 2}},
+    {{Effect::DOUBLE_CLICK, EffectStrength::MEDIUM}, {"3 0", 0}},
+    {{Effect::DOUBLE_CLICK, EffectStrength::STRONG}, {"3 0", 0}},
+    {{Effect::HEAVY_CLICK, EffectStrength::LIGHT}, {"4 0", 2}},
+    {{Effect::HEAVY_CLICK, EffectStrength::MEDIUM}, {"4 0", 0}},
+    {{Effect::HEAVY_CLICK, EffectStrength::STRONG}, {"4 0", 0}},
+    {{Effect::TEXTURE_TICK, EffectStrength::LIGHT}, {"2 0", 2}},
+    {{Effect::TEXTURE_TICK, EffectStrength::MEDIUM}, {"2 0", 0}},
+    {{Effect::TEXTURE_TICK, EffectStrength::STRONG}, {"2 0", 0}},
+};
+
+static uint32_t freqPeriodFormula(uint32_t in) {
+    return 1000000000 / (24615 * in);
+}
+
+template <typename... T>
+class VibratorTestTemplate : public Test, public WithParamInterface<std::tuple<bool, T...>> {
+  public:
+    static auto GetDynamicConfig(typename VibratorTestTemplate::ParamType param) {
+        return std::get<0>(param);
+    }
+    template <std::size_t I>
+    static auto GetOtherParam(typename VibratorTestTemplate::ParamType param) {
+        return std::get<I + 1>(param);
+    }
+
+    static auto PrintParam(const TestParamInfo<typename VibratorTestTemplate::ParamType> &info) {
+        auto dynamic = GetDynamicConfig(info.param);
+        return std::string() + (dynamic ? "Dynamic" : "Static") + "Config";
+    }
+
+    static auto MakeParam(bool dynamicConfig, T... others) {
+        return std::make_tuple(dynamicConfig, others...);
+    }
+
+    void SetUp() override {
+        std::unique_ptr<MockApi> mockapi;
+        std::unique_ptr<MockCal> mockcal;
+
+        mCloseLoopThreshold = std::rand();
+        // ensure close-loop test is possible
+        if (mCloseLoopThreshold == UINT32_MAX) {
+            mCloseLoopThreshold--;
+        }
+
+        mShortLraPeriod = std::rand();
+        if (getDynamicConfig()) {
+            mLongFrequencyShift = std::rand();
+            mLongLraPeriod =
+                freqPeriodFormula(freqPeriodFormula(mShortLraPeriod) - mLongFrequencyShift);
+            mShortVoltageMax = std::rand();
+            mLongVoltageMax = std::rand();
+        }
+
+        mEffectDurations[Effect::CLICK] = std::rand();
+        mEffectDurations[Effect::TICK] = std::rand();
+        mEffectDurations[Effect::DOUBLE_CLICK] = std::rand();
+        mEffectDurations[Effect::HEAVY_CLICK] = std::rand();
+        mEffectDurations[Effect::TEXTURE_TICK] = mEffectDurations[Effect::TICK];
+
+        createMock(&mockapi, &mockcal);
+        createVibrator(std::move(mockapi), std::move(mockcal));
+    }
+
+    void TearDown() override { deleteVibrator(); }
+
+  protected:
+    auto getDynamicConfig() const { return GetDynamicConfig(VibratorTestTemplate::GetParam()); }
+
+    void createMock(std::unique_ptr<MockApi> *mockapi, std::unique_ptr<MockCal> *mockcal) {
+        *mockapi = std::make_unique<MockApi>();
+        *mockcal = std::make_unique<MockCal>();
+
+        mMockApi = mockapi->get();
+        mMockCal = mockcal->get();
+
+        ON_CALL(*mMockApi, destructor()).WillByDefault(Assign(&mMockApi, nullptr));
+        ON_CALL(*mMockApi, setOlLraPeriod(_)).WillByDefault(Return(true));
+        ON_CALL(*mMockApi, setActivate(_)).WillByDefault(Return(true));
+        ON_CALL(*mMockApi, setDuration(_)).WillByDefault(Return(true));
+        ON_CALL(*mMockApi, setMode(_)).WillByDefault(Return(true));
+        ON_CALL(*mMockApi, setCtrlLoop(_)).WillByDefault(Return(true));
+        ON_CALL(*mMockApi, setLraWaveShape(_)).WillByDefault(Return(true));
+        ON_CALL(*mMockApi, setOdClamp(_)).WillByDefault(Return(true));
+
+        ON_CALL(*mMockCal, destructor()).WillByDefault(Assign(&mMockCal, nullptr));
+        ON_CALL(*mMockCal, getLraPeriod(_))
+            .WillByDefault(DoAll(SetArgPointee<0>(mShortLraPeriod), Return(true)));
+        ON_CALL(*mMockCal, getCloseLoopThreshold(_))
+            .WillByDefault(DoAll(SetArgPointee<0>(mCloseLoopThreshold), Return(true)));
+        ON_CALL(*mMockCal, getDynamicConfig(_))
+            .WillByDefault(DoAll(SetArgPointee<0>(getDynamicConfig()), Return(true)));
+
+        if (getDynamicConfig()) {
+            ON_CALL(*mMockCal, getLongFrequencyShift(_))
+                .WillByDefault(DoAll(SetArgPointee<0>(mLongFrequencyShift), Return(true)));
+            ON_CALL(*mMockCal, getShortVoltageMax(_))
+                .WillByDefault(DoAll(SetArgPointee<0>(mShortVoltageMax), Return(true)));
+            ON_CALL(*mMockCal, getLongVoltageMax(_))
+                .WillByDefault(DoAll(SetArgPointee<0>(mLongVoltageMax), Return(true)));
+        }
+
+        ON_CALL(*mMockCal, getClickDuration(_))
+            .WillByDefault(DoAll(SetArgPointee<0>(mEffectDurations[Effect::CLICK]), Return(true)));
+        ON_CALL(*mMockCal, getTickDuration(_))
+            .WillByDefault(DoAll(SetArgPointee<0>(mEffectDurations[Effect::TICK]), Return(true)));
+        ON_CALL(*mMockCal, getDoubleClickDuration(_))
+            .WillByDefault(
+                DoAll(SetArgPointee<0>(mEffectDurations[Effect::DOUBLE_CLICK]), Return(true)));
+        ON_CALL(*mMockCal, getHeavyClickDuration(_))
+            .WillByDefault(
+                DoAll(SetArgPointee<0>(mEffectDurations[Effect::HEAVY_CLICK]), Return(true)));
+
+        relaxMock(false);
+    }
+
+    void createVibrator(std::unique_ptr<MockApi> mockapi, std::unique_ptr<MockCal> mockcal,
+                        bool relaxed = true) {
+        if (relaxed) {
+            relaxMock(true);
+        }
+        mVibrator = new Vibrator(std::move(mockapi), std::move(mockcal));
+        if (relaxed) {
+            relaxMock(false);
+        }
+    }
+
+    void deleteVibrator(bool relaxed = true) {
+        if (relaxed) {
+            relaxMock(true);
+        }
+        mVibrator.clear();
+    }
+
+    void relaxMock(bool relax) {
+        auto times = relax ? AnyNumber() : Exactly(0);
+
+        Mock::VerifyAndClearExpectations(mMockApi);
+        Mock::VerifyAndClearExpectations(mMockCal);
+
+        EXPECT_CALL(*mMockApi, destructor()).Times(times);
+        EXPECT_CALL(*mMockApi, setAutocal(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setOlLraPeriod(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setActivate(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setDuration(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setState(_)).Times(times);
+        EXPECT_CALL(*mMockApi, hasRtpInput()).Times(times);
+        EXPECT_CALL(*mMockApi, setRtpInput(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setMode(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setSequencer(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setScale(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setCtrlLoop(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setLpTriggerEffect(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setLraWaveShape(_)).Times(times);
+        EXPECT_CALL(*mMockApi, setOdClamp(_)).Times(times);
+        EXPECT_CALL(*mMockApi, debug(_)).Times(times);
+
+        EXPECT_CALL(*mMockCal, destructor()).Times(times);
+        EXPECT_CALL(*mMockCal, getAutocal(_)).Times(times);
+        EXPECT_CALL(*mMockCal, getLraPeriod(_)).Times(times);
+        EXPECT_CALL(*mMockCal, getCloseLoopThreshold(_)).Times(times);
+        EXPECT_CALL(*mMockCal, getDynamicConfig(_)).Times(times);
+        EXPECT_CALL(*mMockCal, getLongFrequencyShift(_)).Times(times);
+        EXPECT_CALL(*mMockCal, getShortVoltageMax(_)).Times(times);
+        EXPECT_CALL(*mMockCal, getLongVoltageMax(_)).Times(times);
+        EXPECT_CALL(*mMockCal, getClickDuration(_)).Times(times);
+        EXPECT_CALL(*mMockCal, getTickDuration(_)).Times(times);
+        EXPECT_CALL(*mMockCal, getDoubleClickDuration(_)).Times(times);
+        EXPECT_CALL(*mMockCal, getHeavyClickDuration(_)).Times(times);
+        EXPECT_CALL(*mMockCal, debug(_)).Times(times);
+    }
+
+  protected:
+    MockApi *mMockApi;
+    MockCal *mMockCal;
+    sp<IVibrator> mVibrator;
+
+    EffectDuration mCloseLoopThreshold;
+    uint32_t mLongFrequencyShift;
+    uint32_t mShortLraPeriod;
+    uint32_t mLongLraPeriod;
+    uint32_t mShortVoltageMax;
+    uint32_t mLongVoltageMax;
+    std::map<Effect, EffectDuration> mEffectDurations;
+};
+
+using BasicTest = VibratorTestTemplate<>;
+
+TEST_P(BasicTest, Constructor) {
+    std::unique_ptr<MockApi> mockapi;
+    std::unique_ptr<MockCal> mockcal;
+    std::string autocalVal = std::to_string(std::rand()) + " " + std::to_string(std::rand()) +
+                             " " + std::to_string(std::rand());
+    Sequence autocalSeq, lraPeriodSeq;
+
+    EXPECT_CALL(*mMockApi, destructor()).WillOnce(DoDefault());
+    EXPECT_CALL(*mMockCal, destructor()).WillOnce(DoDefault());
+
+    deleteVibrator(false);
+
+    createMock(&mockapi, &mockcal);
+
+    EXPECT_CALL(*mMockApi, setState(true)).WillOnce(Return(true));
+
+    EXPECT_CALL(*mMockCal, getAutocal(_))
+        .InSequence(autocalSeq)
+        .WillOnce(DoAll(SetArgReferee<0>(autocalVal), Return(true)));
+    EXPECT_CALL(*mMockApi, setAutocal(autocalVal)).InSequence(autocalSeq).WillOnce(DoDefault());
+
+    EXPECT_CALL(*mMockCal, getLraPeriod(_)).InSequence(lraPeriodSeq).WillOnce(DoDefault());
+
+    EXPECT_CALL(*mMockCal, getCloseLoopThreshold(_)).WillOnce(DoDefault());
+    EXPECT_CALL(*mMockCal, getDynamicConfig(_)).WillOnce(DoDefault());
+
+    if (getDynamicConfig()) {
+        EXPECT_CALL(*mMockCal, getLongFrequencyShift(_)).WillOnce(DoDefault());
+        EXPECT_CALL(*mMockCal, getShortVoltageMax(_)).WillOnce(DoDefault());
+        EXPECT_CALL(*mMockCal, getLongVoltageMax(_)).WillOnce(DoDefault());
+    } else {
+        EXPECT_CALL(*mMockApi, setOlLraPeriod(mShortLraPeriod))
+            .InSequence(lraPeriodSeq)
+            .WillOnce(DoDefault());
+    }
+
+    EXPECT_CALL(*mMockCal, getClickDuration(_)).WillOnce(DoDefault());
+    EXPECT_CALL(*mMockCal, getTickDuration(_)).WillOnce(DoDefault());
+    EXPECT_CALL(*mMockCal, getDoubleClickDuration(_)).WillOnce(DoDefault());
+    EXPECT_CALL(*mMockCal, getHeavyClickDuration(_)).WillOnce(DoDefault());
+
+    EXPECT_CALL(*mMockApi, setLpTriggerEffect(1)).WillOnce(Return(true));
+
+    createVibrator(std::move(mockapi), std::move(mockcal), false);
+}
+
+TEST_P(BasicTest, on) {
+    EffectDuration duration = std::rand();
+    ExpectationSet e;
+
+    e += EXPECT_CALL(*mMockApi, setCtrlLoop(_)).WillOnce(DoDefault());
+    e += EXPECT_CALL(*mMockApi, setMode("rtp")).WillOnce(DoDefault());
+    e += EXPECT_CALL(*mMockApi, setDuration(duration)).WillOnce(DoDefault());
+
+    if (getDynamicConfig()) {
+        e += EXPECT_CALL(*mMockApi, setLraWaveShape(0)).WillOnce(DoDefault());
+        e += EXPECT_CALL(*mMockApi, setOdClamp(mLongVoltageMax)).WillOnce(DoDefault());
+        e += EXPECT_CALL(*mMockApi, setOlLraPeriod(mLongLraPeriod)).WillOnce(DoDefault());
+    }
+
+    EXPECT_CALL(*mMockApi, setActivate(true)).After(e).WillOnce(DoDefault());
+
+    EXPECT_EQ(Status::OK, mVibrator->on(duration));
+}
+
+TEST_P(BasicTest, on_openLoop) {
+    EffectDuration duration = mCloseLoopThreshold;
+
+    relaxMock(true);
+
+    EXPECT_CALL(*mMockApi, setCtrlLoop(true)).WillOnce(DoDefault());
+
+    EXPECT_EQ(Status::OK, mVibrator->on(duration));
+}
+
+TEST_P(BasicTest, on_closeLoop) {
+    EffectDuration duration = mCloseLoopThreshold + 1;
+
+    relaxMock(true);
+
+    EXPECT_CALL(*mMockApi, setCtrlLoop(false)).WillOnce(DoDefault());
+
+    EXPECT_EQ(Status::OK, mVibrator->on(duration));
+}
+
+TEST_P(BasicTest, off) {
+    EXPECT_CALL(*mMockApi, setActivate(false)).WillOnce(DoDefault());
+
+    EXPECT_EQ(Status::OK, mVibrator->off());
+}
+
+TEST_P(BasicTest, supportsAmplitudeControl_supported) {
+    EXPECT_CALL(*mMockApi, hasRtpInput()).WillOnce(Return(true));
+
+    EXPECT_EQ(true, mVibrator->supportsAmplitudeControl());
+}
+
+TEST_P(BasicTest, supportsAmplitudeControl_unsupported) {
+    EXPECT_CALL(*mMockApi, hasRtpInput()).WillOnce(Return(false));
+
+    EXPECT_EQ(false, mVibrator->supportsAmplitudeControl());
+}
+
+TEST_P(BasicTest, setAmplitude) {
+    EffectAmplitude amplitude = std::rand();
+
+    EXPECT_CALL(*mMockApi, setRtpInput(amplitudeToRtpInput(amplitude))).WillOnce(Return(true));
+
+    EXPECT_EQ(Status::OK, mVibrator->setAmplitude(amplitude));
+}
+
+TEST_P(BasicTest, supportsExternalControl_unsupported) {
+    EXPECT_EQ(false, mVibrator->supportsExternalControl());
+}
+
+TEST_P(BasicTest, setExternalControl_enable) {
+    EXPECT_EQ(Status::UNSUPPORTED_OPERATION, mVibrator->setExternalControl(true));
+}
+
+TEST_P(BasicTest, setExternalControl_disable) {
+    EXPECT_EQ(Status::UNSUPPORTED_OPERATION, mVibrator->setExternalControl(false));
+}
+
+INSTANTIATE_TEST_CASE_P(VibratorTests, BasicTest,
+                        ValuesIn({BasicTest::MakeParam(false), BasicTest::MakeParam(true)}),
+                        BasicTest::PrintParam);
+
+class EffectsTest : public VibratorTestTemplate<EffectTuple> {
+  public:
+    static auto GetEffectTuple(ParamType param) { return GetOtherParam<0>(param); }
+
+    static auto PrintParam(const TestParamInfo<ParamType> &info) {
+        auto prefix = VibratorTestTemplate::PrintParam(info);
+        auto tuple = GetEffectTuple(info.param);
+        auto effect = std::get<0>(tuple);
+        auto strength = std::get<1>(tuple);
+        return prefix + "_" + toString(effect) + "_" + toString(strength);
+    }
+
+  protected:
+    auto getEffectTuple() const { return GetEffectTuple(GetParam()); }
+};
+
+TEST_P(EffectsTest, perform) {
+    auto tuple = getEffectTuple();
+    auto effect = std::get<0>(tuple);
+    auto strength = std::get<1>(tuple);
+    auto seqIter = EFFECT_SEQUENCES.find(tuple);
+    auto durIter = mEffectDurations.find(effect);
+    EffectDuration duration;
+
+    if (seqIter != EFFECT_SEQUENCES.end() && durIter != mEffectDurations.end()) {
+        auto sequence = std::get<0>(seqIter->second);
+        auto scale = std::get<1>(seqIter->second);
+        ExpectationSet e;
+
+        duration = durIter->second;
+
+        e += EXPECT_CALL(*mMockApi, setSequencer(sequence)).WillOnce(Return(true));
+        e += EXPECT_CALL(*mMockApi, setScale(scale)).WillOnce(Return(true));
+        e += EXPECT_CALL(*mMockApi, setCtrlLoop(1)).WillOnce(DoDefault());
+        e += EXPECT_CALL(*mMockApi, setMode("waveform")).WillOnce(DoDefault());
+        e += EXPECT_CALL(*mMockApi, setDuration(duration)).WillOnce(DoDefault());
+
+        if (getDynamicConfig()) {
+            e += EXPECT_CALL(*mMockApi, setLraWaveShape(1)).WillOnce(DoDefault());
+            e += EXPECT_CALL(*mMockApi, setOdClamp(mShortVoltageMax)).WillOnce(DoDefault());
+            e += EXPECT_CALL(*mMockApi, setOlLraPeriod(mShortLraPeriod)).WillOnce(DoDefault());
+        }
+
+        EXPECT_CALL(*mMockApi, setActivate(true)).After(e).WillOnce(DoDefault());
+    } else {
+        duration = 0;
+    }
+
+    mVibrator->perform_1_3(effect, strength, [&](Status status, uint32_t lengthMs) {
+        if (duration) {
+            EXPECT_EQ(Status::OK, status);
+            EXPECT_LE(duration, lengthMs);
+        } else {
+            EXPECT_EQ(Status::UNSUPPORTED_OPERATION, status);
+            EXPECT_EQ(0, lengthMs);
+        }
+    });
+}
+
+INSTANTIATE_TEST_CASE_P(VibratorTests, EffectsTest,
+                        Combine(ValuesIn({false, true}),
+                                Combine(ValuesIn(hidl_enum_range<Effect>().begin(),
+                                                 hidl_enum_range<Effect>().end()),
+                                        ValuesIn(hidl_enum_range<EffectStrength>().begin(),
+                                                 hidl_enum_range<EffectStrength>().end()))),
+                        EffectsTest::PrintParam);
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
diff --git a/vibrator/tests/types.h b/vibrator/drv2624/tests/types.h
similarity index 81%
rename from vibrator/tests/types.h
rename to vibrator/drv2624/tests/types.h
index 94535c2..60be69c 100644
--- a/vibrator/tests/types.h
+++ b/vibrator/drv2624/tests/types.h
@@ -18,16 +18,10 @@
 
 #include <android/hardware/vibrator/1.3/IVibrator.h>
 
-using EffectIndex = uint16_t;
-using EffectLevel = uint32_t;
 using EffectAmplitude = uint8_t;
-using EffectScale = uint16_t;
 using EffectDuration = uint32_t;
-using EffectQueue = std::tuple<std::string, EffectDuration>;
+using EffectSequence = std::tuple<std::string, uint8_t>;
 using EffectTuple = std::tuple<::android::hardware::vibrator::V1_3::Effect,
                                ::android::hardware::vibrator::V1_0::EffectStrength>;
 
-using QueueEffect = std::tuple<EffectIndex, EffectLevel>;
-using QueueDelay = uint32_t;
-
 #endif  // ANDROID_HARDWARE_VIBRATOR_TEST_TYPES_H
diff --git a/vibrator/tests/main.cpp b/vibrator/drv2624/tests/utils.h
similarity index 66%
rename from vibrator/tests/main.cpp
rename to vibrator/drv2624/tests/utils.h
index 87b18a4..5fe4b62 100644
--- a/vibrator/tests/main.cpp
+++ b/vibrator/drv2624/tests/utils.h
@@ -13,10 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#ifndef ANDROID_HARDWARE_VIBRATOR_TEST_UTILS_H
+#define ANDROID_HARDWARE_VIBRATOR_TEST_UTILS_H
 
-#include <gmock/gmock.h>
+#include <cmath>
 
-int main(int argc, char **argv) {
-    ::testing::InitGoogleMock(&argc, argv);
-    return RUN_ALL_TESTS();
+#include "types.h"
+
+static inline int32_t amplitudeToRtpInput(EffectAmplitude amplitude) {
+    return std::round((amplitude - 1) / 254.0 * 127);
 }
+
+#endif  // ANDROID_HARDWARE_VIBRATOR_TEST_UTILS_H
diff --git a/vibrator/tests/mocks.h b/vibrator/tests/mocks.h
deleted file mode 100644
index 4e0544d..0000000
--- a/vibrator/tests/mocks.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.
- */
-#ifndef ANDROID_HARDWARE_VIBRATOR_TEST_MOCKS_H
-#define ANDROID_HARDWARE_VIBRATOR_TEST_MOCKS_H
-
-#include "Vibrator.h"
-
-class MockApi : public ::android::hardware::vibrator::V1_3::implementation::Vibrator::HwApi {
-  public:
-    MOCK_METHOD0(destructor, void());
-    MOCK_METHOD1(setF0, bool(uint32_t value));
-    MOCK_METHOD1(setRedc, bool(uint32_t value));
-    MOCK_METHOD1(setQ, bool(uint32_t value));
-    MOCK_METHOD1(setActivate, bool(bool value));
-    MOCK_METHOD1(setDuration, bool(uint32_t value));
-    MOCK_METHOD1(getEffectDuration, bool(uint32_t *value));
-    MOCK_METHOD1(setEffectIndex, bool(uint32_t value));
-    MOCK_METHOD1(setEffectQueue, bool(std::string value));
-    MOCK_METHOD0(hasEffectScale, bool());
-    MOCK_METHOD1(setEffectScale, bool(uint32_t value));
-    MOCK_METHOD1(setGlobalScale, bool(uint32_t value));
-    MOCK_METHOD1(setState, bool(bool value));
-    MOCK_METHOD0(hasAspEnable, bool());
-    MOCK_METHOD1(getAspEnable, bool(bool *value));
-    MOCK_METHOD1(setAspEnable, bool(bool value));
-    MOCK_METHOD1(setGpioFallIndex, bool(uint32_t value));
-    MOCK_METHOD1(setGpioFallScale, bool(uint32_t value));
-    MOCK_METHOD1(setGpioRiseIndex, bool(uint32_t value));
-    MOCK_METHOD1(setGpioRiseScale, bool(uint32_t value));
-    MOCK_METHOD1(debug, void(int fd));
-
-    ~MockApi() override { destructor(); };
-};
-
-class MockCal : public ::android::hardware::vibrator::V1_3::implementation::Vibrator::HwCal {
-  public:
-    MOCK_METHOD0(destructor, void());
-    MOCK_METHOD1(getF0, bool(uint32_t *value));
-    MOCK_METHOD1(getRedc, bool(uint32_t *value));
-    MOCK_METHOD1(getQ, bool(uint32_t *value));
-    MOCK_METHOD1(getVolLevels, bool(std::array<uint32_t, 6> *value));
-    MOCK_METHOD1(debug, void(int fd));
-
-    ~MockCal() override { destructor(); };
-};
-
-#endif  // ANDROID_HARDWARE_VIBRATOR_TEST_MOCKS_H
diff --git a/vibrator/tests/test-hwapi.cpp b/vibrator/tests/test-hwapi.cpp
deleted file mode 100644
index 87fdae2..0000000
--- a/vibrator/tests/test-hwapi.cpp
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * 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.
- */
-#define LOG_TAG "android.hardware.vibrator@1.3-tests.redfin"
-
-#include <android-base/file.h>
-#include <gtest/gtest.h>
-
-#include <cstdlib>
-#include <fstream>
-
-#include "Hardware.h"
-
-using namespace ::testing;
-
-namespace android {
-namespace hardware {
-namespace vibrator {
-namespace V1_3 {
-namespace implementation {
-
-class HwApiTest : public Test {
-  private:
-    static constexpr const char *FILE_NAMES[]{
-        "F0_FILEPATH",       "REDC_FILEPATH",     "Q_FILEPATH",           "ACTIVATE_PATH",
-        "DURATION_PATH",     "STATE_PATH",        "EFFECT_DURATION_PATH", "EFFECT_INDEX_PATH",
-        "EFFECT_QUEUE_PATH", "EFFECT_SCALE_PATH", "GLOBAL_SCALE_PATH",    "ASP_ENABLE_PATH",
-        "GPIO_FALL_INDEX",   "GPIO_FALL_SCALE",   "GPIO_RISE_INDEX",      "GPIO_RISE_SCALE",
-    };
-
-  public:
-    void SetUp() override {
-        for (auto n : FILE_NAMES) {
-            auto name = std::string(n);
-            auto path = std::string(mFilesDir.path) + "/" + name;
-            std::ofstream touch{path};
-            setenv(name.c_str(), path.c_str(), true);
-            mFileMap[name] = path;
-        }
-        mHwApi = std::make_unique<HwApi>();
-
-        for (auto n : FILE_NAMES) {
-            auto name = std::string(n);
-            auto path = std::string(mEmptyDir.path) + "/" + name;
-            setenv(name.c_str(), path.c_str(), true);
-        }
-        mNoApi = std::make_unique<HwApi>();
-    }
-
-    void TearDown() override { verifyContents(); }
-
-  protected:
-    // Set expected file content for a test.
-    template <typename T>
-    void expectContent(const std::string &name, const T &value) {
-        mExpectedContent[name] << value << std::endl;
-    }
-
-    // Set actual file content for an input test.
-    template <typename T>
-    void updateContent(const std::string &name, const T &value) {
-        std::ofstream(mFileMap[name]) << value << std::endl;
-    }
-
-    template <typename T>
-    void expectAndUpdateContent(const std::string &name, const T &value) {
-        expectContent(name, value);
-        updateContent(name, value);
-    }
-
-    // Compare all file contents against expected contents.
-    void verifyContents() {
-        for (auto &a : mFileMap) {
-            std::ifstream file{a.second};
-            std::string expect = mExpectedContent[a.first].str();
-            std::string actual = std::string(std::istreambuf_iterator<char>(file),
-                                             std::istreambuf_iterator<char>());
-            EXPECT_EQ(expect, actual) << a.first;
-        }
-    }
-
-  protected:
-    std::unique_ptr<Vibrator::HwApi> mHwApi;
-    std::unique_ptr<Vibrator::HwApi> mNoApi;
-    std::map<std::string, std::string> mFileMap;
-    TemporaryDir mFilesDir;
-    TemporaryDir mEmptyDir;
-    std::map<std::string, std::stringstream> mExpectedContent;
-};
-
-template <typename T>
-class HwApiTypedTest
-    : public HwApiTest,
-      public testing::WithParamInterface<std::tuple<std::string, std::function<T>>> {
-  public:
-    static auto PrintParam(const testing::TestParamInfo<typename HwApiTypedTest::ParamType> &info) {
-        return std::get<0>(info.param);
-    };
-    static auto MakeParam(std::string name, std::function<T> func) {
-        return std::make_tuple(name, func);
-    }
-};
-
-using HasTest = HwApiTypedTest<bool(Vibrator::HwApi &)>;
-
-TEST_P(HasTest, success_returnsTrue) {
-    auto param = GetParam();
-    auto func = std::get<1>(param);
-
-    EXPECT_TRUE(func(*mHwApi));
-}
-
-TEST_P(HasTest, success_returnsFalse) {
-    auto param = GetParam();
-    auto func = std::get<1>(param);
-
-    EXPECT_FALSE(func(*mNoApi));
-}
-
-INSTANTIATE_TEST_CASE_P(HwApiTests, HasTest,
-                        ValuesIn({
-                            HasTest::MakeParam("EFFECT_SCALE_PATH",
-                                               &Vibrator::HwApi::hasEffectScale),
-                            HasTest::MakeParam("ASP_ENABLE_PATH", &Vibrator::HwApi::hasAspEnable),
-                        }),
-                        HasTest::PrintParam);
-
-using GetBoolTest = HwApiTypedTest<bool(Vibrator::HwApi &, bool *)>;
-
-TEST_P(GetBoolTest, success_returnsTrue) {
-    auto param = GetParam();
-    auto name = std::get<0>(param);
-    auto func = std::get<1>(param);
-    bool expect = true;
-    bool actual = !expect;
-
-    expectAndUpdateContent(name, "1");
-
-    EXPECT_TRUE(func(*mHwApi, &actual));
-    EXPECT_EQ(expect, actual);
-}
-
-TEST_P(GetBoolTest, success_returnsFalse) {
-    auto param = GetParam();
-    auto name = std::get<0>(param);
-    auto func = std::get<1>(param);
-    bool expect = false;
-    bool actual = !expect;
-
-    expectAndUpdateContent(name, "0");
-
-    EXPECT_TRUE(func(*mHwApi, &actual));
-    EXPECT_EQ(expect, actual);
-}
-
-TEST_P(GetBoolTest, failure) {
-    auto param = GetParam();
-    auto func = std::get<1>(param);
-    bool value;
-
-    EXPECT_FALSE(func(*mNoApi, &value));
-}
-
-INSTANTIATE_TEST_CASE_P(HwApiTests, GetBoolTest,
-                        ValuesIn({
-                            GetBoolTest::MakeParam("ASP_ENABLE_PATH",
-                                                   &Vibrator::HwApi::getAspEnable),
-                        }),
-                        GetBoolTest::PrintParam);
-
-using GetUint32Test = HwApiTypedTest<bool(Vibrator::HwApi &, uint32_t *)>;
-
-TEST_P(GetUint32Test, success) {
-    auto param = GetParam();
-    auto name = std::get<0>(param);
-    auto func = std::get<1>(param);
-    uint32_t expect = std::rand();
-    uint32_t actual = ~expect;
-
-    expectAndUpdateContent(name, expect);
-
-    EXPECT_TRUE(func(*mHwApi, &actual));
-    EXPECT_EQ(expect, actual);
-}
-
-TEST_P(GetUint32Test, failure) {
-    auto param = GetParam();
-    auto func = std::get<1>(param);
-    uint32_t value;
-
-    EXPECT_FALSE(func(*mNoApi, &value));
-}
-
-INSTANTIATE_TEST_CASE_P(HwApiTests, GetUint32Test,
-                        ValuesIn({
-                            GetUint32Test::MakeParam("EFFECT_DURATION_PATH",
-                                                     &Vibrator::HwApi::getEffectDuration),
-                        }),
-                        GetUint32Test::PrintParam);
-
-using SetBoolTest = HwApiTypedTest<bool(Vibrator::HwApi &, bool)>;
-
-TEST_P(SetBoolTest, success_returnsTrue) {
-    auto param = GetParam();
-    auto name = std::get<0>(param);
-    auto func = std::get<1>(param);
-
-    expectContent(name, "1");
-
-    EXPECT_TRUE(func(*mHwApi, true));
-}
-
-TEST_P(SetBoolTest, success_returnsFalse) {
-    auto param = GetParam();
-    auto name = std::get<0>(param);
-    auto func = std::get<1>(param);
-
-    expectContent(name, "0");
-
-    EXPECT_TRUE(func(*mHwApi, false));
-}
-
-TEST_P(SetBoolTest, failure) {
-    auto param = GetParam();
-    auto func = std::get<1>(param);
-
-    EXPECT_FALSE(func(*mNoApi, true));
-    EXPECT_FALSE(func(*mNoApi, false));
-}
-
-INSTANTIATE_TEST_CASE_P(HwApiTests, SetBoolTest,
-                        ValuesIn({
-                            SetBoolTest::MakeParam("ACTIVATE_PATH", &Vibrator::HwApi::setActivate),
-                            SetBoolTest::MakeParam("STATE_PATH", &Vibrator::HwApi::setState),
-                            SetBoolTest::MakeParam("ASP_ENABLE_PATH",
-                                                   &Vibrator::HwApi::setAspEnable),
-                        }),
-                        SetBoolTest::PrintParam);
-
-using SetUint32Test = HwApiTypedTest<bool(Vibrator::HwApi &, uint32_t)>;
-
-TEST_P(SetUint32Test, success) {
-    auto param = GetParam();
-    auto name = std::get<0>(param);
-    auto func = std::get<1>(param);
-    uint32_t value = std::rand();
-
-    expectContent(name, value);
-
-    EXPECT_TRUE(func(*mHwApi, value));
-}
-
-TEST_P(SetUint32Test, failure) {
-    auto param = GetParam();
-    auto func = std::get<1>(param);
-    uint32_t value = std::rand();
-
-    EXPECT_FALSE(func(*mNoApi, value));
-}
-
-INSTANTIATE_TEST_CASE_P(
-    HwApiTests, SetUint32Test,
-    ValuesIn({
-        SetUint32Test::MakeParam("F0_FILEPATH", &Vibrator::HwApi::setF0),
-        SetUint32Test::MakeParam("REDC_FILEPATH", &Vibrator::HwApi::setRedc),
-        SetUint32Test::MakeParam("Q_FILEPATH", &Vibrator::HwApi::setQ),
-        SetUint32Test::MakeParam("DURATION_PATH", &Vibrator::HwApi::setDuration),
-        SetUint32Test::MakeParam("EFFECT_INDEX_PATH", &Vibrator::HwApi::setEffectIndex),
-        SetUint32Test::MakeParam("EFFECT_SCALE_PATH", &Vibrator::HwApi::setEffectScale),
-        SetUint32Test::MakeParam("GLOBAL_SCALE_PATH", &Vibrator::HwApi::setGlobalScale),
-        SetUint32Test::MakeParam("GPIO_FALL_INDEX", &Vibrator::HwApi::setGpioFallIndex),
-        SetUint32Test::MakeParam("GPIO_FALL_SCALE", &Vibrator::HwApi::setGpioFallScale),
-        SetUint32Test::MakeParam("GPIO_RISE_INDEX", &Vibrator::HwApi::setGpioRiseIndex),
-        SetUint32Test::MakeParam("GPIO_RISE_SCALE", &Vibrator::HwApi::setGpioRiseScale),
-    }),
-    SetUint32Test::PrintParam);
-
-using SetStringTest = HwApiTypedTest<bool(Vibrator::HwApi &, std::string)>;
-
-TEST_P(SetStringTest, success) {
-    auto param = GetParam();
-    auto name = std::get<0>(param);
-    auto func = std::get<1>(param);
-    std::string value = TemporaryFile().path;
-
-    expectContent(name, value);
-
-    EXPECT_TRUE(func(*mHwApi, value));
-}
-
-TEST_P(SetStringTest, failure) {
-    auto param = GetParam();
-    auto func = std::get<1>(param);
-    std::string value = TemporaryFile().path;
-
-    EXPECT_FALSE(func(*mNoApi, value));
-}
-
-INSTANTIATE_TEST_CASE_P(HwApiTests, SetStringTest,
-                        ValuesIn({
-                            SetStringTest::MakeParam("EFFECT_QUEUE_PATH",
-                                                     &Vibrator::HwApi::setEffectQueue),
-                        }),
-                        SetStringTest::PrintParam);
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace vibrator
-}  // namespace hardware
-}  // namespace android
diff --git a/vibrator/tests/test-hwcal.cpp b/vibrator/tests/test-hwcal.cpp
deleted file mode 100644
index 42c7702..0000000
--- a/vibrator/tests/test-hwcal.cpp
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * 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.
- */
-#define LOG_TAG "android.hardware.vibrator@1.3-tests.redfin"
-
-#include <android-base/file.h>
-#include <gtest/gtest.h>
-
-#include <fstream>
-
-#include "Hardware.h"
-
-using namespace ::testing;
-
-namespace android {
-namespace hardware {
-namespace vibrator {
-namespace V1_3 {
-namespace implementation {
-
-class HwCalTest : public Test {
-  protected:
-    static constexpr uint32_t Q_DEFAULT = 15.5f * (1 << 16);
-    static constexpr std::array<uint32_t, 6> V_DEFAULT = {60, 70, 80, 90, 100, 76};
-
-  public:
-    void SetUp() override { setenv("CALIBRATION_FILEPATH", mCalFile.path, true); }
-
-  private:
-    static void pack(std::ostream &stream, const uint32_t &value, std::string lpad,
-                     std::string rpad) {
-        stream << lpad << value << rpad;
-    }
-
-    template <typename T, typename std::array<T, 0>::size_type N>
-    static void pack(std::ostream &stream, const std::array<T, N> &value, std::string lpad,
-                     std::string rpad) {
-        for (auto &entry : value) {
-            pack(stream, entry, lpad, rpad);
-        }
-    }
-
-  protected:
-    void createHwCal() { mHwCal = std::make_unique<HwCal>(); }
-
-    template <typename T>
-    void write(const std::string key, const T &value, std::string lpad = " ",
-               std::string rpad = "") {
-        std::ofstream calfile{mCalFile.path, std::ios_base::app};
-        calfile << key << ":";
-        pack(calfile, value, lpad, rpad);
-        calfile << std::endl;
-    }
-
-    void unlink() { ::unlink(mCalFile.path); }
-
-  protected:
-    std::unique_ptr<Vibrator::HwCal> mHwCal;
-    TemporaryFile mCalFile;
-};
-
-TEST_F(HwCalTest, f0_measured) {
-    uint32_t expect = std::rand();
-    uint32_t actual = ~expect;
-
-    write("f0_measured", expect);
-
-    createHwCal();
-
-    EXPECT_TRUE(mHwCal->getF0(&actual));
-    EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, f0_missing) {
-    uint32_t actual;
-
-    createHwCal();
-
-    EXPECT_FALSE(mHwCal->getF0(&actual));
-}
-
-TEST_F(HwCalTest, redc_measured) {
-    uint32_t expect = std::rand();
-    uint32_t actual = ~expect;
-
-    write("redc_measured", expect);
-
-    createHwCal();
-
-    EXPECT_TRUE(mHwCal->getRedc(&actual));
-    EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, redc_missing) {
-    uint32_t actual;
-
-    createHwCal();
-
-    EXPECT_FALSE(mHwCal->getRedc(&actual));
-}
-
-TEST_F(HwCalTest, q_measured) {
-    uint32_t expect = std::rand();
-    uint32_t actual = ~expect;
-
-    write("q_measured", expect);
-
-    createHwCal();
-
-    EXPECT_TRUE(mHwCal->getQ(&actual));
-    EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, q_index) {
-    uint8_t value = std::rand();
-    uint32_t expect = value * 1.5f * (1 << 16) + 2.0f * (1 << 16);
-    uint32_t actual = ~expect;
-
-    write("q_index", value);
-
-    createHwCal();
-
-    EXPECT_TRUE(mHwCal->getQ(&actual));
-    EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, q_missing) {
-    uint32_t expect = Q_DEFAULT;
-    uint32_t actual = ~expect;
-
-    createHwCal();
-
-    EXPECT_TRUE(mHwCal->getQ(&actual));
-    EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, q_nofile) {
-    uint32_t expect = Q_DEFAULT;
-    uint32_t actual = ~expect;
-
-    write("q_measured", actual);
-    unlink();
-
-    createHwCal();
-
-    EXPECT_TRUE(mHwCal->getQ(&actual));
-    EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, v_levels) {
-    std::array<uint32_t, 6> expect;
-    std::array<uint32_t, 6> actual;
-
-    std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) {
-        e = std::rand();
-        return ~e;
-    });
-
-    write("v_levels", expect);
-
-    createHwCal();
-
-    EXPECT_TRUE(mHwCal->getVolLevels(&actual));
-    EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, v_missing) {
-    std::array<uint32_t, 6> expect = V_DEFAULT;
-    std::array<uint32_t, 6> actual;
-
-    std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { return ~e; });
-
-    createHwCal();
-
-    EXPECT_TRUE(mHwCal->getVolLevels(&actual));
-    EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, v_short) {
-    std::array<uint32_t, 6> expect = V_DEFAULT;
-    std::array<uint32_t, 6> actual;
-
-    std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { return ~e; });
-
-    write("v_levels", std::array<uint32_t, expect.size() - 1>());
-
-    createHwCal();
-
-    EXPECT_TRUE(mHwCal->getVolLevels(&actual));
-    EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, v_long) {
-    std::array<uint32_t, 6> expect = V_DEFAULT;
-    std::array<uint32_t, 6> actual;
-
-    std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { return ~e; });
-
-    write("v_levels", std::array<uint32_t, expect.size() + 1>());
-
-    createHwCal();
-
-    EXPECT_TRUE(mHwCal->getVolLevels(&actual));
-    EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, v_nofile) {
-    std::array<uint32_t, 6> expect = V_DEFAULT;
-    std::array<uint32_t, 6> actual;
-
-    std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { return ~e; });
-
-    write("v_levels", actual);
-    unlink();
-
-    createHwCal();
-
-    EXPECT_TRUE(mHwCal->getVolLevels(&actual));
-    EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, multiple) {
-    uint32_t f0Expect = std::rand();
-    uint32_t f0Actual = ~f0Expect;
-    uint32_t redcExpect = std::rand();
-    uint32_t redcActual = ~redcExpect;
-    uint32_t qExpect = std::rand();
-    uint32_t qActual = ~qExpect;
-    std::array<uint32_t, 6> volExpect;
-    std::array<uint32_t, 6> volActual;
-
-    std::transform(volExpect.begin(), volExpect.end(), volActual.begin(), [](uint32_t &e) {
-        e = std::rand();
-        return ~e;
-    });
-
-    write("f0_measured", f0Expect);
-    write("redc_measured", redcExpect);
-    write("q_measured", qExpect);
-    write("v_levels", volExpect);
-
-    createHwCal();
-
-    EXPECT_TRUE(mHwCal->getF0(&f0Actual));
-    EXPECT_EQ(f0Expect, f0Actual);
-    EXPECT_TRUE(mHwCal->getRedc(&redcActual));
-    EXPECT_EQ(redcExpect, redcActual);
-    EXPECT_TRUE(mHwCal->getQ(&qActual));
-    EXPECT_EQ(qExpect, qActual);
-    EXPECT_TRUE(mHwCal->getVolLevels(&volActual));
-    EXPECT_EQ(volExpect, volActual);
-}
-
-TEST_F(HwCalTest, trimming) {
-    uint32_t f0Expect = std::rand();
-    uint32_t f0Actual = ~f0Expect;
-    uint32_t redcExpect = std::rand();
-    uint32_t redcActual = ~redcExpect;
-    uint32_t qExpect = std::rand();
-    uint32_t qActual = ~qExpect;
-    std::array<uint32_t, 6> volExpect;
-    std::array<uint32_t, 6> volActual;
-
-    std::transform(volExpect.begin(), volExpect.end(), volActual.begin(), [](uint32_t &e) {
-        e = std::rand();
-        return ~e;
-    });
-
-    write("f0_measured", f0Expect, " \t", "\t ");
-    write("redc_measured", redcExpect, " \t", "\t ");
-    write("q_measured", qExpect, " \t", "\t ");
-    write("v_levels", volExpect, " \t", "\t ");
-
-    createHwCal();
-
-    EXPECT_TRUE(mHwCal->getF0(&f0Actual));
-    EXPECT_EQ(f0Expect, f0Actual);
-    EXPECT_TRUE(mHwCal->getRedc(&redcActual));
-    EXPECT_EQ(redcExpect, redcActual);
-    EXPECT_TRUE(mHwCal->getQ(&qActual));
-    EXPECT_EQ(qExpect, qActual);
-    EXPECT_TRUE(mHwCal->getVolLevels(&volActual));
-    EXPECT_EQ(volExpect, volActual);
-}
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace vibrator
-}  // namespace hardware
-}  // namespace android
diff --git a/vibrator/tests/test-vibrator.cpp b/vibrator/tests/test-vibrator.cpp
deleted file mode 100644
index 85109eb..0000000
--- a/vibrator/tests/test-vibrator.cpp
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * 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.
- */
-#define LOG_TAG "PtsVibratorHalRedfinTestSuite"
-
-#include <android-base/logging.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "Vibrator.h"
-#include "mocks.h"
-#include "types.h"
-#include "utils.h"
-
-using namespace ::testing;
-
-namespace android {
-namespace hardware {
-namespace vibrator {
-namespace V1_3 {
-namespace implementation {
-
-using ::android::hardware::vibrator::V1_0::EffectStrength;
-using ::android::hardware::vibrator::V1_0::Status;
-
-// Forward Declarations
-
-static EffectQueue Queue(const QueueEffect &effect);
-static EffectQueue Queue(const QueueDelay &delay);
-template <typename T, typename U, typename... Args>
-static EffectQueue Queue(const T &first, const U &second, Args... rest);
-
-// Constants With Arbitrary Values
-
-static constexpr std::array<EffectLevel, 6> V_LEVELS{40, 50, 60, 70, 80, 90};
-static constexpr EffectDuration EFFECT_DURATION{15};
-
-// Constants With Prescribed Values
-
-static constexpr EffectIndex EFFECT_INDEX{2};
-static constexpr EffectIndex QUEUE_INDEX{65534};
-
-static constexpr EffectIndex GPIO_FALL_INDEX{EFFECT_INDEX};
-static const EffectScale GPIO_FALL_SCALE{levelToScale(V_LEVELS[2])};
-static constexpr EffectIndex GPIO_RISE_INDEX{EFFECT_INDEX};
-static const EffectScale GPIO_RISE_SCALE{levelToScale(V_LEVELS[3])};
-
-static const EffectScale ON_GLOBAL_SCALE{levelToScale(V_LEVELS[5])};
-static const EffectIndex ON_EFFECT_INDEX{0};
-
-static const std::map<EffectTuple, EffectScale> EFFECT_SCALE{
-    {{Effect::CLICK, EffectStrength::LIGHT}, levelToScale(V_LEVELS[1])},
-    {{Effect::CLICK, EffectStrength::MEDIUM}, levelToScale(V_LEVELS[2])},
-    {{Effect::CLICK, EffectStrength::STRONG}, levelToScale(V_LEVELS[3])},
-    {{Effect::TICK, EffectStrength::LIGHT}, levelToScale(V_LEVELS[1])},
-    {{Effect::TICK, EffectStrength::MEDIUM}, levelToScale(V_LEVELS[1])},
-    {{Effect::TICK, EffectStrength::STRONG}, levelToScale(V_LEVELS[1])},
-    {{Effect::HEAVY_CLICK, EffectStrength::LIGHT}, levelToScale(V_LEVELS[2])},
-    {{Effect::HEAVY_CLICK, EffectStrength::MEDIUM}, levelToScale(V_LEVELS[3])},
-    {{Effect::HEAVY_CLICK, EffectStrength::STRONG}, levelToScale(V_LEVELS[4])},
-    {{Effect::TEXTURE_TICK, EffectStrength::LIGHT}, levelToScale(V_LEVELS[0])},
-    {{Effect::TEXTURE_TICK, EffectStrength::MEDIUM}, levelToScale(V_LEVELS[0])},
-    {{Effect::TEXTURE_TICK, EffectStrength::STRONG}, levelToScale(V_LEVELS[0])},
-};
-
-static const std::map<EffectTuple, EffectQueue> EFFECT_QUEUE{
-    {{Effect::DOUBLE_CLICK, EffectStrength::LIGHT},
-     Queue(QueueEffect{EFFECT_INDEX, V_LEVELS[1]}, 100, QueueEffect{EFFECT_INDEX, V_LEVELS[2]})},
-    {{Effect::DOUBLE_CLICK, EffectStrength::MEDIUM},
-     Queue(QueueEffect{EFFECT_INDEX, V_LEVELS[2]}, 100, QueueEffect{EFFECT_INDEX, V_LEVELS[3]})},
-    {{Effect::DOUBLE_CLICK, EffectStrength::STRONG},
-     Queue(QueueEffect{EFFECT_INDEX, V_LEVELS[3]}, 100, QueueEffect{EFFECT_INDEX, V_LEVELS[4]})},
-};
-
-EffectQueue Queue(const QueueEffect &effect) {
-    auto index = std::get<0>(effect);
-    auto level = std::get<1>(effect);
-    auto string = std::to_string(index) + "." + std::to_string(level);
-    auto duration = EFFECT_DURATION;
-    return {string, duration};
-}
-
-EffectQueue Queue(const QueueDelay &delay) {
-    auto string = std::to_string(delay);
-    return {string, delay};
-}
-
-template <typename T, typename U, typename... Args>
-EffectQueue Queue(const T &first, const U &second, Args... rest) {
-    auto head = Queue(first);
-    auto tail = Queue(second, rest...);
-    auto string = std::get<0>(head) + "," + std::get<0>(tail);
-    auto duration = std::get<1>(head) + std::get<1>(tail);
-    return {string, duration};
-}
-
-class VibratorTest : public Test, public WithParamInterface<EffectTuple> {
-  public:
-    void SetUp() override {
-        std::unique_ptr<MockApi> mockapi;
-        std::unique_ptr<MockCal> mockcal;
-
-        createMock(&mockapi, &mockcal);
-        createVibrator(std::move(mockapi), std::move(mockcal));
-    }
-
-    void TearDown() override { deleteVibrator(); }
-
-  protected:
-    void createMock(std::unique_ptr<MockApi> *mockapi, std::unique_ptr<MockCal> *mockcal) {
-        *mockapi = std::make_unique<MockApi>();
-        *mockcal = std::make_unique<MockCal>();
-
-        mMockApi = mockapi->get();
-        mMockCal = mockcal->get();
-
-        ON_CALL(*mMockApi, destructor()).WillByDefault(Assign(&mMockApi, nullptr));
-
-        ON_CALL(*mMockApi, getEffectDuration(_))
-            .WillByDefault(
-                DoAll(SetArgPointee<0>(msToCycles(EFFECT_DURATION)), ::testing::Return(true)));
-
-        ON_CALL(*mMockCal, destructor()).WillByDefault(Assign(&mMockCal, nullptr));
-
-        ON_CALL(*mMockCal, getVolLevels(_))
-            .WillByDefault(DoAll(SetArgPointee<0>(V_LEVELS), ::testing::Return(true)));
-
-        relaxMock(false);
-    }
-
-    void createVibrator(std::unique_ptr<MockApi> mockapi, std::unique_ptr<MockCal> mockcal,
-                        bool relaxed = true) {
-        std::vector<uint32_t> vlevels{std::begin(V_LEVELS), std::end(V_LEVELS)};
-        if (relaxed) {
-            relaxMock(true);
-        }
-        mVibrator = new Vibrator(std::move(mockapi), std::move(mockcal));
-        if (relaxed) {
-            relaxMock(false);
-        }
-    }
-
-    void deleteVibrator(bool relaxed = true) {
-        if (relaxed) {
-            relaxMock(true);
-        }
-        mVibrator.clear();
-    }
-
-  private:
-    void relaxMock(bool relax) {
-        auto times = relax ? AnyNumber() : Exactly(0);
-
-        Mock::VerifyAndClearExpectations(mMockApi);
-        Mock::VerifyAndClearExpectations(mMockCal);
-
-        EXPECT_CALL(*mMockApi, destructor()).Times(times);
-        EXPECT_CALL(*mMockApi, setF0(_)).Times(times);
-        EXPECT_CALL(*mMockApi, setRedc(_)).Times(times);
-        EXPECT_CALL(*mMockApi, setQ(_)).Times(times);
-        EXPECT_CALL(*mMockApi, setActivate(_)).Times(times);
-        EXPECT_CALL(*mMockApi, setDuration(_)).Times(times);
-        EXPECT_CALL(*mMockApi, getEffectDuration(_)).Times(times);
-        EXPECT_CALL(*mMockApi, setEffectIndex(_)).Times(times);
-        EXPECT_CALL(*mMockApi, setEffectQueue(_)).Times(times);
-        EXPECT_CALL(*mMockApi, hasEffectScale()).Times(times);
-        EXPECT_CALL(*mMockApi, setEffectScale(_)).Times(times);
-        EXPECT_CALL(*mMockApi, setGlobalScale(_)).Times(times);
-        EXPECT_CALL(*mMockApi, setState(_)).Times(times);
-        EXPECT_CALL(*mMockApi, hasAspEnable()).Times(times);
-        EXPECT_CALL(*mMockApi, getAspEnable(_)).Times(times);
-        EXPECT_CALL(*mMockApi, setAspEnable(_)).Times(times);
-        EXPECT_CALL(*mMockApi, setGpioFallIndex(_)).Times(times);
-        EXPECT_CALL(*mMockApi, setGpioFallScale(_)).Times(times);
-        EXPECT_CALL(*mMockApi, setGpioRiseIndex(_)).Times(times);
-        EXPECT_CALL(*mMockApi, setGpioRiseScale(_)).Times(times);
-        EXPECT_CALL(*mMockApi, debug(_)).Times(times);
-
-        EXPECT_CALL(*mMockCal, destructor()).Times(times);
-        EXPECT_CALL(*mMockCal, getF0(_)).Times(times);
-        EXPECT_CALL(*mMockCal, getRedc(_)).Times(times);
-        EXPECT_CALL(*mMockCal, getQ(_)).Times(times);
-        EXPECT_CALL(*mMockCal, getVolLevels(_)).Times(times);
-        EXPECT_CALL(*mMockApi, debug(_)).Times(times);
-    }
-
-  protected:
-    MockApi *mMockApi;
-    MockCal *mMockCal;
-    sp<IVibrator> mVibrator;
-};
-
-TEST_F(VibratorTest, HwApi) {
-    std::unique_ptr<MockApi> mockapi;
-    std::unique_ptr<MockCal> mockcal;
-    uint32_t f0Val = std::rand();
-    uint32_t redcVal = std::rand();
-    uint32_t qVal = std::rand();
-    Expectation volGet;
-    Sequence f0Seq, redcSeq, qSeq, volSeq, durSeq;
-
-    EXPECT_CALL(*mMockApi, destructor()).WillOnce(DoDefault());
-    EXPECT_CALL(*mMockCal, destructor()).WillOnce(DoDefault());
-
-    deleteVibrator(false);
-
-    createMock(&mockapi, &mockcal);
-
-    EXPECT_CALL(*mMockCal, getF0(_))
-        .InSequence(f0Seq)
-        .WillOnce(DoAll(SetArgPointee<0>(f0Val), ::testing::Return(true)));
-    EXPECT_CALL(*mMockApi, setF0(f0Val)).InSequence(f0Seq).WillOnce(::testing::Return(true));
-
-    EXPECT_CALL(*mMockCal, getRedc(_))
-        .InSequence(redcSeq)
-        .WillOnce(DoAll(SetArgPointee<0>(redcVal), ::testing::Return(true)));
-    EXPECT_CALL(*mMockApi, setRedc(redcVal)).InSequence(redcSeq).WillOnce(::testing::Return(true));
-
-    EXPECT_CALL(*mMockCal, getQ(_))
-        .InSequence(qSeq)
-        .WillOnce(DoAll(SetArgPointee<0>(qVal), ::testing::Return(true)));
-    EXPECT_CALL(*mMockApi, setQ(qVal)).InSequence(qSeq).WillOnce(::testing::Return(true));
-
-    volGet = EXPECT_CALL(*mMockCal, getVolLevels(_)).WillOnce(DoDefault());
-
-    EXPECT_CALL(*mMockApi, setState(true)).WillOnce(::testing::Return(true));
-    EXPECT_CALL(*mMockApi, setEffectIndex(EFFECT_INDEX))
-        .InSequence(durSeq)
-        .WillOnce(::testing::Return(true));
-    EXPECT_CALL(*mMockApi, getEffectDuration(_)).InSequence(durSeq).WillOnce(DoDefault());
-
-    EXPECT_CALL(*mMockApi, setGpioFallIndex(GPIO_FALL_INDEX)).WillOnce(::testing::Return(true));
-    EXPECT_CALL(*mMockApi, setGpioFallScale(GPIO_FALL_SCALE))
-        .After(volGet)
-        .WillOnce(::testing::Return(true));
-    EXPECT_CALL(*mMockApi, setGpioRiseIndex(GPIO_RISE_INDEX)).WillOnce(::testing::Return(true));
-    EXPECT_CALL(*mMockApi, setGpioRiseScale(GPIO_RISE_SCALE))
-        .After(volGet)
-        .WillOnce(::testing::Return(true));
-
-    createVibrator(std::move(mockapi), std::move(mockcal), false);
-}
-
-TEST_F(VibratorTest, on) {
-    Sequence s1, s2, s3;
-    uint16_t duration = std::rand() + 1;
-
-    EXPECT_CALL(*mMockApi, setGlobalScale(ON_GLOBAL_SCALE))
-        .InSequence(s1)
-        .WillOnce(::testing::Return(true));
-    EXPECT_CALL(*mMockApi, setEffectIndex(ON_EFFECT_INDEX))
-        .InSequence(s2)
-        .WillOnce(::testing::Return(true));
-    EXPECT_CALL(*mMockApi, setDuration(Ge(duration)))
-        .InSequence(s3)
-        .WillOnce(::testing::Return(true));
-    EXPECT_CALL(*mMockApi, setActivate(true))
-        .InSequence(s1, s2, s3)
-        .WillOnce(::testing::Return(true));
-
-    EXPECT_EQ(Status::OK, mVibrator->on(duration));
-}
-
-TEST_F(VibratorTest, off) {
-    EXPECT_CALL(*mMockApi, setActivate(false)).WillOnce(::testing::Return(true));
-    EXPECT_CALL(*mMockApi, setGlobalScale(0)).WillOnce(::testing::Return(true));
-
-    EXPECT_EQ(Status::OK, mVibrator->off());
-}
-
-TEST_F(VibratorTest, supportsAmplitudeControl_supported) {
-    EXPECT_CALL(*mMockApi, hasEffectScale()).WillOnce(::testing::Return(true));
-    EXPECT_CALL(*mMockApi, getAspEnable(_))
-        .WillOnce(DoAll(SetArgPointee<0>(false), ::testing::Return(true)));
-
-    EXPECT_EQ(true, mVibrator->supportsAmplitudeControl());
-}
-
-TEST_F(VibratorTest, supportsAmplitudeControl_unsupported1) {
-    MockFunction<void()> either;
-
-    EXPECT_CALL(*mMockApi, hasEffectScale())
-        .Times(AtMost(1))
-        .WillOnce(DoAll(InvokeWithoutArgs(&either, &MockFunction<void()>::Call),
-                        ::testing::Return(false)));
-    EXPECT_CALL(*mMockApi, getAspEnable(_))
-        .Times(AtMost(1))
-        .WillOnce(DoAll(InvokeWithoutArgs(&either, &MockFunction<void()>::Call),
-                        SetArgPointee<0>(false), ::testing::Return(true)));
-    EXPECT_CALL(either, Call()).Times(AtLeast(1));
-
-    EXPECT_EQ(false, mVibrator->supportsAmplitudeControl());
-}
-
-TEST_F(VibratorTest, supportsAmplitudeControl_unsupported2) {
-    MockFunction<void()> either;
-
-    EXPECT_CALL(*mMockApi, hasEffectScale())
-        .Times(AtMost(1))
-        .WillOnce(DoAll(InvokeWithoutArgs(&either, &MockFunction<void()>::Call),
-                        ::testing::Return(false)));
-    EXPECT_CALL(*mMockApi, getAspEnable(_))
-        .Times(AtMost(1))
-        .WillOnce(DoAll(InvokeWithoutArgs(&either, &MockFunction<void()>::Call),
-                        SetArgPointee<0>(true), ::testing::Return(true)));
-    EXPECT_CALL(either, Call()).Times(AtLeast(1));
-
-    EXPECT_EQ(false, mVibrator->supportsAmplitudeControl());
-}
-
-TEST_F(VibratorTest, supportsAmplitudeControl_unsupported3) {
-    MockFunction<void()> either;
-
-    EXPECT_CALL(*mMockApi, hasEffectScale())
-        .Times(AtMost(1))
-        .WillOnce(DoAll(InvokeWithoutArgs(&either, &MockFunction<void()>::Call),
-                        ::testing::Return(true)));
-    EXPECT_CALL(*mMockApi, getAspEnable(_))
-        .Times(AtMost(1))
-        .WillOnce(DoAll(InvokeWithoutArgs(&either, &MockFunction<void()>::Call),
-                        SetArgPointee<0>(true), ::testing::Return(true)));
-    EXPECT_CALL(either, Call()).Times(AtLeast(1));
-
-    EXPECT_EQ(false, mVibrator->supportsAmplitudeControl());
-}
-
-TEST_F(VibratorTest, setAmplitude_supported) {
-    Sequence s;
-    EffectAmplitude amplitude = std::rand() + 1;
-
-    EXPECT_CALL(*mMockApi, getAspEnable(_))
-        .InSequence(s)
-        .WillOnce(DoAll(SetArgPointee<0>(false), ::testing::Return(true)));
-    EXPECT_CALL(*mMockApi, setEffectScale(amplitudeToScale(amplitude)))
-        .InSequence(s)
-        .WillOnce(::testing::Return(true));
-
-    EXPECT_EQ(Status::OK, mVibrator->setAmplitude(amplitude));
-}
-
-TEST_F(VibratorTest, setAmplitude_unsupported) {
-    EXPECT_CALL(*mMockApi, getAspEnable(_))
-        .WillOnce(DoAll(SetArgPointee<0>(true), ::testing::Return(true)));
-
-    EXPECT_EQ(Status::UNSUPPORTED_OPERATION, mVibrator->setAmplitude(1));
-}
-
-TEST_F(VibratorTest, supportsExternalControl_supported) {
-    EXPECT_CALL(*mMockApi, hasAspEnable()).WillOnce(::testing::Return(true));
-
-    EXPECT_EQ(true, mVibrator->supportsExternalControl());
-}
-
-TEST_F(VibratorTest, supportsExternalControl_unsupported) {
-    EXPECT_CALL(*mMockApi, hasAspEnable()).WillOnce(::testing::Return(false));
-
-    EXPECT_EQ(false, mVibrator->supportsExternalControl());
-}
-
-TEST_F(VibratorTest, setExternalControl_enable) {
-    Sequence s;
-
-    EXPECT_CALL(*mMockApi, setGlobalScale(ON_GLOBAL_SCALE))
-        .InSequence(s)
-        .WillOnce(::testing::Return(true));
-    EXPECT_CALL(*mMockApi, setAspEnable(true)).InSequence(s).WillOnce(::testing::Return(true));
-
-    EXPECT_EQ(Status::OK, mVibrator->setExternalControl(true));
-}
-
-TEST_F(VibratorTest, setExternalControl_disable) {
-    EXPECT_CALL(*mMockApi, setAspEnable(false)).WillOnce(::testing::Return(true));
-    EXPECT_CALL(*mMockApi, setGlobalScale(0)).WillOnce(::testing::Return(true));
-
-    EXPECT_EQ(Status::OK, mVibrator->setExternalControl(false));
-}
-
-TEST_P(VibratorTest, perform) {
-    auto param = GetParam();
-    auto effect = std::get<0>(param);
-    auto strength = std::get<1>(param);
-    auto scale = EFFECT_SCALE.find(param);
-    auto queue = EFFECT_QUEUE.find(param);
-    EffectDuration duration;
-
-    if (scale != EFFECT_SCALE.end()) {
-        Sequence s1, s2, s3;
-
-        duration = EFFECT_DURATION;
-
-        EXPECT_CALL(*mMockApi, setEffectIndex(EFFECT_INDEX))
-            .InSequence(s1)
-            .WillOnce(::testing::Return(true));
-        EXPECT_CALL(*mMockApi, setEffectScale(scale->second))
-            .InSequence(s2)
-            .WillOnce(::testing::Return(true));
-        EXPECT_CALL(*mMockApi, setDuration(Ge(duration)))
-            .InSequence(s3)
-            .WillOnce(::testing::Return(true));
-
-        EXPECT_CALL(*mMockApi, setActivate(true))
-            .InSequence(s1, s2, s3)
-            .WillOnce(::testing::Return(true));
-    } else if (queue != EFFECT_QUEUE.end()) {
-        Sequence s1, s2, s3;
-
-        duration = std::get<1>(queue->second);
-
-        EXPECT_CALL(*mMockApi, setEffectIndex(QUEUE_INDEX))
-            .InSequence(s1)
-            .WillOnce(::testing::Return(true));
-        EXPECT_CALL(*mMockApi, setEffectQueue(std::get<0>(queue->second)))
-            .InSequence(s2)
-            .WillOnce(::testing::Return(true));
-        EXPECT_CALL(*mMockApi, setDuration(Ge(duration)))
-            .InSequence(s3)
-            .WillOnce(::testing::Return(true));
-
-        EXPECT_CALL(*mMockApi, setActivate(true))
-            .InSequence(s1, s2, s3)
-            .WillOnce(::testing::Return(true));
-    } else {
-        duration = 0;
-    }
-
-    mVibrator->perform_1_3(effect, strength, [&](Status status, uint32_t lengthMs) {
-        if (duration) {
-            EXPECT_EQ(Status::OK, status);
-            EXPECT_LE(duration, lengthMs);
-        } else {
-            EXPECT_EQ(Status::UNSUPPORTED_OPERATION, status);
-            EXPECT_EQ(0, lengthMs);
-        }
-    });
-}
-
-INSTANTIATE_TEST_CASE_P(VibratorEffects, VibratorTest,
-                        Combine(ValuesIn(hidl_enum_range<Effect>().begin(),
-                                         hidl_enum_range<Effect>().end()),
-                                ValuesIn(hidl_enum_range<EffectStrength>().begin(),
-                                         hidl_enum_range<EffectStrength>().end())),
-                        [](const testing::TestParamInfo<VibratorTest::ParamType> &info) {
-                            auto effect = std::get<0>(info.param);
-                            auto strength = std::get<1>(info.param);
-                            return toString(effect) + "_" + toString(strength);
-                        });
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace vibrator
-}  // namespace hardware
-}  // namespace android
diff --git a/vibrator/tests/utils.h b/vibrator/tests/utils.h
deleted file mode 100644
index 86cb944..0000000
--- a/vibrator/tests/utils.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- */
-#ifndef ANDROID_HARDWARE_VIBRATOR_TEST_UTILS_H
-#define ANDROID_HARDWARE_VIBRATOR_TEST_UTILS_H
-
-#include <cmath>
-
-#include "types.h"
-
-static inline EffectScale toScale(uint8_t target, uint8_t maximum) {
-    return std::round((-20 * std::log10(target / static_cast<float>(maximum))) / 0.125f);
-}
-
-static inline EffectScale levelToScale(EffectLevel level) {
-    return toScale(level, 100);
-}
-
-static inline EffectScale amplitudeToScale(EffectAmplitude amplitude) {
-    return toScale(amplitude, UINT8_MAX);
-}
-
-static inline uint32_t msToCycles(EffectDuration ms) {
-    return ms * 48;
-}
-
-#endif  // ANDROID_HARDWARE_VIBRATOR_TEST_UTILS_H
diff --git a/vibrator/utils.h b/vibrator/utils.h
deleted file mode 100644
index 078310e..0000000
--- a/vibrator/utils.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.
- */
-#ifndef ANDROID_HARDWARE_VIBRATOR_UTILS_H
-#define ANDROID_HARDWARE_VIBRATOR_UTILS_H
-
-template <typename T>
-class Is_Iterable {
-  private:
-    template <typename U>
-    static std::true_type test(typename U::iterator *u);
-
-    template <typename U>
-    static std::false_type test(U *u);
-
-  public:
-    static const bool value = decltype(test<T>(0))::value;
-};
-
-template <typename T, bool B>
-using Enable_If_Iterable = std::enable_if_t<Is_Iterable<T>::value == B>;
-
-#endif  // ANDROID_HARDWARE_VIBRATOR_UTILS_H