diff --git a/bundle.json b/bundle.json index fe07fe75d4154f55d4f29886e7ed5fbbb6f0dd73..f1ff2dadd5f624ede2226bc80cdca2fe6092c438 100644 --- a/bundle.json +++ b/bundle.json @@ -45,7 +45,8 @@ "os_account", "safwk", "samgr", - "cJSON" + "cJSON", + "runtime_core" ], "third_party": [ ] @@ -55,6 +56,7 @@ "base_group": [], "fwk_group": [ "//base/sensors/miscdevice/frameworks/js/napi:vibrator_js_target", + "//base/sensors/miscdevice/frameworks/js/ani:vibrator_ani_target", "//base/sensors/miscdevice/frameworks/cj:vibrator_cj_target", "//base/sensors/miscdevice/frameworks/native/vibrator:vibrator_target", "//base/sensors/miscdevice/frameworks/native/light:light_target", diff --git a/frameworks/js/ani/BUILD.gn b/frameworks/js/ani/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..9767407f36b56cd018b1a56518e0403e01da1973 --- /dev/null +++ b/frameworks/js/ani/BUILD.gn @@ -0,0 +1,67 @@ +# Copyright (c) 2025 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. + +import("//build/config/components/ets_frontend/ets2abc_config.gni") +import("//build/ohos.gni") +import("./../../../miscdevice.gni") + +ohos_shared_library("vibrator_ani") { + sanitize = { + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + sources = [ "$SUBSYSTEM_DIR/frameworks/js/ani/vibrator/src/vibrator_ani.cpp" ] + include_dirs = [ + "$SUBSYSTEM_DIR/frameworks/js/ani/vibrator/include", + "$SUBSYSTEM_DIR/utils/common/include", + ] + deps = [ + "$SUBSYSTEM_DIR/frameworks/native/vibrator:vibrator_interface_native", + "$SUBSYSTEM_DIR/utils/common:libmiscdevice_utils", + ] + external_deps = [ + "hilog:libhilog", + "napi:ace_napi", + "runtime_core:ani", + ] + subsystem_name = "sensors" + part_name = "miscdevice" + output_extension = "so" +} + +generate_static_abc("vibrator_abc") { + base_url = "./vibrator/ets" + files = [ "./vibrator/ets/@ohos.vibrator.ets" ] + dst_file = "$target_out_dir/vibrator.abc" + out_puts = [ "$target_out_dir/vibrator.abc" ] + is_boot_abc = "True" + device_dst_file = "/system/framework/vibrator.abc" +} + +ohos_prebuilt_etc("vibrator_abc_etc") { + source = "$target_out_dir/vibrator.abc" + module_install_dir = "framework" + subsystem_name = "sensors" + part_name = "miscdevice" + deps = [ ":vibrator_abc" ] +} + +group("vibrator_ani_target") { + deps = [ + ":vibrator_abc_etc", + ":vibrator_ani", + ] +} diff --git a/frameworks/js/ani/vibrator/ets/@ohos.vibrator.ets b/frameworks/js/ani/vibrator/ets/@ohos.vibrator.ets new file mode 100644 index 0000000000000000000000000000000000000000..3104e87f882bbb8f46bda187937c1b24dbb6e305 --- /dev/null +++ b/frameworks/js/ani/vibrator/ets/@ohos.vibrator.ets @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2025 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. + */ + +import type { AsyncCallback } from '@ohos.base'; +import { BusinessError } from '@ohos.base'; + +export default namespace vibrator { + loadLibrary("vibrator_ani"); + + native function startVibrationSync(effect: VibrateEffect, attribute: VibrateAttribute): void; + export function startVibrationIntSync(effect: VibrateEffect, attribute: VibrateAttribute): int { + startVibrationSync(effect, attribute); + return 0; + } + + export function startVibration(effect: VibrateEffect, attribute: VibrateAttribute, callback: AsyncCallback): void { + let p1 = taskpool.execute(startVibrationIntSync, effect, attribute); + p1.then((e: NullishType)=>{ + console.log("in callback startVibration then.") + let err1 : BusinessError + callback(err1, undefined); + }); + p1.catch((err: NullishType) => { + console.log("startVibration catch in callback thread."); + let err2 = err as BusinessError; + callback(err2, undefined); + }) + } + + export function startVibration(effect: VibrateEffect, attribute: VibrateAttribute): Promise { + let p = new Promise((resolve: (v: undefined) => void, reject: (error: Object) => void) : void => { + let p1 = taskpool.execute(startVibrationIntSync, effect, attribute); + p1.then((e: NullishType) : void =>{ + console.log("in Promise startVibration then. e is ", e) + resolve(undefined); + }); + p1.catch((err: Error) : void => { + console.log("startVibration catch in promise thread."); + reject(err); + }); + }); + return p; + } + + export native function isSupportEffectInterally(effectId: string): boolean; + + export function isSupportEffect(effectId: string, callback: AsyncCallback): void { + let p1 = taskpool.execute(isSupportEffectInterally, effectId); + p1.then((e: NullishType)=>{ + let r = e as boolean; + console.log("in callback isSupportEffectInterally then. e is ", e) + let err : BusinessError + callback(err, r); + }); + p1.catch((error: NullishType) => { + console.log("isSupportEffect catch in callback thread."); + let err = error as BusinessError; + let e : boolean; + callback(err, e); + }); + } + + export function isSupportEffect(effectId: string): Promise { + let p = new Promise((resolve: (v: boolean) => void, reject: (error: Object) => void) : boolean => { + let p1 = taskpool.execute(isSupportEffectInterally, effectId); + p1.then((e: NullishType) : boolean=>{ + let r = e as boolean; + console.log("in promise isSupportEffectInterally then. e is ", e) + resolve(r); + }); + p1.catch((err: Error) : boolean => { + console.log("isSupportEffect catch in promise thread."); + reject(err); + }); + }); + return p; + } + + export type Usage = 'unknown' | 'alarm' | 'ring' | 'notification' | 'communication' | + 'touch' | 'media' | 'physicalFeedback' | 'simulateReality'; + + export interface VibrateAttribute { + id?: number; + usage: Usage; + systemUsage?: boolean; + } + + export type VibrateEffect = VibrateTime | VibratePreset | VibrateFromFile | VibrateFromPattern; + + export interface VibrateTime { + type: 'time'; + duration: number; + } + + export interface VibratePreset { + type: 'preset'; + effectId: string; + count?: number; + intensity?: number; + } + + export interface VibrateFromFile { + type: 'file'; + hapticFd: HapticFileDescriptor; + } + + export interface HapticFileDescriptor { + fd: number; + offset?: number; + length?: number; + } + + export interface VibrateFromPattern { + type: 'pattern'; + pattern: VibratorPattern; + } + + export interface VibratorPattern { + time: number; + events: Array; + } + + export interface VibratorEvent { + eventType: VibratorEventType; + time: number; + duration?: number; + intensity?: number; + frequency?: number; + index?: number; + points?: Array; + } + + export enum VibratorEventType { + CONTINUOUS = 0, + TRANSIENT = 1, + } + + export interface VibratorCurvePoint { + time: number; + intensity?: number; + frequency?: number; + } + +} diff --git a/frameworks/js/ani/vibrator/include/ani_utils.h b/frameworks/js/ani/vibrator/include/ani_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..663a794dbe6a1477a0f09e0c0bb4c60fd6fb9d3d --- /dev/null +++ b/frameworks/js/ani/vibrator/include/ani_utils.h @@ -0,0 +1,564 @@ +/* + * Copyright (c) 2025 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 ANI_UTILS_H +#define ANI_UTILS_H + +#include + +#include +#include +#include +#include +#include +#include +#include +class AniStringUtils { +public: + static std::string ToStd(ani_env *env, ani_string ani_str) + { + ani_size strSize; + env->String_GetUTF8Size(ani_str, &strSize); + + std::vector buffer(strSize + 1); // +1 for null terminator + char* utf8_buffer = buffer.data(); + + //String_GetUTF8 Supportted by https://gitee.com/openharmony/arkcompiler_runtime_core/pulls/3416 + ani_size bytes_written = 0; + env->String_GetUTF8(ani_str, utf8_buffer, strSize + 1, &bytes_written); + + utf8_buffer[bytes_written] = '\0'; + std::string content = std::string(utf8_buffer); + return content; + } + + static ani_string ToAni(ani_env* env, const std::string& str) + { + ani_string aniStr = nullptr; + if (ANI_OK != env->String_NewUTF8(str.data(), str.size(), &aniStr)) { + std::cerr << "[ANI] Unsupported ANI_VERSION_1" << std::endl; + return nullptr; + } + return aniStr; + } +}; + +class UnionAccessor { +public: + UnionAccessor(ani_env *env, ani_object &obj) : env_(env), obj_(obj) + { + } + + bool IsInstanceOf(const std::string& cls_name) + { + ani_class cls; + env_->FindClass(cls_name.c_str(), &cls); + + ani_boolean ret; + env_->Object_InstanceOf(obj_, cls, &ret); + return ret; + } + + template + bool IsInstanceOfType(); + + template + bool TryConvert(T &value); + + template + bool TryConvertArray(std::vector &value); + +private: + ani_env *env_; + ani_object obj_; +}; + +template<> +bool UnionAccessor::IsInstanceOfType() +{ + return IsInstanceOf("Lstd/core/Boolean;"); +} + +template<> +bool UnionAccessor::IsInstanceOfType() +{ + return IsInstanceOf("Lstd/core/Int;"); +} + +template<> +bool UnionAccessor::IsInstanceOfType() +{ + return IsInstanceOf("Lstd/core/Double;"); +} + +template<> +bool UnionAccessor::IsInstanceOfType() +{ + return IsInstanceOf("Lstd/core/String;"); +} + +template<> +bool UnionAccessor::TryConvert(bool &value) +{ + if (!IsInstanceOfType()) { + return false; + } + + ani_boolean aniValue; + auto ret = env_->Object_CallMethodByName_Boolean(obj_, "unboxed", nullptr, &aniValue); + if (ret != ANI_OK) { + return false; + } + value = static_cast(aniValue); + return true; +} + +template<> +bool UnionAccessor::TryConvert(int &value) +{ + if (!IsInstanceOfType()) { + return false; + } + + ani_int aniValue; + auto ret = env_->Object_CallMethodByName_Int(obj_, "unboxed", nullptr, &aniValue); + if (ret != ANI_OK) { + return false; + } + value = static_cast(aniValue); + return true; +} + +template<> +bool UnionAccessor::TryConvert(double &value) +{ + if (!IsInstanceOfType()) { + return false; + } + + ani_double aniValue; + auto ret = env_->Object_CallMethodByName_Double(obj_, "unboxed", nullptr, &aniValue); + if (ret != ANI_OK) { + return false; + } + value = static_cast(aniValue); + return true; +} + +template<> +bool UnionAccessor::TryConvert(std::string &value) +{ + if (!IsInstanceOfType()) { + return false; + } + + value = AniStringUtils::ToStd(env_, static_cast(obj_)); + return true; +} + +template<> +bool UnionAccessor::TryConvertArray(std::vector &value) +{ + ani_double length; + if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &length)) { + std::cerr << "Object_GetPropertyByName_Double length failed" << std::endl; + return false; + } + for (int i = 0; i < int(length); i++) { + ani_ref ref; + if (ANI_OK != env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &ref, (ani_int)i)) { + std::cerr << "Object_GetPropertyByName_Ref failed" << std::endl; + return false; + } + ani_boolean val; + if (ANI_OK != env_->Object_CallMethodByName_Boolean(static_cast(ref), "unboxed", nullptr, &val)) { + std::cerr << "Object_CallMethodByName_Double unbox failed" << std::endl; + return false; + } + value.push_back(static_cast(val)); + } + return true; +} + +template<> +bool UnionAccessor::TryConvertArray(std::vector &value) +{ + ani_double length; + if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &length)) { + std::cerr << "Object_GetPropertyByName_Double length failed" << std::endl; + return false; + } + for (int i = 0; i < int(length); i++) { + ani_ref ref; + if (ANI_OK != env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &ref, (ani_int)i)) { + std::cerr << "Object_GetPropertyByName_Ref failed" << std::endl; + return false; + } + ani_int intValue; + if (ANI_OK != env_->Object_CallMethodByName_Int(static_cast(ref), "unboxed", nullptr, &intValue)) { + std::cerr << "Object_CallMethodByName_Double unbox failed" << std::endl; + return false; + } + value.push_back(static_cast(intValue)); + } + return true; +} + +template<> +bool UnionAccessor::TryConvertArray(std::vector &value) +{ + ani_double length; + if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &length)) { + std::cerr << "Object_GetPropertyByName_Double length failed" << std::endl; + return false; + } + for (int i = 0; i < int(length); i++) { + ani_ref ref; + if (ANI_OK != env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &ref, (ani_int)i)) { + std::cerr << "Object_GetPropertyByName_Ref failed" << std::endl; + return false; + } + ani_double val; + if (ANI_OK != env_->Object_CallMethodByName_Double(static_cast(ref), "unboxed", nullptr, &val)) { + std::cerr << "Object_CallMethodByName_Double unbox failed" << std::endl; + return false; + } + value.push_back(static_cast(val)); + } + return true; +} + +template<> +bool UnionAccessor::TryConvertArray(std::vector &value) +{ + std::cout << "TryConvertArray std::vector" << std::endl; + ani_ref buffer; + if (ANI_OK != env_->Object_GetFieldByName_Ref(obj_, "buffer", &buffer)) { + std::cout << "Object_GetFieldByName_Ref failed" << std::endl; + return false; + } + void* data; + size_t length; + if (ANI_OK != env_->ArrayBuffer_GetInfo(static_cast(buffer), &data, &length)) { + std::cerr << "ArrayBuffer_GetInfo failed" << std::endl; + return false; + } + std::cout << "Length of buffer is " << length << std::endl; + for (size_t i = 0; i < length; i++) { + value.push_back(static_cast(data)[i]); + } + return true; +} + +template<> +bool UnionAccessor::TryConvertArray(std::vector &value) +{ + ani_double length; + if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &length)) { + std::cerr << "Object_GetPropertyByName_Double length failed" << std::endl; + return false; + } + + for (int i = 0; i < int(length); i++) { + ani_ref ref; + if (ANI_OK != env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &ref, (ani_int)i)) { + std::cerr << "Object_GetPropertyByName_Double length failed" << std::endl; + return false; + } + value.push_back(AniStringUtils::ToStd(env_, static_cast(ref))); + } + return true; +} + +class OptionalAccessor { +public: + OptionalAccessor(ani_env *env, ani_object &obj) : env_(env), obj_(obj) + { + } + + bool IsUndefined() + { + ani_boolean isUndefined; + env_->Reference_IsUndefined(obj_, &isUndefined); + return isUndefined; + } + + template + std::optional Convert(); + +private: + ani_env *env_; + ani_object obj_; +}; + +template<> +std::optional OptionalAccessor::Convert() +{ + if (IsUndefined()) { + return std::nullopt; + } + + ani_double aniValue; + auto ret = env_->Object_CallMethodByName_Double(obj_, "doubleValue", nullptr, &aniValue); + if (ret != ANI_OK) { + return std::nullopt; + } + auto value = static_cast(aniValue); + return value; +} + +template<> +std::optional OptionalAccessor::Convert() +{ + if (IsUndefined()) { + return std::nullopt; + } + + ani_size strSize; + env_->String_GetUTF8Size(static_cast(obj_), &strSize); + + std::vector buffer(strSize + 1); + char* utf8_buffer = buffer.data(); + + ani_size bytes_written = 0; + env_->String_GetUTF8(static_cast(obj_), utf8_buffer, strSize + 1, &bytes_written); + + utf8_buffer[bytes_written] = '\0'; + std::string content = std::string(utf8_buffer); + return content; +} + +template +class expected { +private: + std::variant data_; + bool has_value_; + +public: + expected(const T &value) + : data_(value), has_value_(true) + { + } + + expected(T &&value) + : data_(std::move(value)), has_value_(true) + { + } + + expected(const E &error) + : data_(error), has_value_(false) + { + } + + expected(E &&error) + : data_(std::move(error)), has_value_(false) + { + } + + bool has_value() const noexcept + { + return has_value_; + } + + explicit operator bool() const noexcept + { + return has_value(); + } + + T &value() & + { + if (!has_value()) { + std::terminate(); + } + return std::get(data_); + } + + const T &value() const & + { + if (!has_value()) { + std::terminate(); + } + return std::get(data_); + } + + T &&value() && + { + if (!has_value()) { + std::terminate(); + } + return std::get(std::move(data_)); + } + + E &error() & + { + if (has_value()) { + std::terminate(); + } + return std::get(data_); + } + + const E &error() const & + { + if (has_value()) { + std::terminate(); + } + return std::get(data_); + } + + E &&error() && + { + if (has_value()) { + std::terminate(); + } + return std::get(std::move(data_)); + } + + T &operator*() & + { + return value(); + } + + const T &operator*() const & + { + return value(); + } + + T &&operator*() && + { + return std::move(*this).value(); + } + + T *operator->() + { + return &value(); + } + + const T *operator->() const + { + return &value(); + } + + template + T value_or(U &&default_value) const & + { + return has_value() ? value() : static_cast(std::forward(default_value)); + } + + template + T value_or(U &&default_value) && + { + return has_value() ? std::move(*this).value() : static_cast(std::forward(default_value)); + } +}; + +class EnumAccessor { + public: + EnumAccessor(ani_env *env, const char* className, ani_int index) : env_(env) + { + initStatus_ = ANI_ERROR; + ani_enum_item item; + initStatus_ = GetItem(className, index, item); + if (ANI_OK == initStatus_) { + item_ = item; + } + } + + EnumAccessor(ani_env *env, ani_enum_item item) : env_(env), item_(item) + { + initStatus_ = ANI_ERROR; + } + + template + expected To() + { + int32_t value{}; + ani_status status = ToInt(value); + if (ANI_OK != status) { + return status; + } + return static_cast(value); + } + + ani_status ToInt(int32_t &value) + { + if (!item_) { + return initStatus_; + } + + ani_status status = env_->EnumItem_GetValue_Int(item_.value(), &value); + if (ANI_OK != status) { + return status; + } + return ANI_OK; + } + + expected ToInt() + { + int32_t value; + ani_status status = ToInt(value); + if (ANI_OK != status) { + return status; + } + return value; + } + + ani_status ToString(std::string &value) + { + if (!item_) { + return initStatus_; + } + + ani_string strValue; + ani_status status = env_->EnumItem_GetValue_String(item_.value(), &strValue); + if (ANI_OK != status) { + return status; + } + value = AniStringUtils::ToStd(env_, strValue); + return ANI_OK; + } + + expected ToString() + { + std::string value; + ani_status status = ToString(value); + if (ANI_OK != status) { + return status; + } + return value; + } + + private: + ani_status GetItem(const char* className, ani_int index, ani_enum_item &item) + { + ani_status status = ANI_ERROR; + ani_enum enumType; + status = env_->FindEnum(className, &enumType); + if (ANI_OK != status) { + return status; + } + + status = env_->Enum_GetEnumItemByIndex(enumType, index, &item); + if (ANI_OK != status) { + return status; + } + return ANI_OK; + } + + private: + ani_env *env_; + std::optional item_; + ani_status initStatus_; +}; +#endif diff --git a/frameworks/js/ani/vibrator/src/vibrator_ani.cpp b/frameworks/js/ani/vibrator/src/vibrator_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a7da7383b264886bbe91afbd22393f9e1e8d53e7 --- /dev/null +++ b/frameworks/js/ani/vibrator/src/vibrator_ani.cpp @@ -0,0 +1,816 @@ +/* + * Copyright (c) 2025 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 +#include +#include +#include "napi/native_api.h" +#include "ani_utils.h" +#include "file_utils.h" +#include +#include "miscdevice_log.h" +#include "vibrator_agent.h" + +#undef LOG_TAG +#define LOG_TAG "VibratorAni" + +using namespace OHOS::Sensors; + +constexpr int32_t INTENSITY_ADJUST_MAX = 100; +constexpr int32_t EVENT_START_TIME_MAX = 1800000; +constexpr int32_t EVENT_NUM_MAX = 128; +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 int32_t EVENT_INDEX_MAX = 2; + +static std::map g_usageType = { + {"unknown", USAGE_UNKNOWN}, + {"alarm", USAGE_ALARM}, + {"ring", USAGE_RING}, + {"notification", USAGE_NOTIFICATION}, + {"communication", USAGE_COMMUNICATION}, + {"touch", USAGE_TOUCH}, + {"media", USAGE_MEDIA}, + {"physicalFeedback", USAGE_PHYSICAL_FEEDBACK}, + {"simulateReality", USAGE_SIMULATE_REALITY}, +}; + +static std::set g_allowedTypes = {"time", "preset", "file", "pattern"}; + +typedef struct VibrateInfo { + std::string type; + std::string usage; + bool systemUsage; + int32_t duration = 0; + std::string effectId; + int32_t count = 0; + int32_t fd = -1; + int64_t offset = 0; + int64_t length = -1; + int32_t intensity = 0; + VibratorPattern vibratorPattern; +} VibrateInfo; + +static void ThrowBusinessError(ani_env *env, int errCode, std::string&& errMsg) +{ + MISC_HILOGD("Begin ThrowBusinessError."); + static const char *errorClsName = "L@ohos/base/BusinessError;"; + ani_class cls {}; + if (ANI_OK != env->FindClass(errorClsName, &cls)) { + MISC_HILOGE("find class BusinessError %{public}s failed", errorClsName); + return; + } + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", ":V", &ctor)) { + MISC_HILOGE("find method BusinessError.constructor failed"); + return; + } + ani_object errorObject; + if (ANI_OK != env->Object_New(cls, ctor, &errorObject)) { + MISC_HILOGE("create BusinessError object failed"); + return; + } + ani_double aniErrCode = static_cast(errCode); + ani_string errMsgStr; + if (ANI_OK != env->String_NewUTF8(errMsg.c_str(), errMsg.size(), &errMsgStr)) { + MISC_HILOGE("convert errMsg to ani_string failed"); + return; + } + if (ANI_OK != env->Object_SetFieldByName_Double(errorObject, "code", aniErrCode)) { + MISC_HILOGE("set error code failed"); + return; + } + if (ANI_OK != env->Object_SetPropertyByName_Ref(errorObject, "message", errMsgStr)) { + MISC_HILOGE("set error message failed"); + return; + } + env->ThrowError(static_cast(errorObject)); + return; +} + +static bool ParserParamFromVibrateTime(ani_env *env, ani_object effect, VibrateInfo &vibrateInfo) +{ + ani_ref type; + if (ANI_OK != env->Object_GetPropertyByName_Ref(effect, "type", &type)) { + MISC_HILOGE("Failed to get property named type"); + return false; + } + auto typeStr = AniStringUtils::ToStd(env, static_cast(type)); + vibrateInfo.type = typeStr; + MISC_HILOGD("vibrateInfo.type: %{public}s", typeStr.c_str()); + + ani_double duration; + if (ANI_OK != env->Object_GetPropertyByName_Double(effect, "duration", &duration)) { + MISC_HILOGE("Failed to get property named duration"); + return false; + } + vibrateInfo.duration = static_cast(duration); + MISC_HILOGD("vibrateInfo.duration: %{public}d", vibrateInfo.duration); + return true; +} + +static bool SetVibrateProperty(ani_env* env, ani_object effect, const char* propertyName, int32_t& propertyValue) +{ + ani_ref propertyRef; + ani_boolean isUndefined = false; + if (env->Object_GetPropertyByName_Ref(effect, propertyName, &propertyRef) != ANI_OK) { + MISC_HILOGD("Can not find \"%{public}s\" property", propertyName); + return false; + } + + env->Reference_IsUndefined(propertyRef, &isUndefined); + if (isUndefined) { + MISC_HILOGD("\"%{public}s\" is undefined", propertyName); + return false; + } + + ani_double result; + if (ANI_OK != env->Object_CallMethodByName_Double(static_cast(propertyRef), "doubleValue", nullptr, + &result)) { + MISC_HILOGE("Failed to call Method named doubleValue on property \"%{public}s\"", propertyName); + return false; + } + + propertyValue = static_cast(result); + MISC_HILOGD("\"%{public}s\": %{public}d", propertyName, propertyValue); + + return true; +} + +static bool ParserParamFromVibratePreset(ani_env *env, ani_object effect, VibrateInfo &vibrateInfo) +{ + ani_ref type; + if (ANI_OK != env->Object_GetPropertyByName_Ref(effect, "type", &type)) { + MISC_HILOGE("Failed to get property named type"); + return false; + } + auto typeStr = AniStringUtils::ToStd(env, static_cast(type)); + vibrateInfo.type = typeStr; + MISC_HILOGD("vibrateInfo.type: %{public}s", typeStr.c_str()); + + ani_ref effectId; + if (ANI_OK != env->Object_GetPropertyByName_Ref(effect, "effectId", &effectId)) { + MISC_HILOGE("Failed to get property named effectId"); + return false; + } + auto effectIdStr = AniStringUtils::ToStd(env, static_cast(effectId)); + vibrateInfo.effectId = effectIdStr; + MISC_HILOGD("effectId: %{public}s", vibrateInfo.effectId.c_str()); + + if (!SetVibrateProperty(env, effect, "count", vibrateInfo.count)) { + vibrateInfo.count = 1; + } + MISC_HILOGD("count: %{public}d", vibrateInfo.count); + + if (!SetVibrateProperty(env, effect, "intensity", vibrateInfo.intensity)) { + vibrateInfo.intensity = INTENSITY_ADJUST_MAX; + } + MISC_HILOGD("intensity: %{public}d", vibrateInfo.intensity); + return true; +} + +static bool SetVibratePropertyInt64(ani_env* env, ani_object effect, const char* propertyName, int64_t& propertyValue) +{ + ani_ref propertyRef; + ani_boolean isUndefined = false; + if (env->Object_GetPropertyByName_Ref(effect, propertyName, &propertyRef) != ANI_OK) { + MISC_HILOGD("Can not find \"%{public}s\" property", propertyName); + return false; + } + + env->Reference_IsUndefined(propertyRef, &isUndefined); + if (isUndefined) { + MISC_HILOGD("\"%{public}s\" is undefined", propertyName); + return false; + } + + ani_double result; + if (ANI_OK != env->Object_CallMethodByName_Double(static_cast(propertyRef), "doubleValue", nullptr, + &result)) { + MISC_HILOGE("Failed to call Method named doubleValue on property \"%{public}s\"", propertyName); + return false; + } + + propertyValue = static_cast(result); + MISC_HILOGD("\"%{public}s\": %{public}lld", propertyName, propertyValue); + + return true; +} + +static bool ParserParamFromVibrateFromFile(ani_env *env, ani_object effect, VibrateInfo &vibrateInfo) +{ + ani_ref type; + if (ANI_OK != env->Object_GetPropertyByName_Ref(effect, "type", &type)) { + MISC_HILOGE("Failed to get property named type"); + return false; + } + auto typeStr = AniStringUtils::ToStd(env, static_cast(type)); + vibrateInfo.type = typeStr; + + ani_ref hapticFd; + if (ANI_OK != env->Object_GetPropertyByName_Ref(effect, "hapticFd", &hapticFd)) { + MISC_HILOGE("Failed to get property named hapticFd"); + return false; + } + + ani_double fd; + if (ANI_OK != env->Object_GetPropertyByName_Double(static_cast(hapticFd), "fd", &fd)) { + MISC_HILOGE("Failed to get property named fd"); + return false; + } + vibrateInfo.fd = static_cast(fd); + MISC_HILOGD("vibrateInfo.type: %{public}s, vibrateInfo.fd: %{public}d", typeStr.c_str(), vibrateInfo.fd); + + SetVibratePropertyInt64(env, static_cast(hapticFd), "offset", vibrateInfo.offset); + MISC_HILOGD("vibrateInfo.offset: %{public}lld", vibrateInfo.offset); + int64_t fdSize = GetFileSize(vibrateInfo.fd); + if (!(vibrateInfo.offset >= 0) && (vibrateInfo.offset <= fdSize)) { + MISC_HILOGE("The parameter of offset is invalid"); + return false; + } + vibrateInfo.length = fdSize - vibrateInfo.offset; + SetVibratePropertyInt64(env, static_cast(hapticFd), "length", vibrateInfo.length); + MISC_HILOGD("vibrateInfo.length: %{public}lld", vibrateInfo.length); + return true; +} + +static bool SetVibrateBooleanProperty(ani_env* env, ani_object attribute, const char* propertyName, + VibrateInfo& vibrateInfo) +{ + ani_ref propertyRef; + ani_boolean isUndefined = false; + if (env->Object_GetPropertyByName_Ref(attribute, propertyName, &propertyRef) != ANI_OK) { + MISC_HILOGE("Failed to get \"%{public}s\" property", propertyName); + return false; + } + + env->Reference_IsUndefined(propertyRef, &isUndefined); + if (isUndefined) { + MISC_HILOGE("\"%{public}s\" is not undefined", propertyName); + return false; + } + + ani_boolean result; + if (ANI_OK != env->Object_CallMethodByName_Boolean(static_cast(propertyRef), "unboxed", nullptr, + &result)) { + MISC_HILOGE("Failed to call Method named unboxed on property \"%{public}s\"", propertyName); + return false; + } + + vibrateInfo.systemUsage = static_cast(result); + return true; +} + +static bool ParserParamFromVibrateAttribute(ani_env *env, ani_object attribute, VibrateInfo &vibrateInfo) +{ + ani_ref usage; + if (ANI_OK != env->Object_GetPropertyByName_Ref(attribute, "usage", &usage)) { + MISC_HILOGE("Object_GetPropertyByName_Ref Fail"); + return false; + } + auto usageStr = AniStringUtils::ToStd(env, static_cast(usage)); + vibrateInfo.usage = usageStr; + MISC_HILOGD("vibrateInfo.usage: %{public}s", vibrateInfo.usage.c_str()); + + if (!SetVibrateBooleanProperty(env, attribute, "systemUsage", vibrateInfo)) { + vibrateInfo.systemUsage = false; + } + MISC_HILOGD("vibrateInfo.systemUsage: %{public}d", vibrateInfo.systemUsage); + return true; +} + +static bool GetPropertyAsDouble(ani_env* env, ani_object obj, const char* propertyName, ani_double* outValue) +{ + ani_ref propRef = nullptr; + ani_boolean isUndefined = false; + + if (env->Object_GetPropertyByName_Ref(obj, propertyName, &propRef) != ANI_OK) { + MISC_HILOGE("GetPropertyAsDouble: Failed to get property '%{punlic}s'", propertyName); + return false; + } + + env->Reference_IsUndefined(propRef, &isUndefined); + if (isUndefined) { + MISC_HILOGE("GetPropertyAsDouble: Property '%{punlic}s' is undefined", propertyName); + return false; + } + + if (env->Object_CallMethodByName_Double(static_cast(propRef), "doubleValue", nullptr, outValue) != + ANI_OK) { + MISC_HILOGE("GetPropertyAsDouble: Failed to call 'doubleValue' on property '%{punlic}s'", propertyName); + return false; + } + + return true; +} + +static bool ParseVibratorCurvePoint(ani_env *env, ani_object pointsArray, uint32_t index, VibratorCurvePoint &point) +{ + auto array = static_cast(pointsArray); + ani_ref arrayRef; + if (env->Array_Get_Ref(array, index, &arrayRef) != ANI_OK) { + MISC_HILOGE("Array_Get_Ref Fail"); + return false; + } + ani_double time = 0; + if (ANI_OK != env->Object_GetPropertyByName_Double(static_cast(arrayRef), "time", &time)) { + MISC_HILOGE("Object_GetPropertyByName_Double Fail"); + return false; + } + point.time = static_cast(time); + MISC_HILOGD("ParseVibrateEvent point.time: %{public}d", point.time); + + ani_double intensity = 0; + ani_double frequency = 0; + if (GetPropertyAsDouble(env, static_cast(arrayRef), "intensity", &intensity)) { + point.intensity = static_cast(intensity); + MISC_HILOGD("ParseVibrateEvent point.intensity: %{public}d", point.intensity); + } + + if (GetPropertyAsDouble(env, static_cast(arrayRef), "frequency", &frequency)) { + point.frequency = static_cast(frequency); + MISC_HILOGD("ParseVibrateEvent point.frequency: %{public}d", point.frequency); + } + + return true; +} + +static bool ParseVibratorCurvePointArray(ani_env *env, ani_object pointsArray, uint32_t pointsLength, + VibratorEvent &event) +{ + if (pointsLength <= 0 || pointsLength > CURVE_POINT_NUM_MAX) { + MISC_HILOGE("pointsLength should not be less than or equal to 0 or greater than CURVE_POINT_NUM_MAX"); + return false; + } + VibratorCurvePoint *points = + static_cast(malloc(sizeof(VibratorCurvePoint) * pointsLength)); + if (points == nullptr) { + MISC_HILOGE("malloc failed"); + return false; + } + for (uint32_t i = 0; i < pointsLength; ++i) { + if (!ParseVibratorCurvePoint(env, pointsArray, i, points[i])) { + MISC_HILOGE("ParseVibratorCurvePoint failed"); + free(points); + points = nullptr; + return false; + } + } + event.points = points; + return true; +} + +static bool ParsePointsArray(ani_env *env, ani_object parentObject, VibratorEvent &event) +{ + ani_ref points = nullptr; + ani_boolean isUndefined = false; + if (env->Object_GetPropertyByName_Ref(parentObject, "points", &points) != ANI_OK) { + MISC_HILOGE("Can not find \"points\" property"); + return false; + } + + env->Reference_IsUndefined(points, &isUndefined); + if (isUndefined) { + MISC_HILOGE("\"points\" is undefined"); + return true; + } + + ani_size sizePoints = 0; + if (env->Array_GetLength(static_cast(points), &sizePoints) != ANI_OK) { + MISC_HILOGE("Get point array length failed"); + return false; + } + + event.pointNum = static_cast(sizePoints); + + if (static_cast(sizePoints) > 0) { + if (!ParseVibratorCurvePointArray(env, static_cast(points), + static_cast(sizePoints), event)) { + MISC_HILOGE("ParseVibratorCurvePointArray failed"); + return false; + } + } + + return true; +} + +static bool ParseVibrateEvent(ani_env *env, ani_object eventArray, int32_t index, VibratorEvent &event) +{ + auto array = static_cast(eventArray); + ani_ref arrayRef; + if (env->Array_Get_Ref(array, index, &arrayRef) != ANI_OK) { + MISC_HILOGE("Array_Get_Ref Fail"); + return false; + } + ani_ref aniEventType; + if (ANI_OK != env->Object_GetPropertyByName_Ref(static_cast(arrayRef), "eventType", &aniEventType)) { + MISC_HILOGE("Can not find \"eventType\" property"); + return false; + } + + EnumAccessor eventTypeAccessor(env, static_cast(aniEventType)); + expected eventTypeExpected = eventTypeAccessor.To(); + if (!eventTypeExpected) { + return false; + } + VibratorEventType eventType = eventTypeExpected.value(); + event.type = eventType; + + ani_double time; + if (ANI_OK != env->Object_GetPropertyByName_Double(static_cast(arrayRef), "time", &time)) { + MISC_HILOGE("Failed to get property named time"); + return false; + } + event.time = static_cast(time); + + ani_double duration; + if (GetPropertyAsDouble(env, static_cast(arrayRef), "duration", &duration)) { + event.duration = static_cast(duration); + } + + ani_double intensity; + if (GetPropertyAsDouble(env, static_cast(arrayRef), "intensity", &intensity)) { + event.intensity = static_cast(intensity); + MISC_HILOGD("intensity: %{public}d", event.intensity); + } + + ani_double frequency; + if (GetPropertyAsDouble(env, static_cast(arrayRef), "frequency", &frequency)) { + event.frequency = static_cast(frequency); + MISC_HILOGD("frequency: %{public}d", event.frequency); + } + + ani_double aniIndex; + if (GetPropertyAsDouble(env, static_cast(arrayRef), "index", &aniIndex)) { + event.index = static_cast(aniIndex); + MISC_HILOGD("index: %{public}d", event.index); + } + + if (!ParsePointsArray(env, static_cast(arrayRef), event)) { + return false; + } + + return true; +} + +static void PrintVibratorPattern(VibratorPattern &vibratorPattern) +{ + CALL_LOG_ENTER; + 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].pointNum > 0) { + 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); + } + } + } +} + +static bool CheckVibratorCurvePoint(const VibratorEvent &event) +{ + if ((event.pointNum < CURVE_POINT_NUM_MIN) || (event.pointNum > CURVE_POINT_NUM_MAX)) { + MISC_HILOGE("The points size is out of range, pointNum:%{public}d", event.pointNum); + return false; + } + for (int32_t j = 0; j < event.pointNum; ++j) { + if ((event.points[j].time < 0) || (event.points[j].time > event.duration)) { + MISC_HILOGE("time in points is out of range, time:%{public}d", event.points[j].time); + return false; + } + if ((event.points[j].intensity < 0) || (event.points[j].intensity > CURVE_POINT_INTENSITY_MAX)) { + MISC_HILOGE("intensity in points is out of range, intensity:%{public}d", event.points[j].intensity); + return false; + } + if ((event.points[j].frequency < CURVE_FREQUENCY_MIN) || (event.points[j].frequency > CURVE_FREQUENCY_MAX)) { + MISC_HILOGE("frequency in points is out of range, frequency:%{public}d", event.points[j].frequency); + return false; + } + } + return true; +} + +static bool CheckVibratorEvent(const VibratorEvent &event) +{ + 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.index < 0) || (event.index > EVENT_INDEX_MAX)) { + MISC_HILOGE("The event index is out of range, index:%{public}d", event.index); + return false; + } + if ((event.type == VibratorEventType::EVENT_TYPE_CONTINUOUS) && (event.pointNum > 0)) { + if (!CheckVibratorCurvePoint(event)) { + MISC_HILOGE("CheckVibratorCurvePoint failed"); + return false; + } + } + return true; +} + +static bool CheckVibratorPatternParameter(VibratorPattern &vibratorPattern) +{ + CALL_LOG_ENTER; + if (vibratorPattern.events == nullptr) { + MISC_HILOGE("Events is nullptr"); + return false; + } + if ((vibratorPattern.eventNum <= 0) || (vibratorPattern.eventNum > EVENT_NUM_MAX)) { + MISC_HILOGE("The event num is out of range, eventNum:%{public}d", vibratorPattern.eventNum); + return false; + } + for (int32_t i = 0; i < vibratorPattern.eventNum; ++i) { + if (!CheckVibratorEvent(vibratorPattern.events[i])) { + MISC_HILOGE("CheckVibratorEvent failed"); + return false; + } + } + return true; +} + +static bool ParseVibratorPatternEvents(ani_env *env, ani_object patternObj, VibratorPattern &pattern) +{ + ani_ref eventArray; + if (ANI_OK != env->Object_GetPropertyByName_Ref(static_cast(patternObj), "events", &eventArray)) { + MISC_HILOGE("Failed to get property named events"); + return false; + } + + ani_size size; + if (ANI_OK != env->Array_GetLength(static_cast(eventArray), &size)) { + MISC_HILOGE("Array_GetLength failed"); + return false; + } + + pattern.eventNum = static_cast(size); + MISC_HILOGD("ProcessVibratorPattern eventNum: %{public}d", pattern.eventNum); + + if (size <= 0 || size > EVENT_NUM_MAX) { + MISC_HILOGE("length should not be less than or equal to 0 or greater than EVENT_NUM_MAX"); + return false; + } + VibratorEvent *eventsAlloc = + static_cast(malloc(sizeof(VibratorEvent) * static_cast(size))); + if (eventsAlloc == nullptr) { + MISC_HILOGE("Events is nullptr"); + return false; + } + + for (uint32_t j = 0; j < size; ++j) { + new (&eventsAlloc[j]) VibratorEvent(); + if (!ParseVibrateEvent(env, static_cast(eventArray), j, eventsAlloc[j])) { + MISC_HILOGE("ParseVibrateEvent failed"); + free(eventsAlloc); + eventsAlloc = nullptr; + return false; + } + } + pattern.events = eventsAlloc; + return true; +} + +static bool ParserParamFromVibratePattern(ani_env *env, ani_object effect, VibrateInfo &vibrateInfo) +{ + MISC_HILOGD("ParserParamFromVibratePattern enter"); + ani_ref type; + if (ANI_OK != env->Object_GetPropertyByName_Ref(effect, "type", &type)) { + MISC_HILOGE("Failed to get property named type"); + return false; + } + auto typeStr = AniStringUtils::ToStd(env, static_cast(type)); + vibrateInfo.type = typeStr; + + ani_ref pattern; + if (ANI_OK != env->Object_GetPropertyByName_Ref(effect, "pattern", &pattern)) { + MISC_HILOGE("Failed to get property named pattern"); + return false; + } + + ani_double time; + if (ANI_OK != env->Object_GetPropertyByName_Double(static_cast(pattern), "time", &time)) { + MISC_HILOGE("Failed to get property named time"); + return false; + } + + vibrateInfo.vibratorPattern.time = static_cast(time); + MISC_HILOGD("ProcessVibratorPattern time: %{public}d", vibrateInfo.vibratorPattern.time); + + if (!ParseVibratorPatternEvents(env, static_cast(pattern), vibrateInfo.vibratorPattern)) { + return false; + } + + PrintVibratorPattern(vibrateInfo.vibratorPattern); + + if (!CheckVibratorPatternParameter(vibrateInfo.vibratorPattern)) { + MISC_HILOGE("CheckVibratorPatternParameter fail"); + return false; + } + return true; +} + +bool SetUsage(const std::string &usage, bool systemUsage) +{ + if (auto iter = g_usageType.find(usage); iter == g_usageType.end()) { + MISC_HILOGE("Wrong usage type"); + return false; + } + return SetUsage(g_usageType[usage], systemUsage); +} + +static int32_t StartVibrate(const VibrateInfo &info) +{ + if (!SetUsage(info.usage, info.systemUsage)) { + MISC_HILOGE("SetUsage fail"); + return PARAMETER_ERROR; + } + if (g_allowedTypes.find(info.type) == g_allowedTypes.end()) { + MISC_HILOGE("Invalid vibrate type, type:%{public}s", info.type.c_str()); + return PARAMETER_ERROR; + } + if (info.type == "preset") { + if (!SetLoopCount(info.count)) { + MISC_HILOGE("SetLoopCount fail"); + return PARAMETER_ERROR; + } + return PlayPrimitiveEffect(info.effectId.c_str(), info.intensity); + } 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); +} + +static ani_class FindClassInNamespace(ani_env *env, ani_namespace &ns, const char *className) +{ + ani_class cls; + if (ANI_OK != env->Namespace_FindClass(ns, className, &cls)) { + MISC_HILOGE("Not found '%{public}s'", className); + return nullptr; + } + return cls; +} + +static bool ParseEffectTypeAndParameters(ani_env *env, ani_object effect, VibrateInfo &vibrateInfo) +{ + ani_namespace ns; + static const char *namespaceName = "L@ohos/vibrator/vibrator;"; + if (ANI_OK != env->FindNamespace(namespaceName, &ns)) { + MISC_HILOGE("Not found '%{public}s'", namespaceName); + return false; + } + + ani_class vibrateTimeClass = FindClassInNamespace(env, ns, "LVibrateTime;"); + ani_class vibratePresetClass = FindClassInNamespace(env, ns, "LVibratePreset;"); + ani_class vibrateFromFileClass = FindClassInNamespace(env, ns, "LVibrateFromFile;"); + ani_class vibratePatternClass = FindClassInNamespace(env, ns, "LVibrateFromPattern;"); + if (!vibrateTimeClass || !vibratePresetClass || !vibrateFromFileClass || !vibratePatternClass) { + return false; + } + + ani_boolean isInstanceOfTime = ANI_FALSE; + env->Object_InstanceOf(effect, vibrateTimeClass, &isInstanceOfTime); + ani_boolean isInstanceOfPreset = ANI_FALSE; + env->Object_InstanceOf(effect, vibratePresetClass, &isInstanceOfPreset); + ani_boolean isInstanceOfFile = ANI_FALSE; + env->Object_InstanceOf(effect, vibrateFromFileClass, &isInstanceOfFile); + ani_boolean isInstanceOfPattern = ANI_FALSE; + env->Object_InstanceOf(effect, vibratePatternClass, &isInstanceOfPattern); + + if (isInstanceOfTime) { + if (!ParserParamFromVibrateTime(env, effect, vibrateInfo)) { + ThrowBusinessError(env, PARAMETER_ERROR, "ParserParamFromVibrateTime failed!"); + return false; + } + } else if (isInstanceOfPreset) { + if (!ParserParamFromVibratePreset(env, effect, vibrateInfo)) { + ThrowBusinessError(env, PARAMETER_ERROR, "ParserParamFromVibratePreset failed!"); + return false; + } + } else if (isInstanceOfFile) { + if (!ParserParamFromVibrateFromFile(env, effect, vibrateInfo)) { + ThrowBusinessError(env, PARAMETER_ERROR, "ParserParamFromVibrateFromFile failed!"); + return false; + } + } else if (isInstanceOfPattern) { + if (!ParserParamFromVibratePattern(env, effect, vibrateInfo)) { + ThrowBusinessError(env, PARAMETER_ERROR, "ParserParamFromVibratePattern failed!"); + return false; + } + } else { + ThrowBusinessError(env, PARAMETER_ERROR, "Unknown effect type"); + return false; + } + + return true; +} + +static void StartVibrationSync([[maybe_unused]] ani_env *env, ani_object effect, ani_object attribute) +{ + ani_namespace ns; + static const char *namespaceName = "L@ohos/vibrator/vibrator;"; + if (ANI_OK != env->FindNamespace(namespaceName, &ns)) { + MISC_HILOGE("Not found '%{public}s'", namespaceName); + return; + } + + ani_class vibrateAttributeClass = FindClassInNamespace(env, ns, "LVibrateAttribute;"); + if (!vibrateAttributeClass) { + return; + } + + VibrateInfo vibrateInfo; + if (!ParseEffectTypeAndParameters(env, effect, vibrateInfo)) { + return; + } + if (!ParserParamFromVibrateAttribute(env, attribute, vibrateInfo)) { + ThrowBusinessError(env, PARAMETER_ERROR, "ParserParamFromVibrateAttribute failed!"); + return; + } + StartVibrate(vibrateInfo); +} + +static bool IsSupportEffectInterally([[maybe_unused]] ani_env *env, ani_string effectId) +{ + auto effectIdStr = AniStringUtils::ToStd(env, static_cast(effectId)); + MISC_HILOGD("effectId:%{public}s", effectIdStr.c_str()); + + bool isSupportEffect = false; + if (IsSupportEffect(effectIdStr.c_str(), &isSupportEffect) != 0) { + MISC_HILOGE("Query effect support failed"); + } + return isSupportEffect; +} + +ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) +{ + ani_env *env; + if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) { + MISC_HILOGE("Unsupported ANI_VERSION_1"); + return ANI_ERROR; + } + + static const char *namespaceName = "L@ohos/vibrator/vibrator;"; + ani_namespace ns; + if (ANI_OK != env->FindNamespace(namespaceName, &ns)) { + MISC_HILOGE("Not found '%{public}s'", namespaceName); + return ANI_NOT_FOUND; + } + + std::array methods = { + ani_native_function {"startVibrationSync", nullptr, reinterpret_cast(StartVibrationSync)}, + ani_native_function {"isSupportEffectInterally", nullptr, reinterpret_cast(IsSupportEffectInterally)}, + }; + + if (ANI_OK != env->Namespace_BindNativeFunctions(ns, methods.data(), methods.size())) { + MISC_HILOGE("Cannot bind native methods to '%{public}s'", namespaceName); + return ANI_NOT_FOUND; + }; + + *result = ANI_VERSION_1; + return ANI_OK; +} \ No newline at end of file