device/vibrator: Add contextual haptics feature am: 0db068b63c
am: 6f3f6dc2b0
Original change: https://googleplex-android-review.googlesource.com/c/device/google/lynx/+/20360548 Change-Id: I17148d10824de1507043308ba9b63dcb77b77678 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
76ce4eb07a
@ -110,3 +110,10 @@ on override-sf-uclamp
|
||||
# it should be written by the system init.
|
||||
on property:ro.boot.hardware.sku=G82U8
|
||||
setprop audio.camerasound.force true
|
||||
|
||||
# Route vibrator.adaptive_haptics.enabled to persist
|
||||
on property:vibrator.adaptive_haptics.enabled=0
|
||||
setprop persist.vendor.vibrator.hal.context.enable false
|
||||
|
||||
on property:vibrator.adaptive_haptics.enabled=1
|
||||
setprop persist.vendor.vibrator.hal.context.enable true
|
||||
|
@ -28,7 +28,7 @@ DEVICE_PACKAGE_OVERLAYS += device/google/lynx/lynx/overlay
|
||||
|
||||
include device/google/lynx/audio/lynx/audio-tables.mk
|
||||
include device/google/gs201/device-shipping-common.mk
|
||||
include hardware/google/pixel/vibrator/cs40l26/device.mk
|
||||
include device/google/lynx/vibrator/cs40l26/device.mk
|
||||
|
||||
# go/lyric-soong-variables
|
||||
$(call soong_config_set,lyric,camera_hardware,lynx)
|
||||
@ -154,7 +154,12 @@ endif
|
||||
PRODUCT_VENDOR_PROPERTIES += \
|
||||
ro.vendor.vibrator.hal.supported_primitives=243 \
|
||||
ro.vendor.vibrator.hal.f0.comp.enabled=1 \
|
||||
ro.vendor.vibrator.hal.redc.comp.enabled=0
|
||||
ro.vendor.vibrator.hal.redc.comp.enabled=0 \
|
||||
persist.vendor.vibrator.hal.context.enable=false \
|
||||
persist.vendor.vibrator.hal.context.scale=40 \
|
||||
persist.vendor.vibrator.hal.context.fade=true \
|
||||
persist.vendor.vibrator.hal.context.cooldowntime=1600 \
|
||||
persist.vendor.vibrator.hal.context.settlingtime=5000
|
||||
|
||||
# Trusty liboemcrypto.so
|
||||
PRODUCT_SOONG_NAMESPACES += vendor/google_devices/lynx/prebuilts
|
||||
|
@ -18,10 +18,10 @@ package {
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "PixelVibratorDefaults",
|
||||
name: "PixelVibratorDefaultsPrivateLynx",
|
||||
relative_install_path: "hw",
|
||||
static_libs: [
|
||||
"PixelVibratorCommon",
|
||||
"PixelVibratorCommonPrivateLynx",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
@ -34,16 +34,16 @@ cc_defaults {
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "PixelVibratorBinaryDefaults",
|
||||
defaults: ["PixelVibratorDefaults"],
|
||||
name: "PixelVibratorBinaryDefaultsPrivateLynx",
|
||||
defaults: ["PixelVibratorDefaultsPrivateLynx"],
|
||||
shared_libs: [
|
||||
"android.hardware.vibrator-V2-ndk",
|
||||
],
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "PixelVibratorTestDefaults",
|
||||
defaults: ["PixelVibratorDefaults"],
|
||||
name: "PixelVibratorTestDefaultsPrivateLynx",
|
||||
defaults: ["PixelVibratorDefaultsPrivateLynx"],
|
||||
static_libs: [
|
||||
"android.hardware.vibrator-V2-ndk",
|
||||
],
|
||||
|
@ -1,3 +1,4 @@
|
||||
chasewu@google.com
|
||||
michaelwr@google.com
|
||||
taikuo@google.com
|
||||
chrispaulo@google.com
|
||||
|
@ -18,7 +18,7 @@ package {
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "PixelVibratorCommon",
|
||||
name: "PixelVibratorCommonPrivateLynx",
|
||||
srcs: [
|
||||
"HardwareBase.cpp",
|
||||
],
|
||||
|
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (C) 2021 The Android Open Source Project
|
||||
// Copyright (C) 2022 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.
|
||||
@ -18,7 +18,7 @@ package {
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "android.hardware.vibrator-defaults.cs40l26",
|
||||
name: "android.hardware.vibrator-defaults.cs40l26-private-lynx",
|
||||
cflags: [
|
||||
"-DATRACE_TAG=(ATRACE_TAG_VIBRATOR | ATRACE_TAG_HAL)",
|
||||
"-DLOG_TAG=\"android.hardware.vibrator-cs40l26\"",
|
||||
@ -29,10 +29,10 @@ cc_defaults {
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "VibratorHalCs40l26BinaryDefaults",
|
||||
name: "VibratorHalCs40l26BinaryDefaultsPrivateLynx",
|
||||
defaults: [
|
||||
"PixelVibratorBinaryDefaults",
|
||||
"android.hardware.vibrator-defaults.cs40l26",
|
||||
"PixelVibratorBinaryDefaultsPrivateLynx",
|
||||
"android.hardware.vibrator-defaults.cs40l26-private-lynx",
|
||||
],
|
||||
include_dirs: [
|
||||
"external/tinyalsa/include",
|
||||
@ -44,43 +44,64 @@ cc_defaults {
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "VibratorHalCs40l26TestDefaults",
|
||||
name: "VibratorHalCs40l26TestDefaultsPrivateLynx",
|
||||
defaults: [
|
||||
"PixelVibratorTestDefaults",
|
||||
"android.hardware.vibrator-defaults.cs40l26",
|
||||
"PixelVibratorTestDefaultsPrivateLynx",
|
||||
"android.hardware.vibrator-defaults.cs40l26-private-lynx",
|
||||
],
|
||||
static_libs: [
|
||||
"android.hardware.vibrator-impl.cs40l26",
|
||||
"libtinyalsa",
|
||||
],
|
||||
shared_libs: ["android.hardware.vibrator-impl.cs40l26-private-lynx"],
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "android.hardware.vibrator-impl.cs40l26",
|
||||
defaults: ["VibratorHalCs40l26BinaryDefaults"],
|
||||
srcs: ["Vibrator.cpp"],
|
||||
export_include_dirs: ["."],
|
||||
cc_library_shared {
|
||||
name: "libvibecapo_proto_lynx",
|
||||
vendor_available: true,
|
||||
owner: "google",
|
||||
srcs: [
|
||||
"proto/capo.proto",
|
||||
],
|
||||
shared_libs: [
|
||||
"libprotobuf-cpp-full",
|
||||
],
|
||||
export_include_dirs: [
|
||||
"inc",
|
||||
],
|
||||
proto: {
|
||||
type: "lite",
|
||||
export_proto_headers: true,
|
||||
},
|
||||
}
|
||||
|
||||
cc_library_shared {
|
||||
name: "android.hardware.vibrator-impl.cs40l26-private-lynx",
|
||||
defaults: ["VibratorHalCs40l26BinaryDefaultsPrivateLynx"],
|
||||
srcs: [
|
||||
"Vibrator.cpp",
|
||||
"CapoDetector.cpp",
|
||||
],
|
||||
static_libs: [
|
||||
"chre_client",
|
||||
],
|
||||
shared_libs: [
|
||||
"libvibecapo_proto_lynx",
|
||||
"libprotobuf-cpp-full",
|
||||
],
|
||||
export_include_dirs: [
|
||||
".",
|
||||
"inc",
|
||||
],
|
||||
vendor_available: true,
|
||||
visibility: [":__subpackages__"],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "android.hardware.vibrator-service.cs40l26",
|
||||
defaults: ["VibratorHalCs40l26BinaryDefaults"],
|
||||
init_rc: ["android.hardware.vibrator-service.cs40l26.rc"],
|
||||
vintf_fragments: ["android.hardware.vibrator-service.cs40l26.xml"],
|
||||
name: "android.hardware.vibrator-service.cs40l26-private-lynx",
|
||||
defaults: ["VibratorHalCs40l26BinaryDefaultsPrivateLynx"],
|
||||
init_rc: ["android.hardware.vibrator-service.cs40l26-private-lynx.rc"],
|
||||
vintf_fragments: ["android.hardware.vibrator-service.cs40l26-private-lynx.xml"],
|
||||
srcs: ["service.cpp"],
|
||||
shared_libs: ["android.hardware.vibrator-impl.cs40l26"],
|
||||
proprietary: true,
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "android.hardware.vibrator-service.cs40l26-dual",
|
||||
defaults: ["VibratorHalCs40l26BinaryDefaults"],
|
||||
init_rc: ["android.hardware.vibrator-service.cs40l26-dual.rc"],
|
||||
vintf_fragments: ["android.hardware.vibrator-service.cs40l26-dual.xml"],
|
||||
srcs: ["service.cpp"],
|
||||
shared_libs: ["android.hardware.vibrator-impl.cs40l26"],
|
||||
cflags: ["-DVIBRATOR_NAME=\"dual\""],
|
||||
shared_libs: ["android.hardware.vibrator-impl.cs40l26-private-lynx"],
|
||||
proprietary: true,
|
||||
}
|
||||
|
216
vibrator/cs40l26/CapoDetector.cpp
Normal file
216
vibrator/cs40l26/CapoDetector.cpp
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright 2022 Google LLC. All Rights Reserved.
|
||||
*
|
||||
* 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 "CapoDetector.h"
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
|
||||
#include <log/log.h>
|
||||
|
||||
#ifdef LOG_TAG
|
||||
#undef LOG_TAG
|
||||
#define LOG_TAG "CapoDetector"
|
||||
#endif
|
||||
|
||||
namespace android {
|
||||
namespace chre {
|
||||
|
||||
namespace { // anonymous namespace for file-local definitions
|
||||
|
||||
static capo::ConfigureDetector_ConfigData config_data = capo::ConfigureDetector_ConfigData();
|
||||
static capo::ConfigureDetector msg = capo::ConfigureDetector();
|
||||
|
||||
|
||||
/**
|
||||
* Called when onConnected() to send NanoappList request.
|
||||
*/
|
||||
void requestNanoappList(SocketClient &client) {
|
||||
flatbuffers::FlatBufferBuilder builder;
|
||||
HostProtocolHost::encodeNanoappListRequest(builder);
|
||||
if (!client.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
|
||||
ALOGE("Failed to send NanoappList request");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* Called when initializing connection with CHRE socket.
|
||||
*/
|
||||
sp<CapoDetector> CapoDetector::start() {
|
||||
sp<CapoDetector> listener = new CapoDetector();
|
||||
if (!listener->connectInBackground(kChreSocketName, listener)) {
|
||||
ALOGE("Couldn't connect to CHRE socket");
|
||||
return nullptr;
|
||||
}
|
||||
ALOGI("%s connect to CHRE socket.", __func__);
|
||||
|
||||
return listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the socket is successfully (re-)connected.
|
||||
* Reset the position and try to send NanoappList request.
|
||||
*/
|
||||
void CapoDetector::onConnected() {
|
||||
flatbuffers::FlatBufferBuilder builder;
|
||||
|
||||
// Reset the last position type.
|
||||
last_position_type_ = capo::PositionType::UNKNOWN;
|
||||
requestNanoappList(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when we have failed to (re-)connect the socket after many attempts
|
||||
* and are giving up.
|
||||
*/
|
||||
void CapoDetector::onConnectionAborted() {
|
||||
ALOGE("%s, Capo Aborting Connection!", __func__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when the socket is disconnected, and this connection loss was not
|
||||
* the result of an explicit call to disconnect().
|
||||
* Reset the position while disconnecting.
|
||||
*/
|
||||
|
||||
void CapoDetector::onDisconnected() {
|
||||
last_position_type_ = capo::PositionType::UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode unix socket msgs to CHRE messages, and call the appropriate
|
||||
* callback depending on the CHRE message.
|
||||
*/
|
||||
void CapoDetector::onMessageReceived(const void *data, size_t length) {
|
||||
if (!HostProtocolHost::decodeMessageFromChre(data, length, *this)) {
|
||||
ALOGE("Failed to decode message");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen for messages from capo nanoapp and handle the message.
|
||||
*/
|
||||
void CapoDetector::handleNanoappMessage(const fbs::NanoappMessageT &message) {
|
||||
ALOGI("%s, Id %" PRIu64 ", type %d, size %d", __func__, message.app_id, message.message_type,
|
||||
static_cast<int>(message.message.size()));
|
||||
// Exclude the message with unmatched nanoapp id.
|
||||
if (message.app_id != kCapoNanoappId)
|
||||
return;
|
||||
|
||||
// Handle the message with message_type.
|
||||
switch (message.message_type) {
|
||||
case capo::MessageType::ACK_NOTIFICATION: {
|
||||
capo::AckNotification gd;
|
||||
gd.set_notification_type(static_cast<capo::NotificationType>(message.message[1]));
|
||||
ALOGD("%s, get notification event from capo nanoapp, type %d", __func__,
|
||||
gd.notification_type());
|
||||
break;
|
||||
}
|
||||
case capo::MessageType::POSITION_DETECTED: {
|
||||
capo::PositionDetected gd;
|
||||
gd.set_position_type(static_cast<capo::PositionType>(message.message[1]));
|
||||
ALOGD("%s, get position event from capo nanoapp, type %d", __func__,
|
||||
gd.position_type());
|
||||
|
||||
// Callback to function while getting carried position event.
|
||||
if (callback_func_ != nullptr) {
|
||||
last_position_type_ = gd.position_type();
|
||||
ALOGD("%s, sent position type %d to callback function", __func__,
|
||||
last_position_type_);
|
||||
callback_func_(last_position_type_);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ALOGE("%s, get invalid message, type: %" PRIu32 ", from capo nanoapp.", __func__,
|
||||
message.message_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the response of a NanoappList request.
|
||||
* Ensure that capo nanoapp is running.
|
||||
*/
|
||||
void CapoDetector::handleNanoappListResponse(const fbs::NanoappListResponseT &response) {
|
||||
for (const std::unique_ptr<fbs::NanoappListEntryT> &nanoapp : response.nanoapps) {
|
||||
if (nanoapp->app_id == kCapoNanoappId) {
|
||||
if (nanoapp->enabled)
|
||||
enable();
|
||||
else
|
||||
ALOGE("Capo nanoapp not enabled");
|
||||
return;
|
||||
}
|
||||
}
|
||||
ALOGE("Capo nanoapp not found");
|
||||
}
|
||||
|
||||
/**
|
||||
* Send enabling message to the nanoapp.
|
||||
*/
|
||||
void CapoDetector::enable() {
|
||||
// Create CHRE message with serialized message
|
||||
flatbuffers::FlatBufferBuilder builder, config_builder, force_builder;
|
||||
|
||||
config_data.set_still_time_threshold_nanosecond(mCapoDetectorMDParameters.still_time_threshold_ns);
|
||||
config_data.set_window_width_nanosecond(mCapoDetectorMDParameters.window_width_ns);
|
||||
config_data.set_motion_confidence_threshold(mCapoDetectorMDParameters.motion_confidence_threshold);
|
||||
config_data.set_still_confidence_threshold(mCapoDetectorMDParameters.still_confidence_threshold);
|
||||
config_data.set_var_threshold(mCapoDetectorMDParameters.var_threshold);
|
||||
config_data.set_var_threshold_delta(mCapoDetectorMDParameters.var_threshold_delta);
|
||||
|
||||
msg.set_allocated_config_data(&config_data);
|
||||
|
||||
auto pb_size = msg.ByteSizeLong();
|
||||
auto pb_data = std::make_unique<uint8_t[]>(pb_size);
|
||||
|
||||
if (!msg.SerializeToArray(pb_data.get(), pb_size)) {
|
||||
ALOGE("Failed to serialize message.");
|
||||
}
|
||||
|
||||
ALOGI("Configuring CapoDetector");
|
||||
// Configure the detector from host-side
|
||||
android::chre::HostProtocolHost::encodeNanoappMessage(
|
||||
config_builder, getNanoppAppId(), capo::MessageType::CONFIGURE_DETECTOR, getHostEndPoint(),
|
||||
pb_data.get(), pb_size);
|
||||
ALOGI("Sending capo config message to Nanoapp, %" PRIu32 " bytes", config_builder.GetSize());
|
||||
if (!sendMessage(config_builder.GetBufferPointer(), config_builder.GetSize())) {
|
||||
ALOGE("Failed to send config event for capo nanoapp");
|
||||
}
|
||||
|
||||
ALOGI("Enabling CapoDetector");
|
||||
android::chre::HostProtocolHost::encodeNanoappMessage(
|
||||
builder, getNanoppAppId(), capo::MessageType::ENABLE_DETECTOR, getHostEndPoint(),
|
||||
/*messageData*/ nullptr, /*messageDataLenbuffer*/ 0);
|
||||
ALOGI("Sending enable message to Nanoapp, %" PRIu32 " bytes", builder.GetSize());
|
||||
if (!sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
|
||||
ALOGE("Failed to send enable event for capo nanoapp");
|
||||
}
|
||||
|
||||
ALOGI("Forcing CapoDetector to update state");
|
||||
// Force an updated state upon connection
|
||||
android::chre::HostProtocolHost::encodeNanoappMessage(
|
||||
force_builder, getNanoppAppId(), capo::MessageType::FORCE_UPDATE, getHostEndPoint(),
|
||||
/*messageData*/ nullptr, /*messageDataLenbuffer*/ 0);
|
||||
ALOGI("Sending force-update message to Nanoapp, %" PRIu32 " bytes", force_builder.GetSize());
|
||||
if (!sendMessage(force_builder.GetBufferPointer(), force_builder.GetSize())) {
|
||||
ALOGE("Failed to send force-update event for capo nanoapp");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace chre
|
||||
} // namespace android
|
@ -92,6 +92,22 @@ class HwApi : public Vibrator::HwApi, private HwApiBase {
|
||||
bool setF0CompEnable(bool value) override { return set(value, &mF0CompEnable); }
|
||||
bool setRedcCompEnable(bool value) override { return set(value, &mRedcCompEnable); }
|
||||
bool setMinOnOffInterval(uint32_t value) override { return set(value, &mMinOnOffInterval); }
|
||||
uint32_t getContextScale() override {
|
||||
return utils::getProperty("persist.vendor.vibrator.hal.context.scale", 100);
|
||||
}
|
||||
bool getContextEnable() override {
|
||||
return utils::getProperty("persist.vendor.vibrator.hal.context.enable", false);
|
||||
}
|
||||
uint32_t getContextSettlingTime() override {
|
||||
return utils::getProperty("persist.vendor.vibrator.hal.context.settlingtime", 3000);
|
||||
}
|
||||
uint32_t getContextCooldownTime() override {
|
||||
return utils::getProperty("persist.vendor.vibrator.hal.context.cooldowntime", 1000);
|
||||
}
|
||||
bool getContextFadeEnable() override {
|
||||
return utils::getProperty("persist.vendor.vibrator.hal.context.fade", false);
|
||||
}
|
||||
|
||||
// TODO(b/234338136): Need to add the force feedback HW API test cases
|
||||
bool setFFGain(int fd, uint16_t value) override {
|
||||
struct input_event gain = {
|
||||
|
@ -28,11 +28,22 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <ctime>
|
||||
#include <chrono>
|
||||
|
||||
#include "CapoDetector.h"
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
#ifdef LOG_TAG
|
||||
#undef LOG_TAG
|
||||
#define LOG_TAG "Vibrator"
|
||||
#endif
|
||||
|
||||
using CapoDetector = android::chre::CapoDetector;
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
@ -89,15 +100,34 @@ static constexpr float PWLE_FREQUENCY_MAX_HZ = 1000.00;
|
||||
static constexpr float PWLE_BW_MAP_SIZE =
|
||||
1 + ((PWLE_FREQUENCY_MAX_HZ - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ);
|
||||
|
||||
static uint16_t amplitudeToScale(float amplitude, float maximum) {
|
||||
float ratio = 100; /* Unit: % */
|
||||
if (maximum != 0)
|
||||
ratio = amplitude / maximum * 100;
|
||||
#ifndef DISABLE_ADAPTIVE_HAPTICS_FEATURE
|
||||
static constexpr bool mAdaptiveHapticsEnable = true;
|
||||
#else
|
||||
static constexpr bool mAdaptiveHapticsEnable = false;
|
||||
#endif /* DISABLE_ADAPTIVE_HAPTICS_FEATURE */
|
||||
|
||||
if (maximum == 0 || ratio > 100)
|
||||
ratio = 100;
|
||||
static sp<CapoDetector> vibeContextListener;
|
||||
uint8_t mCapoDeviceState = 0;
|
||||
uint32_t mLastFaceUpEvent = 0;
|
||||
uint32_t mLastEffectPlayedTime = 0;
|
||||
float mLastPlayedScale = 0;
|
||||
|
||||
return std::round(ratio);
|
||||
static uint32_t getCurrentTimeInMs(void) {
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
static void capoEventCallback(uint8_t eventId) {
|
||||
ALOGD("Vibrator %s, From: 0x%x To: 0x%x", __func__, mCapoDeviceState, (uint32_t)eventId);
|
||||
// Record the last moment we were in FACE_UP state
|
||||
if (mCapoDeviceState == capo::PositionType::ON_TABLE_FACE_UP ||
|
||||
eventId == capo::PositionType::ON_TABLE_FACE_UP) {
|
||||
mLastFaceUpEvent = getCurrentTimeInMs();
|
||||
}
|
||||
mCapoDeviceState = eventId;
|
||||
}
|
||||
|
||||
static uint8_t getDeviceState(void) {
|
||||
return mCapoDeviceState;
|
||||
}
|
||||
|
||||
enum WaveformBankID : uint8_t {
|
||||
@ -366,6 +396,18 @@ Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal)
|
||||
}
|
||||
|
||||
mHwApi->setMinOnOffInterval(MIN_ON_OFF_INTERVAL_US);
|
||||
|
||||
if (mAdaptiveHapticsEnable) {
|
||||
vibeContextListener = CapoDetector::start();
|
||||
if (vibeContextListener == nullptr) {
|
||||
ALOGE("%s, CapoDetector failed to start", __func__);
|
||||
} else {
|
||||
ALOGD("%s, CapoDetector started successfully! NanoAppID: 0x%x", __func__,
|
||||
(uint32_t)vibeContextListener->getNanoppAppId());
|
||||
vibeContextListener->setCallback(capoEventCallback);
|
||||
ALOGD("%s, CapoDetector Set Callback function from vibe", __func__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Vibrator::getCapabilities(int32_t *_aidl_return) {
|
||||
@ -666,8 +708,70 @@ ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex, dspmem
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Vibrator::setEffectAmplitude(float amplitude, float maximum) {
|
||||
uint16_t scale = amplitudeToScale(amplitude, maximum);
|
||||
uint16_t Vibrator::amplitudeToScale(float amplitude, float maximum, bool scalable) {
|
||||
float ratio = 100; /* Unit: % */
|
||||
|
||||
if (maximum != 0)
|
||||
ratio = amplitude / maximum * 100;
|
||||
|
||||
if (maximum == 0 || ratio > 100)
|
||||
ratio = 100;
|
||||
|
||||
if (scalable && mContextEnable & mAdaptiveHapticsEnable) {
|
||||
uint32_t now = getCurrentTimeInMs();
|
||||
uint32_t last_played = mLastEffectPlayedTime;
|
||||
float context_scale = 1.0;
|
||||
bool device_face_up = getDeviceState() == capo::PositionType::ON_TABLE_FACE_UP;
|
||||
float pre_scaled_ratio = ratio;
|
||||
mLastEffectPlayedTime = now;
|
||||
|
||||
ALOGD("Vibrator Now: %u, Last: %u, ScaleTime: %u, Since? %d", now, mLastFaceUpEvent, mScaleTime, (now < mLastFaceUpEvent + mScaleTime));
|
||||
/* If the device is face-up or within the fade scaling range, find new scaling factor */
|
||||
if (device_face_up || now < mLastFaceUpEvent + mScaleTime) {
|
||||
/* Device is face-up, so we will scale it down. Start with highest scaling factor */
|
||||
context_scale = mScalingFactor <= 100 ? static_cast<float>(mScalingFactor)/100 : 1.0;
|
||||
if (mFadeEnable && mScaleTime > 0 && (context_scale < 1.0) && (now < mLastFaceUpEvent + mScaleTime) && !device_face_up) {
|
||||
float fade_scale = static_cast<float>(now - mLastFaceUpEvent)/static_cast<float>(mScaleTime);
|
||||
context_scale += ((1.0 - context_scale)*fade_scale);
|
||||
ALOGD("Vibrator fade scale applied: %f", fade_scale);
|
||||
}
|
||||
ratio *= context_scale;
|
||||
ALOGD("Vibrator adjusting for face-up: pre: %f, post: %f",
|
||||
std::round(pre_scaled_ratio), std::round(ratio));
|
||||
}
|
||||
|
||||
/* If we haven't played an effect within the cooldown time, save the scaling factor */
|
||||
if ((now - last_played) > mScaleCooldown) {
|
||||
ALOGD("Vibrator updating lastplayed scale, old: %f, new: %f", mLastPlayedScale, context_scale);
|
||||
mLastPlayedScale = context_scale;
|
||||
}
|
||||
else {
|
||||
/* Override the scale to match previously played scale */
|
||||
ratio = mLastPlayedScale * pre_scaled_ratio;
|
||||
ALOGD("Vibrator repeating last scale: %f, new ratio: %f, duration since last: %u", mLastPlayedScale, ratio, (now - last_played));
|
||||
}
|
||||
}
|
||||
|
||||
return std::round(ratio);
|
||||
}
|
||||
|
||||
void Vibrator::updateContext() {
|
||||
mContextEnable = mHwApi->getContextEnable();
|
||||
mFadeEnable = mHwApi->getContextFadeEnable();
|
||||
mScalingFactor = mHwApi->getContextScale();
|
||||
mScaleTime = mHwApi->getContextSettlingTime();
|
||||
mScaleCooldown = mHwApi->getContextCooldownTime();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Vibrator::setEffectAmplitude(float amplitude, float maximum, bool scalable) {
|
||||
uint16_t scale;
|
||||
|
||||
if (mAdaptiveHapticsEnable && scalable) {
|
||||
updateContext();
|
||||
}
|
||||
|
||||
scale = amplitudeToScale(amplitude, maximum, scalable);
|
||||
|
||||
if (!mHwApi->setFFGain(mInputFd, scale)) {
|
||||
ALOGE("Failed to set the gain to %u (%d): %s", scale, errno, strerror(errno));
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
@ -680,7 +784,7 @@ ndk::ScopedAStatus Vibrator::setGlobalAmplitude(bool set) {
|
||||
if (!set) {
|
||||
mLongEffectScale = 1.0; // Reset the scale for the later new effect.
|
||||
}
|
||||
return setEffectAmplitude(amplitude, VOLTAGE_SCALE_MAX);
|
||||
return setEffectAmplitude(amplitude, VOLTAGE_SCALE_MAX, true);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect> * /*_aidl_return*/) {
|
||||
@ -1054,6 +1158,16 @@ binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) {
|
||||
|
||||
mHwCal->debug(fd);
|
||||
|
||||
dprintf(fd, "Capo Info\n");
|
||||
if (vibeContextListener) {
|
||||
dprintf(fd, "Capo ID: 0x%x\n", (uint32_t)(vibeContextListener->getNanoppAppId()));
|
||||
dprintf(fd, "Capo State: %d DetectedState: %d\n", vibeContextListener->getCarriedPosition(),
|
||||
getDeviceState());
|
||||
} else {
|
||||
dprintf(fd, "Capo ID: 0x%x\n", (uint32_t)(0xdeadbeef));
|
||||
dprintf(fd, "Capo State: %d DetectedState: %d\n", (uint32_t)0x454545, getDeviceState());
|
||||
}
|
||||
|
||||
fsync(fd);
|
||||
return STATUS_OK;
|
||||
}
|
||||
@ -1265,7 +1379,7 @@ exit:
|
||||
ndk::ScopedAStatus Vibrator::performEffect(uint32_t effectIndex, uint32_t volLevel,
|
||||
dspmem_chunk *ch,
|
||||
const std::shared_ptr<IVibratorCallback> &callback) {
|
||||
setEffectAmplitude(volLevel, VOLTAGE_SCALE_MAX);
|
||||
setEffectAmplitude(volLevel, VOLTAGE_SCALE_MAX, false);
|
||||
|
||||
return on(MAX_TIME_MS, effectIndex, ch, callback);
|
||||
}
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include <array>
|
||||
#include <fstream>
|
||||
#include <future>
|
||||
#include <ctime>
|
||||
#include <chrono>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
@ -61,6 +63,21 @@ class Vibrator : public BnVibrator {
|
||||
virtual bool setRedcCompEnable(bool value) = 0;
|
||||
// Stores the minumun delay time between playback and stop effects.
|
||||
virtual bool setMinOnOffInterval(uint32_t value) = 0;
|
||||
// Gets the scaling factor for contextual haptic events.
|
||||
virtual uint32_t getContextScale() = 0;
|
||||
// Gets the enable status for contextual haptic events.
|
||||
virtual bool getContextEnable() = 0;
|
||||
// Gets the settling time for contextual haptic events.
|
||||
// This will allow the device to stay face up for the duration given,
|
||||
// even if InMotion events were detected.
|
||||
virtual uint32_t getContextSettlingTime() = 0;
|
||||
// Gets the cooldown time for contextual haptic events.
|
||||
// This is used to avoid changing the scale of close playback events.
|
||||
virtual uint32_t getContextCooldownTime() = 0;
|
||||
// Checks the enable status for contextual haptics fade feature. When enabled
|
||||
// this feature will cause the scaling factor to fade back up to max over
|
||||
// the setting time set, instead of instantaneously changing it back to max.
|
||||
virtual bool getContextFadeEnable() = 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.
|
||||
@ -158,7 +175,7 @@ class Vibrator : public BnVibrator {
|
||||
ndk::ScopedAStatus on(uint32_t timeoutMs, uint32_t effectIndex, struct dspmem_chunk *ch,
|
||||
const std::shared_ptr<IVibratorCallback> &callback);
|
||||
// set 'amplitude' based on an arbitrary scale determined by 'maximum'
|
||||
ndk::ScopedAStatus setEffectAmplitude(float amplitude, float maximum);
|
||||
ndk::ScopedAStatus setEffectAmplitude(float amplitude, float maximum, bool scalable);
|
||||
ndk::ScopedAStatus setGlobalAmplitude(bool set);
|
||||
// 'simple' effects are those precompiled and loaded into the controller
|
||||
ndk::ScopedAStatus getSimpleDetails(Effect effect, EffectStrength strength,
|
||||
@ -181,6 +198,8 @@ class Vibrator : public BnVibrator {
|
||||
bool findHapticAlsaDevice(int *card, int *device);
|
||||
bool hasHapticAlsaDevice();
|
||||
bool enableHapticPcmAmp(struct pcm **haptic_pcm, bool enable, int card, int device);
|
||||
uint16_t amplitudeToScale(float amplitude, float maximum, bool scalable);
|
||||
void updateContext();
|
||||
|
||||
std::unique_ptr<HwApi> mHwApi;
|
||||
std::unique_ptr<HwCal> mHwCal;
|
||||
@ -200,6 +219,11 @@ class Vibrator : public BnVibrator {
|
||||
bool mIsUnderExternalControl;
|
||||
float mLongEffectScale = 1.0;
|
||||
bool mIsChirpEnabled;
|
||||
uint32_t mScaleTime;
|
||||
bool mFadeEnable;
|
||||
uint32_t mScalingFactor;
|
||||
uint32_t mScaleCooldown;
|
||||
bool mContextEnable;
|
||||
uint32_t mSupportedPrimitivesBits = 0x0;
|
||||
std::vector<CompositePrimitive> mSupportedPrimitives;
|
||||
bool mConfigHapticAlsaDeviceDone{false};
|
||||
|
@ -20,10 +20,10 @@ on property:vendor.all.modules.ready=1
|
||||
|
||||
enable vendor.vibrator.cs40l26
|
||||
|
||||
service vendor.vibrator.cs40l26 /vendor/bin/hw/android.hardware.vibrator-service.cs40l26
|
||||
service vendor.vibrator.cs40l26 /vendor/bin/hw/android.hardware.vibrator-service.cs40l26-private-lynx
|
||||
class hal
|
||||
user system
|
||||
group system input
|
||||
group system input context_hub
|
||||
|
||||
setenv INPUT_EVENT_NAME cs40l26_input
|
||||
setenv INPUT_EVENT_PATH /dev/input/event*
|
@ -1,5 +1,5 @@
|
||||
PRODUCT_PACKAGES += \
|
||||
android.hardware.vibrator-service.cs40l26
|
||||
android.hardware.vibrator-service.cs40l26-private-lynx
|
||||
|
||||
BOARD_SEPOLICY_DIRS += \
|
||||
hardware/google/pixel-sepolicy/vibrator/common \
|
||||
|
107
vibrator/cs40l26/inc/CapoDetector.h
Normal file
107
vibrator/cs40l26/inc/CapoDetector.h
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2022 Google LLC. All Rights Reserved.
|
||||
*
|
||||
* 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 <chre_host/host_protocol_host.h>
|
||||
#include <chre_host/socket_client.h>
|
||||
|
||||
#include "proto/capo.pb.h"
|
||||
|
||||
using android::sp;
|
||||
using android::chre::HostProtocolHost;
|
||||
using android::chre::IChreMessageHandlers;
|
||||
using android::chre::SocketClient;
|
||||
|
||||
// following convention of CHRE code.
|
||||
namespace fbs = ::chre::fbs;
|
||||
|
||||
namespace android {
|
||||
namespace chre {
|
||||
|
||||
#define NS_FROM_MS(x) ((x)*1000000)
|
||||
|
||||
struct CapoMDParams {
|
||||
uint64_t still_time_threshold_ns;
|
||||
uint32_t window_width_ns;
|
||||
float motion_confidence_threshold;
|
||||
float still_confidence_threshold;
|
||||
float var_threshold;
|
||||
float var_threshold_delta;
|
||||
};
|
||||
|
||||
class CapoDetector : public android::chre::SocketClient::ICallbacks,
|
||||
public android::chre::IChreMessageHandlers,
|
||||
public android::chre::SocketClient {
|
||||
public:
|
||||
// Typedef declaration for callback function.
|
||||
typedef std::function<void(uint8_t)> cb_fn_t;
|
||||
|
||||
// Called when initializing connection with CHRE socket.
|
||||
static android::sp<CapoDetector> start();
|
||||
// Called when the socket is successfully (re-)connected.
|
||||
// Reset the position and try to send NanoappList request.
|
||||
void onConnected() override;
|
||||
// Called when we have failed to (re-)connect the socket after many attempts
|
||||
// and are giving up.
|
||||
void onConnectionAborted() override;
|
||||
// Invoked when the socket is disconnected, and this connection loss
|
||||
// was not the result of an explicit call to disconnect().
|
||||
// Reset the position while disconnecting.
|
||||
void onDisconnected() override;
|
||||
// Decode unix socket msgs to CHRE messages, and call the appropriate
|
||||
// callback depending on the CHRE message.
|
||||
void onMessageReceived(const void *data, size_t length) override;
|
||||
// Listen for messages from capo nanoapp and handle the message.
|
||||
void handleNanoappMessage(const ::chre::fbs::NanoappMessageT &message) override;
|
||||
// Handle the response of a NanoappList request.
|
||||
// Ensure that capo nanoapp is running.
|
||||
void handleNanoappListResponse(const ::chre::fbs::NanoappListResponseT &response) override;
|
||||
// Send enabling message to the nanoapp.
|
||||
void enable();
|
||||
|
||||
// Get last carried position type.
|
||||
uint8_t getCarriedPosition() { return last_position_type_; }
|
||||
// Get the host endpoint.
|
||||
uint16_t getHostEndPoint() { return kHostEndpoint; }
|
||||
// Get the capo nanoapp ID.
|
||||
uint64_t getNanoppAppId() { return kCapoNanoappId; }
|
||||
// Set up callback_func_ if needed.
|
||||
void setCallback(cb_fn_t cb) { callback_func_ = cb; }
|
||||
|
||||
private:
|
||||
// Nanoapp ID of capo, ref: go/nanoapp-id-tracker.
|
||||
static constexpr uint64_t kCapoNanoappId = 0x476f6f676c001020ULL;
|
||||
// String of socket name for connecting chre.
|
||||
static constexpr char kChreSocketName[] = "chre";
|
||||
// The host endpoint we use when sending message.
|
||||
// Set with 0x9020 based on 0x8000 AND capo_app_id(1020).
|
||||
// Ref: go/host-endpoint-id-tracker.
|
||||
static constexpr uint16_t kHostEndpoint = 0x9020;
|
||||
// Using for hal layer callback function.
|
||||
cb_fn_t callback_func_ = nullptr;
|
||||
// Last carried position received from the nano app
|
||||
capo::PositionType last_position_type_ = capo::PositionType::UNKNOWN;
|
||||
// Motion detector parameters for host-driven capo config
|
||||
const struct CapoMDParams mCapoDetectorMDParameters {
|
||||
.still_time_threshold_ns = NS_FROM_MS(500),
|
||||
.window_width_ns = NS_FROM_MS(100),
|
||||
.motion_confidence_threshold = 0.98f,
|
||||
.still_confidence_threshold = 0.99f,
|
||||
.var_threshold = 0.0125f,
|
||||
.var_threshold_delta = 0.0125f,
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace chre
|
||||
} // namespace android
|
148
vibrator/cs40l26/proto/capo.proto
Normal file
148
vibrator/cs40l26/proto/capo.proto
Normal file
@ -0,0 +1,148 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package capo;
|
||||
|
||||
// The message types used in capo nanoapp. Some of them are H2C
|
||||
// (Host-To-CHRE) and others are C2H (CHRE-To-Host). One message type must be
|
||||
// either H2C or C2H. Each message type can choose to have payload or not.
|
||||
enum MessageType {
|
||||
// Explicitly prevents 0 from being used as a valid message type.
|
||||
// Doing so protects from obscure bugs caused by default-initialized values.
|
||||
INVALID = 0;
|
||||
|
||||
// Detector configuration related message start from 100.
|
||||
// Signal for host to acknowledge the notification.
|
||||
// It contains AckNotification payload.
|
||||
ACK_NOTIFICATION = 100;
|
||||
|
||||
// Signal to enable the carried position detector for device. No payload.
|
||||
ENABLE_DETECTOR = 101;
|
||||
|
||||
// Signal to disable the carried position detector for device. No payload.
|
||||
DISABLE_DETECTOR = 102;
|
||||
|
||||
// Signal to request most recent carried position detector state. No payload.
|
||||
REQUEST_UPDATE = 103;
|
||||
|
||||
// Signal to force carried position detector to refresh state. No payload.
|
||||
FORCE_UPDATE = 104;
|
||||
|
||||
// Configure the detector with desired parameters. ConfigureDetector payload.
|
||||
CONFIGURE_DETECTOR = 105;
|
||||
|
||||
// Position Detection related message start from 200.
|
||||
// Signal while carried position of device detected.
|
||||
// It contains PositionDetected payload.
|
||||
POSITION_DETECTED = 200;
|
||||
}
|
||||
|
||||
// Notification Type.
|
||||
enum NotificationType {
|
||||
// Explicitly prevents 0 from being used as a valid notification type.
|
||||
// Doing so protects from obscure bugs caused by default-initialized values.
|
||||
INVALID_NOTIFICATION = 0;
|
||||
|
||||
// Notification of enabling the carried position detector for device.
|
||||
ENABLE_NOTIFICATION = 1;
|
||||
|
||||
// Notification of disabling the carried position detector for device.
|
||||
DISABLE_NOTIFICATION = 2;
|
||||
|
||||
// Notification of request update from the carried position detector.
|
||||
REQUEST_UPDATE_NOTIFICATION = 3;
|
||||
|
||||
// Notification of force update from the carried position detector.
|
||||
FORCE_UPDATE_NOTIFICATION = 4;
|
||||
|
||||
// Notification of configure message.
|
||||
CONFIGURE_NOTIFICATION = 5;
|
||||
}
|
||||
|
||||
// This message type used for host to acknowledge the notification.
|
||||
message AckNotification {
|
||||
// Sent a notification type for host to acknowledge.
|
||||
NotificationType notification_type = 1;
|
||||
}
|
||||
|
||||
// Position type.
|
||||
enum PositionType {
|
||||
// Explicitly prevents 0 from being used as a valid carried position type.
|
||||
// Doing so protects from obscure bugs caused by default-initialized values.
|
||||
UNKNOWN = 0;
|
||||
|
||||
// Carried position while device is in motion.
|
||||
IN_MOTION = 1;
|
||||
|
||||
// Carried position while device is on table and faces up.
|
||||
ON_TABLE_FACE_UP = 2;
|
||||
|
||||
// Carried position while device is on table and faces down.
|
||||
ON_TABLE_FACE_DOWN = 3;
|
||||
|
||||
// Carried position while device is stationary in unknown orientation.
|
||||
STATIONARY_UNKNOWN = 4;
|
||||
}
|
||||
|
||||
// This message type used to notify host a position was a detected.
|
||||
message PositionDetected {
|
||||
// Sent a position type that is defined in PositionTypes.
|
||||
PositionType position_type = 1;
|
||||
}
|
||||
|
||||
// Predefined configurations for detector.
|
||||
enum ConfigPresetType {
|
||||
// Explicitly prevents 0 from being used as a valid type.
|
||||
// Doing so protects from obscure bugs caused by default-initialized values.
|
||||
CONFIG_PRESET_UNSPECIFIED = 0;
|
||||
|
||||
// Default preset.
|
||||
CONFIG_PRESET_DEFAULT = 1;
|
||||
|
||||
// Preset for sticky-stationary behavior.
|
||||
CONFIG_PRESET_STICKY_STATIONARY = 2;
|
||||
}
|
||||
|
||||
message ConfigureDetector {
|
||||
// Ref: cs/location/lbs/contexthub/nanoapps/motiondetector/motion_detector.h
|
||||
message ConfigData {
|
||||
// These algo parameters are exposed to enable tuning via server flags.
|
||||
// The amount of time that the algorithm's computed stillness confidence
|
||||
// must exceed still_confidence_threshold before entering the stationary
|
||||
// state. Increasing this value will make the algorithm take longer to
|
||||
// transition from the in motion state to the stationary state.
|
||||
uint64 still_time_threshold_nanosecond = 1;
|
||||
|
||||
// The amount of time in which the variance should be averaged. Increasing
|
||||
// this value will effectively smooth the input data, making the algorithm
|
||||
// less likely to transition between states.
|
||||
uint32 window_width_nanosecond = 2;
|
||||
|
||||
// The required confidence that the device is in motion before entering the
|
||||
// motion state. Valid range is [0.0, 1.0], where 1.0 indicates that the
|
||||
// algorithm must be 100% certain that the device is moving before entering
|
||||
// the motion state. If the Instant Motion sensor is triggered, this value
|
||||
// is ignored and the algorithm is immediately transitioned into the in
|
||||
// motion state.
|
||||
float motion_confidence_threshold = 3;
|
||||
|
||||
// The required confidence that the device is stationary before entering the
|
||||
// stationary state. Valid range is [0.0, 1.0], where 1.0 indicates that the
|
||||
// algorithm must be 100% certain that the device is stationary before
|
||||
// entering the stationary state.
|
||||
float still_confidence_threshold = 4;
|
||||
|
||||
// The variance threshold for the StillnessDetector algorithm. Increasing
|
||||
// this value causes the algorithm to be less likely to detect motion.
|
||||
float var_threshold = 5;
|
||||
|
||||
// The variance threshold delta for the StillnessDetector algorithm about
|
||||
// which the stationary confidence is calculated. Valid range is
|
||||
// [0.0, var_threshold].
|
||||
float var_threshold_delta = 6;
|
||||
}
|
||||
|
||||
oneof type {
|
||||
ConfigPresetType preset_type = 1;
|
||||
ConfigData config_data = 2;
|
||||
}
|
||||
}
|
@ -18,8 +18,8 @@ package {
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "VibratorHalCs40l26TestSuite",
|
||||
defaults: ["VibratorHalCs40l26TestDefaults"],
|
||||
name: "VibratorHalCs40l26TestSuitePrivateLynx",
|
||||
defaults: ["VibratorHalCs40l26TestDefaultsPrivateLynx"],
|
||||
srcs: [
|
||||
"test-hwcal.cpp",
|
||||
"test-hwapi.cpp",
|
||||
|
@ -34,6 +34,11 @@ class MockApi : public ::aidl::android::hardware::vibrator::Vibrator::HwApi {
|
||||
MOCK_METHOD1(setF0CompEnable, bool(bool value));
|
||||
MOCK_METHOD1(setRedcCompEnable, bool(bool value));
|
||||
MOCK_METHOD1(setMinOnOffInterval, bool(uint32_t value));
|
||||
MOCK_METHOD0(getContextScale, uint32_t());
|
||||
MOCK_METHOD0(getContextEnable, bool());
|
||||
MOCK_METHOD0(getContextSettlingTime, uint32_t());
|
||||
MOCK_METHOD0(getContextCooldownTime, uint32_t());
|
||||
MOCK_METHOD0(getContextFadeEnable, bool());
|
||||
MOCK_METHOD2(setFFGain, bool(int fd, uint16_t value));
|
||||
MOCK_METHOD3(setFFEffect, bool(int fd, struct ff_effect *effect, uint16_t timeoutMs));
|
||||
MOCK_METHOD3(setFFPlay, bool(int fd, int8_t index, bool value));
|
||||
|
@ -284,6 +284,11 @@ class VibratorTest : public Test {
|
||||
EXPECT_CALL(*mMockApi, setFFEffect(_, _, _)).Times(times);
|
||||
EXPECT_CALL(*mMockApi, setFFPlay(_, _, _)).Times(times);
|
||||
EXPECT_CALL(*mMockApi, setMinOnOffInterval(_)).Times(times);
|
||||
EXPECT_CALL(*mMockApi, getContextScale()).Times(times);
|
||||
EXPECT_CALL(*mMockApi, getContextEnable()).Times(times);
|
||||
EXPECT_CALL(*mMockApi, getContextSettlingTime()).Times(times);
|
||||
EXPECT_CALL(*mMockApi, getContextCooldownTime()).Times(times);
|
||||
EXPECT_CALL(*mMockApi, getContextFadeEnable()).Times(times);
|
||||
EXPECT_CALL(*mMockApi, getHapticAlsaDevice(_, _)).Times(times);
|
||||
EXPECT_CALL(*mMockApi, setHapticPcmAmp(_, _, _, _)).Times(times);
|
||||
|
||||
@ -363,6 +368,11 @@ TEST_F(VibratorTest, Constructor) {
|
||||
.WillOnce(DoAll(SetArgPointee<0>(supportedPrimitivesBits), Return(true)));
|
||||
|
||||
EXPECT_CALL(*mMockApi, setMinOnOffInterval(MIN_ON_OFF_INTERVAL_US)).WillOnce(Return(true));
|
||||
EXPECT_CALL(*mMockApi, getContextScale()).WillOnce(Return(0));
|
||||
EXPECT_CALL(*mMockApi, getContextEnable()).WillOnce(Return(false));
|
||||
EXPECT_CALL(*mMockApi, getContextSettlingTime()).WillOnce(Return(0));
|
||||
EXPECT_CALL(*mMockApi, getContextCooldownTime()).WillOnce(Return(0));
|
||||
EXPECT_CALL(*mMockApi, getContextFadeEnable()).WillOnce(Return(false));
|
||||
createVibrator(std::move(mockapi), std::move(mockcal), false);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user