• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &params)
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, &params.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 &params)
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, &params.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 &params)
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 &params)
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