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