1 /*
2 * Copyright (c) 2021-2022 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_CALL(env, napi_queue_async_work(env, asynccallbackinfo->asyncWork));
152
153 if (asynccallbackinfo->info.isCallback) {
154 return Common::NapiGetNull(env);
155 } else {
156 return promise;
157 }
158 }
159
CheckProperty(const napi_env & env,const napi_value & content,const std::string & property)160 bool CheckProperty(const napi_env &env, const napi_value &content, const std::string &property)
161 {
162 ANS_LOGI("enter");
163
164 bool hasProperty = false;
165
166 NAPI_CALL_BASE(env, napi_has_named_property(env, content, property.data(), &hasProperty), false);
167 if (!hasProperty) {
168 ANS_LOGW("Property %{public}s expected.", property.c_str());
169 }
170 return hasProperty;
171 }
172
GetStringProperty(const napi_env & env,const napi_value & content,const std::string & property,std::string & result)173 napi_value GetStringProperty(
174 const napi_env &env, const napi_value &content, const std::string &property, std::string &result)
175 {
176 ANS_LOGI("enter");
177
178 if (!CheckProperty(env, content, property)) {
179 return nullptr;
180 }
181
182 napi_valuetype valuetype = napi_undefined;
183 napi_value value = nullptr;
184 char str[STR_MAX_SIZE] = {0};
185 size_t strLen = 0;
186
187 napi_get_named_property(env, content, property.data(), &value);
188 NAPI_CALL(env, napi_typeof(env, value, &valuetype));
189 if (valuetype != napi_string) {
190 ANS_LOGW("Wrong argument type. String expected.");
191 return nullptr;
192 }
193 NAPI_CALL(env, napi_get_value_string_utf8(env, value, str, STR_MAX_SIZE - 1, &strLen));
194 ANS_LOGI("normal::%{public}s = %{public}s", property.c_str(), str);
195 result = str;
196 return Common::NapiGetNull(env);
197 }
198
GetObjectProperty(const napi_env & env,const napi_value & content,const std::string & property,napi_value & result)199 napi_value GetObjectProperty(
200 const napi_env &env, const napi_value &content, const std::string &property, napi_value &result)
201 {
202 ANS_LOGI("enter");
203
204 if (!CheckProperty(env, content, property)) {
205 return nullptr;
206 }
207
208 napi_valuetype valuetype = napi_undefined;
209 napi_get_named_property(env, content, property.data(), &result);
210 NAPI_CALL(env, napi_typeof(env, result, &valuetype));
211 if (valuetype != napi_object) {
212 ANS_LOGW("Wrong argument type. Object expected.");
213 return nullptr;
214 }
215 return Common::NapiGetNull(env);
216 }
217
ParseShowOptions(const napi_env & env,const napi_callback_info & info,ParametersInfoPublish & params)218 napi_value ParseShowOptions(const napi_env &env, const napi_callback_info &info, ParametersInfoPublish ¶ms)
219 {
220 ANS_LOGI("enter");
221
222 size_t argc = SHOW_NOTIFICATION_MAX;
223 napi_value argv[SHOW_NOTIFICATION_MAX] = {nullptr};
224 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
225 if (argc == 0) {
226 ANS_LOGW("Wrong number of arguments.");
227 return nullptr;
228 }
229
230 // argv[0] : ShowNotificationOptions
231 napi_valuetype valuetype = napi_undefined;
232 NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype));
233 if (valuetype != napi_object) {
234 ANS_LOGW("Wrong argument type. Object expected.");
235 return nullptr;
236 }
237
238 std::shared_ptr<NotificationNormalContent> normalContent = std::make_shared<NotificationNormalContent>();
239
240 // contentTitle
241 std::string contentTitle;
242 if (GetStringProperty(env, argv[PARAM0], "contentTitle", contentTitle) != nullptr) {
243 normalContent->SetTitle(contentTitle);
244 }
245
246 // contentText
247 std::string contentText;
248 if (GetStringProperty(env, argv[PARAM0], "contentText", contentText) != nullptr) {
249 normalContent->SetText(contentText);
250 }
251
252 std::shared_ptr<NotificationContent> content = std::make_shared<NotificationContent>(normalContent);
253 params.request.SetContent(content);
254
255 // clickAction
256 napi_value clickAction = nullptr;
257 if (GetObjectProperty(env, argv[PARAM0], "clickAction", clickAction) != nullptr) {
258 ANS_LOGD("create wantagent");
259 // bundleName & abilityName
260 std::shared_ptr<AAFwk::Want> want = std::make_shared<AAFwk::Want>();
261 std::string bundleName;
262 std::string abilityName;
263 if (GetStringProperty(env, clickAction, "bundleName", bundleName) == nullptr) {
264 return nullptr;
265 }
266 if (GetStringProperty(env, clickAction, "abilityName", abilityName) == nullptr) {
267 return nullptr;
268 }
269 want->SetElementName(bundleName, abilityName);
270 // uri
271 std::string uri;
272 if (GetStringProperty(env, clickAction, "uri", uri) == nullptr) {
273 return nullptr;
274 }
275 want->SetUri(uri);
276
277 std::vector<std::shared_ptr<AAFwk::Want>> wants = {};
278 std::vector<WantAgentConstant::Flags> wantAgentFlags = {};
279 std::shared_ptr<AAFwk::WantParams> extraInfo = std::make_shared<AAFwk::WantParams>();
280 wants.emplace_back(want);
281 WantAgentInfo wantAgentInfo(-1, WantAgentConstant::OperationType::START_ABILITY, wantAgentFlags,
282 wants, extraInfo);
283 std::shared_ptr<AbilityRuntime::ApplicationContext> context = AbilityRuntime::Context::GetApplicationContext();
284
285 std::shared_ptr<WantAgent> wantAgent = nullptr;
286 WantAgentHelper::GetWantAgent(context, wantAgentInfo, wantAgent);
287 params.request.SetWantAgent(wantAgent);
288 }
289
290 ANS_LOGI("end");
291 return Common::NapiGetNull(env);
292 }
293
ShowNotification(napi_env env,napi_callback_info info)294 napi_value ShowNotification(napi_env env, napi_callback_info info)
295 {
296 ANS_LOGI("enter");
297
298 ParametersInfoPublish params;
299 if (ParseShowOptions(env, info, params) == nullptr) {
300 ANS_LOGW("parse showOptions failed");
301 return Common::NapiGetUndefined(env);
302 }
303
304 auto asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoPublish {.env = env, .asyncWork = nullptr};
305 if (!asynccallbackinfo) {
306 ANS_LOGW("failed to create asynccallbackinfo");
307 return Common::JSParaError(env, params.callback);
308 }
309
310 asynccallbackinfo->request = params.request;
311
312 napi_value resourceName = nullptr;
313 napi_create_string_latin1(env, "show", NAPI_AUTO_LENGTH, &resourceName);
314
315 ANS_LOGI("before napi_create_async_work");
316 napi_create_async_work(env,
317 nullptr,
318 resourceName,
319 [](napi_env env, void *data) {
320 ANS_LOGI("Show napi_create_async_work start");
321 AsyncCallbackInfoPublish *asynccallbackinfo = static_cast<AsyncCallbackInfoPublish *>(data);
322 if (asynccallbackinfo) {
323 ANS_LOGI("Show napi_create_async_work start notificationId = %{public}d, contentType = "
324 "%{public}d",
325 asynccallbackinfo->request.GetNotificationId(),
326 asynccallbackinfo->request.GetContent()->GetContentType());
327
328 asynccallbackinfo->info.errorCode =
329 NotificationHelper::PublishNotification(asynccallbackinfo->request);
330 }
331 },
332 [](napi_env env, napi_status status, void *data) {
333 ANS_LOGI("Show napi_create_async_work complete start");
334 AsyncCallbackInfoPublish *asynccallbackinfo = static_cast<AsyncCallbackInfoPublish *>(data);
335 if (asynccallbackinfo) {
336 if (asynccallbackinfo->info.callback != nullptr) {
337 napi_delete_reference(env, asynccallbackinfo->info.callback);
338 }
339 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
340 delete asynccallbackinfo;
341 asynccallbackinfo = nullptr;
342 }
343 ANS_LOGI("Show napi_create_async_work complete end");
344 },
345 (void *)asynccallbackinfo,
346 &asynccallbackinfo->asyncWork);
347
348 NAPI_CALL(env, napi_queue_async_work(env, asynccallbackinfo->asyncWork));
349 return nullptr;
350 }
351
ParsePublishAsBundleParameters(const napi_env & env,const napi_callback_info & info,ParametersInfoPublish & params)352 napi_value ParsePublishAsBundleParameters(
353 const napi_env &env, const napi_callback_info &info, ParametersInfoPublish ¶ms)
354 {
355 ANS_LOGI("enter");
356
357 size_t argc = PUBLISH_AS_BUNDLE_MAX;
358 napi_value argv[PUBLISH_AS_BUNDLE_MAX] = {nullptr};
359 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
360 if (argc < 1) {
361 ANS_LOGW("Wrong number of arguments");
362 return nullptr;
363 }
364
365 napi_valuetype valuetype = napi_undefined;
366 NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype));
367 if (valuetype != napi_object) {
368 ANS_LOGW("Wrong argument type. Object expected.");
369 return nullptr;
370 }
371
372 // argv[0] : NotificationRequest
373 if (Common::GetNotificationRequest(env, argv[PARAM0], params.request) == nullptr) {
374 return nullptr;
375 }
376
377 // argv[1] : bundleName
378 NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype));
379 if (valuetype != napi_string) {
380 ANS_LOGW("Wrong argument type. String expected.");
381 return nullptr;
382 }
383
384 char str[STR_MAX_SIZE] = {0};
385 size_t strLen = 0;
386 napi_get_value_string_utf8(env, argv[PARAM1], str, STR_MAX_SIZE - 1, &strLen);
387 params.request.SetOwnerBundleName(str);
388
389 // argv[2] : userId
390 NAPI_CALL(env, napi_typeof(env, argv[PARAM2], &valuetype));
391 if (valuetype != napi_number) {
392 ANS_LOGW("Wrong argument type. Number expected.");
393 return nullptr;
394 }
395 int32_t userId = 0;
396 napi_get_value_int32(env, argv[PARAM2], &userId);
397 params.request.SetOwnerUserId(userId);
398 params.request.SetIsAgentNotification(true);
399
400 // argv[3] : callback
401 if (argc >= PUBLISH_AS_BUNDLE_MAX) {
402 if (GetCallback(env, argv[PARAM3], params) == nullptr) {
403 return nullptr;
404 }
405 }
406
407 ANS_LOGI("end");
408 return Common::NapiGetNull(env);
409 }
410
PublishAsBundle(napi_env env,napi_callback_info info)411 napi_value PublishAsBundle(napi_env env, napi_callback_info info)
412 {
413 ANS_LOGI("enter");
414
415 ParametersInfoPublish params;
416 if (ParsePublishAsBundleParameters(env, info, params) == nullptr) {
417 return Common::NapiGetUndefined(env);
418 }
419
420 napi_value promise = nullptr;
421 auto asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoPublish {.env = env, .asyncWork = nullptr};
422 if (!asynccallbackinfo) {
423 return Common::JSParaError(env, params.callback);
424 }
425
426 asynccallbackinfo->request = params.request;
427 Common::PaddingCallbackPromiseInfo(env, params.callback, asynccallbackinfo->info, promise);
428
429 napi_value resourceName = nullptr;
430 napi_create_string_latin1(env, "publishasbundle", NAPI_AUTO_LENGTH, &resourceName);
431
432 napi_create_async_work(env,
433 nullptr,
434 resourceName,
435 [](napi_env env, void *data) {
436 ANS_LOGI("PublishAsBundle napi_create_async_work start");
437 AsyncCallbackInfoPublish *asynccallbackinfo = static_cast<AsyncCallbackInfoPublish *>(data);
438 if (asynccallbackinfo) {
439 ANS_LOGI("PublishAsBundle napi_create_async_work start notificationId = %{public}d, contentType = "
440 "%{public}d",
441 asynccallbackinfo->request.GetNotificationId(),
442 asynccallbackinfo->request.GetContent()->GetContentType());
443
444 asynccallbackinfo->info.errorCode =
445 NotificationHelper::PublishNotification(asynccallbackinfo->request);
446 }
447 },
448 [](napi_env env, napi_status status, void *data) {
449 ANS_LOGI("PublishAsBundle napi_create_async_work complete start");
450 AsyncCallbackInfoPublish *asynccallbackinfo = static_cast<AsyncCallbackInfoPublish *>(data);
451 if (asynccallbackinfo) {
452 Common::ReturnCallbackPromise(env, asynccallbackinfo->info, Common::NapiGetNull(env));
453 if (asynccallbackinfo->info.callback != nullptr) {
454 napi_delete_reference(env, asynccallbackinfo->info.callback);
455 }
456 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
457 delete asynccallbackinfo;
458 asynccallbackinfo = nullptr;
459 }
460 ANS_LOGI("PublishAsBundle napi_create_async_work complete end");
461 },
462 (void *)asynccallbackinfo,
463 &asynccallbackinfo->asyncWork);
464
465 NAPI_CALL(env, napi_queue_async_work(env, asynccallbackinfo->asyncWork));
466
467 if (asynccallbackinfo->info.isCallback) {
468 return Common::NapiGetNull(env);
469 } else {
470 return promise;
471 }
472 }
473 } // namespace NotificationNapi
474 } // namespace OHOS