1 
2 /*
3  * Copyright (c) 2023 Huawei Device Co., Ltd.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "js_form_observer.h"
18 
19 #include "fms_log_wrapper.h"
20 #include "form_callback_interface.h"
21 #include "form_host_client.h"
22 #include "form_info.h"
23 #include "form_instance.h"
24 #include "form_instances_filter.h"
25 #include "form_mgr.h"
26 #include "form_mgr_errors.h"
27 #include "ipc_skeleton.h"
28 #include "js_form_state_observer.h"
29 #include "js_runtime.h"
30 #include "js_runtime_utils.h"
31 #include "napi/native_api.h"
32 #include "napi/native_node_api.h"
33 #include "napi_common_util.h"
34 #include "napi_common_want.h"
35 #include "napi_form_util.h"
36 #include "runtime.h"
37 #include "tokenid_kit.h"
38 
39 namespace OHOS {
40 namespace AbilityRuntime {
41 using FormMgr = AppExecFwk::FormMgr;
42 namespace {
43 const std::string EMPTY_BUNDLE = "";
44 const std::string EMPTY_TYPE = "";
45 }
46 class JsFormObserver {
47 public:
48     JsFormObserver() = default;
49     ~JsFormObserver() = default;
50 
Finalizer(napi_env env,void * data,void * hint)51     static void Finalizer(napi_env env, void *data, void *hint)
52     {
53         HILOG_DEBUG("call");
54         std::unique_ptr<JsFormObserver>(static_cast<JsFormObserver*>(data));
55     }
56 
RegisterFormObserver(napi_env env,napi_callback_info info)57     static napi_value RegisterFormObserver(napi_env env, napi_callback_info info)
58     {
59         GET_CB_INFO_AND_CALL(env, info, JsFormObserver, OnRegisterFormObserver);
60     }
61 
UnregisterFormObserver(napi_env env,napi_callback_info info)62     static napi_value UnregisterFormObserver(napi_env env, napi_callback_info info)
63     {
64         GET_CB_INFO_AND_CALL(env, info, JsFormObserver, OnUnregisterFormObserver);
65     }
66 
GetRunningFormInfos(napi_env env,napi_callback_info info)67     static napi_value GetRunningFormInfos(napi_env env, napi_callback_info info)
68     {
69         GET_CB_INFO_AND_CALL(env, info, JsFormObserver, OnGetRunningFormInfos);
70     }
71 
GetFormInstancesByFilter(napi_env env,napi_callback_info info)72     static napi_value GetFormInstancesByFilter(napi_env env, napi_callback_info info)
73     {
74         GET_CB_INFO_AND_CALL(env, info, JsFormObserver, OnGetFormInstancesByFilter);
75     }
76 
GetFormInstanceById(napi_env env,napi_callback_info info)77     static napi_value GetFormInstanceById(napi_env env, napi_callback_info info)
78     {
79         GET_CB_INFO_AND_CALL(env, info, JsFormObserver, OnGetFormInstanceById);
80     }
81 private:
CheckCallerIsSystemApp()82     bool CheckCallerIsSystemApp()
83     {
84         auto selfToken = IPCSkeleton::GetSelfTokenID();
85         return Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(selfToken);
86     }
87 
CheckParamNum(napi_env env,size_t argc,size_t minParamNum,size_t maxParamNum)88     bool CheckParamNum(napi_env env, size_t argc, size_t minParamNum, size_t maxParamNum)
89     {
90         HILOG_DEBUG("argc is %{public}zu,param range is [%{public}zu,%{public}zu]",
91             argc, minParamNum, maxParamNum);
92         if (argc > maxParamNum || argc < minParamNum) {
93             HILOG_ERROR("invalid param number %{public}zu", argc);
94             std::string errMsg = "[" + std::to_string(minParamNum) + ", " + std::to_string(maxParamNum) + "]";
95             NapiFormUtil::ThrowParamNumError(env, std::to_string(argc), errMsg);
96             return false;
97         }
98         return true;
99     }
100 
ConvertFromId(napi_env env,napi_value jsValue,int64_t & formId)101     static bool ConvertFromId(napi_env env, napi_value jsValue, int64_t &formId)
102     {
103         std::string strFormId;
104         if (!ConvertFromJsValue(env, jsValue, strFormId)) {
105             HILOG_ERROR("Convert strFormId failed");
106             return false;
107         }
108 
109         if (strFormId.empty()) {
110             HILOG_ERROR("empty strFormId");
111             return false;
112         }
113 
114         if (!ConvertStringToInt64(strFormId, formId)) {
115             HILOG_ERROR("Convert string formId to int64 failed");
116             return false;
117         }
118         return true;
119     }
120 
OnRegisterFormAddObserver(napi_env env,size_t argc,napi_value * argv)121     napi_value OnRegisterFormAddObserver(napi_env env, size_t argc, napi_value *argv)
122     {
123         HILOG_DEBUG("call");
124         if (CheckParamNum(env, argc, ARGS_TWO, ARGS_THREE) == false) {
125             return CreateJsUndefined(env);
126         }
127 
128         std::string bundleName("");
129         if (argc == ARGS_THREE) {
130             if (!ConvertFromJsValue(env, argv[PARAM1], bundleName)) {
131                 HILOG_ERROR("Convert type failed");
132                 NapiFormUtil::ThrowParamTypeError(env, "bundleName", "string");
133                 return CreateJsUndefined(env);
134             }
135         } else {
136             bundleName = "all";
137         }
138 
139         if (!AppExecFwk::IsTypeForNapiValue(env, argv[argc - 1], napi_function)) {
140             HILOG_ERROR("invalid lastParam");
141             NapiFormUtil::ThrowParamTypeError(env, "callback", "Callback<formInfo.RunningFormInfo>");
142             return CreateJsUndefined(env);
143         }
144 
145         // Check the size of the map.
146         if (!JsFormStateObserver::GetInstance()->CheckMapSize("formAdd", bundleName)) {
147             NapiFormUtil::ThrowParamError(env,
148                 "The number of bundleNames registered to listen has exceeded the limit.");
149             return CreateJsUndefined(env);
150         }
151 
152         if (!JsFormStateObserver::GetInstance()->RegisterFormAddCallback(env, bundleName, argv[argc - 1])) {
153             return CreateJsUndefined(env);
154         }
155         FormMgr::GetInstance().RegisterFormAddObserverByBundle(bundleName, JsFormStateObserver::GetInstance());
156         return CreateJsUndefined(env);
157     }
158 
OnRegisterFormRemoveObserver(napi_env env,size_t argc,napi_value * argv)159     napi_value OnRegisterFormRemoveObserver(napi_env env, size_t argc, napi_value *argv)
160     {
161         HILOG_DEBUG("call");
162         if (CheckParamNum(env, argc, ARGS_TWO, ARGS_THREE) == false) {
163             return CreateJsUndefined(env);
164         }
165 
166         std::string bundleName("");
167         if (argc == ARGS_THREE) {
168             if (!ConvertFromJsValue(env, argv[PARAM1], bundleName)) {
169                 HILOG_ERROR("Convert type failed");
170                 NapiFormUtil::ThrowParamTypeError(env, "bundleName", "string");
171                 return CreateJsUndefined(env);
172             }
173         } else {
174             bundleName = "all";
175         }
176 
177         if (!AppExecFwk::IsTypeForNapiValue(env, argv[argc - 1], napi_function)) {
178             HILOG_ERROR("invalid lastParam");
179             NapiFormUtil::ThrowParamTypeError(env, "callback", "Callback<formInfo.RunningFormInfo>");
180             return CreateJsUndefined(env);
181         }
182 
183         // Check the size of the map.
184         if (!JsFormStateObserver::GetInstance()->CheckMapSize("formRemove", bundleName)) {
185             NapiFormUtil::ThrowParamError(env,
186                 "The number of bundleNames registered to listen has exceeded the limit.");
187             return CreateJsUndefined(env);
188         }
189 
190         if (!JsFormStateObserver::GetInstance()->RegisterFormRemoveCallback(env, bundleName, argv[argc - 1])) {
191             return CreateJsUndefined(env);
192         }
193 
194         FormMgr::GetInstance().RegisterFormRemoveObserverByBundle(bundleName, JsFormStateObserver::GetInstance());
195         return CreateJsUndefined(env);
196     }
197 
OnRegisterFormObserver(napi_env env,size_t argc,napi_value * argv)198     napi_value OnRegisterFormObserver(napi_env env, size_t argc, napi_value *argv)
199     {
200         HILOG_DEBUG("call");
201         if (!CheckCallerIsSystemApp()) {
202             HILOG_ERROR("The app not system-app,can't use system-api");
203             NapiFormUtil::ThrowByExternalErrorCode(env, AppExecFwk::ERR_FORM_EXTERNAL_NOT_SYSTEM_APP);
204             return CreateJsUndefined(env);
205         }
206 
207         std::string type;
208         if (!ConvertFromJsValue(env, argv[PARAM0], type)) {
209             HILOG_ERROR("Convert type failed");
210             NapiFormUtil::ThrowParamTypeError(env, "type",
211                 "formAdd, formRemove, notifyVisible, notifyInvisible, router, message, call.");
212             return CreateJsUndefined(env);
213         }
214 
215         if (type == "formAdd") {
216             return OnRegisterFormAddObserver(env, argc, argv);
217         } else if (type == "formRemove") {
218             return OnRegisterFormRemoveObserver(env, argc, argv);
219         } else if (type == "notifyVisible") {
220             return OnRegisterFormIsVisibleObserver(env, argc, argv, true);
221         } else if (type == "notifyInvisible") {
222             return OnRegisterFormIsVisibleObserver(env, argc, argv, false);
223         } else if (type == "router" || type == "message" || type == "call") {
224             return OnRegisterClickEventCallback(env, argc, argv, type);
225         } else {
226             HILOG_ERROR("args[0] not formAdd,formRemove,notifyVisible,notifyInvisible,router,message,call");
227             NapiFormUtil::ThrowParamTypeError(env, "type",
228                 "formAdd, formRemove, notifyVisible, notifyInvisible, router, message, call.");
229             return CreateJsUndefined(env);
230         }
231     }
232 
OnRegisterFormIsVisibleObserver(napi_env env,size_t argc,napi_value * argv,bool isVisibility)233     napi_value OnRegisterFormIsVisibleObserver(napi_env env, size_t argc, napi_value *argv, bool isVisibility)
234     {
235         HILOG_DEBUG("call");
236         if (CheckParamNum(env, argc, ARGS_TWO, ARGS_THREE) == false) {
237             return CreateJsUndefined(env);
238         }
239 
240         int32_t funcPos = 0;
241         std::string bundleName(EMPTY_BUNDLE);
242         if (AppExecFwk::IsTypeForNapiValue(env, argv[PARAM1], napi_function)) {
243             // There are two or more arguments, and the type of argument2 is function.
244             funcPos = PARAM1;
245         } else if (AppExecFwk::IsTypeForNapiValue(env, argv[PARAM1], napi_string)) {
246             // There are three or more arguments, and the type of argument2 is string.
247             if (!ConvertFromJsValue(env, argv[PARAM1], bundleName)) {
248                 HILOG_ERROR("invalid secondParam");
249                 NapiFormUtil::ThrowParamTypeError(env, "bundleName", "string");
250                 return CreateJsUndefined(env);
251             }
252             if (bundleName.empty()) {
253                 HILOG_ERROR("empty bundleName");
254                 NapiFormUtil::ThrowParamTypeError(env, "bundleName", "string");
255                 return CreateJsUndefined(env);
256             }
257             funcPos = PARAM2;
258         } else {
259             HILOG_ERROR("invalid secondParam");
260             NapiFormUtil::ThrowParamTypeError(env, "param 2", "type");
261             return CreateJsUndefined(env);
262         }
263 
264         if (!AppExecFwk::IsTypeForNapiValue(env, argv[funcPos], napi_function)) {
265             HILOG_ERROR("invalid lastParam");
266             NapiFormUtil::ThrowParamTypeError(env, "callback", "Callback<Array<RunningFormInfo>>");
267             return CreateJsUndefined(env);
268         }
269 
270         if (formObserver_ == nullptr) {
271             HILOG_ERROR("null formObserver_");
272             formObserver_ = JsFormStateObserver::GetInstance();
273         }
274         JsFormStateObserver::GetInstance()->
275             RegisterFormInstanceCallback(env, argv[funcPos], isVisibility, bundleName, formObserver_);
276         return CreateJsUndefined(env);
277     }
278 
OnUnregisterFormIsVisibleObserver(napi_env env,size_t argc,napi_value * argv,bool isVisibility)279     napi_value OnUnregisterFormIsVisibleObserver(napi_env env, size_t argc, napi_value *argv, bool isVisibility)
280     {
281         HILOG_DEBUG("argc is %{public}zu, isVisibility is %{public}d", argc, isVisibility);
282         int32_t funcPos = 0;
283         int32_t bundlePos = 0;
284         if (CheckParamNum(env, argc, ARGS_ONE, ARGS_THREE) == false) {
285             return CreateJsUndefined(env);
286         }
287         std::string bundleName(EMPTY_BUNDLE);
288         if (argc == ARGS_TWO) {
289             if (AppExecFwk::IsTypeForNapiValue(env, argv[PARAM1], napi_function)) {
290                 HILOG_DEBUG("The second param is function");
291                 funcPos = PARAM1;
292             } else if (AppExecFwk::IsTypeForNapiValue(env, argv[PARAM1], napi_string)) {
293                 bundlePos = PARAM1;
294             } else {
295                 NapiFormUtil::ThrowParamTypeError(env, "param 2", "type");
296                 return CreateJsUndefined(env);
297             }
298         }
299 
300         if (argc == ARGS_THREE) {
301             if (AppExecFwk::IsTypeForNapiValue(env, argv[PARAM1], napi_string)
302                 && AppExecFwk::IsTypeForNapiValue(env, argv[PARAM2], napi_function)) {
303                 bundlePos = PARAM1;
304                 funcPos = PARAM2;
305             } else {
306                 NapiFormUtil::ThrowParamTypeError(env, "param 2 or 3", "type");
307                 return CreateJsUndefined(env);
308             }
309         }
310 
311         if (bundlePos != 0) {
312             if (!ConvertFromJsValue(env, argv[bundlePos], bundleName) || bundleName.empty()) {
313                 HILOG_ERROR("Convert bundleName failed.bundleName is %{public}s", bundleName.c_str());
314                 NapiFormUtil::ThrowParamTypeError(env, "bundleName", "string");
315                 return CreateJsUndefined(env);
316             }
317         }
318 
319         if (funcPos != 0) {
320             JsFormStateObserver::GetInstance()->
321                 DelFormNotifyVisibleCallbackByBundle(bundleName, isVisibility, argv[funcPos], formObserver_);
322             return CreateJsUndefined(env);
323         }
324         // If there is only one argument.
325         JsFormStateObserver::GetInstance()->
326             ClearFormNotifyVisibleCallbackByBundle(bundleName, isVisibility, formObserver_);
327         return CreateJsUndefined(env);
328     }
329 
OnUnregisterFormRemoveObserverWithTwoParams(napi_env env,size_t argc,napi_value * argv)330     napi_value OnUnregisterFormRemoveObserverWithTwoParams(napi_env env, size_t argc, napi_value *argv)
331     {
332         if (argc != ARGS_TWO) {
333             return CreateJsUndefined(env);
334         }
335         if (AppExecFwk::IsTypeForNapiValue(env, argv[PARAM1], napi_function)) {
336             JsFormStateObserver::GetInstance()->DelFormRemoveCallbackByBundle(
337                 reinterpret_cast<napi_value>(argv[PARAM1]), "all");
338             return CreateJsUndefined(env);
339         } else if (AppExecFwk::IsTypeForNapiValue(env, argv[PARAM1], napi_string)) {
340             std::string bundleName;
341             if (!ConvertFromJsValue(env, argv[PARAM1], bundleName)) {
342                 HILOG_ERROR("Convert bundleName error");
343                 NapiFormUtil::ThrowParamTypeError(env, "bundleName", "string");
344                 return CreateJsUndefined(env);
345             }
346             JsFormStateObserver::GetInstance()->ClearFormRemoveCallbackByBundle(bundleName);
347             return CreateJsUndefined(env);
348         } else {
349             HILOG_ERROR("The second param is ineffective");
350             NapiFormUtil::ThrowParamTypeError(env, "callback or bundleName",
351                 "Callback<formInfo.RunningFormInfo> or string");
352             return CreateJsUndefined(env);
353         }
354         return CreateJsUndefined(env);
355     }
356 
OnUnregisterFormRemoveObserverWithThreeParams(napi_env env,size_t argc,napi_value * argv)357     napi_value OnUnregisterFormRemoveObserverWithThreeParams(napi_env env, size_t argc, napi_value *argv)
358     {
359         if (argc != ARGS_THREE) {
360             return CreateJsUndefined(env);
361         }
362         if (!AppExecFwk::IsTypeForNapiValue(env, argv[PARAM1], napi_string)) {
363             HILOG_ERROR("The second param is ineffective");
364             NapiFormUtil::ThrowParamTypeError(env, "bundleName", "string");
365             return CreateJsUndefined(env);
366         }
367         if (!AppExecFwk::IsTypeForNapiValue(env, argv[PARAM2], napi_function)) {
368             HILOG_ERROR("The third param is ineffective");
369             NapiFormUtil::ThrowParamTypeError(env, "callback", "Callback<formInfo.RunningFormInfo>");
370             return CreateJsUndefined(env);
371         }
372         std::string bundleName;
373         if (!ConvertFromJsValue(env, argv[PARAM1], bundleName)) {
374             HILOG_ERROR("Convert bundleName failed");
375             NapiFormUtil::ThrowParamTypeError(env, "bundleName", "string");
376             return CreateJsUndefined(env);
377         }
378         JsFormStateObserver::GetInstance()->DelFormRemoveCallbackByBundle(argv[PARAM2], bundleName);
379         return CreateJsUndefined(env);
380     }
381 
OnUnregisterFormRemoveObserver(napi_env env,size_t argc,napi_value * argv)382     napi_value OnUnregisterFormRemoveObserver(napi_env env, size_t argc, napi_value *argv)
383     {
384         HILOG_DEBUG("call");
385         if (CheckParamNum(env, argc, ARGS_ONE, ARGS_THREE) == false) {
386             return CreateJsUndefined(env);
387         }
388 
389         if (argc == ARGS_ONE) {
390             // If there is only one argument, all listening will be cancelled.
391             JsFormStateObserver::GetInstance()->ClearFormRemoveCallbackByBundle("all");
392             return CreateJsUndefined(env);
393         } else if (argc == ARGS_TWO) {
394             return OnUnregisterFormRemoveObserverWithTwoParams(env, argc, argv);
395         } else {
396             return OnUnregisterFormRemoveObserverWithThreeParams(env, argc, argv);
397         }
398         return CreateJsUndefined(env);
399     }
400 
OnUnregisterFormAddObserverWithTwoParams(napi_env env,size_t argc,napi_value * argv)401     napi_value OnUnregisterFormAddObserverWithTwoParams(napi_env env, size_t argc, napi_value *argv)
402     {
403         if (argc != ARGS_TWO) {
404             return CreateJsUndefined(env);
405         }
406         if (AppExecFwk::IsTypeForNapiValue(env, argv[PARAM1], napi_function)) {
407             JsFormStateObserver::GetInstance()->DelFormAddCallbackByBundle(argv[PARAM1], "all");
408             return CreateJsUndefined(env);
409         } else if (AppExecFwk::IsTypeForNapiValue(env, argv[PARAM1], napi_string)) {
410             std::string bundleName;
411             if (!ConvertFromJsValue(env, argv[PARAM1], bundleName)) {
412                 HILOG_ERROR("Convert bundleName failed");
413                 NapiFormUtil::ThrowParamTypeError(env, "bundleName", "string");
414                 return CreateJsUndefined(env);
415             }
416             JsFormStateObserver::GetInstance()->ClearFormAddCallbackByBundle(bundleName);
417             return CreateJsUndefined(env);
418         } else {
419             HILOG_ERROR("invalid secondParam");
420             NapiFormUtil::ThrowParamTypeError(env, "callback or bundleName",
421                 "Callback<formInfo.RunningFormInfo> or string");
422             return CreateJsUndefined(env);
423         }
424         return CreateJsUndefined(env);
425     }
426 
OnUnregisterFormAddObserverWithThreeParams(napi_env env,size_t argc,napi_value * argv)427     napi_value OnUnregisterFormAddObserverWithThreeParams(napi_env env, size_t argc, napi_value *argv)
428     {
429         if (argc != ARGS_THREE) {
430             return CreateJsUndefined(env);
431         }
432         if (!AppExecFwk::IsTypeForNapiValue(env, argv[PARAM1], napi_string)) {
433             HILOG_ERROR("invalid secondParam");
434             NapiFormUtil::ThrowParamTypeError(env, "bundleName", "string");
435             return CreateJsUndefined(env);
436         }
437         if (!AppExecFwk::IsTypeForNapiValue(env, argv[PARAM2], napi_function)) {
438             HILOG_ERROR("invalid thirdParam");
439             NapiFormUtil::ThrowParamTypeError(env, "callback", "Callback<formInfo.RunningFormInfo>");
440             return CreateJsUndefined(env);
441         }
442         std::string bundleName;
443         if (!ConvertFromJsValue(env, argv[PARAM1], bundleName)) {
444             HILOG_ERROR("Convert bundleName failed");
445             NapiFormUtil::ThrowParamTypeError(env, "bundleName", "string");
446             return CreateJsUndefined(env);
447         }
448         JsFormStateObserver::GetInstance()->DelFormAddCallbackByBundle(argv[PARAM2], bundleName);
449         return CreateJsUndefined(env);
450     }
451 
OnUnregisterFormAddObserver(napi_env env,size_t argc,napi_value * argv)452     napi_value OnUnregisterFormAddObserver(napi_env env, size_t argc, napi_value *argv)
453     {
454         HILOG_DEBUG("call");
455         if (CheckParamNum(env, argc, ARGS_ONE, ARGS_THREE) == false) {
456             return CreateJsUndefined(env);
457         }
458 
459         if (argc == ARGS_ONE) {
460             // If there is only one argument, full listening will be cancelled.
461             JsFormStateObserver::GetInstance()->ClearFormAddCallbackByBundle("all");
462             return CreateJsUndefined(env);
463         } else if (argc == ARGS_TWO) {
464             return OnUnregisterFormAddObserverWithTwoParams(env, argc, argv);
465         } else if (argc == ARGS_THREE) {
466             return OnUnregisterFormAddObserverWithThreeParams(env, argc, argv);
467         }
468         return CreateJsUndefined(env);
469     }
470 
OnUnregisterFormObserver(napi_env env,size_t argc,napi_value * argv)471     napi_value OnUnregisterFormObserver(napi_env env, size_t argc, napi_value *argv)
472     {
473         HILOG_DEBUG("call");
474         if (!CheckCallerIsSystemApp()) {
475             HILOG_ERROR("The application not system-app, can't use system-api");
476             NapiFormUtil::ThrowByExternalErrorCode(env, AppExecFwk::ERR_FORM_EXTERNAL_NOT_SYSTEM_APP);
477             return CreateJsUndefined(env);
478         }
479 
480         // Check the type of the PARAM0 and convert it to string.
481         std::string type;
482         if (!ConvertFromJsValue(env, argv[PARAM0], type)) {
483             HILOG_ERROR("Convert type error");
484             NapiFormUtil::ThrowParamTypeError(env, "type",
485                 "formAdd, formRemove, formUninstall, notifyVisible or notifyInvisible.");
486             return CreateJsUndefined(env);
487         }
488 
489         if (type == "formAdd") {
490             return OnUnregisterFormAddObserver(env, argc, argv);
491         } else if (type == "formRemove") {
492             return OnUnregisterFormRemoveObserver(env, argc, argv);
493         } else if (type == "notifyVisible") {
494             return OnUnregisterFormIsVisibleObserver(env, argc, argv, true);
495         } else if (type == "notifyInvisible") {
496             return OnUnregisterFormIsVisibleObserver(env, argc, argv, false);
497         } else if (type == "router" || type == "message" || type == "call") {
498             return OnUnregisterClickEventCallback(env, argc, argv, type);
499         } else {
500             HILOG_ERROR("args[0] not formAdd,formRemove,notifyVisible,notifyInvisible,router,message,call");
501             NapiFormUtil::ThrowParamTypeError(env, "type",
502                 "args[0] should be formAdd, formRemove,"
503                 "notifyVisible, notifyInvisible, router, message, call");
504             return CreateJsUndefined(env);
505         }
506     }
507 
ParseGetRunningFormInfosOneParam(const napi_env & env,const napi_value * argv,std::string & bundleName,bool & hasBundleName,bool & isUnusedIncluded)508     bool ParseGetRunningFormInfosOneParam(const napi_env &env, const napi_value *argv, std::string &bundleName,
509         bool &hasBundleName, bool &isUnusedIncluded)
510     {
511         HILOG_DEBUG("call");
512         if (AppExecFwk::IsTypeForNapiValue(env, argv[PARAM0], napi_string)) {
513             if (!ConvertFromJsValue(env, argv[PARAM0], bundleName)) {
514                 HILOG_ERROR("Convert bundleName failed");
515                 NapiFormUtil::ThrowParamTypeError(env, "bundleName", "string");
516                 return false;
517             }
518             if (bundleName.empty()) {
519                 HILOG_ERROR("empty bundleName");
520                 NapiFormUtil::ThrowParamError(env, "bundleName is empty.");
521                 return false;
522             }
523             hasBundleName = true;
524         } else if (AppExecFwk::IsTypeForNapiValue(env, argv[PARAM0], napi_boolean)) {
525             if (!ConvertFromJsValue(env, argv[PARAM0], isUnusedIncluded)) {
526                 HILOG_ERROR("Convert isUnusedIncluded failed");
527                 NapiFormUtil::ThrowParamTypeError(env, "isUnusedIncluded", "bool");
528                 return false;
529             }
530         } else {
531             HILOG_ERROR("Input params not string or boolean");
532             NapiFormUtil::ThrowParamTypeError(env, "the first param", "string or boolean");
533             return false;
534         }
535         return true;
536     }
537 
ParseGetRunningFormInfosParams(const napi_env & env,const napi_value * argv,std::string & bundleName,bool & isUnusedIncluded,int startPos)538     bool ParseGetRunningFormInfosParams(const napi_env &env, const napi_value *argv, std::string &bundleName,
539         bool &isUnusedIncluded, int startPos)
540     {
541         HILOG_DEBUG("call");
542         if (!ConvertFromJsValue(env, argv[startPos], isUnusedIncluded)) {
543             HILOG_ERROR("Convert isUnusedIncluded failed");
544             NapiFormUtil::ThrowParamTypeError(env, "isUnusedIncluded", "bool");
545             return false;
546         }
547         if (!ConvertFromJsValue(env, argv[startPos + 1], bundleName)) {
548             HILOG_ERROR("Convert bundleName failed");
549             NapiFormUtil::ThrowParamTypeError(env, "bundleName", "string");
550             return false;
551         }
552         return true;
553     }
554 
ParseGetRunningFormInfosTwoParams(const napi_env & env,const napi_value * argv,std::string & bundleName,bool & hasBundleName,bool & isUnusedIncluded)555     bool ParseGetRunningFormInfosTwoParams(const napi_env &env, const napi_value *argv, std::string &bundleName,
556         bool &hasBundleName, bool &isUnusedIncluded)
557     {
558         HILOG_DEBUG("call");
559         if (AppExecFwk::IsTypeForNapiValue(env, argv[PARAM0], napi_function)) {
560             if (AppExecFwk::IsTypeForNapiValue(env, argv[PARAM1], napi_string)) {
561                 if (!ConvertFromJsValue(env, argv[PARAM1], bundleName)) {
562                     HILOG_ERROR("Convert bundleName failed");
563                     NapiFormUtil::ThrowParamTypeError(env, "bundleName", "string");
564                     return false;
565                 }
566                 hasBundleName = true;
567             } else if (AppExecFwk::IsTypeForNapiValue(env, argv[PARAM1], napi_boolean)) {
568                 if (!ConvertFromJsValue(env, argv[PARAM1], isUnusedIncluded)) {
569                     HILOG_ERROR("Convert isUnusedIncluded failed");
570                     NapiFormUtil::ThrowParamTypeError(env, "isUnusedIncluded", "bool");
571                     return false;
572                 }
573             } else {
574                 HILOG_ERROR("Input params not a string or boolean");
575                 NapiFormUtil::ThrowParamTypeError(env, "the second param", "string or boolean");
576                 return false;
577             }
578         } else {
579             if (!ParseGetRunningFormInfosParams(env, argv, bundleName, isUnusedIncluded, PARAM0)) {
580                 return false;
581             }
582             hasBundleName = true;
583         }
584         return true;
585     }
586 
OnGetRunningFormInfos(napi_env env,size_t argc,napi_value * argv)587     napi_value OnGetRunningFormInfos(napi_env env, size_t argc, napi_value *argv)
588     {
589         HILOG_DEBUG("call");
590         if (CheckParamNum(env, argc, ARGS_ZERO, ARGS_THREE) == false) {
591             return CreateJsUndefined(env);
592         }
593 
594         std::string bundleName("");
595         bool hasBundleName = false;
596         bool isUnusedIncluded = false;
597         if (argc == ARGS_ONE && !AppExecFwk::IsTypeForNapiValue(env, argv[PARAM0], napi_function)) {
598             if (!ParseGetRunningFormInfosOneParam(env, argv, bundleName, hasBundleName, isUnusedIncluded)) {
599                 return CreateJsUndefined(env);
600             }
601         } else if (argc == ARGS_TWO) {
602             if (!ParseGetRunningFormInfosTwoParams(env, argv, bundleName, hasBundleName, isUnusedIncluded)) {
603                 return CreateJsUndefined(env);
604             }
605         } else if (argc == ARGS_THREE) {
606             if (!ParseGetRunningFormInfosParams(env, argv, bundleName, isUnusedIncluded, PARAM1)) {
607                 return CreateJsUndefined(env);
608             }
609             hasBundleName = true;
610         }
611 
612         auto complete = [hostBundleName = bundleName, isUnusedIncluded, hasBundleName](
613                             napi_env env, NapiAsyncTask &task, int32_t status) {
614             std::vector<AppExecFwk::RunningFormInfo> runningFormInfos;
615             auto ret = hasBundleName ? FormMgr::GetInstance().GetRunningFormInfosByBundleName(
616                 hostBundleName, isUnusedIncluded, runningFormInfos)
617                                      : FormMgr::GetInstance().GetRunningFormInfos(isUnusedIncluded, runningFormInfos);
618             if (ret != ERR_OK) {
619                 task.Reject(env, NapiFormUtil::CreateErrorByInternalErrorCode(env, ret));
620                 return;
621             }
622             task.ResolveWithNoError(env, CreateRunningFormInfos(env, runningFormInfos));
623         };
624         napi_value result = nullptr;
625         napi_value callbackParam =
626             (argc >= ARGS_ONE) &&
627                 (AppExecFwk::IsTypeForNapiValue(env, argv[PARAM0], napi_function)) ? argv[PARAM0] : nullptr;
628         NapiAsyncTask::ScheduleWithDefaultQos("JsFormObserver::OnGetRunningFormInfos", env,
629             CreateAsyncTaskWithLastParam(env, callbackParam, nullptr, std::move(complete), &result));
630         return result;
631     }
632 
OnGetFormInstancesByFilter(napi_env env,size_t argc,napi_value * argv)633     napi_value OnGetFormInstancesByFilter(napi_env env, size_t argc, napi_value *argv)
634     {
635         HILOG_DEBUG("call");
636         if (CheckParamNum(env, argc, ARGS_ONE, ARGS_THREE) == false) {
637             return CreateJsUndefined(env);
638         }
639 
640         AppExecFwk::FormInstancesFilter filter;
641         if (!AppExecFwk::IsTypeForNapiValue(env, argv[PARAM0], napi_object)) {
642             HILOG_ERROR("Input params not object");
643             NapiFormUtil::ThrowParamTypeError(env, "formProviderFilter", "object");
644             return CreateJsUndefined(env);
645         }
646         if (!ParseParam(env, argv[PARAM0], filter)) {
647             HILOG_ERROR("Input params parse failed");
648             NapiFormUtil::ThrowParamTypeError(env, "formProviderFilter", "object");
649             return CreateJsUndefined(env);
650         }
651         if (argc == ARGS_TWO && !AppExecFwk::IsTypeForNapiValue(env, argv[PARAM1], napi_function)) {
652             HILOG_ERROR("invalid secondParam");
653             NapiFormUtil::ThrowParamTypeError(env, "callback", "Callback<string>");
654             return CreateJsUndefined(env);
655         }
656         auto formInstances = std::make_shared<std::vector<AppExecFwk::FormInstance>>();
657         auto apiResult = std::make_shared<int32_t>();
658         auto execute = [filter, formInstances, ret = apiResult]() {
659             *ret = FormMgr::GetInstance().GetFormInstancesByFilter(filter, *formInstances);
660         };
661 
662         auto complete =
663             [formInstances, ret = apiResult](napi_env env, NapiAsyncTask &task, int32_t status) {
664                 if (*ret != ERR_OK) {
665                     HILOG_ERROR("Get FormInstances by filter failed");
666                     task.Reject(env, NapiFormUtil::CreateErrorByInternalErrorCode(env, *ret));
667                 } else {
668                     task.ResolveWithNoError(env, CreateFormInstances(env, *formInstances));
669                 }
670             };
671         napi_value lastParam = (argc == ARGS_ONE) ? nullptr : argv[PARAM1];
672         napi_value result = nullptr;
673         NapiAsyncTask::ScheduleWithDefaultQos("JsFormObserver::OnGetFormInstancesByFilter",
674             env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
675         return result;
676     }
677 
OnGetFormInstanceById(napi_env env,size_t argc,napi_value * argv)678     napi_value OnGetFormInstanceById(napi_env env, size_t argc, napi_value *argv)
679     {
680         HILOG_DEBUG("call");
681         if (CheckParamNum(env, argc, ARGS_ONE, ARGS_THREE) == false) {
682             return CreateJsUndefined(env);
683         }
684         decltype(argc) convertArgc = 0;
685         int64_t formId;
686         if (!ConvertFromId(env, argv[PARAM0], formId)) {
687             HILOG_ERROR("Convert strFormIdList failed");
688             NapiFormUtil::ThrowParamTypeError(env, "formId", "string");
689             return CreateJsUndefined(env);
690         }
691         convertArgc++;
692         bool isUnusedIncluded = false;
693         if ((argc == ARGS_TWO || argc == ARGS_THREE) &&
694             !AppExecFwk::IsTypeForNapiValue(env, argv[PARAM1], napi_function)) {
695             if (!ConvertFromJsValue(env, argv[PARAM1], isUnusedIncluded)) {
696                 HILOG_ERROR("Convert isUnusedIncluded failed");
697                 NapiFormUtil::ThrowParamTypeError(env, "isUnusedIncluded", "bool");
698                 return CreateJsUndefined(env);
699             }
700             convertArgc++;
701         }
702         if (argc == ARGS_THREE && !AppExecFwk::IsTypeForNapiValue(env, argv[PARAM2], napi_function)) {
703             HILOG_ERROR("invalid thirdParam");
704             NapiFormUtil::ThrowParamTypeError(env, "callback", "Callback<string>");
705             return CreateJsUndefined(env);
706         }
707         std::shared_ptr<AppExecFwk::FormInstance> formInstance = std::make_shared<AppExecFwk::FormInstance>();
708         auto apiResult = std::make_shared<int32_t>();
709         auto execute = [formId, isUnusedIncluded, formInstance, ret = apiResult]() {
710             *ret = FormMgr::GetInstance().GetFormInstanceById(formId, isUnusedIncluded, *formInstance);
711         };
712 
713         auto complete =
714             [formInstance, ret = apiResult](napi_env env, NapiAsyncTask &task, int32_t status) {
715                 if (*ret != ERR_OK) {
716                     HILOG_ERROR("Get formInstance by id failed");
717                     task.Reject(env, NapiFormUtil::CreateErrorByInternalErrorCode(env, *ret));
718                 } else {
719                     task.ResolveWithNoError(env, CreateFormInstance(env, *formInstance));
720                 }
721             };
722         napi_value lastParam = (argc == convertArgc) ? nullptr : argv[convertArgc];
723         napi_value result = nullptr;
724         NapiAsyncTask::ScheduleWithDefaultQos("JsFormObserver::OnGetFormInstanceById",
725             env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
726         return result;
727     }
728     sptr<JsFormStateObserver> formObserver_ = nullptr;
729 
OnRegisterClickEventCallback(napi_env env,size_t argc,napi_value * argv,const std::string & type)730     napi_value OnRegisterClickEventCallback(
731         napi_env env, size_t argc, napi_value *argv, const std::string &type)
732     {
733         HILOG_DEBUG("call");
734         if (argc < ARGS_TWO) {
735             HILOG_ERROR("invalid argc");
736             NapiFormUtil::ThrowParamNumError(env, std::to_string(argc), "2");
737             return CreateJsUndefined(env);
738         }
739         std::string bundleName(EMPTY_BUNDLE);
740         napi_value callFunc = nullptr;
741         if (argc >= ARGS_THREE) {
742             if (!ConvertFromJsValue(env, argv[PARAM1], bundleName)) {
743                 HILOG_ERROR("Convert bundleName from js fail");
744                 NapiFormUtil::ThrowParamTypeError(env, "bundleName", "string");
745                 return CreateJsUndefined(env);
746             }
747             if (!AppExecFwk::IsTypeForNapiValue(env, argv[PARAM2], napi_function)) {
748                 HILOG_ERROR("invalid thirdParam");
749                 NapiFormUtil::ThrowParamTypeError(env, "callback", "Callback<formInfo.RunningFormInfo>");
750                 return CreateJsUndefined(env);
751             }
752             callFunc = argv[PARAM2];
753             JsFormStateObserver::GetInstance()->RegisterClickEventCallback(env, bundleName, callFunc, type);
754             return CreateJsUndefined(env);
755         }
756         if (!AppExecFwk::IsTypeForNapiValue(env, argv[PARAM1], napi_function)) {
757             HILOG_ERROR("invalid secondParam");
758             NapiFormUtil::ThrowParamTypeError(env, "callback", "Callback<formInfo.RunningFormInfo>");
759             return CreateJsUndefined(env);
760         }
761         callFunc = argv[PARAM1];
762         JsFormStateObserver::GetInstance()->RegisterClickEventCallback(env, bundleName, callFunc, type);
763         return CreateJsUndefined(env);
764     }
765 
OnUnregisterClickEventCallback(napi_env env,size_t argc,napi_value * argv,const std::string & type)766     napi_value OnUnregisterClickEventCallback(
767         napi_env env, size_t argc, napi_value *argv, const std::string &type)
768     {
769         HILOG_DEBUG("call");
770         std::string bundleName(EMPTY_BUNDLE);
771         napi_value callback = nullptr;
772         if (argc < ARGS_ONE) {
773             HILOG_ERROR("invalid argc");
774             NapiFormUtil::ThrowParamNumError(env, std::to_string(argc), "1");
775             return CreateJsUndefined(env);
776         }
777         if (argc == ARGS_ONE) {
778             JsFormStateObserver::GetInstance()->ClearFormClickCallbackByBundleName(type, EMPTY_BUNDLE);
779             return CreateJsUndefined(env);
780         }
781         if (argc == ARGS_TWO) {
782             if (!AppExecFwk::IsTypeForNapiValue(env, argv[PARAM1], napi_string)) {
783                 HILOG_DEBUG("secondParam bundlename not string");
784                 JsFormStateObserver::GetInstance()->ClearFormClickCallbackByBundleName(type, EMPTY_BUNDLE);
785                 return CreateJsUndefined(env);
786             } else if (!ConvertFromJsValue(env, argv[PARAM1], bundleName)) {
787                 HILOG_ERROR("Convert bundleName failed");
788                 return CreateJsUndefined(env);
789             }
790             JsFormStateObserver::GetInstance()->ClearFormClickCallbackByBundleName(type, bundleName);
791             return CreateJsUndefined(env);
792         }
793         if (!AppExecFwk::IsTypeForNapiValue(env, argv[PARAM1], napi_string)) {
794             HILOG_DEBUG("secondParam bundlename not string");
795         } else if (!ConvertFromJsValue(env, argv[PARAM1], bundleName)) {
796             HILOG_ERROR("Convert bundleName failed");
797             return CreateJsUndefined(env);
798         }
799         if (AppExecFwk::IsTypeForNapiValue(env, argv[PARAM2], napi_null) ||
800             AppExecFwk::IsTypeForNapiValue(env, argv[PARAM2], napi_undefined)) {
801             HILOG_DEBUG("null or undefined thirdParam");
802             JsFormStateObserver::GetInstance()->ClearFormClickCallbackByBundleName(type, bundleName);
803             return CreateJsUndefined(env);
804         } else if (AppExecFwk::IsTypeForNapiValue(env, argv[PARAM2], napi_function)) {
805             HILOG_DEBUG("The third param is callback");
806             callback = argv[PARAM2];
807             JsFormStateObserver::GetInstance()->ClearFormClickCallback(type, bundleName, callback);
808             return CreateJsUndefined(env);
809         } else {
810             HILOG_ERROR("invalid thirdParam");
811             NapiFormUtil::ThrowParamTypeError(env, "callback", "Callback<formInfo.RunningFormInfo>");
812             return CreateJsUndefined(env);
813         }
814         return CreateJsUndefined(env);
815     }
816 };
817 
JsFormObserverInit(napi_env env,napi_value exportObj)818 napi_value JsFormObserverInit(napi_env env, napi_value exportObj)
819 {
820     HILOG_DEBUG("call");
821     std::unique_ptr<JsFormObserver> jsFormObserver = std::make_unique<JsFormObserver>();
822     napi_wrap(env, exportObj, jsFormObserver.release(), JsFormObserver::Finalizer, nullptr, nullptr);
823 
824     const char *moduleName = "JsFormObserver";
825     BindNativeFunction(env, exportObj, "on", moduleName, JsFormObserver::RegisterFormObserver);
826     BindNativeFunction(env, exportObj, "off", moduleName, JsFormObserver::UnregisterFormObserver);
827     BindNativeFunction(env, exportObj, "getRunningFormInfos", moduleName, JsFormObserver::GetRunningFormInfos);
828     BindNativeFunction(env, exportObj, "getRunningFormInfosByFilter", moduleName,
829         JsFormObserver::GetFormInstancesByFilter);
830     BindNativeFunction(env, exportObj, "getRunningFormInfoById", moduleName, JsFormObserver::GetFormInstanceById);
831 
832     return CreateJsUndefined(env);
833 }
834 } // namespace AbilityRuntime
835 } // namespace OHOS
836