• 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 "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 &params)
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], &params.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, &params.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 &params)
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], &params.userId));
108         params.hasUserId = true;
109     } else {
110         napi_create_reference(env, argv[PARAM0], 1, &params.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, &params.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