From e504e08de7e7a08eaeb2cd0b243c10594a9d71a5 Mon Sep 17 00:00:00 2001 From: dongqingran Date: Sun, 22 Oct 2023 20:02:33 +0800 Subject: [PATCH] local live view framwork js Signed-off-by: dongqingran --- frameworks/js/napi/include/common.h | 92 ++++- frameworks/js/napi/src/common.cpp | 358 ++++++++++++++++++ frameworks/js/napi/src/manager/BUILD.gn | 2 + .../js/napi/src/manager/init_module.cpp | 3 + .../src/manager/local_live_view_subscribe.cpp | 336 ++++++++++++++++ .../napi/src/manager/napi_local_live_view.cpp | 251 ++++++++++++ 6 files changed, 1041 insertions(+), 1 deletion(-) create mode 100644 frameworks/js/napi/src/manager/local_live_view_subscribe.cpp create mode 100644 frameworks/js/napi/src/manager/napi_local_live_view.cpp diff --git a/frameworks/js/napi/include/common.h b/frameworks/js/napi/include/common.h index d7bb8acf9..4f4db010c 100644 --- a/frameworks/js/napi/include/common.h +++ b/frameworks/js/napi/include/common.h @@ -19,6 +19,8 @@ #include "napi/native_api.h" #include "napi/native_node_api.h" #include "notification_helper.h" +#include "notification_local_live_view_button.h" +#include "notification_local_live_view_content.h" namespace OHOS { namespace NotificationNapi { @@ -38,7 +40,8 @@ enum class ContentType { NOTIFICATION_CONTENT_LONG_TEXT, NOTIFICATION_CONTENT_PICTURE, NOTIFICATION_CONTENT_CONVERSATION, - NOTIFICATION_CONTENT_MULTILINE + NOTIFICATION_CONTENT_MULTILINE, + NOTIFICATION_CONTENT_LOCAL_LIVE_VIEW }; enum class SlotType { @@ -46,6 +49,7 @@ enum class SlotType { SOCIAL_COMMUNICATION = 1, SERVICE_INFORMATION = 2, CONTENT_INFORMATION = 3, + LIVE_VIEW = 4, OTHER_TYPES = 0xFFFF, }; @@ -226,6 +230,16 @@ public: static void SetCallback( const napi_env &env, const napi_ref &callbackIn, const napi_value &result); + /** + * @brief Calls the callback with the result + * + * @param env Indicates the environment that the API is invoked under + * @param callbackIn Indicates the callback to be called + * @param result Indicates the result returned by the callback + */ + static void SetCallbackArg2( + const napi_env &env, const napi_ref &callbackIn, const napi_value &result0, const napi_value &result1); + /** * @brief Processes the promise with the result and error code * @@ -1203,6 +1217,72 @@ public: const napi_env &env, const napi_value &contentResult, std::shared_ptr &pictureContent); + /** + * @brief Gets a NotificationLocalLiveViewContent object from specified js object + * + * @param env Indicates the environment that the API is invoked under + * @param result Indicates a js object to be converted + * @param request Indicates a NotificationLocalLiveViewContent object from specified js object + * @return Returns the null object if success, returns the null value otherwise + */ + static napi_value GetNotificationLocalLiveViewContent( + const napi_env &env, const napi_value &result, NotificationRequest &request); + + /** + * @brief Gets a capsule of NotificationLocalLiveViewContent object from specified js object + * + * @param env Indicates the environment that the API is invoked under + * @param contentResult Indicates a js object to be converted + * @param pictureContent Indicates a capsule object from specified js object + * @return Returns the null object if success, returns the null value otherwise + */ + static napi_value GetNotificationLocalLiveViewCapsule( + const napi_env &env, const napi_value &contentResult, std::shared_ptr content); + + /** + * @brief Gets a button of NotificationLocalLiveViewContent object from specified js object + * + * @param env Indicates the environment that the API is invoked under + * @param contentResult Indicates a js object to be converted + * @param pictureContent Indicates a button object from specified js object + * @return Returns the null object if success, returns the null value otherwise + */ + static napi_value GetNotificationLocalLiveViewButton( + const napi_env &env, const napi_value &contentResult, std::shared_ptr content); + + /** + * @brief Gets a time of NotificationLocalLiveViewContent object from specified js object + * + * @param env Indicates the environment that the API is invoked under + * @param contentResult Indicates a js object to be converted + * @param pictureContent Indicates a time object from specified js object + * @return Returns the null object if success, returns the null value otherwise + */ + static napi_value GetNotificationLocalLiveViewTime( + const napi_env &env, const napi_value &contentResult, std::shared_ptr content); + + /** + * @brief Gets a progress of NotificationLocalLiveViewContent object from specified js object + * + * @param env Indicates the environment that the API is invoked under + * @param contentResult Indicates a js object to be converted + * @param pictureContent Indicates a progress object from specified js object + * @return Returns the null object if success, returns the null value otherwise + */ + static napi_value GetNotificationLocalLiveViewProgress( + const napi_env &env, const napi_value &contentResult, std::shared_ptr content); + + /** + * @brief Gets a NotificationPictureContent object from specified js object + * + * @param env Indicates the environment that the API is invoked under + * @param contentResult Indicates a js object to be converted + * @param pictureContent Indicates a NotificationPictureContent object from specified js object + * @return Returns the null object if success, returns the null value otherwise + */ + static napi_value GetNotificationLocalLiveViewContentDetailed( + const napi_env &env, const napi_value &contentResult, std::shared_ptr content); + /** * @brief Gets a conversational content of NotificationRequest object from specified js object * @@ -1369,6 +1449,16 @@ public: */ static napi_value GetBundleOption(const napi_env &env, const napi_value &value, NotificationBundleOption &option); + /** + * @brief Gets a NotificationButtonOption object from specified js object + * + * @param env Indicates the environment that the API is invoked under + * @param value Indicates a js object to be converted + * @param option Indicates a NotificationButtonOption object from specified js object + * @return Returns the null object if success, returns the null value otherwise + */ + static napi_value GetButtonOption(const napi_env &env, const napi_value &value, NotificationButtonOption &option); + static napi_value GetHashCodes(const napi_env &env, const napi_value &value, std::vector &hashCodes); /** diff --git a/frameworks/js/napi/src/common.cpp b/frameworks/js/napi/src/common.cpp index f1614d2dd..c8eb4ffa5 100644 --- a/frameworks/js/napi/src/common.cpp +++ b/frameworks/js/napi/src/common.cpp @@ -16,6 +16,9 @@ #include "common.h" #include "ans_inner_errors.h" #include "napi_common.h" +#include "notification_action_button.h" +#include "notification_capsule.h" +#include "notification_progress.h" #include "pixel_map_napi.h" namespace OHOS { @@ -169,6 +172,21 @@ void Common::SetCallback( ANS_LOGI("end"); } +void Common::SetCallbackArg2( + const napi_env &env, const napi_ref &callbackIn, const napi_value &result0, const napi_value &result1) +{ + ANS_LOGI("enter"); + napi_value result[ARGS_TWO] = {result0, result1}; + napi_value undefined = nullptr; + napi_get_undefined(env, &undefined); + + napi_value callback = nullptr; + napi_value resultout = nullptr; + napi_get_reference_value(env, callbackIn, &callback); + NAPI_CALL_RETURN_VOID(env, napi_call_function(env, undefined, callback, ARGS_TWO, result, &resultout)); + ANS_LOGI("end"); +} + void Common::SetPromise(const napi_env &env, const napi_deferred &deferred, const int32_t &errorCode, const napi_value &result, bool newType) { @@ -1794,6 +1812,11 @@ napi_value Common::GetNotificationContent(const napi_env &env, const napi_value return nullptr; } break; + case NotificationContent::Type::LOCAL_LIVE_VIEW: + if (GetNotificationLocalLiveViewContent(env, result, request) == nullptr) { + return nullptr; + } + break; default: return nullptr; } @@ -3976,6 +3999,307 @@ napi_value Common::GetNotificationMultiLineContentLines(const napi_env &env, con return NapiGetNull(env); } +napi_value Common::GetNotificationLocalLiveViewContent( + const napi_env &env, const napi_value &result, NotificationRequest &request) +{ + ANS_LOGI("enter"); + + napi_valuetype valuetype = napi_undefined; + napi_value contentResult = nullptr; + bool hasProperty = false; + NAPI_CALL(env, napi_has_named_property(env, result, "localLiveView", &hasProperty)); + if (!hasProperty) { + ANS_LOGE("Property localLiveView expected."); + return nullptr; + } + napi_get_named_property(env, result, "localLiveView", &contentResult); + NAPI_CALL(env, napi_typeof(env, contentResult, &valuetype)); + if (valuetype != napi_object) { + ANS_LOGE("Wrong argument type. Object expected."); + return nullptr; + } + + std::shared_ptr localLiveViewContent = std::make_shared(); + if (localLiveViewContent == nullptr) { + ANS_LOGE("localLiveViewContent is null"); + return nullptr; + } + + if (GetNotificationLocalLiveViewContentDetailed(env, contentResult, localLiveViewContent) == nullptr) { + return nullptr; + } + + request.SetContent(std::make_shared(localLiveViewContent)); + + return NapiGetNull(env); +} + +napi_value Common::GetNotificationLocalLiveViewCapsule( + const napi_env &env, const napi_value &contentResult, std::shared_ptr content) +{ + napi_value capsuleResult = nullptr; + napi_valuetype valuetype = napi_undefined; + bool hasProperty = false; + size_t strLen = 0; + char str[STR_MAX_SIZE] = {0}; + std::shared_ptr pixelMap = nullptr; + napi_value result = nullptr; + + ANS_LOGI("enter"); + + NAPI_CALL(env, napi_has_named_property(env, contentResult, "capsule", &hasProperty)); + + napi_get_named_property(env, contentResult, "capsule", &capsuleResult); + NAPI_CALL(env, napi_typeof(env, capsuleResult, &valuetype)); + if (valuetype != napi_object) { + ANS_LOGE("Wrong argument type. Object expected."); + return nullptr; + } + + NotificationCapsule capsule; + + NAPI_CALL(env, napi_has_named_property(env, capsuleResult, "title", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, capsuleResult, "title", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_string) { + ANS_LOGE("Wrong argument type. String expected."); + return nullptr; + } + + NAPI_CALL(env, napi_get_value_string_utf8(env, result, str, STR_MAX_SIZE - 1, &strLen)); + capsule.SetTitle(str); + ANS_LOGD("capsule title = %{public}s", str); + } + + NAPI_CALL(env, napi_has_named_property(env, capsuleResult, "backgroundColor", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, capsuleResult, "backgroundColor", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_string) { + ANS_LOGE("Wrong argument type. String expected."); + return nullptr; + } + NAPI_CALL(env, napi_get_value_string_utf8(env, result, str, STR_MAX_SIZE - 1, &strLen)); + capsule.SetBackgroundColor(str); + ANS_LOGD("capsule backgroundColor = %{public}s", str); + } + NAPI_CALL(env, napi_has_named_property(env, capsuleResult, "icon", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, capsuleResult, "icon", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_object) { + ANS_LOGE("Wrong argument type. Object expected."); + return nullptr; + } + pixelMap = Media::PixelMapNapi::GetPixelMap(env, result); + if (pixelMap == nullptr) { + ANS_LOGE("Invalid object pixelMap"); + return nullptr; + } + capsule.SetIcon(pixelMap); + ANS_LOGD("capsule icon = %{public}s", str); + } + + content->SetCapsule(capsule); + + return NapiGetNull(env); +} + +napi_value Common::GetNotificationLocalLiveViewButton( + const napi_env &env, const napi_value &contentResult, std::shared_ptr content) +{ + napi_value result = nullptr; + napi_valuetype valuetype = napi_undefined; + bool isArray = false; + uint32_t length = 0; + napi_value buttonResult = nullptr; + bool hasProperty = false; + char str[STR_MAX_SIZE] = {0}; + size_t strLen = 0; + + ANS_LOGI("enter"); + + napi_get_named_property(env, contentResult, "button", &buttonResult); + NAPI_CALL(env, napi_typeof(env, buttonResult, &valuetype)); + if (valuetype != napi_object) { + ANS_LOGE("Wrong argument type. Object expected."); + return nullptr; + } + + NotificationLocalLiveViewButton button; + + NAPI_CALL(env, napi_has_named_property(env, buttonResult, "buttonNames", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, buttonResult, "buttonNames", &result); + napi_is_array(env, result, &isArray); + if (!isArray) { + ANS_LOGE("Property buttonNames is expected to be an array."); + return nullptr; + } + napi_get_array_length(env, result, &length); + for (size_t i = 0; i < length; i++) { + napi_value buttonName = nullptr; + napi_get_element(env, result, i, &buttonName); + NAPI_CALL(env, napi_typeof(env, buttonName, &valuetype)); + if (valuetype != napi_string) { + ANS_LOGE("Wrong argument type. String expected."); + return nullptr; + } + NAPI_CALL(env, napi_get_value_string_utf8(env, buttonName, str, STR_MAX_SIZE - 1, &strLen)); + button.addSingleButtonName(str); + ANS_LOGD("button buttonName = %{public}s.", str); + } + } + + NAPI_CALL(env, napi_has_named_property(env, buttonResult, "buttonIcons", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, buttonResult, "buttonIcons", &result); + napi_is_array(env, result, &isArray); + if (!isArray) { + ANS_LOGE("Property buttonIcons is expected to be an array."); + return nullptr; + } + napi_get_array_length(env, result, &length); + for (size_t i = 0; i < length; i++) { + napi_value buttonIcon = nullptr; + std::shared_ptr pixelMap = nullptr; + napi_get_element(env, result, i, &buttonIcon); + NAPI_CALL(env, napi_typeof(env, buttonIcon, &valuetype)); + if (valuetype != napi_object) { + ANS_LOGE("Wrong argument type. Object expected."); + return nullptr; + } + pixelMap = Media::PixelMapNapi::GetPixelMap(env, buttonIcon); + if (pixelMap == nullptr) { + ANS_LOGE("Invalid object pixelMap"); + return nullptr; + } + button.addSingleButtonIcon(pixelMap); + } + } + ANS_LOGD("button buttonIcon = %{public}s", str); + + return NapiGetNull(env); +} + +napi_value Common::GetNotificationLocalLiveViewProgress(const napi_env &env, + const napi_value &contentResult, std::shared_ptr content) +{ + napi_value result = nullptr; + napi_valuetype valuetype = napi_undefined; + bool hasProperty = false; + int32_t intValue = -1; + napi_value progressResult = nullptr; + + ANS_LOGI("enter"); + + napi_get_named_property(env, contentResult, "progress", &progressResult); + NAPI_CALL(env, napi_typeof(env, progressResult, &valuetype)); + if (valuetype != napi_object) { + ANS_LOGE("Wrong argument type. Object expected."); + return nullptr; + } + + NotificationProgress progress; + + NAPI_CALL(env, napi_has_named_property(env, progressResult, "maxValue", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, progressResult, "maxValue", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_number) { + ANS_LOGE("Wrong argument type. Number expected."); + return nullptr; + } + napi_get_value_int32(env, result, &intValue); + progress.SetMaxValue(intValue); + ANS_LOGD("progress intValue = %{public}d", intValue); + } + + NAPI_CALL(env, napi_has_named_property(env, progressResult, "currentValue", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, progressResult, "currentValue", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_number) { + ANS_LOGE("Wrong argument type. Number expected."); + return nullptr; + } + napi_get_value_int32(env, result, &intValue); + progress.SetCurrentValue(intValue); + ANS_LOGD("progress currentValue = %{public}d", intValue); + } + + NAPI_CALL(env, napi_has_named_property(env, progressResult, "isPercentage", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, progressResult, "isPercentage", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_number) { + ANS_LOGE("Wrong argument type. Number expected."); + return nullptr; + } + napi_get_value_int32(env, result, &intValue); + progress.SetIsPercentage(intValue); + ANS_LOGD("progress isPercentage = %{public}d", intValue); + } + + content->SetProgress(progress); + return NapiGetNull(env); +} + +napi_value Common::GetNotificationLocalLiveViewContentDetailed( + const napi_env &env, const napi_value &contentResult, std::shared_ptr content) +{ + bool hasProperty = false; + int32_t type = -1; + napi_value result = nullptr; + napi_valuetype valuetype = napi_undefined; + + ANS_LOGI("enter"); + + //title, text + if (GetNotificationBasicContentDetailed(env, contentResult, content) == nullptr) { + ANS_LOGE("Basic content get fail."); + return nullptr; + } + + //type + NAPI_CALL(env, napi_has_named_property(env, contentResult, "type", &hasProperty)); + if (!hasProperty) { + ANS_LOGE("Property type expected."); + return nullptr; + } + napi_get_named_property(env, contentResult, "type", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_number) { + ANS_LOGE("Wrong argument type. Number expected."); + return nullptr; + } + napi_get_value_int32(env, result, &type); + content->SetType(type); + ANS_LOGD("localLiveView type = %{public}d", type); + + + //capsule? + NAPI_CALL(env, napi_has_named_property(env, contentResult, "capsule", &hasProperty)); + if (hasProperty && GetNotificationLocalLiveViewCapsule(env, contentResult, content) == nullptr) { + return nullptr; + } + + //button? + NAPI_CALL(env, napi_has_named_property(env, contentResult, "button", &hasProperty)); + if (hasProperty && GetNotificationLocalLiveViewButton(env, contentResult, content) == nullptr) { + return nullptr; + } + + //progess? + NAPI_CALL(env, napi_has_named_property(env, contentResult, "progress", &hasProperty)); + if (hasProperty && GetNotificationLocalLiveViewProgress(env, contentResult, content) == nullptr) { + return nullptr; + } + + return NapiGetNull(env); +} + napi_value Common::GetNotificationSlot(const napi_env &env, const napi_value &value, NotificationSlot &slot) { ANS_LOGI("enter"); @@ -4280,6 +4604,34 @@ napi_value Common::GetBundleOption(const napi_env &env, const napi_value &value, return NapiGetNull(env); } +napi_value Common::GetButtonOption(const napi_env &env, const napi_value &value, NotificationButtonOption &option) +{ + ANS_LOGI("enter"); + + bool hasProperty {false}; + napi_valuetype valuetype = napi_undefined; + napi_value result = nullptr; + + char str[STR_MAX_SIZE] = {0}; + size_t strLen = 0; + // buttonName: string + NAPI_CALL(env, napi_has_named_property(env, value, "buttonName", &hasProperty)); + if (!hasProperty) { + ANS_LOGE("Property buttonName expected."); + return nullptr; + } + napi_get_named_property(env, value, "buttonName", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_string) { + ANS_LOGE("Wrong argument type. String expected."); + return nullptr; + } + NAPI_CALL(env, napi_get_value_string_utf8(env, result, str, STR_MAX_SIZE - 1, &strLen)); + option.SetButtonName(str); + + return NapiGetNull(env); +} + napi_value Common::GetHashCodes(const napi_env &env, const napi_value &value, std::vector &hashCodes) { ANS_LOGD("enter"); @@ -4365,6 +4717,9 @@ bool Common::ContentTypeJSToC(const ContentType &inType, NotificationContent::Ty case ContentType::NOTIFICATION_CONTENT_CONVERSATION: outType = NotificationContent::Type::CONVERSATION; break; + case ContentType::NOTIFICATION_CONTENT_LOCAL_LIVE_VIEW: + outType = NotificationContent::Type::LOCAL_LIVE_VIEW; + break; default: ANS_LOGE("ContentType %{public}d is an invalid value", inType); return false; @@ -4390,6 +4745,9 @@ bool Common::ContentTypeCToJS(const NotificationContent::Type &inType, ContentTy case NotificationContent::Type::CONVERSATION: outType = ContentType::NOTIFICATION_CONTENT_CONVERSATION; break; + case NotificationContent::Type::LOCAL_LIVE_VIEW: + outType = ContentType::NOTIFICATION_CONTENT_LOCAL_LIVE_VIEW; + break; default: ANS_LOGE("ContentType %{public}d is an invalid value", inType); return false; diff --git a/frameworks/js/napi/src/manager/BUILD.gn b/frameworks/js/napi/src/manager/BUILD.gn index c84977487..c7acf8f8d 100644 --- a/frameworks/js/napi/src/manager/BUILD.gn +++ b/frameworks/js/napi/src/manager/BUILD.gn @@ -60,12 +60,14 @@ ohos_shared_library("notificationmanager") { "../publish.cpp", "../slot.cpp", "init_module.cpp", + "local_live_view_subscribe.cpp", "napi_cancel.cpp", "napi_display_badge.cpp", "napi_distributed.cpp", "napi_disturb_mode.cpp", "napi_enable_notification.cpp", "napi_get_active.cpp", + "napi_local_live_view.cpp", "napi_publish.cpp", "napi_push.cpp", "napi_push_callback.cpp", diff --git a/frameworks/js/napi/src/manager/init_module.cpp b/frameworks/js/napi/src/manager/init_module.cpp index 232d2d689..fba1197e3 100644 --- a/frameworks/js/napi/src/manager/init_module.cpp +++ b/frameworks/js/napi/src/manager/init_module.cpp @@ -30,6 +30,7 @@ #include "napi_template.h" #include "pixel_map_napi.h" #include "napi_push.h" +#include "napi_local_live_view.h" namespace OHOS { namespace NotificationNapi { @@ -101,6 +102,8 @@ napi_value NotificationManagerInit(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("getDeviceRemindType", NapiGetDeviceRemindType), DECLARE_NAPI_FUNCTION("setSyncNotificationEnabledWithoutApp", NapiSetSyncNotificationEnabledWithoutApp), DECLARE_NAPI_FUNCTION("getSyncNotificationEnabledWithoutApp", NapiGetSyncNotificationEnabledWithoutApp), + DECLARE_NAPI_FUNCTION("subscribeLocalLiveView", NapiSubscriteLocalLiveView), + DECLARE_NAPI_FUNCTION("triggerLocalLiveView", NapiTriggerLocalLiveView), }; NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); diff --git a/frameworks/js/napi/src/manager/local_live_view_subscribe.cpp b/frameworks/js/napi/src/manager/local_live_view_subscribe.cpp new file mode 100644 index 000000000..156fc0ca5 --- /dev/null +++ b/frameworks/js/napi/src/manager/local_live_view_subscribe.cpp @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2021-2023 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 "local_live_view_subscribe.h" +#include "notification_button_option.h" + +#include +#include + +namespace OHOS { +namespace NotificationNapi { +const int32_t SUBSRIBE_MAX_PARA = 2; +const std::string RESPONSE = "onResponse"; + +struct LocalLiveViewReceiveDataWorker { + napi_env env = nullptr; + napi_ref ref = nullptr; + int32_t notificationId; + sptr buttonOption; + LocalLiveViewSubscriberInstance *subscriber = nullptr; +}; + +LocalLiveViewSubscriberInstance::LocalLiveViewSubscriberInstance() +{} + +LocalLiveViewSubscriberInstance::~LocalLiveViewSubscriberInstance() +{ + if (responseCallbackInfo_.ref != nullptr) { + napi_delete_reference(responseCallbackInfo_.env, responseCallbackInfo_.ref); + } +} + +void LocalLiveViewSubscriberInstance::OnDied() +{ + ANS_LOGI("enter"); +} + +void LocalLiveViewSubscriberInstance::OnConnected() +{ + ANS_LOGI("enter"); +} + +void LocalLiveViewSubscriberInstance::OnDisconnected() +{ + ANS_LOGI("enter"); +} + +void UvQueueWorkOnResponse(uv_work_t *work, int status) +{ + ANS_LOGI("OnResponse uv_work_t start"); + + if (work == nullptr) { + ANS_LOGE("work is nullptr"); + return; + } + + auto dataWorkerData = reinterpret_cast(work->data); + if (dataWorkerData == nullptr) { + ANS_LOGD("dataWorkerData is null."); + delete work; + work = nullptr; + return; + } + napi_value buttonOption = nullptr; + napi_value buttonName = nullptr; + napi_handle_scope scope; + napi_value notificationId = nullptr; + napi_open_handle_scope(dataWorkerData->env, &scope); + + // notificationId: number + napi_create_int32(dataWorkerData->env, dataWorkerData->notificationId, ¬ificationId); + + napi_create_object(dataWorkerData->env, &buttonOption); + napi_create_string_utf8(dataWorkerData->env, dataWorkerData->buttonOption->GetButtonName().c_str(), + NAPI_AUTO_LENGTH, &buttonName); + napi_set_named_property(dataWorkerData->env, buttonOption, "buttonName", buttonName); + + Common::SetCallbackArg2(dataWorkerData->env, dataWorkerData->ref, notificationId, buttonOption); + napi_close_handle_scope(dataWorkerData->env, scope); + + delete dataWorkerData; + dataWorkerData = nullptr; + delete work; +} + +void LocalLiveViewSubscriberInstance::OnResponse(int32_t notificationId, sptr buttonOption) +{ + ANS_LOGI("enter"); + + if (responseCallbackInfo_.ref == nullptr) { + ANS_LOGI("response callback unset"); + return; + } + + if (buttonOption == nullptr) { + ANS_LOGE("buttonOption is null"); + return; + } + + ANS_LOGI("OnResponse NotificationId = %{public}d", notificationId); + ANS_LOGI("OnResponse buttonOption size = %{public}s", buttonOption->GetButtonName().c_str()); + + uv_loop_s *loop = nullptr; + napi_get_uv_event_loop(responseCallbackInfo_.env, &loop); + if (loop == nullptr) { + ANS_LOGE("loop instance is nullptr"); + return; + } + + LocalLiveViewReceiveDataWorker *dataWorker = new (std::nothrow) LocalLiveViewReceiveDataWorker(); + if (dataWorker == nullptr) { + ANS_LOGE("DataWorker is nullptr."); + return; + } + + dataWorker->notificationId = notificationId; + dataWorker->buttonOption = buttonOption; + dataWorker->env = responseCallbackInfo_.env; + dataWorker->ref = responseCallbackInfo_.ref; + + uv_work_t *work = new (std::nothrow) uv_work_t; + if (work == nullptr) { + ANS_LOGE("new work failed"); + delete dataWorker; + dataWorker = nullptr; + return; + } + + work->data = reinterpret_cast(dataWorker); + + int ret = uv_queue_work_with_qos(loop, work, [](uv_work_t *work) {}, + UvQueueWorkOnResponse, uv_qos_user_initiated); + if (ret != 0) { + delete dataWorker; + dataWorker = nullptr; + delete work; + work = nullptr; + } +} + +void LocalLiveViewSubscriberInstance::SetResponseCallbackInfo(const napi_env &env, const napi_ref &ref) +{ + responseCallbackInfo_.env = env; + responseCallbackInfo_.ref = ref; +} + +void LocalLiveViewSubscriberInstance::SetCallbackInfo(const napi_env &env, const std::string &type, const napi_ref &ref) +{ + if (type == RESPONSE) { + SetResponseCallbackInfo(env, ref); + } else { + ANS_LOGW("type is error"); + } +} + +bool HasNotificationSubscriber(const napi_env &env, const napi_value &value, LocalLiveViewSubscriberInstancesInfo &subscriberInfo) +{ + std::lock_guard lock(mutex_); + for (auto vec : subscriberInstances_) { + napi_value callback = nullptr; + napi_get_reference_value(env, vec.ref, &callback); + bool isEquals = false; + napi_strict_equals(env, value, callback, &isEquals); + if (isEquals) { + subscriberInfo = vec; + return true; + } + } + return false; +} + +napi_value GetNotificationSubscriber( + const napi_env &env, const napi_value &value, LocalLiveViewSubscriberInstancesInfo &subscriberInfo) +{ + ANS_LOGI("enter"); + bool hasProperty = false; + napi_valuetype valuetype = napi_undefined; + napi_ref result = nullptr; + + subscriberInfo.subscriber = new (std::nothrow) LocalLiveViewSubscriberInstance(); + if (subscriberInfo.subscriber == nullptr) { + ANS_LOGE("subscriber is null"); + return nullptr; + } + + napi_create_reference(env, value, 1, &subscriberInfo.ref); + + // onResponse? + NAPI_CALL(env, napi_has_named_property(env, value, "onResponse", &hasProperty)); + if (hasProperty) { + napi_value onResponse = nullptr; + napi_get_named_property(env, value, "onResponse", &onResponse); + NAPI_CALL(env, napi_typeof(env, onResponse, &valuetype)); + if (valuetype != napi_function) { + ANS_LOGE("Wrong argument type. Function expected."); + return nullptr; + } + napi_create_reference(env, onResponse, 1, &result); + subscriberInfo.subscriber->SetCallbackInfo(env, RESPONSE, result); + } + + return Common::NapiGetNull(env); +} + +bool AddSubscriberInstancesInfo(const napi_env &env, const LocalLiveViewSubscriberInstancesInfo &subscriberInfo) +{ + ANS_LOGI("enter"); + if (subscriberInfo.ref == nullptr) { + ANS_LOGE("subscriberInfo.ref is null"); + return false; + } + if (subscriberInfo.subscriber == nullptr) { + ANS_LOGE("subscriberInfo.subscriber is null"); + return false; + } + std::lock_guard lock(mutex_); + subscriberInstances_.emplace_back(subscriberInfo); + + return true; +} + +bool DelSubscriberInstancesInfo(const napi_env &env, const LocalLiveViewSubscriberInstance *subscriber) +{ + ANS_LOGI("enter"); + if (subscriber == nullptr) { + ANS_LOGE("subscriber is null"); + return false; + } + + std::lock_guard lock(mutex_); + for (auto it = subscriberInstances_.begin(); it != subscriberInstances_.end(); ++it) { + if ((*it).subscriber == subscriber) { + if ((*it).ref != nullptr) { + napi_delete_reference(env, (*it).ref); + } + DelDeletingSubscriber((*it).subscriber); + delete (*it).subscriber; + (*it).subscriber = nullptr; + subscriberInstances_.erase(it); + return true; + } + } + return false; +} +napi_value ParseParameters(const napi_env &env, const napi_callback_info &info, + LocalLiveViewSubscriberInstance *&subscriber, napi_ref &callback) +{ + ANS_LOGI("enter"); + + size_t argc = SUBSRIBE_MAX_PARA; + napi_value argv[SUBSRIBE_MAX_PARA] = {nullptr}; + napi_value thisVar = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL)); + if (argc < 1) { + ANS_LOGE("Wrong number of arguments"); + return nullptr; + } + + napi_valuetype valuetype = napi_undefined; + + // argv[0]:LocalLiveViewButton + NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype)); + if (valuetype != napi_object) { + ANS_LOGE("Wrong argument type for arg0. LocalLiveViewButton object expected."); + return nullptr; + } + + LocalLiveViewSubscriberInstancesInfo subscriberInstancesInfo; + if (!HasNotificationSubscriber(env, argv[PARAM0], subscriberInstancesInfo)) { + if (GetNotificationSubscriber(env, argv[PARAM0], subscriberInstancesInfo) == nullptr) { + ANS_LOGE("LocalLiveViewButton parse failed"); + if (subscriberInstancesInfo.subscriber) { + delete subscriberInstancesInfo.subscriber; + subscriberInstancesInfo.subscriber = nullptr; + } + return nullptr; + } + if (!AddSubscriberInstancesInfo(env, subscriberInstancesInfo)) { + ANS_LOGE("AddSubscriberInstancesInfo add failed"); + if (subscriberInstancesInfo.subscriber) { + delete subscriberInstancesInfo.subscriber; + subscriberInstancesInfo.subscriber = nullptr; + } + return nullptr; + } + } + subscriber = subscriberInstancesInfo.subscriber; + + // argv[1]:callback + if (argc >= SUBSRIBE_MAX_PARA) { + NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype)); + if (valuetype != napi_function) { + ANS_LOGE("Callback is not function enforce promise."); + return Common::NapiGetNull(env); + } + napi_create_reference(env, argv[PARAM1], 1, &callback); + } + + return Common::NapiGetNull(env); +} + +bool AddDeletingSubscriber(LocalLiveViewSubscriberInstance *subscriber) +{ + std::lock_guard lock(delMutex_); + auto iter = std::find(DeletingSubscriber.begin(), DeletingSubscriber.end(), subscriber); + if (iter != DeletingSubscriber.end()) { + return false; + } + + DeletingSubscriber.push_back(subscriber); + return true; +} + +void DelDeletingSubscriber(LocalLiveViewSubscriberInstance *subscriber) +{ + std::lock_guard lock(delMutex_); + auto iter = std::find(DeletingSubscriber.begin(), DeletingSubscriber.end(), subscriber); + if (iter != DeletingSubscriber.end()) { + DeletingSubscriber.erase(iter); + } +} + +} // namespace NotificationNapi +} // namespace OHOS diff --git a/frameworks/js/napi/src/manager/napi_local_live_view.cpp b/frameworks/js/napi/src/manager/napi_local_live_view.cpp new file mode 100644 index 000000000..b6aa2a85f --- /dev/null +++ b/frameworks/js/napi/src/manager/napi_local_live_view.cpp @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2022-2023 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 "napi_local_live_view.h" + #include "local_live_view_subscribe.h" + #include "ans_inner_errors.h" + #include "common.h" + +namespace OHOS { +namespace NotificationNapi { +//const int32_t SUBSRIBE_MAX_PARA = 1; +const int32_t TRIGGER_PARA = 3; + +napi_value NapiSubscriteLocalLiveView(napi_env env, napi_callback_info info) +{ + ANS_LOGI("enter"); + napi_ref callback = nullptr; + LocalLiveViewSubscriberInstance *objectInfo = nullptr; + if (ParseParameters(env, info, objectInfo, callback) == nullptr) { + if (objectInfo) { + delete objectInfo; + objectInfo = nullptr; + } + Common::NapiThrow(env, ERROR_PARAM_INVALID); + return Common::NapiGetUndefined(env); + } + + AsyncCallbackInfoSubscribeLocalLiveView *asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoSubscribeLocalLiveView { + .env = env, .asyncWork = nullptr, .objectInfo = objectInfo + }; + if (!asynccallbackinfo) { + if (objectInfo) { + delete objectInfo; + objectInfo = nullptr; + } + return Common::JSParaError(env, callback); + } + napi_value promise = nullptr; + Common::PaddingCallbackPromiseInfo(env, callback, asynccallbackinfo->info, promise); + + napi_value resourceName = nullptr; + napi_create_string_latin1(env, "subscribeLocalLiveViewNotification", NAPI_AUTO_LENGTH, &resourceName); + // Asynchronous function call + napi_create_async_work(env, + nullptr, + resourceName, + [](napi_env env, void *data) { + ANS_LOGI("NapiSubscribeLocalLiveView work excute."); + if (!data) { + ANS_LOGE("Invalid asynccallbackinfo!"); + return; + } + auto asynccallbackinfo = reinterpret_cast(data); + + asynccallbackinfo->info.errorCode = + NotificationHelper::SubscribeLocalLiveViewNotification(*(asynccallbackinfo->objectInfo)); + + }, + [](napi_env env, napi_status status, void *data) { + ANS_LOGI("NapiSubscribeLocalLiveView work complete."); + if (!data) { + ANS_LOGE("Invalid asynccallbackinfo!"); + return; + } + auto asynccallbackinfo = reinterpret_cast(data); + if (asynccallbackinfo) { + Common::CreateReturnValue(env, asynccallbackinfo->info, Common::NapiGetNull(env)); + if (asynccallbackinfo->info.callback != nullptr) { + ANS_LOGD("Delete napiSubscribeLocalLiveView callback reference."); + napi_delete_reference(env, asynccallbackinfo->info.callback); + } + napi_delete_async_work(env, asynccallbackinfo->asyncWork); + delete asynccallbackinfo; + asynccallbackinfo = nullptr; + } + ANS_LOGD("NapiSubscribeLocalLiveView work complete end."); + }, + (void *)asynccallbackinfo, + &asynccallbackinfo->asyncWork); + + bool isCallback = asynccallbackinfo->info.isCallback; + napi_status status = napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated); + if (status != napi_ok) { + ANS_LOGE("Queue napiSubscribeLocalLiveView work failed return: %{public}d", status); + asynccallbackinfo->info.errorCode = ERROR_INTERNAL_ERROR; + Common::CreateReturnValue(env, asynccallbackinfo->info, Common::NapiGetNull(env)); + if (asynccallbackinfo->info.callback != nullptr) { + ANS_LOGD("Delete napiSubscribeLocalLiveView callback reference."); + napi_delete_reference(env, asynccallbackinfo->info.callback); + } + napi_delete_async_work(env, asynccallbackinfo->asyncWork); + delete asynccallbackinfo; + asynccallbackinfo = nullptr; + } + + if (isCallback) { + ANS_LOGD("napiSubscribeLocalLiveView callback is nullptr."); + return Common::NapiGetNull(env); + } else { + return promise; + } +} + +napi_value NapiUnsubscriteLocalLiveView(napi_env env, napi_callback_info info) +{ + return nullptr; +} + +napi_value ParseTriggerParameters(const napi_env &env, const napi_callback_info &info, + AsyncCallbackInfoSubscribeLocalLiveView *asynccallbackinfo, napi_ref &callback) +{ + ANS_LOGI("enter"); + + size_t argc = TRIGGER_PARA; + napi_value argv[TRIGGER_PARA] = {nullptr, nullptr}; + napi_value thisVar = nullptr; + + int32_t notificationId = -1; + + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL)); + if (argc != TRIGGER_PARA) { + ANS_LOGE("Wrong number of arguments"); + return nullptr; + } + + napi_valuetype valuetype = napi_undefined; + + // argv[0]:BundleOption + auto retValue = Common::GetBundleOption(env, argv[PARAM0], asynccallbackinfo->bundleOption); + if (retValue == nullptr) { + ANS_LOGE("GetBundleOption failed"); + return nullptr; + } + + // argv[1]:notificationId + NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype)); + if (valuetype != napi_number) { + ANS_LOGE("Wrong argument type. Number expected."); + return nullptr; + } + napi_get_value_int32(env, argv[PARAM1], ¬ificationId); + ANS_LOGI("notificationId = %{public}d", notificationId); + asynccallbackinfo->notificationId = notificationId; + + // argv[2]:buttonOption + retValue = Common::GetButtonOption(env, argv[PARAM2], asynccallbackinfo->buttonOption); + if (retValue == nullptr) { + ANS_LOGE("GetButtonOption failed"); + return nullptr; + } + return Common::NapiGetNull(env); +} + +napi_value NapiTriggerLocalLiveView(napi_env env, napi_callback_info info) +{ + ANS_LOGI("enter"); + napi_ref callback = nullptr; + + AsyncCallbackInfoSubscribeLocalLiveView *asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoSubscribeLocalLiveView { + .env = env, .asyncWork = nullptr, + }; + if (!asynccallbackinfo) { + return Common::JSParaError(env, callback); + } + + if (ParseTriggerParameters(env, info, asynccallbackinfo, callback) == nullptr) { + Common::NapiThrow(env, ERROR_PARAM_INVALID); + return Common::NapiGetUndefined(env); + } + + napi_value promise = nullptr; + Common::PaddingCallbackPromiseInfo(env, callback, asynccallbackinfo->info, promise); + + napi_value resourceName = nullptr; + napi_create_string_latin1(env, "triggerLocalLiveView", NAPI_AUTO_LENGTH, &resourceName); + // Asynchronous function call + napi_create_async_work(env, + nullptr, + resourceName, + [](napi_env env, void *data) { + ANS_LOGI("NapiTriggerLocalLiveView work excute."); + if (!data) { + ANS_LOGE("Invalid asynccallbackinfo!"); + return; + } + auto asynccallbackinfo = reinterpret_cast(data); + + asynccallbackinfo->info.errorCode = + NotificationHelper::TriggerLocalLiveView(asynccallbackinfo->bundleOption, + asynccallbackinfo->notificationId, asynccallbackinfo->buttonOption); + + }, + [](napi_env env, napi_status status, void *data) { + ANS_LOGI("NapiSubscribeLocalLiveView work complete."); + if (!data) { + ANS_LOGE("Invalid asynccallbackinfo!"); + return; + } + auto asynccallbackinfo = reinterpret_cast(data); + if (asynccallbackinfo) { + Common::CreateReturnValue(env, asynccallbackinfo->info, Common::NapiGetNull(env)); + if (asynccallbackinfo->info.callback != nullptr) { + ANS_LOGD("Delete napiSubscribeLocalLiveView callback reference."); + napi_delete_reference(env, asynccallbackinfo->info.callback); + } + napi_delete_async_work(env, asynccallbackinfo->asyncWork); + delete asynccallbackinfo; + asynccallbackinfo = nullptr; + } + ANS_LOGD("NapiSubscribeLocalLiveView work complete end."); + }, + (void *)asynccallbackinfo, + &asynccallbackinfo->asyncWork); + + bool isCallback = asynccallbackinfo->info.isCallback; + napi_status status = napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated); + if (status != napi_ok) { + ANS_LOGE("Queue napiSubscribeLocalLiveView work failed return: %{public}d", status); + asynccallbackinfo->info.errorCode = ERROR_INTERNAL_ERROR; + Common::CreateReturnValue(env, asynccallbackinfo->info, Common::NapiGetNull(env)); + if (asynccallbackinfo->info.callback != nullptr) { + ANS_LOGD("Delete napiSubscribeLocalLiveView callback reference."); + napi_delete_reference(env, asynccallbackinfo->info.callback); + } + napi_delete_async_work(env, asynccallbackinfo->asyncWork); + delete asynccallbackinfo; + asynccallbackinfo = nullptr; + } + + if (isCallback) { + ANS_LOGD("napiSubscribeLocalLiveView callback is nullptr."); + return Common::NapiGetNull(env); + } else { + return promise; + } +} + +} // namespace NotificationNapi +} // namespace OHOS -- Gitee