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