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 <uv.h>
17 #include "enable_notification.h"
18 #include "ability_manager_client.h"
19
20 namespace OHOS {
21 namespace NotificationNapi {
22 const int ENABLE_NOTIFICATION_MAX_PARA = 3;
23 const int ENABLE_NOTIFICATION_MIN_PARA = 2;
24 const int IS_NOTIFICATION_ENABLE_MAX_PARA = 2;
25
ParseParameters(const napi_env & env,const napi_callback_info & info,EnableParams & params)26 napi_value ParseParameters(const napi_env &env, const napi_callback_info &info, EnableParams ¶ms)
27 {
28 ANS_LOGI("enter");
29
30 size_t argc = ENABLE_NOTIFICATION_MAX_PARA;
31 napi_value argv[ENABLE_NOTIFICATION_MAX_PARA] = {nullptr};
32 napi_value thisVar = nullptr;
33 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
34 if (argc < ENABLE_NOTIFICATION_MIN_PARA) {
35 ANS_LOGW("Wrong number of arguments.");
36 return nullptr;
37 }
38
39 // argv[0]: bundle
40 napi_valuetype valuetype = napi_undefined;
41 NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype));
42 if (valuetype != napi_object) {
43 ANS_LOGW("Wrong argument type. Object expected.");
44 return nullptr;
45 }
46 auto retValue = Common::GetBundleOption(env, argv[PARAM0], params.option);
47 if (retValue == nullptr) {
48 ANS_LOGE("GetBundleOption failed.");
49 return nullptr;
50 }
51
52 // argv[1]: enable
53 NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype));
54 if (valuetype != napi_boolean) {
55 ANS_LOGW("Wrong argument type. Bool expected.");
56 return nullptr;
57 }
58 napi_get_value_bool(env, argv[PARAM1], ¶ms.enable);
59
60 // argv[2]:callback
61 if (argc >= ENABLE_NOTIFICATION_MAX_PARA) {
62 NAPI_CALL(env, napi_typeof(env, argv[PARAM2], &valuetype));
63 if (valuetype != napi_function) {
64 ANS_LOGW("Callback is not function excute promise.");
65 return Common::NapiGetNull(env);
66 }
67 napi_create_reference(env, argv[PARAM2], 1, ¶ms.callback);
68 }
69
70 return Common::NapiGetNull(env);
71 }
72
ParseParameters(const napi_env & env,const napi_callback_info & info,IsEnableParams & params)73 napi_value ParseParameters(const napi_env &env, const napi_callback_info &info, IsEnableParams ¶ms)
74 {
75 ANS_LOGI("enter");
76
77 size_t argc = IS_NOTIFICATION_ENABLE_MAX_PARA;
78 napi_value argv[IS_NOTIFICATION_ENABLE_MAX_PARA] = {nullptr};
79 napi_value thisVar = nullptr;
80 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
81
82 if (argc == 0) {
83 return Common::NapiGetNull(env);
84 }
85
86 // argv[0]: bundle / userId / callback
87 napi_valuetype valuetype = napi_undefined;
88 NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype));
89 if ((valuetype != napi_object) && (valuetype != napi_number) && (valuetype != napi_function)) {
90 ANS_LOGW("Wrong argument type. Function or object expected. Excute promise.");
91 return Common::NapiGetNull(env);
92 }
93 if (valuetype == napi_object) {
94 auto retValue = Common::GetBundleOption(env, argv[PARAM0], params.option);
95 if (retValue == nullptr) {
96 ANS_LOGE("GetBundleOption failed.");
97 return nullptr;
98 }
99 params.hasBundleOption = true;
100 } else if (valuetype == napi_number) {
101 NAPI_CALL(env, napi_get_value_int32(env, argv[PARAM0], ¶ms.userId));
102 params.hasUserId = true;
103 } else {
104 napi_create_reference(env, argv[PARAM0], 1, ¶ms.callback);
105 }
106
107 // argv[1]:callback
108 if (argc >= IS_NOTIFICATION_ENABLE_MAX_PARA) {
109 NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype));
110 if (valuetype != napi_function) {
111 ANS_LOGW("Callback is not function excute promise.");
112 return Common::NapiGetNull(env);
113 }
114 napi_create_reference(env, argv[PARAM1], 1, ¶ms.callback);
115 }
116
117 return Common::NapiGetNull(env);
118 }
119
AsyncCompleteCallbackEnableNotification(napi_env env,napi_status status,void * data)120 void AsyncCompleteCallbackEnableNotification(napi_env env, napi_status status, void *data)
121 {
122 ANS_LOGI("enter");
123 if (!data) {
124 ANS_LOGE("Invalid async callback data");
125 return;
126 }
127 AsyncCallbackInfoEnable *asynccallbackinfo = static_cast<AsyncCallbackInfoEnable *>(data);
128 if (asynccallbackinfo) {
129 Common::ReturnCallbackPromise(env, asynccallbackinfo->info, Common::NapiGetNull(env));
130 if (asynccallbackinfo->info.callback != nullptr) {
131 napi_delete_reference(env, asynccallbackinfo->info.callback);
132 }
133 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
134 delete asynccallbackinfo;
135 asynccallbackinfo = nullptr;
136 }
137 }
138
EnableNotification(napi_env env,napi_callback_info info)139 napi_value EnableNotification(napi_env env, napi_callback_info info)
140 {
141 ANS_LOGI("enter");
142
143 EnableParams params {};
144 if (ParseParameters(env, info, params) == nullptr) {
145 return Common::NapiGetUndefined(env);
146 }
147
148 AsyncCallbackInfoEnable *asynccallbackinfo =
149 new (std::nothrow) AsyncCallbackInfoEnable {.env = env, .asyncWork = nullptr, .params = params};
150 if (!asynccallbackinfo) {
151 return Common::JSParaError(env, params.callback);
152 }
153 napi_value promise = nullptr;
154 Common::PaddingCallbackPromiseInfo(env, params.callback, asynccallbackinfo->info, promise);
155
156 napi_value resourceName = nullptr;
157 napi_create_string_latin1(env, "enableNotification", NAPI_AUTO_LENGTH, &resourceName);
158 // Asynchronous function call
159 napi_create_async_work(env,
160 nullptr,
161 resourceName,
162 [](napi_env env, void *data) {
163 ANS_LOGI("EnableNotification napi_create_async_work start");
164 AsyncCallbackInfoEnable *asynccallbackinfo = static_cast<AsyncCallbackInfoEnable *>(data);
165 if (asynccallbackinfo) {
166 std::string deviceId {""};
167 asynccallbackinfo->info.errorCode = NotificationHelper::SetNotificationsEnabledForSpecifiedBundle(
168 asynccallbackinfo->params.option, deviceId, asynccallbackinfo->params.enable);
169 ANS_LOGI("asynccallbackinfo->info.errorCode = %{public}d", asynccallbackinfo->info.errorCode);
170 }
171 },
172 AsyncCompleteCallbackEnableNotification,
173 (void *)asynccallbackinfo,
174 &asynccallbackinfo->asyncWork);
175
176 napi_status status = napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
177 if (status != napi_ok) {
178 ANS_LOGE("napi_queue_async_work failed return: %{public}d", status);
179 if (asynccallbackinfo->info.callback != nullptr) {
180 napi_delete_reference(env, asynccallbackinfo->info.callback);
181 }
182 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
183 delete asynccallbackinfo;
184 asynccallbackinfo = nullptr;
185 return Common::JSParaError(env, params.callback);
186 }
187
188 if (asynccallbackinfo->info.isCallback) {
189 return Common::NapiGetNull(env);
190 } else {
191 return promise;
192 }
193 }
194
AsyncCompleteCallbackIsNotificationEnabled(napi_env env,napi_status status,void * data)195 void AsyncCompleteCallbackIsNotificationEnabled(napi_env env, napi_status status, void *data)
196 {
197 ANS_LOGI("enter");
198 if (!data) {
199 ANS_LOGE("Invalid async callback data");
200 return;
201 }
202 AsyncCallbackInfoIsEnable *asynccallbackinfo = static_cast<AsyncCallbackInfoIsEnable *>(data);
203 if (asynccallbackinfo) {
204 napi_value result = nullptr;
205 napi_get_boolean(env, asynccallbackinfo->allowed, &result);
206 if (asynccallbackinfo->newInterface) {
207 Common::CreateReturnValue(env, asynccallbackinfo->info, result);
208 } else {
209 Common::ReturnCallbackPromise(env, asynccallbackinfo->info, result);
210 }
211 if (asynccallbackinfo->info.callback != nullptr) {
212 napi_delete_reference(env, asynccallbackinfo->info.callback);
213 }
214 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
215 delete asynccallbackinfo;
216 asynccallbackinfo = nullptr;
217 }
218 }
219
IsNotificationEnabled(napi_env env,napi_callback_info info)220 napi_value IsNotificationEnabled(napi_env env, napi_callback_info info)
221 {
222 ANS_LOGI("enter");
223
224 IsEnableParams params {};
225 if (ParseParameters(env, info, params) == nullptr) {
226 return Common::NapiGetUndefined(env);
227 }
228
229 AsyncCallbackInfoIsEnable *asynccallbackinfo =
230 new (std::nothrow) AsyncCallbackInfoIsEnable {.env = env, .asyncWork = nullptr, .params = params};
231 if (!asynccallbackinfo) {
232 return Common::JSParaError(env, params.callback);
233 }
234 napi_value promise = nullptr;
235 Common::PaddingCallbackPromiseInfo(env, params.callback, asynccallbackinfo->info, promise);
236
237 napi_value resourceName = nullptr;
238 napi_create_string_latin1(env, "isNotificationEnabled", NAPI_AUTO_LENGTH, &resourceName);
239 // Asynchronous function call
240 napi_create_async_work(env,
241 nullptr,
242 resourceName,
243 [](napi_env env, void *data) {
244 ANS_LOGI("IsNotificationEnabled napi_create_async_work start");
245 AsyncCallbackInfoIsEnable *asynccallbackinfo = static_cast<AsyncCallbackInfoIsEnable *>(data);
246 if (asynccallbackinfo) {
247 if (asynccallbackinfo->params.hasBundleOption) {
248 ANS_LOGI("option.bundle = %{public}s option.uid = %{public}d",
249 asynccallbackinfo->params.option.GetBundleName().c_str(),
250 asynccallbackinfo->params.option.GetUid());
251 asynccallbackinfo->info.errorCode = NotificationHelper::IsAllowedNotify(
252 asynccallbackinfo->params.option, asynccallbackinfo->allowed);
253 } else if (asynccallbackinfo->params.hasUserId) {
254 ANS_LOGI("userId = %{public}d", asynccallbackinfo->params.userId);
255 asynccallbackinfo->info.errorCode = NotificationHelper::IsAllowedNotify(
256 asynccallbackinfo->params.userId, asynccallbackinfo->allowed);
257 } else {
258 asynccallbackinfo->info.errorCode = NotificationHelper::IsAllowedNotify(
259 asynccallbackinfo->allowed);
260 }
261 ANS_LOGI("asynccallbackinfo->info.errorCode = %{public}d, allowed = %{public}d",
262 asynccallbackinfo->info.errorCode, asynccallbackinfo->allowed);
263 }
264 },
265 AsyncCompleteCallbackIsNotificationEnabled,
266 (void *)asynccallbackinfo,
267 &asynccallbackinfo->asyncWork);
268
269 napi_status status = napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
270 if (status != napi_ok) {
271 ANS_LOGE("napi_queue_async_work failed return: %{public}d", status);
272 if (asynccallbackinfo->info.callback != nullptr) {
273 napi_delete_reference(env, asynccallbackinfo->info.callback);
274 }
275 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
276 delete asynccallbackinfo;
277 asynccallbackinfo = nullptr;
278 return Common::JSParaError(env, params.callback);
279 }
280
281 if (asynccallbackinfo->info.isCallback) {
282 return Common::NapiGetNull(env);
283 } else {
284 return promise;
285 }
286 }
287
IsNotificationEnabledSelf(napi_env env,napi_callback_info info)288 napi_value IsNotificationEnabledSelf(napi_env env, napi_callback_info info)
289 {
290 ANS_LOGI("enter");
291
292 IsEnableParams params {};
293 if (ParseParameters(env, info, params) == nullptr) {
294 return Common::NapiGetUndefined(env);
295 }
296
297 AsyncCallbackInfoIsEnable *asynccallbackinfo =
298 new (std::nothrow) AsyncCallbackInfoIsEnable {.env = env, .asyncWork = nullptr, .params = params};
299 if (!asynccallbackinfo) {
300 return Common::JSParaError(env, params.callback);
301 }
302 napi_value promise = nullptr;
303 Common::PaddingCallbackPromiseInfo(env, params.callback, asynccallbackinfo->info, promise);
304
305 napi_value resourceName = nullptr;
306 napi_create_string_latin1(env, "IsNotificationEnabledSelf", NAPI_AUTO_LENGTH, &resourceName);
307 // Asynchronous function call
308 napi_create_async_work(env,
309 nullptr,
310 resourceName,
311 [](napi_env env, void *data) {
312 ANS_LOGI("IsNotificationEnabledSelf napi_create_async_work start");
313 AsyncCallbackInfoIsEnable *asynccallbackinfo = static_cast<AsyncCallbackInfoIsEnable *>(data);
314 if (asynccallbackinfo) {
315 if (asynccallbackinfo->params.hasBundleOption) {
316 ANS_LOGE("Not allowed to query another application");
317 } else {
318 asynccallbackinfo->info.errorCode =
319 NotificationHelper::IsAllowedNotifySelf(asynccallbackinfo->allowed);
320 }
321 ANS_LOGI("asynccallbackinfo->info.errorCode = %{public}d, allowed = %{public}d",
322 asynccallbackinfo->info.errorCode, asynccallbackinfo->allowed);
323 }
324 },
325 AsyncCompleteCallbackIsNotificationEnabled,
326 (void *)asynccallbackinfo,
327 &asynccallbackinfo->asyncWork);
328
329 napi_status status = napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
330 if (status != napi_ok) {
331 ANS_LOGE("napi_queue_async_work failed return: %{public}d", status);
332 if (asynccallbackinfo->info.callback != nullptr) {
333 napi_delete_reference(env, asynccallbackinfo->info.callback);
334 }
335 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
336 delete asynccallbackinfo;
337 asynccallbackinfo = nullptr;
338 return Common::JSParaError(env, params.callback);
339 }
340
341 if (asynccallbackinfo->info.isCallback) {
342 return Common::NapiGetNull(env);
343 } else {
344 return promise;
345 }
346 }
347
RequestEnableNotification(napi_env env,napi_callback_info info)348 napi_value RequestEnableNotification(napi_env env, napi_callback_info info)
349 {
350 ANS_LOGI("enter");
351
352 IsEnableParams params {};
353 if (ParseParameters(env, info, params) == nullptr) {
354 return Common::NapiGetUndefined(env);
355 }
356
357 AsyncCallbackInfoIsEnable *asynccallbackinfo =
358 new (std::nothrow) AsyncCallbackInfoIsEnable {.env = env, .asyncWork = nullptr, .params = params};
359
360 if (!asynccallbackinfo) {
361 return Common::JSParaError(env, params.callback);
362 }
363 napi_value promise = nullptr;
364 Common::PaddingCallbackPromiseInfo(env, params.callback, asynccallbackinfo->info, promise);
365
366 napi_value resourceName = nullptr;
367 napi_create_string_latin1(env, "RequestEnableNotification", NAPI_AUTO_LENGTH, &resourceName);
368 // Asynchronous function call
369 napi_create_async_work(env,
370 nullptr,
371 resourceName,
372 [](napi_env env, void *data) {
373 AsyncCallbackInfoIsEnable *asynccallbackinfo = static_cast<AsyncCallbackInfoIsEnable *>(data);
374 if (asynccallbackinfo) {
375 std::string deviceId {""};
376 asynccallbackinfo->info.errorCode =
377 NotificationHelper::RequestEnableNotification(deviceId, asynccallbackinfo->params.callerToken);
378 }
379 },
380 [](napi_env env, napi_status status, void *data) {
381 AsyncCallbackInfoIsEnable *asynccallbackinfo = static_cast<AsyncCallbackInfoIsEnable *>(data);
382 if (asynccallbackinfo) {
383 AsyncCompleteCallbackIsNotificationEnabled(env, status, data);
384 }
385 },
386 (void *)asynccallbackinfo,
387 &asynccallbackinfo->asyncWork);
388
389 napi_status status = napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
390 if (status != napi_ok) {
391 ANS_LOGE("napi_queue_async_work failed return: %{public}d", status);
392 if (asynccallbackinfo->info.callback != nullptr) {
393 napi_delete_reference(env, asynccallbackinfo->info.callback);
394 }
395 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
396 delete asynccallbackinfo;
397 asynccallbackinfo = nullptr;
398 return Common::JSParaError(env, params.callback);
399 }
400
401 if (asynccallbackinfo->info.isCallback) {
402 return Common::NapiGetNull(env);
403 } else {
404 return promise;
405 }
406 }
407
408 } // namespace NotificationNapi
409 } // namespace OHOS
410