From 7dff70631866ca5f8309a56c66d56b15a3a4eb60 Mon Sep 17 00:00:00 2001 From: songhuan Date: Sat, 29 Mar 2025 19:09:49 +0800 Subject: [PATCH 1/2] =?UTF-8?q?sensor=20on&off=E6=8E=A5=E5=8F=A3ANI?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: songhuan Change-Id: Ida2ecffdc9d02dbe87c6db72b9668feb0e4af581 --- bundle.json | 4 +- frameworks/js/ani/BUILD.gn | 76 +++++ frameworks/js/ani/ets/@ohos.sensor.ets | 46 +++ frameworks/js/ani/include/ani_utils.h | 383 +++++++++++++++++++++++++ frameworks/js/ani/include/sensor_ani.h | 126 ++++++++ frameworks/js/ani/src/sensor_ani.cpp | 270 +++++++++++++++++ 6 files changed, 904 insertions(+), 1 deletion(-) create mode 100644 frameworks/js/ani/BUILD.gn create mode 100644 frameworks/js/ani/ets/@ohos.sensor.ets create mode 100644 frameworks/js/ani/include/ani_utils.h create mode 100644 frameworks/js/ani/include/sensor_ani.h create mode 100644 frameworks/js/ani/src/sensor_ani.cpp diff --git a/bundle.json b/bundle.json index b5207319..d024ec08 100755 --- a/bundle.json +++ b/bundle.json @@ -32,7 +32,8 @@ "memmgr", "safwk", "samgr", - "eventhandler" + "eventhandler", + "runtime_core" ], "third_party": [] }, @@ -41,6 +42,7 @@ "base_group": [], "fwk_group": [ "//base/sensors/sensor/frameworks/js/napi:sensor_js_target", + "//base/sensors/sensor/frameworks/js/ani:sensor_ani_target", "//base/sensors/sensor/frameworks/cj:cj_sensor_ffi", "//base/sensors/sensor/frameworks/native:sensor_target", "//base/sensors/sensor/frameworks/native:ohsensor", diff --git a/frameworks/js/ani/BUILD.gn b/frameworks/js/ani/BUILD.gn new file mode 100644 index 00000000..94d9e6f2 --- /dev/null +++ b/frameworks/js/ani/BUILD.gn @@ -0,0 +1,76 @@ +# 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("./../../../sensor.gni") + +ohos_shared_library("sensor_ani") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + + sources = [ "src/sensor_ani.cpp" ] + include_dirs = [ + "include", + "$SUBSYSTEM_DIR/frameworks/native/include", + "$SUBSYSTEM_DIR/interfaces/inner_api", + "$SUBSYSTEM_DIR/utils/common/include", + ] + deps = [ + "$SUBSYSTEM_DIR/frameworks/native:sensor_interface_native", + "$SUBSYSTEM_DIR/utils/common:libsensor_utils", + ] + + external_deps = [ + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_single", + "runtime_core:ani", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + ] + + subsystem_name = "sensors" + part_name = "sensor" + output_extension = "so" +} + +generate_static_abc("sensor_abc") { + base_url = "./ets" + files = [ "./ets/@ohos.sensor.ets" ] + dst_file = "$target_out_dir/sensor.abc" + out_puts = [ "$target_out_dir/sensor.abc" ] + is_boot_abc = "True" + device_dst_file = "/system/framework/sensor.abc" +} + +ohos_prebuilt_etc("sensor_abc_etc") { + source = "$target_out_dir/sensor.abc" + module_install_dir = "framework" + subsystem_name = "sensors" + part_name = "sensor" + deps = [ ":sensor_abc" ] +} + +group("sensor_ani_target") { + deps = [ + ":sensor_abc_etc", + ":sensor_ani", + ] +} diff --git a/frameworks/js/ani/ets/@ohos.sensor.ets b/frameworks/js/ani/ets/@ohos.sensor.ets new file mode 100644 index 00000000..4ebcdf77 --- /dev/null +++ b/frameworks/js/ani/ets/@ohos.sensor.ets @@ -0,0 +1,46 @@ +/* + * 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 { Callback } from '@ohos.base'; +import { BusinessError } from '@ohos.base'; + +export default namespace sensor { + loadLibrary("sensor_ani"); + + export native function on(type: 'ORIENTATION', callback: Callback, options?: Options): void; + export native function off(type: 'ORIENTATION', callback?: Callback): void; + export type SensorFrequency = 'game' | 'ui' | 'normal'; + export interface Options { + interval?: number | SensorFrequency; + } + + export enum SensorAccuracy { + ACCURACY_UNRELIABLE = 0, + ACCURACY_LOW = 1, + ACCURACY_MEDIUM = 2, + ACCURACY_HIGH = 3 + } + + export interface Response { + timestamp: number; + accuracy: SensorAccuracy; + } + + export interface OrientationResponse extends Response { + alpha: number; + beta: number; + gamma: number; + } +} \ No newline at end of file diff --git a/frameworks/js/ani/include/ani_utils.h b/frameworks/js/ani/include/ani_utils.h new file mode 100644 index 00000000..a1ea2975 --- /dev/null +++ b/frameworks/js/ani/include/ani_utils.h @@ -0,0 +1,383 @@ +/* + * 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 + +template +class NativeObjectWrapper { +public: + static ani_object Create([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_class clazz) + { + T* nativePtr = new T; + return Wrap(env, clazz, nativePtr); + } + + static ani_object Wrap([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_class clazz, T* nativePtr) + { + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(clazz, "", "J:V", &ctor)) { + std::cerr << "Not found ''" << std::endl; + ani_object nullobj = nullptr; + return nullobj; + } + + ani_object obj; + if (ANI_OK != env->Object_New(clazz, ctor, &obj, reinterpret_cast(nativePtr))) { + std::cerr << "Object_New failed" << std::endl; + } + return obj; + } + + static T* Unwrap(ani_env *env, ani_object object, const char* propName = "nativePtr") + { + ani_long nativePtr; + if (ANI_OK != env->Object_GetFieldByName_Long(object, propName, &nativePtr)) { + return nullptr; + } + return reinterpret_cast(nativePtr); + } + + static ani_status Attach(ani_env *env, ani_object object, T* nativePtr, const char* propName = "nativePtr") + { + return env->Object_SetFieldByName_Long(object, propName, reinterpret_cast(nativePtr)); + } +}; + +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; +} +#endif diff --git a/frameworks/js/ani/include/sensor_ani.h b/frameworks/js/ani/include/sensor_ani.h new file mode 100644 index 00000000..e7e3f888 --- /dev/null +++ b/frameworks/js/ani/include/sensor_ani.h @@ -0,0 +1,126 @@ +/* + * 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 SENSOR_ANI_H +#define SENSOR_ANI_H + +#include "refbase.h" + +#include "sensor_agent_type.h" +#include "sensor_errors.h" +#include "sensor_log.h" + +#undef LOG_TAG +#define LOG_TAG "SensorAniAPI" + +namespace OHOS { +namespace Sensors { +using std::vector; +using std::string; +using namespace OHOS::HiviewDFX; +constexpr int32_t THREE_DIMENSIONAL_MATRIX_LENGTH = 9; +constexpr static int32_t DATA_LENGTH = 16; +constexpr int32_t CALLBACK_NUM = 3; +enum CallbackDataType { + SUBSCRIBE_FAIL = -2, + FAIL = -1, + OFF_CALLBACK = 0, + ON_CALLBACK = 1, + ONCE_CALLBACK = 2, + GET_GEOMAGNETIC_FIELD = 3, + GET_ALTITUDE = 4, + GET_GEOMAGNETIC_DIP = 5, + GET_ANGLE_MODIFY = 6, + CREATE_ROTATION_MATRIX = 7, + TRANSFORM_COORDINATE_SYSTEM = 8, + CREATE_QUATERNION = 9, + GET_DIRECTION = 10, + ROTATION_INCLINATION_MATRIX = 11, + GET_SENSOR_LIST = 12, + GET_SINGLE_SENSOR = 13, + SUBSCRIBE_CALLBACK = 14, + SUBSCRIBE_COMPASS = 15, + GET_BODY_STATE = 16, +}; + +struct GeomagneticData { + float x; + float y; + float z; + float geomagneticDip; + float deflectionAngle; + float levelIntensity; + float totalIntensity; +}; + +struct RationMatrixData { + float rotationMatrix[THREE_DIMENSIONAL_MATRIX_LENGTH]; + float inclinationMatrix[THREE_DIMENSIONAL_MATRIX_LENGTH]; +}; + +struct CallbackSensorData { + int32_t sensorTypeId; + uint32_t dataLength; + float data[DATA_LENGTH]; + int64_t timestamp; + int32_t sensorAccuracy; +}; + +struct ReserveData { + float reserve[DATA_LENGTH]; + int32_t length; +}; + +union CallbackData { + CallbackSensorData sensorData; + GeomagneticData geomagneticData; + RationMatrixData rationMatrixData; + ReserveData reserveData; +}; + +struct BusinessError { + int32_t code { 0 }; + string message; + string name; + string stack; +}; + +class AsyncCallbackInfo : public RefBase { +public: + ani_env* env = nullptr; + ani_ref callback[CALLBACK_NUM] = { 0 }; + CallbackData data; + BusinessError error; + CallbackDataType type; + vector sensorInfos; + AsyncCallbackInfo(ani_env* env, CallbackDataType type) : env(env), type(type) {} + ~AsyncCallbackInfo() + { + CALL_LOG_ENTER; + if (type != ONCE_CALLBACK) { + for (int32_t i = 0; i < CALLBACK_NUM; ++i) { + if (callback[i] != nullptr) { + SEN_HILOGD("Delete reference, i:%{public}d", i); + env->GlobalReference_Delete(callback[i]); + callback[i] = nullptr; + } + } + } + } + +private: +}; +} // namespace Sensors +} // namespace OHOS +#endif // SENSOR_ANI_H \ No newline at end of file diff --git a/frameworks/js/ani/src/sensor_ani.cpp b/frameworks/js/ani/src/sensor_ani.cpp new file mode 100644 index 00000000..779ae500 --- /dev/null +++ b/frameworks/js/ani/src/sensor_ani.cpp @@ -0,0 +1,270 @@ +/* + * 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 +#include +#include +#include +#include + +#include "refbase.h" +#include "securec.h" + +#include "ani_utils.h" +#include "sensor_agent.h" +#include "sensor_errors.h" +#include "sensor_agent_type.h" +#include "sensor_ani.h" + +#undef LOG_TAG +#define LOG_TAG "SensorAniAPI" + +using namespace OHOS; +using namespace OHOS::Sensors; + +constexpr int32_t REPORTING_INTERVAL = 200000000; +constexpr int32_t INVALID_SENSOR_ID = -1; +static std::mutex onMutex_; + +std::unordered_map stringToNumberMap = { + {"ORIENTATION", 256}, + {"MAGNETIC_FIELD_UNCALIBRATED", 261} +}; + +static std::map g_samplingPeriod = { + {"normal", 200000000}, + {"ui", 60000000}, + {"game", 20000000}, +}; + +static void EmitOnCallback(SensorEvent *event) +{ + return; +} + +void DataCallbackImpl(SensorEvent *event) +{ + EmitOnCallback(event); +} + +const SensorUser user = { + .callback = DataCallbackImpl +}; + +int32_t SubscribeSensor(int32_t sensorTypeId, int64_t interval, RecordSensorCallback callback) +{ + int32_t ret = SubscribeSensor(sensorTypeId, &user); + if (ret != ERR_OK) { + SEN_HILOGE("SubscribeSensor failed"); + return ret; + } + ret = SetBatch(sensorTypeId, &user, interval, 0); + if (ret != ERR_OK) { + SEN_HILOGE("SetBatch failed"); + return ret; + } + return ActivateSensor(sensorTypeId, &user); +} + +static void UpdateCallbackInfos(ani_env *env, int32_t sensorTypeId, ani_object callback) +{ + return; +} + +bool GetIntervalValue(ani_env *env, ani_object options, int64_t& interval) +{ + ani_boolean isUndefined; + env->Reference_IsUndefined(options, &isUndefined); + if (isUndefined) { + return true; + } + + ani_ref intervalRef; + ani_boolean isIntervalUndefined; + if (ANI_OK != env->Object_GetPropertyByName_Ref(options, "interval", &intervalRef)) { + SEN_HILOGE("Failed to get property named interval"); + return false; + } + + env->Reference_IsUndefined(intervalRef, &isIntervalUndefined); + if (isIntervalUndefined) { + std::cerr << "interval is undefined" << std::endl; + return false; + } + + ani_class stringClass; + env->FindClass("Lstd/core/String;", &stringClass); + + ani_class doubleClass; + env->FindClass("Lstd/core/Double;", &doubleClass); + + ani_boolean isDouble; + env->Object_InstanceOf(static_cast(intervalRef), doubleClass, &isDouble); + ani_boolean isString; + env->Object_InstanceOf(static_cast(intervalRef), stringClass, &isString); + if (isDouble) { + ani_double doubleValue; + auto ret = env->Object_CallMethodByName_Double(static_cast(intervalRef), "unboxed", + nullptr, &doubleValue); + if (ret != ANI_OK) { + SEN_HILOGE("Failed to get property named doubleValue"); + return false; + } + interval = static_cast(doubleValue); + return true; + } + + if (isString) { + auto mode = AniStringUtils::ToStd(env, static_cast(intervalRef)); + auto iter = g_samplingPeriod.find(mode); + if (iter == g_samplingPeriod.end()) { + SEN_HILOGE("Find interval mode failed"); + return false; + } + interval = iter->second; + return true; + } + + SEN_HILOGE("Invalid interval type"); + return false; +} + +int ParseStringToNumber(const std::string& str) +{ + std::string upperStr; + for (char c : str) { + upperStr += std::toupper(c); + } + + if (stringToNumberMap.find(upperStr) != stringToNumberMap.end()) { + return stringToNumberMap[upperStr]; + } else { + return -1; + } +} + +static void On([[maybe_unused]] ani_env *env, ani_string typeId, ani_object callback, ani_object options) +{ + SEN_HILOGD("sensor on start"); + + int32_t sensorTypeId = INVALID_SENSOR_ID; + auto typeIdStr = AniStringUtils::ToStd(env, static_cast(typeId)); + auto typeIdVal = ParseStringToNumber(typeIdStr); + if (typeIdVal == -1) { + SEN_HILOGE("Invalid sensor typeId: %{public}s", typeIdStr.c_str()); + return; + } + std::cout << "typeIdVal: " << typeIdVal << std::endl; + sensorTypeId = typeIdVal; + + int64_t interval = REPORTING_INTERVAL; + if (!GetIntervalValue(env, options, interval)) { + SEN_HILOGW("Get interval failed"); + } + int32_t ret = SubscribeSensor(sensorTypeId, interval, DataCallbackImpl); + if (ret != ERR_OK) { + SEN_HILOGE("SubscribeSensor fail"); + return; + } + UpdateCallbackInfos(env, sensorTypeId, callback); + SEN_HILOGD("sensor on end"); +} + +static int32_t RemoveAllCallback(ani_env *env, int32_t sensorTypeId) +{ + return 0; +} + +static int32_t RemoveCallback(ani_env *env, int32_t sensorTypeId, ani_object callback) +{ + return 0; +} + +int32_t UnsubscribeSensor(int32_t sensorTypeId) +{ + int32_t ret = DeactivateSensor(sensorTypeId, &user); + if (ret != ERR_OK) { + SEN_HILOGE("DeactivateSensor failed"); + return ret; + } + return UnsubscribeSensor(sensorTypeId, &user); +} + +static void Off([[maybe_unused]] ani_env *env, ani_string type, ani_object callback) +{ + SEN_HILOGD("sensor off start"); + + int32_t sensorTypeId = INVALID_SENSOR_ID; + auto typeStr = AniStringUtils::ToStd(env, static_cast(type)); + auto typeStrVal = ParseStringToNumber(typeStr); + if (typeStrVal == -1) { + SEN_HILOGE("Invalid sensor type: %{public}s", typeStr.c_str()); + return; + } + sensorTypeId = typeStrVal; + + int32_t subscribeSize = -1; + ani_boolean isUndefined; + env->Reference_IsUndefined(callback, &isUndefined); + if (isUndefined) { + subscribeSize = RemoveAllCallback(env, sensorTypeId); + } else { + ani_boolean result; + if (env->Reference_IsNull(callback, &result) == ANI_OK && result) { + subscribeSize = RemoveAllCallback(env, sensorTypeId); + } else { + subscribeSize = RemoveCallback(env, sensorTypeId, callback); + } + } + + int32_t ret = UnsubscribeSensor(sensorTypeId); + if (ret == PARAMETER_ERROR || ret == PERMISSION_DENIED) { + SEN_HILOGE("UnsubscribeSensor fail"); + } + SEN_HILOGD("sensor off end"); + return; +} + +ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) +{ + ani_env *env; + if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) { + SEN_HILOGE("Unsupported ANI_VERSION_1"); + return ANI_ERROR; + } + + ani_namespace ns; + static const char *spaceName = "L@ohos/sensor/sensor;"; + if (ANI_OK != env->FindNamespace(spaceName, &ns)) { + SEN_HILOGE("Not found space name"); + return ANI_ERROR; + } + + std::array methods = { + ani_native_function {"on", nullptr, reinterpret_cast(On)}, + ani_native_function {"off", nullptr, reinterpret_cast(Off)}, + }; + + if (ANI_OK != env->Namespace_BindNativeFunctions(ns, methods.data(), methods.size())) { + SEN_HILOGE("Cannot bind native methods to %{public}s", spaceName); + return ANI_ERROR; + } + + *result = ANI_VERSION_1; + return ANI_OK; +} \ No newline at end of file -- Gitee From c1bd60cc9e7f71c4b6d1c4f7cef38a1c2ea0277d Mon Sep 17 00:00:00 2001 From: songhuan Date: Mon, 31 Mar 2025 17:36:16 +0800 Subject: [PATCH 2/2] =?UTF-8?q?sensor=20on&off=E6=8E=A5=E5=8F=A3=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ifc5f4cbbdd1d47fccd9a3d7dc246038e57a3a803 Signed-off-by: songhuan --- frameworks/js/ani/BUILD.gn | 1 + frameworks/js/ani/ets/@ohos.sensor.ets | 8 + frameworks/js/ani/include/ani_utils.h | 32 +- frameworks/js/ani/include/sensor_ani.h | 10 +- frameworks/js/ani/src/sensor_ani.cpp | 471 ++++++++++++++++++++++--- 5 files changed, 469 insertions(+), 53 deletions(-) diff --git a/frameworks/js/ani/BUILD.gn b/frameworks/js/ani/BUILD.gn index 94d9e6f2..c56092f3 100644 --- a/frameworks/js/ani/BUILD.gn +++ b/frameworks/js/ani/BUILD.gn @@ -39,6 +39,7 @@ ohos_shared_library("sensor_ani") { "bundle_framework:appexecfwk_base", "bundle_framework:appexecfwk_core", "c_utils:utils", + "eventhandler:libeventhandler", "hilog:libhilog", "ipc:ipc_single", "runtime_core:ani", diff --git a/frameworks/js/ani/ets/@ohos.sensor.ets b/frameworks/js/ani/ets/@ohos.sensor.ets index 4ebcdf77..31b4c552 100644 --- a/frameworks/js/ani/ets/@ohos.sensor.ets +++ b/frameworks/js/ani/ets/@ohos.sensor.ets @@ -43,4 +43,12 @@ export default namespace sensor { beta: number; gamma: number; } + + class OrientationResponseImpl implements OrientationResponse { + timestamp: number; + accuracy: SensorAccuracy; + alpha: number; + beta: number; + gamma: number; + } } \ No newline at end of file diff --git a/frameworks/js/ani/include/ani_utils.h b/frameworks/js/ani/include/ani_utils.h index a1ea2975..8f2605f0 100644 --- a/frameworks/js/ani/include/ani_utils.h +++ b/frameworks/js/ani/include/ani_utils.h @@ -380,4 +380,34 @@ std::optional OptionalAccessor::Convert() std::string content = std::string(utf8_buffer); return content; } -#endif + +class AniLocalScopeGuard { +public: + AniLocalScopeGuard(ani_env *env, size_t nrRefs) : env_(env) + { + status_ = env_->CreateLocalScope(nrRefs); + } + + ~AniLocalScopeGuard() + { + if (ANI_OK != status_) { + return; + } + env_->DestroyLocalScope(); + } + + bool IsStatusOK() + { + return ANI_OK == status_; + } + + ani_status GetStatus() + { + return status_; + } + +private: + ani_env *env_ = nullptr; + ani_status status_ = ANI_ERROR; +}; +#endif \ No newline at end of file diff --git a/frameworks/js/ani/include/sensor_ani.h b/frameworks/js/ani/include/sensor_ani.h index e7e3f888..3fd5c5a6 100644 --- a/frameworks/js/ani/include/sensor_ani.h +++ b/frameworks/js/ani/include/sensor_ani.h @@ -15,8 +15,16 @@ #ifndef SENSOR_ANI_H #define SENSOR_ANI_H -#include "refbase.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "refbase.h" #include "sensor_agent_type.h" #include "sensor_errors.h" #include "sensor_log.h" diff --git a/frameworks/js/ani/src/sensor_ani.cpp b/frameworks/js/ani/src/sensor_ani.cpp index 779ae500..93998192 100644 --- a/frameworks/js/ani/src/sensor_ani.cpp +++ b/frameworks/js/ani/src/sensor_ani.cpp @@ -13,23 +13,11 @@ * limitations under the License. */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "refbase.h" +#include "sensor_ani.h" #include "securec.h" - #include "ani_utils.h" #include "sensor_agent.h" -#include "sensor_errors.h" -#include "sensor_agent_type.h" -#include "sensor_ani.h" +#include "event_handler.h" #undef LOG_TAG #define LOG_TAG "SensorAniAPI" @@ -39,11 +27,44 @@ using namespace OHOS::Sensors; constexpr int32_t REPORTING_INTERVAL = 200000000; constexpr int32_t INVALID_SENSOR_ID = -1; -static std::mutex onMutex_; +constexpr float BODY_STATE_EXCEPT = 1.0f; +constexpr float THRESHOLD = 0.000001f; +constexpr int32_t ANI_SCOPE_SIZE = 16; + +static std::unordered_map g_sensorTypeToClassName = { + {256, "LOrientationResponseImpl;"}, +}; + +std::map> g_sensorAttributeList = { + { 0, { "x" } }, + { SENSOR_TYPE_ID_ACCELEROMETER, { "x", "y", "z" } }, + { SENSOR_TYPE_ID_GYROSCOPE, { "x", "y", "z" } }, + { SENSOR_TYPE_ID_AMBIENT_LIGHT, { "intensity", "colorTemperature", "infraredLuminance" } }, + { SENSOR_TYPE_ID_MAGNETIC_FIELD, { "x", "y", "z" } }, + { SENSOR_TYPE_ID_BAROMETER, { "pressure" } }, + { SENSOR_TYPE_ID_HALL, { "status" } }, + { SENSOR_TYPE_ID_TEMPERATURE, { "temperature" } }, + { SENSOR_TYPE_ID_PROXIMITY, { "distance" } }, + { SENSOR_TYPE_ID_HUMIDITY, { "humidity" } }, + { SENSOR_TYPE_ID_ORIENTATION, { "alpha", "beta", "gamma" } }, + { SENSOR_TYPE_ID_GRAVITY, { "x", "y", "z" } }, + { SENSOR_TYPE_ID_LINEAR_ACCELERATION, { "x", "y", "z" } }, + { SENSOR_TYPE_ID_ROTATION_VECTOR, { "x", "y", "z", "w" } }, + { SENSOR_TYPE_ID_AMBIENT_TEMPERATURE, { "temperature" } }, + { SENSOR_TYPE_ID_MAGNETIC_FIELD_UNCALIBRATED, { "x", "y", "z", "biasX", "biasY", "biasZ" } }, + { SENSOR_TYPE_ID_GYROSCOPE_UNCALIBRATED, { "x", "y", "z", "biasX", "biasY", "biasZ" } }, + { SENSOR_TYPE_ID_SIGNIFICANT_MOTION, { "scalar" } }, + { SENSOR_TYPE_ID_PEDOMETER_DETECTION, { "scalar" } }, + { SENSOR_TYPE_ID_PEDOMETER, { "steps" } }, + { SENSOR_TYPE_ID_HEART_RATE, { "heartRate" } }, + { SENSOR_TYPE_ID_WEAR_DETECTION, { "value" } }, + { SENSOR_TYPE_ID_ACCELEROMETER_UNCALIBRATED, { "x", "y", "z", "biasX", "biasY", "biasZ" } }, + { SENSOR_TYPE_ID_COLOR, { "lightIntensity", "colorTemperature" } }, + { SENSOR_TYPE_ID_SAR, { "absorptionRatio" } } +}; std::unordered_map stringToNumberMap = { {"ORIENTATION", 256}, - {"MAGNETIC_FIELD_UNCALIBRATED", 261} }; static std::map g_samplingPeriod = { @@ -52,13 +73,280 @@ static std::map g_samplingPeriod = { {"game", 20000000}, }; +using ConvertDataFunc = bool(*)(sptr asyncCallbackInfo, std::vector &data); +bool ConvertToSensorData(sptr asyncCallbackInfo, std::vector &data); + +std::map g_convertfuncList = { + {ON_CALLBACK, ConvertToSensorData}, +}; + +static std::mutex mutex_; +static std::mutex bodyMutex_; +static float g_bodyState = -1.0f; +static std::map>> g_subscribeCallbacks; +static std::mutex onMutex_; +static std::map>> g_onCallbackInfos; + +static ani_error CreateAniError(ani_env *env, std::string &&errMsg) +{ + static const char *errorClsName = "Lescompat/Error;"; + ani_class cls {}; + if (ANI_OK != env->FindClass(errorClsName, &cls)) { + SEN_HILOGE("Not found namespace %{public}s.", errorClsName); + return nullptr; + } + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", "Lstd/core/String;:V", &ctor)) { + SEN_HILOGE("Not found in %{public}s.", errorClsName); + return nullptr; + } + ani_string error_msg; + env->String_NewUTF8(errMsg.c_str(), 17U, &error_msg); + ani_object errorObject; + env->Object_New(cls, ctor, &errorObject, error_msg); + return static_cast(errorObject); +} + +static bool CheckSubscribe(int32_t sensorTypeId) +{ + std::lock_guard onCallbackLock(onMutex_); + auto iter = g_onCallbackInfos.find(sensorTypeId); + return iter != g_onCallbackInfos.end(); +} + +static bool CopySensorData(sptr callbackInfo, SensorEvent *event) +{ + CHKPF(callbackInfo); + CHKPF(event); + int32_t sensorTypeId = event->sensorTypeId; + callbackInfo->data.sensorData.sensorTypeId = sensorTypeId; + callbackInfo->data.sensorData.dataLength = event->dataLen; + callbackInfo->data.sensorData.timestamp = event->timestamp; + callbackInfo->data.sensorData.sensorAccuracy = event->option; + CHKPF(event->data); + if (event->dataLen < sizeof(float)) { + SEN_HILOGE("Event dataLen less than float size"); + return false; + } + auto data = reinterpret_cast(event->data); + if (sensorTypeId == SENSOR_TYPE_ID_WEAR_DETECTION && callbackInfo->type == SUBSCRIBE_CALLBACK) { + std::lock_guard onBodyLock(bodyMutex_); + g_bodyState = *data; + callbackInfo->data.sensorData.data[0] = + (fabs(g_bodyState - BODY_STATE_EXCEPT) < THRESHOLD) ? true : false; + return true; + } + if (memcpy_s(callbackInfo->data.sensorData.data, sizeof(callbackInfo->data.sensorData.data), + data, event->dataLen) != EOK) { + SEN_HILOGE("Copy data failed"); + return false; + } + return true; +} + +static bool CheckSystemSubscribe(int32_t sensorTypeId) +{ + std::lock_guard subscribeLock(mutex_); + auto iter = g_subscribeCallbacks.find(sensorTypeId); + if (iter == g_subscribeCallbacks.end()) { + return false; + } + return true; +} + +static ani_boolean IsInstanceOf(ani_env *env, const std::string &cls_name, ani_object obj) +{ + ani_class cls; + if (ANI_OK != env->FindClass(cls_name.c_str(), &cls)) { + SEN_HILOGE("FindClass failed"); + return ANI_FALSE; + } + + ani_boolean ret; + env->Object_InstanceOf(obj, cls, &ret); + return ret; +} + +static bool SendEventToMainThread(const std::function func) +{ + if (func == nullptr) { + SEN_HILOGE("func == nullptr"); + return false; + } + std::shared_ptr runner = OHOS::AppExecFwk::EventRunner::GetMainEventRunner(); + if (!runner) { + SEN_HILOGE("runner == nullptr"); + return false; + } + std::shared_ptr handler = std::make_shared(runner); + handler->PostTask(func, "", 0, OHOS::AppExecFwk::EventQueue::Priority::HIGH, {}); + SEN_HILOGD("PostTask success"); + return true; +} + +bool ValidateAndInitialize(sptr asyncCallbackInfo, ani_object &obj) +{ + CHKPF(asyncCallbackInfo); + int32_t sensorTypeId = asyncCallbackInfo->data.sensorData.sensorTypeId; + if (g_sensorAttributeList.find(sensorTypeId) == g_sensorAttributeList.end()) { + SEN_HILOGE("Invalid sensor type"); + return false; + } + if (sensorTypeId == SENSOR_TYPE_ID_WEAR_DETECTION && asyncCallbackInfo->type == SUBSCRIBE_CALLBACK) { + return false; + } + size_t size = g_sensorAttributeList[sensorTypeId].size(); + uint32_t dataLength = asyncCallbackInfo->data.sensorData.dataLength / sizeof(float); + if (size > dataLength) { + SEN_HILOGE("Data length mismatch"); + return false; + } + + if (g_sensorTypeToClassName.find(sensorTypeId) == g_sensorTypeToClassName.end()) { + SEN_HILOGE("Find class by sensorType failed"); + return false; + } + + ani_namespace ns; + static const char *namespaceName = "L@ohos/sensor/sensor;"; + if (ANI_OK != asyncCallbackInfo->env->FindNamespace(namespaceName, &ns)) { + SEN_HILOGE("Not found '%{public}s'", namespaceName); + return false; + } + + ani_class cls; + const char *className = g_sensorTypeToClassName[sensorTypeId].c_str(); + if (ANI_OK != asyncCallbackInfo->env->Namespace_FindClass(ns, className, &cls)) { + SEN_HILOGE("FindClass %{public}s failed", className); + return false; + } + + ani_method ctor; + if (ANI_OK != asyncCallbackInfo->env->Class_FindMethod(cls, "", nullptr, &ctor)) { + SEN_HILOGE("Class_FindMethod 'constructor' failed"); + return false; + } + + if (ANI_OK != asyncCallbackInfo->env->Object_New(cls, ctor, &obj)) { + SEN_HILOGE("Object_New '%{public}s' failed", className); + return false; + } + return true; +} + +bool SetSensorPropertiesAndPushData(sptr asyncCallbackInfo, ani_object obj, + std::vector &data) +{ + int32_t sensorTypeId = asyncCallbackInfo->data.sensorData.sensorTypeId; + size_t size = g_sensorAttributeList[sensorTypeId].size(); + auto sensorAttributes = g_sensorAttributeList[sensorTypeId]; + for (uint32_t i = 0; i < size; ++i) { + if (ANI_OK != asyncCallbackInfo->env->Object_SetPropertyByName_Float(obj, sensorAttributes[i].c_str(), + asyncCallbackInfo->data.sensorData.data[i])) { + SEN_HILOGE("Object_SetPropertyByName_Double failed"); + return false; + } + } + + if (ANI_OK != asyncCallbackInfo->env->Object_SetPropertyByName_Long(obj, "timestamp", + asyncCallbackInfo->data.sensorData.timestamp)) { + SEN_HILOGE("Object_SetPropertyByName_Long failed"); + return false; + } + + if (ANI_OK != asyncCallbackInfo->env->Object_SetPropertyByName_Int(obj, "accuracy", + asyncCallbackInfo->data.sensorData.sensorAccuracy)) { + SEN_HILOGE("Object_SetPropertyByName_Int failed"); + return false; + } + + data.push_back(obj); + return true; +} +bool ConvertToSensorData(sptr asyncCallbackInfo, std::vector &data) +{ + ani_object obj; + if (!ValidateAndInitialize(asyncCallbackInfo, obj)) { + return false; + } + + if (!SetSensorPropertiesAndPushData(asyncCallbackInfo, obj, data)) { + return false; + } + + return true; +} + +static void EmitUvEventLoop(sptr asyncCallbackInfo) +{ + CHKPV(asyncCallbackInfo); + auto task = [asyncCallbackInfo]() { + SEN_HILOGD("Begin to call task"); + AniLocalScopeGuard aniLocalScopeGuard(asyncCallbackInfo->env, ANI_SCOPE_SIZE); + if (!aniLocalScopeGuard.IsStatusOK()) { + SEN_HILOGE("CreateLocalScope failed"); + return; + } + + ani_error error; + if (!(g_convertfuncList.find(asyncCallbackInfo->type) != g_convertfuncList.end())) { + SEN_HILOGE("asyncCallbackInfo type is invalid"); + error = CreateAniError(asyncCallbackInfo->env, "asyncCallbackInfo type is invalid"); + asyncCallbackInfo->env->ThrowError(error); + return; + } + std::vector args; + g_convertfuncList[asyncCallbackInfo->type](asyncCallbackInfo, args); + + auto fnObj = reinterpret_cast(asyncCallbackInfo->callback[0]); + SEN_HILOGD("Begin to call FunctionalObject_Call"); + if (fnObj == nullptr) { + SEN_HILOGE("fnObj == nullptr"); + error = CreateAniError(asyncCallbackInfo->env, "fnObj == nullptr"); + asyncCallbackInfo->env->ThrowError(error); + return; + } + if (IsInstanceOf(asyncCallbackInfo->env, "Lstd/core/Function1;", fnObj) == 0) { + SEN_HILOGE("fnObj is not instance Of function"); + error = CreateAniError(asyncCallbackInfo->env, "fnObj is not instance Of function"); + asyncCallbackInfo->env->ThrowError(error); + return; + } + + ani_ref result; + if (ANI_OK != asyncCallbackInfo->env->FunctionalObject_Call(fnObj, 1, args.data(), &result)) { + SEN_HILOGE("FunctionalObject_Call failed"); + error = CreateAniError(asyncCallbackInfo->env, "FunctionalObject_Call failed"); + asyncCallbackInfo->env->ThrowError(error); + return; + } + SEN_HILOGD("FunctionalObject_Call success"); + }; + if (!SendEventToMainThread(task)) { + SEN_HILOGE("failed to send event"); + } +} static void EmitOnCallback(SensorEvent *event) { - return; + CHKPV(event); + int32_t sensorTypeId = event->sensorTypeId; + if (!CheckSubscribe(sensorTypeId)) { + return; + } + std::lock_guard onCallbackLock(onMutex_); + auto onCallbackInfos = g_onCallbackInfos[sensorTypeId]; + for (auto &onCallbackInfo : onCallbackInfos) { + if (!CopySensorData(onCallbackInfo, event)) { + SEN_HILOGE("Copy sensor data failed"); + continue; + } + EmitUvEventLoop(onCallbackInfo); + } } void DataCallbackImpl(SensorEvent *event) { + CHKPV(event); EmitOnCallback(event); } @@ -68,6 +356,7 @@ const SensorUser user = { int32_t SubscribeSensor(int32_t sensorTypeId, int64_t interval, RecordSensorCallback callback) { + CALL_LOG_ENTER; int32_t ret = SubscribeSensor(sensorTypeId, &user); if (ret != ERR_OK) { SEN_HILOGE("SubscribeSensor failed"); @@ -81,9 +370,47 @@ int32_t SubscribeSensor(int32_t sensorTypeId, int64_t interval, RecordSensorCall return ActivateSensor(sensorTypeId, &user); } +static bool IsSubscribed(ani_env *env, int32_t sensorTypeId, ani_object callback) +{ + CALL_LOG_ENTER; + if (auto iter = g_onCallbackInfos.find(sensorTypeId); iter == g_onCallbackInfos.end()) { + SEN_HILOGW("No client subscribe, sensorTypeId:%{public}d", sensorTypeId); + return false; + } + std::vector> callbackInfos = g_onCallbackInfos[sensorTypeId]; + for (auto callbackInfo : callbackInfos) { + CHKPC(callbackInfo); + if (callbackInfo->env != env) { + continue; + } + + ani_boolean isEquals = false; + if (ANI_OK != env->Reference_StrictEquals(callback, callbackInfo->callback[0], &isEquals)) { + SEN_HILOGE("StrictEquals failed"); + return false; + } + if (isEquals) { + return true; + } + } + return false; +} static void UpdateCallbackInfos(ani_env *env, int32_t sensorTypeId, ani_object callback) { - return; + CALL_LOG_ENTER; + std::lock_guard onCallbackLock(onMutex_); + CHKCV((!IsSubscribed(env, sensorTypeId, callback)), "The callback has been subscribed"); + sptr asyncCallbackInfo = new (std::nothrow) AsyncCallbackInfo(env, ON_CALLBACK); + CHKPV(asyncCallbackInfo); + + if (ANI_OK != env->GlobalReference_Create(callback, &asyncCallbackInfo->callback[0])) { + SEN_HILOGE("GlobalReference_Create failed"); + return; + } + + std::vector> callbackInfos = g_onCallbackInfos[sensorTypeId]; + callbackInfos.push_back(asyncCallbackInfo); + g_onCallbackInfos[sensorTypeId] = callbackInfos; } bool GetIntervalValue(ani_env *env, ani_object options, int64_t& interval) @@ -103,13 +430,12 @@ bool GetIntervalValue(ani_env *env, ani_object options, int64_t& interval) env->Reference_IsUndefined(intervalRef, &isIntervalUndefined); if (isIntervalUndefined) { - std::cerr << "interval is undefined" << std::endl; + SEN_HILOGE("interval is undefined"); return false; } ani_class stringClass; env->FindClass("Lstd/core/String;", &stringClass); - ani_class doubleClass; env->FindClass("Lstd/core/Double;", &doubleClass); @@ -137,6 +463,7 @@ bool GetIntervalValue(ani_env *env, ani_object options, int64_t& interval) return false; } interval = iter->second; + SEN_HILOGI("GetIntervalValue mode: %{public}s", mode.c_str()); return true; } @@ -144,33 +471,21 @@ bool GetIntervalValue(ani_env *env, ani_object options, int64_t& interval) return false; } -int ParseStringToNumber(const std::string& str) -{ - std::string upperStr; - for (char c : str) { - upperStr += std::toupper(c); - } - - if (stringToNumberMap.find(upperStr) != stringToNumberMap.end()) { - return stringToNumberMap[upperStr]; - } else { - return -1; - } -} - static void On([[maybe_unused]] ani_env *env, ani_string typeId, ani_object callback, ani_object options) { - SEN_HILOGD("sensor on start"); + CALL_LOG_ENTER; + if (!IsInstanceOf(env, "Lstd/core/Function1;", callback)) { + SEN_HILOGE("Wrong argument type"); + return; + } int32_t sensorTypeId = INVALID_SENSOR_ID; auto typeIdStr = AniStringUtils::ToStd(env, static_cast(typeId)); - auto typeIdVal = ParseStringToNumber(typeIdStr); - if (typeIdVal == -1) { + if (stringToNumberMap.find(typeIdStr) == stringToNumberMap.end()) { SEN_HILOGE("Invalid sensor typeId: %{public}s", typeIdStr.c_str()); return; } - std::cout << "typeIdVal: " << typeIdVal << std::endl; - sensorTypeId = typeIdVal; + sensorTypeId = stringToNumberMap[typeIdStr]; int64_t interval = REPORTING_INTERVAL; if (!GetIntervalValue(env, options, interval)) { @@ -178,21 +493,66 @@ static void On([[maybe_unused]] ani_env *env, ani_string typeId, ani_object call } int32_t ret = SubscribeSensor(sensorTypeId, interval, DataCallbackImpl); if (ret != ERR_OK) { - SEN_HILOGE("SubscribeSensor fail"); + auto error = CreateAniError(env, "SubscribeSensor fail"); + env->ThrowError(error); return; } UpdateCallbackInfos(env, sensorTypeId, callback); - SEN_HILOGD("sensor on end"); } static int32_t RemoveAllCallback(ani_env *env, int32_t sensorTypeId) { - return 0; + CALL_LOG_ENTER; + std::lock_guard onCallbackLock(onMutex_); + std::vector> callbackInfos = g_onCallbackInfos[sensorTypeId]; + for (auto iter = callbackInfos.begin(); iter != callbackInfos.end();) { + CHKPC(*iter); + if ((*iter)->env != env) { + ++iter; + continue; + } + iter = callbackInfos.erase(iter); + } + if (callbackInfos.empty()) { + SEN_HILOGD("No subscription to change sensor data"); + g_onCallbackInfos.erase(sensorTypeId); + return 0; + } + g_onCallbackInfos[sensorTypeId] = callbackInfos; + return callbackInfos.size(); } static int32_t RemoveCallback(ani_env *env, int32_t sensorTypeId, ani_object callback) { - return 0; + CALL_LOG_ENTER; + std::lock_guard onCallbackLock(onMutex_); + std::vector> callbackInfos = g_onCallbackInfos[sensorTypeId]; + for (auto iter = callbackInfos.begin(); iter != callbackInfos.end();) { + CHKPC(*iter); + if ((*iter)->env != env) { + continue; + } + + ani_boolean isEquals = false; + if (ANI_OK != env->Reference_StrictEquals(callback, (*iter)->callback[0], &isEquals)) { + SEN_HILOGE("Reference_StrictEquals failed"); + return false; + } + if (isEquals) { + iter = callbackInfos.erase(iter); + SEN_HILOGD("Remove callback success"); + break; + } else { + ++iter; + } + } + if (callbackInfos.empty()) { + SEN_HILOGD("No subscription to change sensor data"); + g_onCallbackInfos.erase(sensorTypeId); + return 0; + } + g_onCallbackInfos[sensorTypeId] = callbackInfos; + return callbackInfos.size(); } int32_t UnsubscribeSensor(int32_t sensorTypeId) @@ -207,16 +567,17 @@ int32_t UnsubscribeSensor(int32_t sensorTypeId) static void Off([[maybe_unused]] ani_env *env, ani_string type, ani_object callback) { - SEN_HILOGD("sensor off start"); - + CALL_LOG_ENTER; int32_t sensorTypeId = INVALID_SENSOR_ID; auto typeStr = AniStringUtils::ToStd(env, static_cast(type)); - auto typeStrVal = ParseStringToNumber(typeStr); - if (typeStrVal == -1) { + ani_error error; + if (stringToNumberMap.find(typeStr) == stringToNumberMap.end()) { SEN_HILOGE("Invalid sensor type: %{public}s", typeStr.c_str()); + error = CreateAniError(env, "Invalid sensor type"); + env->ThrowError(error); return; } - sensorTypeId = typeStrVal; + sensorTypeId = stringToNumberMap[typeStr]; int32_t subscribeSize = -1; ani_boolean isUndefined; @@ -227,16 +588,24 @@ static void Off([[maybe_unused]] ani_env *env, ani_string type, ani_object callb ani_boolean result; if (env->Reference_IsNull(callback, &result) == ANI_OK && result) { subscribeSize = RemoveAllCallback(env, sensorTypeId); - } else { + } else if (IsInstanceOf(env, "Lstd/core/Function1;", callback)) { subscribeSize = RemoveCallback(env, sensorTypeId, callback); + } else { + error = CreateAniError(env, "Invalid sensor type"); + env->ThrowError(error); + return; } } + if (CheckSystemSubscribe(sensorTypeId) || (subscribeSize > 0)) { + SEN_HILOGW("There are other client subscribe system js api as well, not need unsubscribe"); + return; + } int32_t ret = UnsubscribeSensor(sensorTypeId); if (ret == PARAMETER_ERROR || ret == PERMISSION_DENIED) { - SEN_HILOGE("UnsubscribeSensor fail"); + error = CreateAniError(env, "UnsubscribeSensor fail"); + env->ThrowError(error); } - SEN_HILOGD("sensor off end"); return; } -- Gitee