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("Wrong argument type. Function expected.");
38 return nullptr;
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.");
74 return nullptr;
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(env, asynccallbackinfo->asyncWork);
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(env, asynccallbackinfo->asyncWork);
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) {
400 ANS_LOGW("Wrong argument type. String expected.");
401 return nullptr;
402 }
403
404 char str[STR_MAX_SIZE] = {0};
405 size_t strLen = 0;
406 napi_get_value_string_utf8(env, argv[PARAM1], str, STR_MAX_SIZE - 1, &strLen);
407 params.request.SetOwnerBundleName(str);
408
409 // argv[2] : userId
410 NAPI_CALL(env, napi_typeof(env, argv[PARAM2], &valuetype));
411 if (valuetype != napi_number) {
412 ANS_LOGW("Wrong argument type. Number expected.");
413 return nullptr;
414 }
415 int32_t userId = 0;
416 napi_get_value_int32(env, argv[PARAM2], &userId);
417 params.request.SetOwnerUserId(userId);
418 params.request.SetIsAgentNotification(true);
419
420 // argv[3] : callback
421 if (argc >= PUBLISH_AS_BUNDLE_MAX) {
422 if (GetCallback(env, argv[PARAM3], params) == nullptr) {
423 return nullptr;
424 }
425 }
426
427 ANS_LOGI("end");
428 return Common::NapiGetNull(env);
429 }
430
PublishAsBundle(napi_env env,napi_callback_info info)431 napi_value PublishAsBundle(napi_env env, napi_callback_info info)
432 {
433 ANS_LOGI("enter");
434
435 ParametersInfoPublish params;
436 if (ParsePublishAsBundleParameters(env, info, params) == nullptr) {
437 return Common::NapiGetUndefined(env);
438 }
439
440 napi_value promise = nullptr;
441 auto asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoPublish {.env = env, .asyncWork = nullptr};
442 if (!asynccallbackinfo) {
443 return Common::JSParaError(env, params.callback);
444 }
445
446 asynccallbackinfo->request = params.request;
447 Common::PaddingCallbackPromiseInfo(env, params.callback, asynccallbackinfo->info, promise);
448
449 napi_value resourceName = nullptr;
450 napi_create_string_latin1(env, "publishasbundle", NAPI_AUTO_LENGTH, &resourceName);
451
452 napi_create_async_work(env,
453 nullptr,
454 resourceName,
455 [](napi_env env, void *data) {
456 ANS_LOGI("PublishAsBundle napi_create_async_work start");
457 AsyncCallbackInfoPublish *asynccallbackinfo = static_cast<AsyncCallbackInfoPublish *>(data);
458 if (asynccallbackinfo) {
459 ANS_LOGI("PublishAsBundle napi_create_async_work start notificationId = %{public}d, contentType = "
460 "%{public}d",
461 asynccallbackinfo->request.GetNotificationId(),
462 asynccallbackinfo->request.GetContent()->GetContentType());
463
464 asynccallbackinfo->info.errorCode =
465 NotificationHelper::PublishNotification(asynccallbackinfo->request);
466 }
467 },
468 [](napi_env env, napi_status status, void *data) {
469 ANS_LOGI("PublishAsBundle napi_create_async_work complete start");
470 AsyncCallbackInfoPublish *asynccallbackinfo = static_cast<AsyncCallbackInfoPublish *>(data);
471 if (asynccallbackinfo) {
472 Common::ReturnCallbackPromise(env, asynccallbackinfo->info, Common::NapiGetNull(env));
473 if (asynccallbackinfo->info.callback != nullptr) {
474 napi_delete_reference(env, asynccallbackinfo->info.callback);
475 }
476 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
477 delete asynccallbackinfo;
478 asynccallbackinfo = nullptr;
479 }
480 ANS_LOGI("PublishAsBundle napi_create_async_work complete end");
481 },
482 (void *)asynccallbackinfo,
483 &asynccallbackinfo->asyncWork);
484
485 napi_status status = napi_queue_async_work(env, asynccallbackinfo->asyncWork);
486 if (status != napi_ok) {
487 ANS_LOGE("napi_queue_async_work failed return: %{public}d", status);
488 if (asynccallbackinfo->info.callback != nullptr) {
489 napi_delete_reference(env, asynccallbackinfo->info.callback);
490 }
491 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
492 delete asynccallbackinfo;
493 asynccallbackinfo = nullptr;
494 return Common::JSParaError(env, params.callback);
495 }
496
497 if (asynccallbackinfo->info.isCallback) {
498 return Common::NapiGetNull(env);
499 } else {
500 return promise;
501 }
502 }
503 } // namespace NotificationNapi
504 } // namespace OHOS