1 /*
2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "publish.h"
17
18 #include "want_agent_helper.h"
19
20 namespace OHOS {
21 namespace NotificationNapi {
22 using namespace AbilityRuntime::WantAgent;
23
24 namespace {
25 constexpr int8_t PUBLISH_NOTIFICATION_MAX = 3;
26 constexpr int8_t SHOW_NOTIFICATION_MAX = 1;
27 constexpr int8_t PUBLISH_AS_BUNDLE_MAX = 4;
28 }
29
GetCallback(const napi_env & env,const napi_value & value,ParametersInfoPublish & params)30 napi_value GetCallback(const napi_env &env, const napi_value &value, ParametersInfoPublish ¶ms)
31 {
32 ANS_LOGI("enter");
33
34 napi_valuetype valuetype = napi_undefined;
35 NAPI_CALL(env, napi_typeof(env, value, &valuetype));
36 if (valuetype != napi_function) {
37 ANS_LOGW("Callback is not function excute promise.");
38 return Common::NapiGetNull(env);
39 }
40 napi_create_reference(env, value, 1, ¶ms.callback);
41 ANS_LOGI("end");
42 return Common::NapiGetNull(env);
43 }
44
ParseParameters(const napi_env & env,const napi_callback_info & info,ParametersInfoPublish & params)45 napi_value ParseParameters(const napi_env &env, const napi_callback_info &info, ParametersInfoPublish ¶ms)
46 {
47 ANS_LOGI("enter");
48
49 size_t argc = PUBLISH_NOTIFICATION_MAX;
50 napi_value argv[PUBLISH_NOTIFICATION_MAX] = {nullptr};
51 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
52 if (argc < 1) {
53 ANS_LOGW("Wrong number of arguments.");
54 return nullptr;
55 }
56
57 napi_valuetype valuetype = napi_undefined;
58 NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype));
59 if (valuetype != napi_object) {
60 ANS_LOGW("Wrong argument type. Object expected.");
61 return nullptr;
62 }
63
64 // argv[0] : NotificationRequest
65 if (Common::GetNotificationRequest(env, argv[PARAM0], params.request) == nullptr) {
66 return nullptr;
67 }
68
69 // argv[1] : userId / callback
70 if (argc >= PUBLISH_NOTIFICATION_MAX - 1) {
71 NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype));
72 if ((valuetype != napi_number) && (valuetype != napi_function)) {
73 ANS_LOGW("Wrong argument type. Function or object expected. Execute promise");
74 return Common::NapiGetNull(env);
75 }
76
77 if (valuetype == napi_number) {
78 int32_t recvUserId = SUBSCRIBE_USER_INIT;
79 NAPI_CALL(env, napi_get_value_int32(env, argv[PARAM1], &recvUserId));
80 params.request.SetReceiverUserId(recvUserId);
81 } else {
82 napi_create_reference(env, argv[PARAM1], 1, ¶ms.callback);
83 }
84 }
85
86 // argv[2] : callback
87 if (argc >= PUBLISH_NOTIFICATION_MAX) {
88 if (GetCallback(env, argv[PARAM2], params) == nullptr) {
89 return nullptr;
90 }
91 }
92
93 ANS_LOGI("end");
94 return Common::NapiGetNull(env);
95 }
96
Publish(napi_env env,napi_callback_info info)97 napi_value Publish(napi_env env, napi_callback_info info)
98 {
99 ANS_LOGI("enter");
100
101 ParametersInfoPublish params;
102 if (ParseParameters(env, info, params) == nullptr) {
103 return Common::NapiGetUndefined(env);
104 }
105
106 napi_value promise = nullptr;
107 auto asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoPublish {.env = env, .asyncWork = nullptr};
108 if (!asynccallbackinfo) {
109 return Common::JSParaError(env, params.callback);
110 }
111
112 asynccallbackinfo->request = params.request;
113 Common::PaddingCallbackPromiseInfo(env, params.callback, asynccallbackinfo->info, promise);
114
115 napi_value resourceName = nullptr;
116 napi_create_string_latin1(env, "publish", NAPI_AUTO_LENGTH, &resourceName);
117
118 napi_create_async_work(env,
119 nullptr,
120 resourceName,
121 [](napi_env env, void *data) {
122 ANS_LOGI("Publish napi_create_async_work start");
123 AsyncCallbackInfoPublish *asynccallbackinfo = static_cast<AsyncCallbackInfoPublish *>(data);
124 if (asynccallbackinfo) {
125 ANS_LOGI("Publish napi_create_async_work start notificationId = %{public}d, contentType = "
126 "%{public}d",
127 asynccallbackinfo->request.GetNotificationId(),
128 asynccallbackinfo->request.GetContent()->GetContentType());
129
130 asynccallbackinfo->info.errorCode =
131 NotificationHelper::PublishNotification(asynccallbackinfo->request);
132 }
133 },
134 [](napi_env env, napi_status status, void *data) {
135 ANS_LOGI("Publish napi_create_async_work complete start");
136 AsyncCallbackInfoPublish *asynccallbackinfo = static_cast<AsyncCallbackInfoPublish *>(data);
137 if (asynccallbackinfo) {
138 Common::ReturnCallbackPromise(env, asynccallbackinfo->info, Common::NapiGetNull(env));
139 if (asynccallbackinfo->info.callback != nullptr) {
140 napi_delete_reference(env, asynccallbackinfo->info.callback);
141 }
142 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
143 delete asynccallbackinfo;
144 asynccallbackinfo = nullptr;
145 }
146 ANS_LOGI("Publish napi_create_async_work complete end");
147 },
148 (void *)asynccallbackinfo,
149 &asynccallbackinfo->asyncWork);
150
151 napi_status status = napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
152 if (status != napi_ok) {
153 ANS_LOGE("napi_queue_async_work failed return: %{public}d", status);
154 if (asynccallbackinfo->info.callback != nullptr) {
155 napi_delete_reference(env, asynccallbackinfo->info.callback);
156 }
157 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
158 delete asynccallbackinfo;
159 asynccallbackinfo = nullptr;
160 return Common::JSParaError(env, params.callback);
161 }
162
163 if (asynccallbackinfo->info.isCallback) {
164 return Common::NapiGetNull(env);
165 } else {
166 return promise;
167 }
168 }
169
CheckProperty(const napi_env & env,const napi_value & content,const std::string & property)170 bool CheckProperty(const napi_env &env, const napi_value &content, const std::string &property)
171 {
172 ANS_LOGI("enter");
173
174 bool hasProperty = false;
175
176 NAPI_CALL_BASE(env, napi_has_named_property(env, content, property.data(), &hasProperty), false);
177 if (!hasProperty) {
178 ANS_LOGW("Property %{public}s expected.", property.c_str());
179 }
180 return hasProperty;
181 }
182
GetStringProperty(const napi_env & env,const napi_value & content,const std::string & property,std::string & result)183 napi_value GetStringProperty(
184 const napi_env &env, const napi_value &content, const std::string &property, std::string &result)
185 {
186 ANS_LOGI("enter");
187
188 if (!CheckProperty(env, content, property)) {
189 return nullptr;
190 }
191
192 napi_valuetype valuetype = napi_undefined;
193 napi_value value = nullptr;
194 char str[STR_MAX_SIZE] = {0};
195 size_t strLen = 0;
196
197 napi_get_named_property(env, content, property.data(), &value);
198 NAPI_CALL(env, napi_typeof(env, value, &valuetype));
199 if (valuetype != napi_string) {
200 ANS_LOGW("Wrong argument type. String expected.");
201 return nullptr;
202 }
203 NAPI_CALL(env, napi_get_value_string_utf8(env, value, str, STR_MAX_SIZE - 1, &strLen));
204 ANS_LOGI("normal::%{public}s = %{public}s", property.c_str(), str);
205 result = str;
206 return Common::NapiGetNull(env);
207 }
208
GetObjectProperty(const napi_env & env,const napi_value & content,const std::string & property,napi_value & result)209 napi_value GetObjectProperty(
210 const napi_env &env, const napi_value &content, const std::string &property, napi_value &result)
211 {
212 ANS_LOGI("enter");
213
214 if (!CheckProperty(env, content, property)) {
215 return nullptr;
216 }
217
218 napi_valuetype valuetype = napi_undefined;
219 napi_get_named_property(env, content, property.data(), &result);
220 NAPI_CALL(env, napi_typeof(env, result, &valuetype));
221 if (valuetype != napi_object) {
222 ANS_LOGW("Wrong argument type. Object expected.");
223 return nullptr;
224 }
225 return Common::NapiGetNull(env);
226 }
227
ParseShowOptions(const napi_env & env,const napi_callback_info & info,ParametersInfoPublish & params)228 napi_value ParseShowOptions(const napi_env &env, const napi_callback_info &info, ParametersInfoPublish ¶ms)
229 {
230 ANS_LOGI("enter");
231
232 size_t argc = SHOW_NOTIFICATION_MAX;
233 napi_value argv[SHOW_NOTIFICATION_MAX] = {nullptr};
234 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
235 if (argc == 0) {
236 ANS_LOGW("Wrong number of arguments.");
237 return nullptr;
238 }
239
240 // argv[0] : ShowNotificationOptions
241 napi_valuetype valuetype = napi_undefined;
242 NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype));
243 if (valuetype != napi_object) {
244 ANS_LOGW("Wrong argument type. Object expected.");
245 return nullptr;
246 }
247
248 std::shared_ptr<NotificationNormalContent> normalContent = std::make_shared<NotificationNormalContent>();
249
250 // contentTitle
251 std::string contentTitle;
252 if (GetStringProperty(env, argv[PARAM0], "contentTitle", contentTitle) != nullptr) {
253 normalContent->SetTitle(contentTitle);
254 }
255
256 // contentText
257 std::string contentText;
258 if (GetStringProperty(env, argv[PARAM0], "contentText", contentText) != nullptr) {
259 normalContent->SetText(contentText);
260 }
261
262 std::shared_ptr<NotificationContent> content = std::make_shared<NotificationContent>(normalContent);
263 params.request.SetContent(content);
264
265 // clickAction
266 napi_value clickAction = nullptr;
267 if (GetObjectProperty(env, argv[PARAM0], "clickAction", clickAction) != nullptr) {
268 ANS_LOGD("create wantagent");
269 // bundleName & abilityName
270 std::shared_ptr<AAFwk::Want> want = std::make_shared<AAFwk::Want>();
271 std::string bundleName;
272 std::string abilityName;
273 if (GetStringProperty(env, clickAction, "bundleName", bundleName) == nullptr) {
274 return nullptr;
275 }
276 if (GetStringProperty(env, clickAction, "abilityName", abilityName) == nullptr) {
277 return nullptr;
278 }
279 want->SetElementName(bundleName, abilityName);
280 // uri
281 std::string uri;
282 if (GetStringProperty(env, clickAction, "uri", uri) == nullptr) {
283 return nullptr;
284 }
285 want->SetUri(uri);
286
287 std::vector<std::shared_ptr<AAFwk::Want>> wants = {};
288 std::vector<WantAgentConstant::Flags> wantAgentFlags = {};
289 std::shared_ptr<AAFwk::WantParams> extraInfo = std::make_shared<AAFwk::WantParams>();
290 wants.emplace_back(want);
291 WantAgentInfo wantAgentInfo(-1, WantAgentConstant::OperationType::START_ABILITY, wantAgentFlags,
292 wants, extraInfo);
293 std::shared_ptr<AbilityRuntime::ApplicationContext> context = AbilityRuntime::Context::GetApplicationContext();
294
295 std::shared_ptr<WantAgent> wantAgent = nullptr;
296 WantAgentHelper::GetWantAgent(context, wantAgentInfo, wantAgent);
297 params.request.SetWantAgent(wantAgent);
298 }
299
300 ANS_LOGI("end");
301 return Common::NapiGetNull(env);
302 }
303
ShowNotification(napi_env env,napi_callback_info info)304 napi_value ShowNotification(napi_env env, napi_callback_info info)
305 {
306 ANS_LOGI("enter");
307
308 ParametersInfoPublish params;
309 if (ParseShowOptions(env, info, params) == nullptr) {
310 ANS_LOGW("parse showOptions failed");
311 return Common::NapiGetUndefined(env);
312 }
313
314 auto asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoPublish {.env = env, .asyncWork = nullptr};
315 if (!asynccallbackinfo) {
316 ANS_LOGW("failed to create asynccallbackinfo");
317 return Common::JSParaError(env, params.callback);
318 }
319
320 asynccallbackinfo->request = params.request;
321
322 napi_value resourceName = nullptr;
323 napi_create_string_latin1(env, "show", NAPI_AUTO_LENGTH, &resourceName);
324
325 ANS_LOGI("before napi_create_async_work");
326 napi_create_async_work(env,
327 nullptr,
328 resourceName,
329 [](napi_env env, void *data) {
330 ANS_LOGI("Show napi_create_async_work start");
331 AsyncCallbackInfoPublish *asynccallbackinfo = static_cast<AsyncCallbackInfoPublish *>(data);
332 if (asynccallbackinfo) {
333 ANS_LOGI("Show napi_create_async_work start notificationId = %{public}d, contentType = "
334 "%{public}d",
335 asynccallbackinfo->request.GetNotificationId(),
336 asynccallbackinfo->request.GetContent()->GetContentType());
337
338 asynccallbackinfo->info.errorCode =
339 NotificationHelper::PublishNotification(asynccallbackinfo->request);
340 }
341 },
342 [](napi_env env, napi_status status, void *data) {
343 ANS_LOGI("Show napi_create_async_work complete start");
344 AsyncCallbackInfoPublish *asynccallbackinfo = static_cast<AsyncCallbackInfoPublish *>(data);
345 if (asynccallbackinfo) {
346 if (asynccallbackinfo->info.callback != nullptr) {
347 napi_delete_reference(env, asynccallbackinfo->info.callback);
348 }
349 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
350 delete asynccallbackinfo;
351 asynccallbackinfo = nullptr;
352 }
353 ANS_LOGI("Show napi_create_async_work complete end");
354 },
355 (void *)asynccallbackinfo,
356 &asynccallbackinfo->asyncWork);
357
358 napi_status status = napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
359 if (status != napi_ok) {
360 ANS_LOGE("napi_queue_async_work failed return: %{public}d", status);
361 if (asynccallbackinfo->info.callback != nullptr) {
362 napi_delete_reference(env, asynccallbackinfo->info.callback);
363 }
364 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
365 delete asynccallbackinfo;
366 asynccallbackinfo = nullptr;
367 return Common::JSParaError(env, params.callback);
368 }
369 return nullptr;
370 }
371
ParsePublishAsBundleParameters(const napi_env & env,const napi_callback_info & info,ParametersInfoPublish & params)372 napi_value ParsePublishAsBundleParameters(
373 const napi_env &env, const napi_callback_info &info, ParametersInfoPublish ¶ms)
374 {
375 ANS_LOGI("enter");
376
377 size_t argc = PUBLISH_AS_BUNDLE_MAX;
378 napi_value argv[PUBLISH_AS_BUNDLE_MAX] = {nullptr};
379 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
380 if (argc < 1) {
381 ANS_LOGW("Wrong number of arguments");
382 return nullptr;
383 }
384
385 napi_valuetype valuetype = napi_undefined;
386 NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype));
387 if (valuetype != napi_object) {
388 ANS_LOGW("Wrong argument type. Object expected.");
389 return nullptr;
390 }
391
392 // argv[0] : NotificationRequest
393 if (Common::GetNotificationRequest(env, argv[PARAM0], params.request) == nullptr) {
394 return nullptr;
395 }
396
397 // argv[1] : bundleName
398 NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype));
399 if (valuetype != napi_string && valuetype != napi_number && valuetype != napi_boolean) {
400 ANS_LOGW("Wrong argument type. String number boolean expected.");
401 return nullptr;
402 }
403
404 if (valuetype == napi_string) {
405 char str[STR_MAX_SIZE] = {0};
406 size_t strLen = 0;
407 napi_get_value_string_utf8(env, argv[PARAM1], str, STR_MAX_SIZE - 1, &strLen);
408 params.request.SetOwnerBundleName(str);
409 } else if (valuetype == napi_number) {
410 int64_t number = 0;
411 NAPI_CALL(env, napi_get_value_int64(env, argv[PARAM1], &number));
412 params.request.SetOwnerBundleName(std::to_string(number));
413 } else {
414 bool result = false;
415 NAPI_CALL(env, napi_get_value_bool(env, argv[PARAM1], &result));
416 params.request.SetOwnerBundleName(std::to_string(result));
417 }
418
419 // argv[2] : userId
420 NAPI_CALL(env, napi_typeof(env, argv[PARAM2], &valuetype));
421 if (valuetype != napi_number) {
422 ANS_LOGW("Wrong argument type. Number expected.");
423 return nullptr;
424 }
425 int32_t userId = 0;
426 napi_get_value_int32(env, argv[PARAM2], &userId);
427 params.request.SetOwnerUserId(userId);
428 params.request.SetIsAgentNotification(true);
429
430 // argv[3] : callback
431 if (argc >= PUBLISH_AS_BUNDLE_MAX) {
432 if (GetCallback(env, argv[PARAM3], params) == nullptr) {
433 return nullptr;
434 }
435 }
436
437 ANS_LOGI("end");
438 return Common::NapiGetNull(env);
439 }
440
PublishAsBundle(napi_env env,napi_callback_info info)441 napi_value PublishAsBundle(napi_env env, napi_callback_info info)
442 {
443 ANS_LOGI("enter");
444
445 ParametersInfoPublish params;
446 if (ParsePublishAsBundleParameters(env, info, params) == nullptr) {
447 return Common::NapiGetUndefined(env);
448 }
449
450 napi_value promise = nullptr;
451 auto asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoPublish {.env = env, .asyncWork = nullptr};
452 if (!asynccallbackinfo) {
453 return Common::JSParaError(env, params.callback);
454 }
455
456 asynccallbackinfo->request = params.request;
457 Common::PaddingCallbackPromiseInfo(env, params.callback, asynccallbackinfo->info, promise);
458
459 napi_value resourceName = nullptr;
460 napi_create_string_latin1(env, "publishasbundle", NAPI_AUTO_LENGTH, &resourceName);
461
462 napi_create_async_work(env,
463 nullptr,
464 resourceName,
465 [](napi_env env, void *data) {
466 ANS_LOGI("PublishAsBundle napi_create_async_work start");
467 AsyncCallbackInfoPublish *asynccallbackinfo = static_cast<AsyncCallbackInfoPublish *>(data);
468 if (asynccallbackinfo) {
469 ANS_LOGI("PublishAsBundle napi_create_async_work start notificationId = %{public}d, contentType = "
470 "%{public}d",
471 asynccallbackinfo->request.GetNotificationId(),
472 asynccallbackinfo->request.GetContent()->GetContentType());
473
474 asynccallbackinfo->info.errorCode =
475 NotificationHelper::PublishNotification(asynccallbackinfo->request);
476 }
477 },
478 [](napi_env env, napi_status status, void *data) {
479 ANS_LOGI("PublishAsBundle napi_create_async_work complete start");
480 AsyncCallbackInfoPublish *asynccallbackinfo = static_cast<AsyncCallbackInfoPublish *>(data);
481 if (asynccallbackinfo) {
482 Common::ReturnCallbackPromise(env, asynccallbackinfo->info, Common::NapiGetNull(env));
483 if (asynccallbackinfo->info.callback != nullptr) {
484 napi_delete_reference(env, asynccallbackinfo->info.callback);
485 }
486 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
487 delete asynccallbackinfo;
488 asynccallbackinfo = nullptr;
489 }
490 ANS_LOGI("PublishAsBundle napi_create_async_work complete end");
491 },
492 (void *)asynccallbackinfo,
493 &asynccallbackinfo->asyncWork);
494
495 napi_status status = napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
496 if (status != napi_ok) {
497 ANS_LOGE("napi_queue_async_work failed return: %{public}d", status);
498 if (asynccallbackinfo->info.callback != nullptr) {
499 napi_delete_reference(env, asynccallbackinfo->info.callback);
500 }
501 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
502 delete asynccallbackinfo;
503 asynccallbackinfo = nullptr;
504 return Common::JSParaError(env, params.callback);
505 }
506
507 if (asynccallbackinfo->info.isCallback) {
508 return Common::NapiGetNull(env);
509 } else {
510 return promise;
511 }
512 }
513 } // namespace NotificationNapi
514 } // namespace OHOS