/* * 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 "publish.h" #include "ans_const_define.h" #include "js_native_api_types.h" #include "want_agent_helper.h" #include "ans_inner_errors.h" namespace OHOS { namespace NotificationNapi { using namespace AbilityRuntime::WantAgent; namespace { constexpr int8_t PUBLISH_NOTIFICATION_MAX = 3; constexpr int8_t SHOW_NOTIFICATION_MAX = 1; constexpr int8_t PUBLISH_AS_BUNDLE_MAX = 4; constexpr int8_t PUBLISH_AS_BUNDLEOPTION_MAX = 2; } napi_value GetCallback(const napi_env &env, const napi_value &value, ParametersInfoPublish ¶ms) { ANS_LOGD("enter"); napi_valuetype valuetype = napi_undefined; NAPI_CALL(env, napi_typeof(env, value, &valuetype)); if (valuetype != napi_function) { ANS_LOGW("Callback is not function excute promise."); return Common::NapiGetNull(env); } napi_create_reference(env, value, 1, ¶ms.callback); ANS_LOGD("end"); return Common::NapiGetNull(env); } napi_value ParseParameters(const napi_env &env, const napi_callback_info &info, ParametersInfoPublish ¶ms) { ANS_LOGD("enter"); size_t argc = PUBLISH_NOTIFICATION_MAX; napi_value argv[PUBLISH_NOTIFICATION_MAX] = {nullptr}; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); if (argc < 1) { ANS_LOGW("Wrong number of arguments."); Common::NapiThrow(env, ERROR_PARAM_INVALID, MANDATORY_PARAMETER_ARE_LEFT_UNSPECIFIED); return nullptr; } napi_valuetype valuetype = napi_undefined; NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype)); if (valuetype != napi_object) { ANS_LOGW("Argument type error. Object expected."); std::string msg = "Incorrect parameter types.The type of param must be object."; Common::NapiThrow(env, ERROR_PARAM_INVALID, msg); return nullptr; } // argv[0] : NotificationRequest if (Common::GetNotificationRequest(env, argv[PARAM0], params.request) == nullptr) { return nullptr; } // argv[1] : userId / callback if (argc >= PUBLISH_NOTIFICATION_MAX - 1) { NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype)); if ((valuetype != napi_number) && (valuetype != napi_function)) { ANS_LOGW("Wrong argument type. Function or object expected. Execute promise"); return Common::NapiGetNull(env); } if (valuetype == napi_number) { int32_t recvUserId = SUBSCRIBE_USER_INIT; NAPI_CALL(env, napi_get_value_int32(env, argv[PARAM1], &recvUserId)); params.request.SetOwnerUserId(recvUserId); } else { napi_create_reference(env, argv[PARAM1], 1, ¶ms.callback); } } // argv[2] : callback if (argc >= PUBLISH_NOTIFICATION_MAX) { if (GetCallback(env, argv[PARAM2], params) == nullptr) { return nullptr; } } ANS_LOGD("end"); return Common::NapiGetNull(env); } napi_value Publish(napi_env env, napi_callback_info info) { ANS_LOGD("enter"); ParametersInfoPublish params; if (ParseParameters(env, info, params) == nullptr) { return Common::NapiGetUndefined(env); } napi_value promise = nullptr; auto asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoPublish {.env = env, .asyncWork = nullptr}; if (!asynccallbackinfo) { ANS_LOGD("Asynccallbackinfo is nullptr."); return Common::JSParaError(env, params.callback); } asynccallbackinfo->request = params.request; Common::PaddingCallbackPromiseInfo(env, params.callback, asynccallbackinfo->info, promise); ANS_LOGD("Create publish string."); napi_value resourceName = nullptr; napi_create_string_latin1(env, "publish", NAPI_AUTO_LENGTH, &resourceName); napi_create_async_work(env, nullptr, resourceName, [](napi_env env, void *data) { ANS_LOGI("Publish napi_create_async_work start"); AsyncCallbackInfoPublish *asynccallbackinfo = static_cast(data); if (asynccallbackinfo) { ANS_LOGI("Publish napi_create_async_work start notificationId = %{public}d, contentType = " "%{public}d", asynccallbackinfo->request.GetNotificationId(), asynccallbackinfo->request.GetContent()->GetContentType()); asynccallbackinfo->info.errorCode = NotificationHelper::PublishNotification(asynccallbackinfo->request); } }, [](napi_env env, napi_status status, void *data) { ANS_LOGI("Publish napi_create_async_work complete start"); AsyncCallbackInfoPublish *asynccallbackinfo = static_cast(data); if (asynccallbackinfo) { Common::ReturnCallbackPromise(env, asynccallbackinfo->info, Common::NapiGetNull(env)); if (asynccallbackinfo->info.callback != nullptr) { ANS_LOGD("Delete publish callback reference."); napi_delete_reference(env, asynccallbackinfo->info.callback); } napi_delete_async_work(env, asynccallbackinfo->asyncWork); delete asynccallbackinfo; asynccallbackinfo = nullptr; } ANS_LOGD("Publish work complete end."); }, (void *)asynccallbackinfo, &asynccallbackinfo->asyncWork); napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated); if (asynccallbackinfo->info.isCallback) { ANS_LOGD("publish callback is nullptr."); return Common::NapiGetNull(env); } else { return promise; } } bool CheckProperty(const napi_env &env, const napi_value &content, const std::string &property) { ANS_LOGD("enter"); bool hasProperty = false; NAPI_CALL_BASE(env, napi_has_named_property(env, content, property.data(), &hasProperty), false); if (!hasProperty) { ANS_LOGW("Property %{public}s expected.", property.c_str()); } return hasProperty; } napi_value GetStringProperty( const napi_env &env, const napi_value &content, const std::string &property, std::string &result) { ANS_LOGD("enter"); if (!CheckProperty(env, content, property)) { return nullptr; } napi_valuetype valuetype = napi_undefined; napi_value value = nullptr; char str[STR_MAX_SIZE] = {0}; size_t strLen = 0; napi_get_named_property(env, content, property.data(), &value); NAPI_CALL(env, napi_typeof(env, value, &valuetype)); if (valuetype != napi_string) { ANS_LOGW("Wrong argument type. String expected."); std::string msg = "Incorrect parameter types.The type of param must be string."; Common::NapiThrow(env, ERROR_PARAM_INVALID, msg); return nullptr; } NAPI_CALL(env, napi_get_value_string_utf8(env, value, str, STR_MAX_SIZE - 1, &strLen)); ANS_LOGI("normal::%{public}s = %{public}s", property.c_str(), str); result = str; return Common::NapiGetNull(env); } napi_value GetObjectProperty( const napi_env &env, const napi_value &content, const std::string &property, napi_value &result) { ANS_LOGD("enter"); if (!CheckProperty(env, content, property)) { return nullptr; } napi_valuetype valuetype = napi_undefined; napi_get_named_property(env, content, property.data(), &result); NAPI_CALL(env, napi_typeof(env, result, &valuetype)); if (valuetype != napi_object) { ANS_LOGW("Wrong argument type. Object expected."); std::string msg = "Incorrect parameter types.The type of param must be object."; Common::NapiThrow(env, ERROR_PARAM_INVALID, msg); return nullptr; } return Common::NapiGetNull(env); } napi_value ParseShowOptions(const napi_env &env, const napi_callback_info &info, ParametersInfoPublish ¶ms) { ANS_LOGD("enter"); size_t argc = SHOW_NOTIFICATION_MAX; napi_value argv[SHOW_NOTIFICATION_MAX] = {nullptr}; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); if (argc == 0) { ANS_LOGW("Wrong number of arguments."); return nullptr; } // argv[0] : ShowNotificationOptions napi_valuetype valuetype = napi_undefined; NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype)); if (valuetype != napi_object) { ANS_LOGW("Wrong argument type. Object expected."); return nullptr; } std::shared_ptr normalContent = std::make_shared(); // contentTitle std::string contentTitle; if (GetStringProperty(env, argv[PARAM0], "contentTitle", contentTitle) != nullptr) { normalContent->SetTitle(contentTitle); } // contentText std::string contentText; if (GetStringProperty(env, argv[PARAM0], "contentText", contentText) != nullptr) { normalContent->SetText(contentText); } std::shared_ptr content = std::make_shared(normalContent); params.request.SetContent(content); // clickAction napi_value clickAction = nullptr; if (GetObjectProperty(env, argv[PARAM0], "clickAction", clickAction) != nullptr) { ANS_LOGD("create wantagent"); // bundleName & abilityName std::shared_ptr want = std::make_shared(); std::string bundleName; std::string abilityName; if (GetStringProperty(env, clickAction, "bundleName", bundleName) == nullptr) { return nullptr; } if (GetStringProperty(env, clickAction, "abilityName", abilityName) == nullptr) { return nullptr; } want->SetElementName(bundleName, abilityName); // uri std::string uri; if (GetStringProperty(env, clickAction, "uri", uri) == nullptr) { return nullptr; } want->SetUri(uri); std::vector> wants = {}; std::vector wantAgentFlags = {}; std::shared_ptr extraInfo = std::make_shared(); wants.emplace_back(want); WantAgentInfo wantAgentInfo(-1, WantAgentConstant::OperationType::START_ABILITY, wantAgentFlags, wants, extraInfo); std::shared_ptr context = AbilityRuntime::Context::GetApplicationContext(); std::shared_ptr wantAgent = nullptr; WantAgentHelper::GetWantAgent(context, wantAgentInfo, wantAgent); params.request.SetWantAgent(wantAgent); } ANS_LOGD("end"); return Common::NapiGetNull(env); } napi_value ShowNotification(napi_env env, napi_callback_info info) { ANS_LOGD("enter"); ParametersInfoPublish params; if (ParseShowOptions(env, info, params) == nullptr) { ANS_LOGW("parse showOptions failed"); return Common::NapiGetUndefined(env); } auto asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoPublish {.env = env, .asyncWork = nullptr}; if (!asynccallbackinfo) { ANS_LOGW("failed to create asynccallbackinfo"); return Common::JSParaError(env, params.callback); } asynccallbackinfo->request = params.request; ANS_LOGD("Create show string."); napi_value resourceName = nullptr; napi_create_string_latin1(env, "show", NAPI_AUTO_LENGTH, &resourceName); ANS_LOGI("before napi_create_async_work"); napi_create_async_work(env, nullptr, resourceName, [](napi_env env, void *data) { ANS_LOGD("ShowNotification work excute."); AsyncCallbackInfoPublish *asynccallbackinfo = static_cast(data); if (asynccallbackinfo) { ANS_LOGI("Show napi_create_async_work start notificationId = %{public}d, contentType = " "%{public}d", asynccallbackinfo->request.GetNotificationId(), asynccallbackinfo->request.GetContent()->GetContentType()); asynccallbackinfo->info.errorCode = NotificationHelper::PublishNotification(asynccallbackinfo->request); } }, [](napi_env env, napi_status status, void *data) { ANS_LOGD("ShowNotification work complete."); AsyncCallbackInfoPublish *asynccallbackinfo = static_cast(data); if (asynccallbackinfo) { if (asynccallbackinfo->info.callback != nullptr) { napi_delete_reference(env, asynccallbackinfo->info.callback); } napi_delete_async_work(env, asynccallbackinfo->asyncWork); delete asynccallbackinfo; asynccallbackinfo = nullptr; } ANS_LOGI("Show napi_create_async_work complete end"); }, (void *)asynccallbackinfo, &asynccallbackinfo->asyncWork); napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated); return nullptr; } napi_value ParsePublishAsBundleParameters( const napi_env &env, const napi_callback_info &info, ParametersInfoPublish ¶ms) { ANS_LOGD("enter"); size_t argc = PUBLISH_AS_BUNDLE_MAX; napi_value argv[PUBLISH_AS_BUNDLE_MAX] = {nullptr}; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); if (argc < 1) { ANS_LOGW("Wrong number of arguments"); Common::NapiThrow(env, ERROR_PARAM_INVALID, MANDATORY_PARAMETER_ARE_LEFT_UNSPECIFIED); return nullptr; } // argv[0] : NotificationRequest / bundleOption napi_valuetype valuetype = napi_undefined; NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype)); if (valuetype != napi_object) { ANS_LOGW("Wrong argument type. Object expected."); std::string msg = "Incorrect parameter types.The type of param must be object."; Common::NapiThrow(env, ERROR_PARAM_INVALID, msg); return nullptr; } if (argc > PUBLISH_AS_BUNDLEOPTION_MAX) { if (Common::GetNotificationRequest(env, argv[PARAM0], params.request) == nullptr) { return nullptr; } } else { NotificationBundleOption option; auto retValue = Common::GetBundleOption(env, argv[PARAM0], option); if (retValue == nullptr) { ANS_LOGE("GetBundleOption failed."); Common::NapiThrow(env, ERROR_PARAM_INVALID, PARAMETER_VERIFICATION_FAILED); return nullptr; } params.request.SetOwnerBundleName(option.GetBundleName()); params.request.SetOwnerUid(option.GetUid()); params.request.SetIsAgentNotification(true); } // argv[1] : bundleName / NotificationRequest NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype)); if (valuetype != napi_string && valuetype != napi_number && valuetype != napi_boolean && valuetype != napi_object) { ANS_LOGW("Error argument type. String number boolean object expected."); std::string msg = "Incorrect parameter types.The type of param must be string or number or boolean."; Common::NapiThrow(env, ERROR_PARAM_INVALID, msg); return nullptr; } if (argc > PUBLISH_AS_BUNDLEOPTION_MAX) { if (valuetype == napi_string) { char str[STR_MAX_SIZE] = {0}; size_t strLen = 0; napi_get_value_string_utf8(env, argv[PARAM1], str, STR_MAX_SIZE - 1, &strLen); params.request.SetOwnerBundleName(str); } else if (valuetype == napi_number) { int64_t number = 0; NAPI_CALL(env, napi_get_value_int64(env, argv[PARAM1], &number)); params.request.SetOwnerBundleName(std::to_string(number)); } else { bool result = false; NAPI_CALL(env, napi_get_value_bool(env, argv[PARAM1], &result)); params.request.SetOwnerBundleName(std::to_string(result)); } } else { if (Common::GetNotificationRequest(env, argv[PARAM1], params.request) == nullptr) { return nullptr; } } // argv[2] : userId if (argc > PUBLISH_AS_BUNDLEOPTION_MAX) { NAPI_CALL(env, napi_typeof(env, argv[PARAM2], &valuetype)); if (valuetype != napi_number) { ANS_LOGW("Wrong argument type. Number expected."); std::string msg = "Incorrect parameter types.The type of userId must be number."; Common::NapiThrow(env, ERROR_PARAM_INVALID, msg); return nullptr; } int32_t userId = 0; napi_get_value_int32(env, argv[PARAM2], &userId); params.request.SetOwnerUserId(userId); params.request.SetIsAgentNotification(true); } // argv[3] : callback if (argc >= PUBLISH_AS_BUNDLE_MAX) { if (GetCallback(env, argv[PARAM3], params) == nullptr) { return nullptr; } } ANS_LOGD("end"); return Common::NapiGetNull(env); } napi_value PublishAsBundle(napi_env env, napi_callback_info info) { ANS_LOGD("enter"); ParametersInfoPublish params; if (ParsePublishAsBundleParameters(env, info, params) == nullptr) { return Common::NapiGetUndefined(env); } napi_value promise = nullptr; auto asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoPublish {.env = env, .asyncWork = nullptr}; if (!asynccallbackinfo) { ANS_LOGD("Create asynccallbackinfo failed."); return Common::JSParaError(env, params.callback); } asynccallbackinfo->request = params.request; Common::PaddingCallbackPromiseInfo(env, params.callback, asynccallbackinfo->info, promise); ANS_LOGD("Create publishasbundle string."); napi_value resourceName = nullptr; napi_create_string_latin1(env, "publishasbundle", NAPI_AUTO_LENGTH, &resourceName); napi_create_async_work(env, nullptr, resourceName, [](napi_env env, void *data) { ANS_LOGD("PublishAsBundle work excute."); AsyncCallbackInfoPublish *asynccallbackinfo = static_cast(data); if (asynccallbackinfo) { ANS_LOGI("PublishAsBundle napi_create_async_work start notificationId = %{public}d, contentType = " "%{public}d", asynccallbackinfo->request.GetNotificationId(), asynccallbackinfo->request.GetContent()->GetContentType()); asynccallbackinfo->info.errorCode = NotificationHelper::PublishNotification(asynccallbackinfo->request); } }, [](napi_env env, napi_status status, void *data) { ANS_LOGD("PublishAsBundle work complete."); AsyncCallbackInfoPublish *asynccallbackinfo = static_cast(data); if (asynccallbackinfo) { Common::ReturnCallbackPromise(env, asynccallbackinfo->info, Common::NapiGetNull(env)); if (asynccallbackinfo->info.callback != nullptr) { ANS_LOGD("Delete publishAsBundle callback reference."); napi_delete_reference(env, asynccallbackinfo->info.callback); } napi_delete_async_work(env, asynccallbackinfo->asyncWork); delete asynccallbackinfo; asynccallbackinfo = nullptr; } ANS_LOGD("PublishAsBundle complete end"); }, (void *)asynccallbackinfo, &asynccallbackinfo->asyncWork); napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated); if (asynccallbackinfo->info.isCallback) { ANS_LOGD("publishAsBundle callback is nullptr."); return Common::NapiGetNull(env); } else { return promise; } } } // namespace NotificationNapi } // namespace OHOS