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