From 84b93a679fa7b55b551cf66231e7f49294a291b3 Mon Sep 17 00:00:00 2001 From: hellohyh001 Date: Fri, 29 Mar 2024 08:07:55 +0000 Subject: [PATCH] sensor supports Programmatic haptics Signed-off-by: hellohyh001 Change-Id: I33030ec69011a894b0368196f1dbad71c3a4a247 --- frameworks/js/napi/BUILD.gn | 1 + .../vibrator/include/vibrator_napi_utils.h | 4 + .../vibrator/include/vibrator_pattern_js.h | 74 +++ .../js/napi/vibrator/src/vibrator_js.cpp | 130 +++++- .../napi/vibrator/src/vibrator_napi_utils.cpp | 37 ++ .../napi/vibrator/src/vibrator_pattern_js.cpp | 428 ++++++++++++++++++ .../inner_api/vibrator/vibrator_agent_type.h | 16 +- 7 files changed, 681 insertions(+), 9 deletions(-) create mode 100644 frameworks/js/napi/vibrator/include/vibrator_pattern_js.h create mode 100644 frameworks/js/napi/vibrator/src/vibrator_pattern_js.cpp diff --git a/frameworks/js/napi/BUILD.gn b/frameworks/js/napi/BUILD.gn index e467a4c..86bf341 100644 --- a/frameworks/js/napi/BUILD.gn +++ b/frameworks/js/napi/BUILD.gn @@ -37,6 +37,7 @@ ohos_shared_library("vibrator") { "$SUBSYSTEM_DIR/frameworks/js/napi/vibrator/src/vibrator_js.cpp", "$SUBSYSTEM_DIR/frameworks/js/napi/vibrator/src/vibrator_napi_error.cpp", "$SUBSYSTEM_DIR/frameworks/js/napi/vibrator/src/vibrator_napi_utils.cpp", + "$SUBSYSTEM_DIR/frameworks/js/napi/vibrator/src/vibrator_pattern_js.cpp", ] deps = [ diff --git a/frameworks/js/napi/vibrator/include/vibrator_napi_utils.h b/frameworks/js/napi/vibrator/include/vibrator_napi_utils.h index 8ccf665..46061e5 100644 --- a/frameworks/js/napi/vibrator/include/vibrator_napi_utils.h +++ b/frameworks/js/napi/vibrator/include/vibrator_napi_utils.h @@ -25,6 +25,7 @@ #include "refbase.h" #include "sensors_errors.h" +#include "vibrator_agent_type.h" namespace OHOS { namespace Sensors { @@ -61,9 +62,12 @@ public: using ConstructResultFunc = bool(*)(const napi_env &env, sptr asyncCallbackInfo, napi_value result[], int32_t length); +bool FreeVibratorPattern(VibratorPattern &vibratorPattern); +bool IsMatchArrayType(const napi_env &env, const napi_value &value); bool IsMatchType(const napi_env &env, const napi_value &value, const napi_valuetype &type); bool GetNapiInt32(const napi_env &env, const int32_t value, napi_value &result); bool GetInt32Value(const napi_env &env, const napi_value &value, int32_t &result); +bool GetDoubleValue(const napi_env &env, const napi_value &value, double &result); bool GetInt64Value(const napi_env &env, const napi_value &value, int64_t &result); bool GetStringValue(const napi_env &env, const napi_value &value, string &result); bool GetPropertyItem(const napi_env &env, const napi_value &value, const std::string &type, napi_value &item); diff --git a/frameworks/js/napi/vibrator/include/vibrator_pattern_js.h b/frameworks/js/napi/vibrator/include/vibrator_pattern_js.h new file mode 100644 index 0000000..e0e9c9a --- /dev/null +++ b/frameworks/js/napi/vibrator/include/vibrator_pattern_js.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * 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 VIBRATOR_PATTERN_BUILDER_H +#define VIBRATOR_PATTERN_BUILDER_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +#include "vibrator_agent_type.h" + +namespace OHOS { +namespace Sensors { + +enum VibrateTag { + EVENT_TAG_UNKNOWN = -1, + EVENT_TAG_CONTINUOUS = 0, + EVENT_TAG_TRANSIENT = 1, +}; + +struct VibrateCurvePoint { + int32_t time = 0; + int32_t intensity = 0; + int32_t frequency = 0; +}; + +struct VibrateEvent { + VibrateTag tag; + int32_t time = 0; + int32_t duration = 0; + int32_t intensity = 0; + int32_t frequency = 0; + int32_t index = 0; + std::vector points; +}; + +class VibratorPatternBuilder { +public: + VibratorPatternBuilder() = default; + ~VibratorPatternBuilder() = default; + static napi_value AddContinuousEvent(napi_env env, napi_callback_info info); + static napi_value AddTransientEvent(napi_env env, napi_callback_info info); + static napi_value Build(napi_env env, napi_callback_info info); + static napi_value Release(napi_env env, napi_callback_info info); + static napi_value VibratorPatternConstructor(const napi_env env, const napi_callback_info info); + +private: + static bool ParameterOptions(const napi_env &env, const napi_value &value, VibrateEvent &event); + static bool ConvertVibrateEvent(const std::vector &vibrateEvents, VibratorPattern &vibratorPattern); + static napi_value ConvertVibratorPatternToNapiValue(napi_env env, const VibratorPattern &vibratorPattern); + static napi_value ConvertVibratorEvent(napi_env env, const VibratorEvent &event); + static bool CreateInt32Property(napi_env env, napi_value &eventObj, const char* name, int32_t value); + static napi_value ConvertVibratorCurvePoint(napi_env env, const VibratorCurvePoint &point); + static bool CheckParameters(const VibrateEvent &event); + +private: + std::vector events_; + VibratorPattern vibratorPattern_; +}; +} // namespace Sensors +} // namespace OHOS +#endif // VIBRATOR_PATTERN_BUILDER_H \ No newline at end of file diff --git a/frameworks/js/napi/vibrator/src/vibrator_js.cpp b/frameworks/js/napi/vibrator/src/vibrator_js.cpp index bb5aed3..efb9c99 100644 --- a/frameworks/js/napi/vibrator/src/vibrator_js.cpp +++ b/frameworks/js/napi/vibrator/src/vibrator_js.cpp @@ -27,6 +27,7 @@ #include "vibrator_agent.h" #include "vibrator_napi_error.h" #include "vibrator_napi_utils.h" +#include "vibrator_pattern_js.h" #undef LOG_TAG #define LOG_TAG "VibratorJs" @@ -59,6 +60,7 @@ struct VibrateInfo { int32_t fd = -1; int64_t offset = 0; int64_t length = -1; + VibratorPattern vibratorPattern; }; static napi_value EmitAsyncWork(napi_value param, sptr info) @@ -171,6 +173,103 @@ static napi_value VibrateMode(napi_env env, napi_value args[], size_t argc) return nullptr; } +static bool ParameterVibrateEvent(napi_env env, napi_value eventArray, int32_t index, VibratorEvent &event) +{ + napi_value element = nullptr; + CHKCF((napi_get_element(env, eventArray, index, &element) == napi_ok), "napi_get_element eventArray fail"); + CHKCF(IsMatchType(env, element, napi_object), "Wrong argument type. napi_object or function expected"); + int32_t type = 0; + CHKCF(GetPropertyInt32(env, element, "eventType", type), "Get type fail"); + event.type = static_cast(type); + CHKCF(GetPropertyInt32(env, element, "time", event.time), "Get time fail"); + CHKCF(GetPropertyInt32(env, element, "duration", event.duration), "Get duration fail"); + CHKCF(GetPropertyInt32(env, element, "intensity", event.intensity), "Get intensity fail"); + CHKCF(GetPropertyInt32(env, element, "frequency", event.frequency), "Get frequency fail"); + CHKCF(GetPropertyInt32(env, element, "index", event.index), "Get index fail"); + bool exist = false; + napi_status status = napi_has_named_property(env, element, "points", &exist); + if ((status == napi_ok) && (exist)) { + napi_value pointsArray = nullptr; + CHKCF(GetPropertyItem(env, element, "points", pointsArray), "Get points fail"); + CHKCF(IsMatchArrayType(env, pointsArray), "Wrong argument type. Napi array expected"); + uint32_t pointsLength = 0; + CHKCF((napi_get_array_length(env, pointsArray, &pointsLength) == napi_ok), + "napi_get_array_length pointsArray fail"); + event.pointNum = pointsLength; + VibratorCurvePoint *points = (VibratorCurvePoint *)malloc(sizeof(VibratorCurvePoint) * pointsLength); + if (points == nullptr) { + MISC_HILOGE("points is nullptr"); + return false; + } + for (int32_t k = 0; k < pointsLength; ++k) { + napi_value pointsElement = nullptr; + CHKCF((napi_get_element(env, pointsArray, k, &pointsElement) == napi_ok), + "napi_get_element pointsArray fail"); + CHKCF(IsMatchType(env, pointsElement, napi_object), + "Wrong argument type. napi_object or function expected"); + CHKCF(GetPropertyInt32(env, pointsElement, "time", points[k].time), "Get points time fail"); + CHKCF(GetPropertyInt32(env, pointsElement, "intensity", points[k].intensity), + "Get points intensity fail"); + CHKCF(GetPropertyInt32(env, pointsElement, "frequency", points[k].frequency), + "Get points frequency fail"); + } + event.points = points; + } + return true; +} + +static bool ParameterVibratePattern(napi_env env, napi_value args[], VibrateInfo &info) +{ + napi_value patternBuilder = nullptr; + CHKCF(GetPropertyItem(env, args[0], "patternBuilder", patternBuilder), "Get patternBuilder fail"); + CHKCF(IsMatchType(env, patternBuilder, napi_object), "Wrong argument type. Napi object expected"); + CHKCF(GetPropertyInt32(env, patternBuilder, "time", info.vibratorPattern.time), "Get time fail"); + napi_value eventArray = nullptr; + CHKCF(GetPropertyItem(env, patternBuilder, "events", eventArray), "Get events fail"); + CHKCF(IsMatchArrayType(env, eventArray), "Wrong argument type. Napi array expected"); + uint32_t length = 0; + CHKCF((napi_get_array_length(env, eventArray, &length) == napi_ok), "napi_get_array_length fail"); + info.vibratorPattern.eventNum = length; + VibratorEvent *events = (VibratorEvent *)malloc(sizeof(VibratorEvent) * length); + if (events == nullptr) { + MISC_HILOGE("events is nullptr"); + return false; + } + for (int32_t j = 0; j < length; ++j) { + if (!ParameterVibrateEvent(env, eventArray, j, events[j])) { + MISC_HILOGE("ParameterVibrateEvent failed"); + return false; + } + } + info.vibratorPattern.events = events; + return true; +} + +static void PrintVibratorPattern(VibratorPattern &vibratorPattern) +{ + if (vibratorPattern.events == nullptr) { + MISC_HILOGE("events is nullptr"); + return; + } + MISC_HILOGD("PrintVibratorPattern, time:%{public}d, eventNum:%{public}d", + vibratorPattern.time, vibratorPattern.eventNum); + for (int32_t i = 0; i < vibratorPattern.eventNum; ++i) { + MISC_HILOGD("PrintVibratorPattern, type:%{public}d, time:%{public}d, duration:%{public}d, \ + intensity:%{public}d, frequency:%{public}d, index:%{public}d, pointNum:%{public}d", + static_cast(vibratorPattern.events[i].type), vibratorPattern.events[i].time, + vibratorPattern.events[i].duration, vibratorPattern.events[i].intensity, + vibratorPattern.events[i].frequency, vibratorPattern.events[i].index, vibratorPattern.events[i].pointNum); + + if (vibratorPattern.events[i].points != nullptr) { + VibratorCurvePoint *point = vibratorPattern.events[i].points; + for (int32_t j = 0; j < vibratorPattern.events[i].pointNum; ++j) { + MISC_HILOGD("PrintVibratorPattern, time:%{public}d, intensity:%{public}d, frequency:%{public}d", + point[j].time, point[j].intensity, point[j].frequency); + } + } + } +} + bool ParseParameter(napi_env env, napi_value args[], size_t argc, VibrateInfo &info) { CHKCF((argc >= 2), "Wrong argument number"); @@ -190,6 +289,9 @@ bool ParseParameter(napi_env env, napi_value args[], size_t argc, VibrateInfo &i CHKCF((info.offset >= 0) && (info.offset <= fdSize), "The parameter of offset is invalid"); info.length = fdSize - info.offset; GetPropertyInt64(env, hapticFd, "length", info.length); + } else if (info.type == "pattern") { + CHKCF(ParameterVibratePattern(env, args, info), "ParameterVibratePattern fail"); + PrintVibratorPattern(info.vibratorPattern); } CHKCF(GetPropertyString(env, args[1], "usage", info.usage), "Get vibrate usage fail"); return true; @@ -206,11 +308,12 @@ bool SetUsage(const std::string &usage) int32_t StartVibrate(const VibrateInfo &info) { + CALL_LOG_ENTER; if (!SetUsage(info.usage)) { MISC_HILOGE("SetUsage fail"); return PARAMETER_ERROR; } - if ((info.type != "time") && (info.type != "preset") && (info.type != "file")) { + if ((info.type != "time") && (info.type != "preset") && (info.type != "file") && (info.type != "pattern")) { MISC_HILOGE("Invalid vibrate type, type:%{public}s", info.type.c_str()); return PARAMETER_ERROR; } @@ -222,6 +325,8 @@ int32_t StartVibrate(const VibrateInfo &info) return StartVibrator(info.effectId.c_str()); } else if (info.type == "file") { return PlayVibratorCustom(info.fd, info.offset, info.length); + } else if (info.type == "pattern") { + return PlayPattern(info.vibratorPattern); } return StartVibratorOnce(info.duration); } @@ -236,6 +341,10 @@ static napi_value VibrateEffect(napi_env env, napi_value args[], size_t argc) sptr asyncCallbackInfo = new (std::nothrow) AsyncCallbackInfo(env); CHKPP(asyncCallbackInfo); asyncCallbackInfo->error.code = StartVibrate(info); + + if (info.vibratorPattern.events != nullptr) { + CHKCP(FreeVibratorPattern(info.vibratorPattern), "FreeVibratorPattern fail"); + } if ((asyncCallbackInfo->error.code != SUCCESS) && (asyncCallbackInfo->error.code == PARAMETER_ERROR)) { ThrowErr(env, PARAMETER_ERROR, "parameters invalid"); return nullptr; @@ -248,6 +357,7 @@ static napi_value VibrateEffect(napi_env env, napi_value args[], size_t argc) static napi_value StartVibrate(napi_env env, napi_callback_info info) { + CALL_LOG_ENTER; CHKPP(env); CHKPP(info); size_t argc = 3; @@ -390,6 +500,22 @@ static napi_value CreateEnumStopMode(const napi_env env, napi_value exports) return exports; } +static napi_value CreateClassVibratePattern(const napi_env env, const napi_value exports) +{ + napi_property_descriptor clzDes[] = { + DECLARE_NAPI_FUNCTION("addContinuousEvent", VibratorPatternBuilder::AddContinuousEvent), + DECLARE_NAPI_FUNCTION("addTransientEvent", VibratorPatternBuilder::AddTransientEvent), + DECLARE_NAPI_FUNCTION("build", VibratorPatternBuilder::Build), + DECLARE_NAPI_FUNCTION("release", VibratorPatternBuilder::Release), + }; + napi_value cons = nullptr; + NAPI_CALL(env, napi_define_class(env, "VibratorPatternBuilder", NAPI_AUTO_LENGTH, + VibratorPatternBuilder::VibratorPatternConstructor, nullptr, sizeof(clzDes) / sizeof(napi_property_descriptor), + clzDes, &cons)); + NAPI_CALL(env, napi_set_named_property(env, exports, "VibratorPatternBuilder", cons)); + return exports; +} + static napi_value CreateEnumEffectId(const napi_env env, const napi_value exports) { napi_value clockTime = nullptr; @@ -416,6 +542,8 @@ static napi_value Init(napi_env env, napi_value exports) NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(napi_property_descriptor), desc)); NAPI_ASSERT_BASE(env, CreateEnumStopMode(env, exports) != nullptr, "Create enum stop mode fail", exports); NAPI_ASSERT_BASE(env, CreateEnumEffectId(env, exports) != nullptr, "Create enum effect id fail", exports); + NAPI_ASSERT_BASE(env, CreateClassVibratePattern(env, exports) != nullptr, + "CreateClassVibratePattern fail", exports); return exports; } diff --git a/frameworks/js/napi/vibrator/src/vibrator_napi_utils.cpp b/frameworks/js/napi/vibrator/src/vibrator_napi_utils.cpp index 27a16dd..b223efe 100644 --- a/frameworks/js/napi/vibrator/src/vibrator_napi_utils.cpp +++ b/frameworks/js/napi/vibrator/src/vibrator_napi_utils.cpp @@ -45,6 +45,33 @@ AsyncCallbackInfo::~AsyncCallbackInfo() } } +bool FreeVibratorPattern(VibratorPattern &vibratorPattern) +{ + CALL_LOG_ENTER; + int32_t eventSize = vibratorPattern.eventNum; + if ((eventSize <= 0) || (vibratorPattern.events == nullptr)) { + MISC_HILOGW("events is not need to free, events size:%{public}d", eventSize); + return false; + } + auto events = vibratorPattern.events; + for (int32_t j = 0; j < eventSize; ++j) { + if (events[j].points != nullptr) { + free(events[j].points); + events[j].points = nullptr; + } + } + free(events); + events = nullptr; + return true; +} + +bool IsMatchArrayType(const napi_env &env, const napi_value &value) +{ + bool result = false; + CHKCF((napi_is_array(env, value, &result) == napi_ok), "napi_is_array fail"); + return result; +} + bool IsMatchType(const napi_env &env, const napi_value &value, const napi_valuetype &type) { napi_valuetype paramType = napi_undefined; @@ -77,6 +104,16 @@ bool GetInt32Value(const napi_env &env, const napi_value &value, int32_t &result return true; } +bool GetDoubleValue(const napi_env &env, const napi_value &value, double &result) +{ + CALL_LOG_ENTER; + napi_valuetype valuetype = napi_undefined; + CHKCF(napi_typeof(env, value, &valuetype) == napi_ok, "napi_typeof failed"); + CHKCF((valuetype == napi_number), "Wrong argument type. Number expected"); + CHKCF(napi_get_value_double(env, value, &result) == napi_ok, "napi_get_value_double failed"); + return true; +} + bool GetInt64Value(const napi_env &env, const napi_value &value, int64_t &result) { CALL_LOG_ENTER; diff --git a/frameworks/js/napi/vibrator/src/vibrator_pattern_js.cpp b/frameworks/js/napi/vibrator/src/vibrator_pattern_js.cpp new file mode 100644 index 0000000..92bee18 --- /dev/null +++ b/frameworks/js/napi/vibrator/src/vibrator_pattern_js.cpp @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * 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_pattern_js.h" + +#include +#include "hilog/log.h" +#include "securec.h" + +#include "miscdevice_log.h" +#include "vibrator_napi_error.h" +#include "vibrator_napi_utils.h" + +#include + +#undef LOG_TAG +#define LOG_TAG "VibratorPatternJs" + +namespace OHOS { +namespace Sensors { +namespace { +constexpr int32_t EVENT_START_TIME_MAX = 1800000; +constexpr int32_t EVENT_NUM_MAX = 128; +constexpr int32_t TRANSIENT_VIBRATION_DURATION = 48; +constexpr int32_t INTENSITY_MIN = 0; +constexpr int32_t INTENSITY_MAX = 100; +constexpr int32_t FREQUENCY_MIN = 0; +constexpr int32_t FREQUENCY_MAX = 100; +constexpr int32_t CURVE_POINT_INTENSITY_MAX = 100; +constexpr int32_t CURVE_POINT_NUM_MIN = 4; +constexpr int32_t CURVE_POINT_NUM_MAX = 16; +constexpr int32_t CURVE_FREQUENCY_MIN = -100; +constexpr int32_t CURVE_FREQUENCY_MAX = 100; +constexpr int32_t CONTINUOUS_DURATION_MAX = 5000; +constexpr double CURVE_INTENSITY_SCALE = 100.0; +} // namespace + +napi_value VibratorPatternBuilder::VibratorPatternConstructor(const napi_env env, const napi_callback_info info) +{ + CALL_LOG_ENTER; + size_t argc = 0; + napi_value args[1] = {0}; + napi_value res = nullptr; + void *data = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &res, &data)); + + auto vibratorPattern = new VibratorPatternBuilder(); + napi_wrap( + env, res, vibratorPattern, + [](napi_env env, void* data, void* hint) { + auto vibratorPattern = static_cast(data); + if (vibratorPattern != nullptr) { + delete vibratorPattern; + } + }, + nullptr, nullptr); + return res; +} + +bool VibratorPatternBuilder::ParameterOptions(const napi_env &env, const napi_value &value, VibrateEvent &event) +{ + CALL_LOG_ENTER; + bool exist = false; + napi_status status = napi_has_named_property(env, value, "points", &exist); + if ((status == napi_ok) && (exist)) { + napi_value points = nullptr; + CHKCF((napi_get_named_property(env, value, "points", &points) == napi_ok), "napi get points fail"); + uint32_t length = 0; + CHKCF((napi_get_array_length(env, points, &length) == napi_ok), "napi_get_array_length fail"); + for (size_t i = 0; i < length; ++i) { + napi_value element = nullptr; + CHKCF((napi_get_element(env, points, i, &element) == napi_ok), "napi_get_element fail"); + VibrateCurvePoint point; + napi_value timeValue = nullptr; + CHKCF((napi_get_named_property(env, element, "time", &timeValue) == napi_ok), "napi get time fail"); + CHKCF(GetInt32Value(env, timeValue, point.time), "Get int number fail"); + status = napi_has_named_property(env, element, "intensity", &exist); + if ((status == napi_ok) && (exist)) { + napi_value intensityValue = nullptr; + CHKCF((napi_get_named_property(env, element, "intensity", &intensityValue) == napi_ok), + "napi get intensity fail"); + double intensityResult = 0.0; + CHKCF(GetDoubleValue(env, intensityValue, intensityResult), "Get double number fail"); + point.intensity = static_cast(intensityResult * CURVE_INTENSITY_SCALE); + } + status = napi_has_named_property(env, element, "frequency", &exist); + if ((status == napi_ok) && (exist)) { + napi_value frequencyValue = nullptr; + CHKCF((napi_get_named_property(env, element, "frequency", &frequencyValue) == napi_ok), + "napi get frequency fail"); + CHKCF(GetInt32Value(env, frequencyValue, point.frequency), "Get int number fail"); + } + event.points.push_back(point); + } + } + status = napi_has_named_property(env, value, "intensity", &exist); + if ((status == napi_ok) && (exist)) { + napi_value intensity = nullptr; + CHKCF((napi_get_named_property(env, value, "intensity", &intensity) == napi_ok), "napi get intensity fail"); + CHKCF(GetInt32Value(env, intensity, event.intensity), "Get int number intensity fail"); + } + status = napi_has_named_property(env, value, "frequency", &exist); + if ((status == napi_ok) && (exist)) { + napi_value frequency = nullptr; + CHKCF((napi_get_named_property(env, value, "frequency", &frequency) == napi_ok), "napi get frequency fail"); + CHKCF(GetInt32Value(env, frequency, event.frequency), "Get int number frequency fail"); + } + return true; +} + +bool VibratorPatternBuilder::CheckParameters(const VibrateEvent &event) +{ + CALL_LOG_ENTER; + if ((event.time < 0) || (event.time > EVENT_START_TIME_MAX)) { + MISC_HILOGE("The event time is out of range, time:%{public}d", event.time); + return false; + } + if ((event.frequency < FREQUENCY_MIN) || (event.frequency > FREQUENCY_MAX)) { + MISC_HILOGE("The event frequency is out of range, frequency:%{public}d", event.frequency); + return false; + } + if ((event.intensity < INTENSITY_MIN) || (event.intensity > INTENSITY_MAX)) { + MISC_HILOGE("The event intensity is out of range, intensity:%{public}d", event.intensity); + return false; + } + if ((event.duration <= 0) || (event.duration > CONTINUOUS_DURATION_MAX)) { + MISC_HILOGE("The event duration is out of range, duration:%{public}d", event.duration); + return false; + } + + if ((event.tag == VibrateTag::EVENT_TAG_CONTINUOUS) && !event.points.empty()) { + int32_t pointNum = static_cast(event.points.size()); + if ((pointNum < CURVE_POINT_NUM_MIN) || (pointNum > CURVE_POINT_NUM_MAX)) { + MISC_HILOGE("The points size is out of range, size:%{public}d", pointNum); + return false; + } + for (int32_t i = 0; i < pointNum; ++i) { + if ((event.points[i].time < 0) || (event.points[i].time > event.duration)) { + MISC_HILOGE("time in points is out of range, time:%{public}d", event.points[i].time); + return false; + } + if ((event.points[i].intensity < 0) || (event.points[i].intensity > CURVE_POINT_INTENSITY_MAX)) { + MISC_HILOGE("intensity in points is out of range, intensity:%{public}d", event.points[i].intensity); + return false; + } + if ((event.points[i].frequency < CURVE_FREQUENCY_MIN) || + (event.points[i].frequency > CURVE_FREQUENCY_MAX)) { + MISC_HILOGE("frequency in points is out of range, frequency:%{public}d", event.points[i].frequency); + return false; + } + } + } + return true; +} + +bool VibratorPatternBuilder::ConvertVibrateEvent(const std::vector &vibrateEvents, + VibratorPattern &vibratorPattern) +{ + CALL_LOG_ENTER; + if (vibrateEvents.empty()) { + MISC_HILOGE("vibrateEvents is empty"); + return false; + } + vibratorPattern.time = 0; + int32_t eventSize = static_cast(vibrateEvents.size()); + vibratorPattern.eventNum = eventSize; + VibratorEvent *events = (VibratorEvent *)malloc(sizeof(VibratorEvent) * eventSize); + if (events == nullptr) { + MISC_HILOGE("events is nullptr"); + return false; + } + for (int32_t j = 0; j < eventSize; ++j) { + events[j].type = static_cast(vibrateEvents[j].tag); + events[j].time = vibrateEvents[j].time; + events[j].duration = vibrateEvents[j].duration; + events[j].intensity = vibrateEvents[j].intensity; + events[j].frequency = vibrateEvents[j].frequency; + events[j].index = vibrateEvents[j].index; + auto vibratePoints = vibrateEvents[j].points; + events[j].pointNum = static_cast(vibratePoints.size()); + VibratorCurvePoint *points = (VibratorCurvePoint *)malloc(sizeof(VibratorCurvePoint) * events[j].pointNum); + if (points == nullptr) { + free(events); + events = nullptr; + MISC_HILOGE("points is nullptr"); + return false; + } + for (int32_t k = 0; k < events[j].pointNum; ++k) { + points[k].time = vibratePoints[k].time; + points[k].intensity = vibratePoints[k].intensity; + points[k].frequency = vibratePoints[k].frequency; + } + events[j].points = points; + } + vibratorPattern.events = events; + return true; +} + +bool VibratorPatternBuilder::CreateInt32Property(napi_env env, napi_value &eventObj, const char* name, int32_t value) +{ + CALL_LOG_ENTER; + napi_value propValue = nullptr; + napi_status status = napi_create_int32(env, value, &propValue); + if (status != napi_ok) { + MISC_HILOGE("napi_create_int32 fail"); + return false; + } + CHKCF((napi_set_named_property(env, eventObj, name, propValue) == napi_ok), "napi_set_named_property fail"); + return true; +} + +napi_value VibratorPatternBuilder::ConvertVibratorCurvePoint(napi_env env, const VibratorCurvePoint &point) +{ + CALL_LOG_ENTER; + napi_value pointObj; + napi_status status = napi_create_object(env, &pointObj); + if (status != napi_ok) { + MISC_HILOGE("napi_create_object fail"); + return nullptr; + } + CHKCP(CreateInt32Property(env, pointObj, "time", point.time), "CreateInt32Property time fail"); + CHKCP(CreateInt32Property(env, pointObj, "intensity", point.intensity), "CreateInt32Property intensity fail"); + CHKCP(CreateInt32Property(env, pointObj, "frequency", point.frequency), "CreateInt32Property frequency fail"); + return pointObj; +} + +napi_value VibratorPatternBuilder::ConvertVibratorEvent(napi_env env, const VibratorEvent &event) +{ + CALL_LOG_ENTER; + napi_value eventObj = nullptr; + CHKCP((napi_create_object(env, &eventObj) == napi_ok), "napi_create_object fail"); + CHKCP(CreateInt32Property(env, eventObj, "eventType", static_cast(event.type)), + "CreateInt32Property type fail"); + CHKCP(CreateInt32Property(env, eventObj, "time", event.time), "CreateInt32Property time fail"); + CHKCP(CreateInt32Property(env, eventObj, "duration", event.duration), "CreateInt32Property duration fail"); + CHKCP(CreateInt32Property(env, eventObj, "intensity", event.intensity), "CreateInt32Property intensity fail"); + CHKCP(CreateInt32Property(env, eventObj, "frequency", event.frequency), "CreateInt32Property frequency fail"); + CHKCP(CreateInt32Property(env, eventObj, "index", event.index), "CreateInt32Property index fail"); + napi_value pointsArray = nullptr; + CHKCP((napi_create_array_with_length(env, event.pointNum, &pointsArray) == napi_ok), + "napi_create_array_with_length fail"); + for (int i = 0; i < event.pointNum; ++i) { + napi_value pointObj = ConvertVibratorCurvePoint(env, event.points[i]); + if (pointObj == nullptr) { + MISC_HILOGE("ConvertToNapiValue fail"); + return nullptr; + } + CHKCP((napi_set_element(env, pointsArray, i, pointObj) == napi_ok), "napi_set_element fail"); + } + CHKCP((napi_set_named_property(env, eventObj, "points", pointsArray) == napi_ok), "napi_set_named_property fail"); + return eventObj; +} + +napi_value VibratorPatternBuilder::ConvertVibratorPatternToNapiValue(napi_env env, + const VibratorPattern &vibratorPattern) +{ + CALL_LOG_ENTER; + napi_value result = nullptr; + CHKCP((napi_create_object(env, &result) == napi_ok), "napi_create_object fail"); + + napi_value time = nullptr; + CHKCP((napi_create_int32(env, vibratorPattern.time, &time) == napi_ok), "napi_create_int32 time fail"); + CHKCP((napi_set_named_property(env, result, "time", time) == napi_ok), "napi_set_named_property time fail"); + napi_value eventsArray = nullptr; + CHKCP((napi_create_array_with_length(env, vibratorPattern.eventNum, &eventsArray) == napi_ok), + "napi_create_array_with_length fail"); + for (int32_t i = 0; i < vibratorPattern.eventNum; ++i) { + napi_value eventObj = ConvertVibratorEvent(env, vibratorPattern.events[i]); + if (eventObj == nullptr) { + MISC_HILOGE("ConvertToNapiValue fail"); + return nullptr; + } + CHKCP((napi_set_element(env, eventsArray, i, eventObj) == napi_ok), "napi_set_element fail"); + } + CHKCP((napi_set_named_property(env, result, "events", eventsArray) == napi_ok), + "napi_setnapi_set_named_property_element fail"); + return result; +} + +napi_value VibratorPatternBuilder::AddContinuousEvent(napi_env env, napi_callback_info info) +{ + CALL_LOG_ENTER; + size_t argc = 3; + napi_value args[3] = {}; + napi_value thisArg = nullptr; + napi_status status = napi_get_cb_info(env, info, &argc, args, &thisArg, nullptr); + if ((status != napi_ok) || (argc < 2) || !IsMatchType(env, args[0], napi_number) || + !IsMatchType(env, args[1], napi_number)) { + ThrowErr(env, PARAMETER_ERROR, "napi_get_cb_info fail or number of parameter invalid"); + return nullptr; + } + VibrateEvent event; + event.tag = VibrateTag::EVENT_TAG_CONTINUOUS; + CHKCP(GetInt32Value(env, args[0], event.time), "Get int number time fail"); + CHKCP(GetInt32Value(env, args[1], event.duration), "Get int number duration fail"); + if (argc > 2) { + if (!IsMatchType(env, args[2], napi_object)) { + ThrowErr(env, PARAMETER_ERROR, "parameter invalid"); + return nullptr; + } + if (!ParameterOptions(env, args[2], event)) { + ThrowErr(env, PARAMETER_ERROR, "ParameterOptions fail"); + return nullptr; + } + } + if (!CheckParameters(event)) { + ThrowErr(env, PARAMETER_ERROR, "Invalid parameter"); + return nullptr; + } + VibratorPatternBuilder *vibratorPattern = nullptr; + CHKCP((napi_unwrap(env, thisArg, (void **)(&vibratorPattern)) == napi_ok), "napi_unwrap fail"); + if (vibratorPattern == nullptr) { + MISC_HILOGE("vibratorPattern is nullptr"); + return nullptr; + } + vibratorPattern->events_.push_back(event); + return thisArg; +} + +napi_value VibratorPatternBuilder::AddTransientEvent(napi_env env, napi_callback_info info) +{ + CALL_LOG_ENTER; + size_t argc = 3; + napi_value args[3] = {}; + napi_value thisArg = nullptr; + napi_status status = napi_get_cb_info(env, info, &argc, args, &thisArg, nullptr); + if ((status != napi_ok) || (argc < 2) || !IsMatchType(env, args[0], napi_number) || + !IsMatchType(env, args[1], napi_number)) { + ThrowErr(env, PARAMETER_ERROR, "napi_get_cb_info fail or number of parameter invalid"); + return nullptr; + } + VibrateEvent event; + event.tag = VibrateTag::EVENT_TAG_TRANSIENT; + event.duration = TRANSIENT_VIBRATION_DURATION; + CHKCP(GetInt32Value(env, args[0], event.time), "Get int number time fail"); + CHKCP(GetInt32Value(env, args[1], event.frequency), "Get int number frequency fail"); + if (argc > 2) { + if (!IsMatchType(env, args[2], napi_number)) { + ThrowErr(env, PARAMETER_ERROR, "parameter invalid"); + return nullptr; + } + CHKCP(GetInt32Value(env, args[2], event.intensity), "Get int number intensity fail"); + } + if (!CheckParameters(event)) { + ThrowErr(env, PARAMETER_ERROR, "Invalid parameter"); + return nullptr; + } + VibratorPatternBuilder *vibratorPattern = nullptr; + CHKCP((napi_unwrap(env, thisArg, (void **)(&vibratorPattern)) == napi_ok), "napi_unwrap fail"); + if (vibratorPattern == nullptr) { + MISC_HILOGE("vibratorPattern is nullptr"); + return nullptr; + } + vibratorPattern->events_.push_back(event); + return thisArg; +} + +napi_value VibratorPatternBuilder::Build(napi_env env, napi_callback_info info) +{ + CALL_LOG_ENTER; + size_t argc = 1; + napi_value args[1] = {}; + napi_value thisArg = nullptr; + napi_status status = napi_get_cb_info(env, info, &argc, args, &thisArg, nullptr); + if (status != napi_ok) { + ThrowErr(env, PARAMETER_ERROR, "napi_get_cb_info fail"); + return nullptr; + } + VibratorPatternBuilder *vibratorPattern = nullptr; + CHKCP((napi_unwrap(env, thisArg, (void **)(&vibratorPattern)) == napi_ok), "napi_unwrap fail"); + if (vibratorPattern == nullptr) { + MISC_HILOGE("vibratorPattern is nullptr"); + return nullptr; + } + int32_t eventNum = vibratorPattern->events_.size(); + if ((eventNum <= 0) || (eventNum > EVENT_NUM_MAX)) { + ThrowErr(env, PARAMETER_ERROR, "The number of events exceeds the range"); + return nullptr; + } + if (!ConvertVibrateEvent(vibratorPattern->events_, vibratorPattern->vibratorPattern_)) { + MISC_HILOGE("ConvertVibrateEvent fail"); + return nullptr; + } + napi_value result = ConvertVibratorPatternToNapiValue(env, vibratorPattern->vibratorPattern_); + if (result == nullptr) { + MISC_HILOGE("ConvertVibratorPatternToNapiValue fail"); + return nullptr; + } + return result; +} + +napi_value VibratorPatternBuilder::Release(napi_env env, napi_callback_info info) +{ + CALL_LOG_ENTER; + size_t argc = 1; + napi_value args[1] = {}; + napi_value thisArg = nullptr; + napi_status status = napi_get_cb_info(env, info, &argc, args, &thisArg, nullptr); + if (status != napi_ok) { + ThrowErr(env, PARAMETER_ERROR, "napi_get_cb_info fail"); + return nullptr; + } + VibratorPatternBuilder *vibratorPattern = nullptr; + CHKCP((napi_unwrap(env, thisArg, (void **)(&vibratorPattern)) == napi_ok), "napi_unwrap fail"); + if (vibratorPattern == nullptr) { + MISC_HILOGE("vibratorPattern is nullptr"); + return nullptr; + } + if (!FreeVibratorPattern(vibratorPattern->vibratorPattern_)) { + MISC_HILOGE("FreeVibratorPattern fail"); + return nullptr; + } + return nullptr; +} +} // namespace Sensors +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/inner_api/vibrator/vibrator_agent_type.h b/interfaces/inner_api/vibrator/vibrator_agent_type.h index 73b23f5..076a16e 100644 --- a/interfaces/inner_api/vibrator/vibrator_agent_type.h +++ b/interfaces/inner_api/vibrator/vibrator_agent_type.h @@ -25,56 +25,56 @@ extern "C" { * * @since 1 */ -const char *VIBRATOR_TYPE_CLOCK_TIMER = "haptic.clock.timer"; +inline const char *VIBRATOR_TYPE_CLOCK_TIMER = "haptic.clock.timer"; /** * @brief Describes the vibration effect of the vibrator when authentication fails. * * @since 11 */ -const char *VIBRATOR_TYPE_FAIL = "haptic.fail"; +inline const char *VIBRATOR_TYPE_FAIL = "haptic.fail"; /** * @brief Describes the vibration effect of the vibrator when charging. * * @since 11 */ -const char *VIBRATOR_TYPE_CHARGING = "haptic.charging"; +inline const char *VIBRATOR_TYPE_CHARGING = "haptic.charging"; /** * @brief Describes the vibration effect of the vibrator when long pressed. * * @since 11 */ -const char *VIBRATOR_TYPE_LONG_PRESS_LIGHT = "haptic.long_press.light"; +inline const char *VIBRATOR_TYPE_LONG_PRESS_LIGHT = "haptic.long_press.light"; /** * @brief Describes the vibration effect of the vibrator when long pressed. * * @since 11 */ -const char *VIBRATOR_TYPE_LONG_PRESS_MEDIUM = "haptic.long_press.medium"; +inline const char *VIBRATOR_TYPE_LONG_PRESS_MEDIUM = "haptic.long_press.medium"; /** * @brief Describes the vibration effect of the vibrator when long pressed. * * @since 11 */ -const char *VIBRATOR_TYPE_LONG_PRESS_HEAVY = "haptic.long_press.heavy"; +inline const char *VIBRATOR_TYPE_LONG_PRESS_HEAVY = "haptic.long_press.heavy"; /** * @brief Describes the vibration effect of the vibrator when slide. * * @since 11 */ -const char *VIBRATOR_TYPE_SLIDE_LIGHT = "haptic.slide.light"; +inline const char *VIBRATOR_TYPE_SLIDE_LIGHT = "haptic.slide.light"; /** * @brief Describes the vibration effect of the vibrator when the threshold is reached. * * @since 11 */ -const char *VIBRATOR_TYPE_THRESHOID = "haptic.threshold"; +inline const char *VIBRATOR_TYPE_THRESHOID = "haptic.threshold"; /** * @brief Enumerates vibration usages. -- Gitee