• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "js_form_state_observer.h"
17 
18 #include <regex>
19 
20 #include "fms_log_wrapper.h"
21 #include "form_mgr_errors.h"
22 #include "js_runtime_utils.h"
23 #include "napi_common_util.h"
24 #include "napi_form_util.h"
25 #include "napi/native_api.h"
26 #include "napi/native_node_api.h"
27 #include "running_form_info.h"
28 
29 namespace OHOS {
30 namespace AbilityRuntime {
31 namespace {
32     constexpr int REF_COUNT = 1;
33     constexpr uint KEY_LIMIT = 16;
34 }
35 
36 sptr<JsFormStateObserver> JsFormStateObserver::instance_ = nullptr;
37 std::mutex JsFormStateObserver::mutex_;
38 
FormAddCallbackClient(napi_env env,napi_ref callbackRef)39 FormAddCallbackClient::FormAddCallbackClient(napi_env env, napi_ref callbackRef)
40 {
41     env_ = env;
42     callbackRef_ = callbackRef;
43     handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
44 }
45 
~FormAddCallbackClient()46 FormAddCallbackClient::~FormAddCallbackClient()
47 {
48     napi_delete_reference(env_, callbackRef_);
49 }
50 
ProcessFormAdd(const std::string & bundleName,const AppExecFwk::RunningFormInfo & runningFormInfo)51 void FormAddCallbackClient::ProcessFormAdd(const std::string &bundleName,
52     const AppExecFwk::RunningFormInfo &runningFormInfo)
53 {
54     if (handler_ == nullptr) {
55         HILOG_INFO("null handler");
56         return;
57     }
58     handler_->PostSyncTask([thisWeakPtr = weak_from_this(), bundleName, runningFormInfo]() {
59         auto sharedThis = thisWeakPtr.lock();
60         if (sharedThis == nullptr) {
61             HILOG_ERROR("null sharedThis");
62             return;
63         }
64         napi_value callbackValues = nullptr;
65         napi_create_object(sharedThis->env_, &callbackValues);
66         ParseRunningFormInfoIntoNapi(sharedThis->env_, runningFormInfo, callbackValues);
67         napi_value callResult;
68         napi_value myCallback = nullptr;
69         napi_get_reference_value(sharedThis->env_, sharedThis->callbackRef_, &myCallback);
70         if (myCallback != nullptr) {
71             napi_call_function(sharedThis->env_, nullptr, myCallback, ARGS_ONE, &callbackValues, &callResult);
72         }
73     });
74 }
75 
IsStrictEqual(napi_value callback)76 bool FormAddCallbackClient::IsStrictEqual(napi_value callback)
77 {
78     bool isEqual = false;
79     napi_value myCallback = nullptr;
80     napi_get_reference_value(env_, callbackRef_, &myCallback);
81     napi_strict_equals(env_, myCallback, callback, &isEqual);
82     HILOG_INFO("isStrictEqual:%{public}d", isEqual);
83     return isEqual;
84 }
85 
FormRemoveCallbackClient(napi_env env,napi_ref callbackRef)86 FormRemoveCallbackClient::FormRemoveCallbackClient(napi_env env, napi_ref callbackRef)
87 {
88     env_ = env;
89     callbackRef_ = callbackRef;
90     handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
91 }
92 
~FormRemoveCallbackClient()93 FormRemoveCallbackClient::~FormRemoveCallbackClient()
94 {
95     napi_delete_reference(env_, callbackRef_);
96 }
97 
ProcessFormRemove(const std::string & bundleName,const AppExecFwk::RunningFormInfo & runningFormInfo)98 void FormRemoveCallbackClient::ProcessFormRemove(const std::string &bundleName,
99     const AppExecFwk::RunningFormInfo &runningFormInfo)
100 {
101     if (handler_ == nullptr) {
102         HILOG_INFO("null handler");
103         return;
104     }
105     handler_->PostSyncTask([thisWeakPtr = weak_from_this(), bundleName, runningFormInfo]() {
106         auto sharedThis = thisWeakPtr.lock();
107         if (sharedThis == nullptr) {
108             HILOG_ERROR("null sharedThis");
109             return;
110         }
111         napi_value callbackValues = nullptr;
112         napi_create_object(sharedThis->env_, &callbackValues);
113         ParseRunningFormInfoIntoNapi(sharedThis->env_, runningFormInfo, callbackValues);
114         napi_value callResult;
115         napi_value myCallback = nullptr;
116         napi_get_reference_value(sharedThis->env_, sharedThis->callbackRef_, &myCallback);
117         if (myCallback != nullptr) {
118             napi_call_function(sharedThis->env_, nullptr, myCallback, ARGS_ONE, &callbackValues, &callResult);
119         }
120     });
121 }
122 
IsStrictEqual(napi_value callback)123 bool FormRemoveCallbackClient::IsStrictEqual(napi_value callback)
124 {
125     bool isEqual = false;
126     napi_value myCallback = nullptr;
127     napi_get_reference_value(env_, callbackRef_, &myCallback);
128     napi_strict_equals(env_, myCallback, callback, &isEqual);
129     HILOG_INFO("isStrictEqual:%{public}d", isEqual);
130     return isEqual;
131 }
132 
GetInstance()133 sptr<JsFormStateObserver> JsFormStateObserver::GetInstance()
134 {
135     if (instance_ == nullptr) {
136         std::lock_guard<std::mutex> lock(mutex_);
137         if (instance_ == nullptr) {
138             instance_ = new (std::nothrow) JsFormStateObserver();
139             if (instance_ == nullptr) {
140                 HILOG_ERROR("create JsFormStateObserver failed");
141             }
142         }
143     }
144     return instance_;
145 }
146 
CheckMapSize(const std::string & type,const std::string & bundleName)147 bool JsFormStateObserver::CheckMapSize(const std::string &type, const std::string &bundleName)
148 {
149     HILOG_DEBUG("start");
150     if (type == "formAdd") {
151         std::lock_guard<std::mutex> lock(addFormCallbackMutex_);
152         if (formAddCallbackMap_.find(bundleName) == formAddCallbackMap_.end()) {
153             if (formAddCallbackMap_.size() >= KEY_LIMIT) {
154                 HILOG_ERROR("the number of the bundleName exceeds the limit");
155                 return false;
156             }
157         }
158     } else if (type == "formRemove") {
159         std::lock_guard<std::mutex> lock(removeFormCallbackMutex_);
160         if (formRemoveCallbackMap_.find(bundleName) == formRemoveCallbackMap_.end()) {
161             if (formRemoveCallbackMap_.size() >= KEY_LIMIT) {
162                 HILOG_ERROR("the number of the bundleName exceeds the limit");
163                 return false;
164             }
165         }
166     } else {
167         return false;
168     }
169     return true;
170 }
171 
RegisterFormAddCallback(const napi_env env,const std::string & bundleName,const napi_value callback)172 bool JsFormStateObserver::RegisterFormAddCallback(const napi_env env,
173     const std::string &bundleName, const napi_value callback)
174 {
175     HILOG_DEBUG("start");
176     napi_ref callbackRef;
177     napi_create_reference(env, callback, REF_COUNT, &callbackRef);
178     std::shared_ptr<FormAddCallbackClient> callbackClient = std::make_shared<FormAddCallbackClient>(env,
179         callbackRef);
180 
181     std::lock_guard<std::mutex> lock(addFormCallbackMutex_);
182     auto formAddCallbacks = formAddCallbackMap_.find(bundleName);
183     if (formAddCallbacks == formAddCallbackMap_.end()) {
184         std::vector<std::shared_ptr<FormAddCallbackClient>> callbacks;
185         callbacks.emplace_back(callbackClient);
186         formAddCallbackMap_.emplace(bundleName, callbacks);
187         return true;
188     } else {
189         auto &callbacks = formAddCallbacks->second;
190         for (auto &iter : callbacks) {
191             if (iter->IsStrictEqual(callback)) {
192                 HILOG_ERROR("found equal callback");
193                 return false;
194             }
195         }
196         formAddCallbacks->second.emplace_back(callbackClient);
197         return true;
198     }
199 }
200 
RegisterFormRemoveCallback(const napi_env env,const std::string & bundleName,const napi_value callback)201 bool JsFormStateObserver::RegisterFormRemoveCallback(const napi_env env,
202     const std::string &bundleName, const napi_value callback)
203 {
204     HILOG_DEBUG("start");
205     napi_ref callbackRef;
206     napi_create_reference(env, callback, REF_COUNT, &callbackRef);
207     std::shared_ptr<FormRemoveCallbackClient> callbackClient =
208         std::make_shared<FormRemoveCallbackClient>(env, callbackRef);
209 
210     std::lock_guard<std::mutex> lock(removeFormCallbackMutex_);
211     auto formRemoveCallbacks = formRemoveCallbackMap_.find(bundleName);
212     if (formRemoveCallbacks == formRemoveCallbackMap_.end()) {
213         std::vector<std::shared_ptr<FormRemoveCallbackClient>> callbacks;
214         callbacks.emplace_back(callbackClient);
215         formRemoveCallbackMap_.emplace(bundleName, callbacks);
216         return true;
217     } else {
218         auto &callbacks = formRemoveCallbacks->second;
219         for (auto &iter : callbacks) {
220             if (iter->IsStrictEqual(callback)) {
221                 HILOG_ERROR("found equal callback");
222                 return false;
223             }
224         }
225         formRemoveCallbacks->second.emplace_back(callbackClient);
226         return true;
227     }
228 }
229 
ClearFormAddCallbackByBundle(const std::string & bundleName)230 void JsFormStateObserver::ClearFormAddCallbackByBundle(const std::string &bundleName)
231 {
232     HILOG_DEBUG("start");
233     std::lock_guard<std::mutex> lock(addFormCallbackMutex_);
234     auto formAddCallbacks = formAddCallbackMap_.find(bundleName);
235     if (formAddCallbacks == formAddCallbackMap_.end()) {
236         HILOG_INFO("No formAddCallback register");
237     } else {
238         auto &callbacks = formAddCallbacks->second;
239         callbacks.clear();
240         formAddCallbackMap_.erase(formAddCallbacks);
241     }
242 }
243 
DelFormAddCallbackByBundle(const napi_value callback,const std::string & bundleName)244 void JsFormStateObserver::DelFormAddCallbackByBundle(const napi_value callback, const std::string &bundleName)
245 {
246     HILOG_DEBUG("start");
247 
248     std::lock_guard<std::mutex> lock(addFormCallbackMutex_);
249     auto formAddCallbacks = formAddCallbackMap_.find(bundleName);
250     if (formAddCallbacks == formAddCallbackMap_.end()) {
251         HILOG_INFO("no formAddCallback registered with this bundleName");
252     } else {
253         auto &callbacks = formAddCallbacks->second;
254         auto iter = std::find_if(callbacks.begin(), callbacks.end(), [&](const auto &cb) {
255             return cb->IsStrictEqual(callback);
256         });
257         if (iter != callbacks.end()) {
258             HILOG_INFO("equal callback");
259             callbacks.erase(iter);
260         } else {
261             HILOG_INFO("no formAddCallback");
262         }
263     }
264 }
265 
OnAddForm(const std::string & bundleName,const AppExecFwk::RunningFormInfo & runningFormInfo)266 int32_t JsFormStateObserver::OnAddForm(const std::string &bundleName,
267     const AppExecFwk::RunningFormInfo &runningFormInfo)
268 {
269     HILOG_DEBUG("call");
270 
271     std::lock_guard<std::mutex> lock(addFormCallbackMutex_);
272     auto callbackClient = formAddCallbackMap_.find(bundleName);
273     if (callbackClient != formAddCallbackMap_.end()) {
274         for (auto iter : callbackClient->second) {
275             iter->ProcessFormAdd(bundleName, runningFormInfo);
276         }
277     }
278     return ERR_OK;
279 }
280 
ClearFormRemoveCallbackByBundle(const std::string & bundleName)281 void JsFormStateObserver::ClearFormRemoveCallbackByBundle(const std::string &bundleName)
282 {
283     HILOG_DEBUG("start");
284     std::lock_guard<std::mutex> lock(removeFormCallbackMutex_);
285     auto formRemoveCallbacks = formRemoveCallbackMap_.find(bundleName);
286     if (formRemoveCallbacks == formRemoveCallbackMap_.end()) {
287         HILOG_INFO("no formRemoveCallback register");
288     } else {
289         auto &callbacks = formRemoveCallbacks->second;
290         callbacks.clear();
291         formRemoveCallbackMap_.erase(formRemoveCallbacks);
292     }
293 }
294 
DelFormRemoveCallbackByBundle(const napi_value callback,const std::string & bundleName)295 void JsFormStateObserver::DelFormRemoveCallbackByBundle(const napi_value callback, const std::string &bundleName)
296 {
297     HILOG_DEBUG("start");
298 
299     std::lock_guard<std::mutex> lock(removeFormCallbackMutex_);
300     auto formRemoveCallbacks = formRemoveCallbackMap_.find(bundleName);
301     if (formRemoveCallbacks == formRemoveCallbackMap_.end()) {
302         HILOG_INFO("no formRemoveCallback registered with this bundleName");
303     } else {
304         auto &callbacks = formRemoveCallbacks->second;
305         auto iter = std::find_if(callbacks.begin(), callbacks.end(), [&](const auto &cb) {
306             return cb->IsStrictEqual(callback);
307         });
308         if (iter != callbacks.end()) {
309             HILOG_INFO("equal callback");
310             callbacks.erase(iter);
311         } else {
312             HILOG_INFO("no formRemoveCallback");
313         }
314     }
315 }
316 
OnRemoveForm(const std::string & bundleName,const AppExecFwk::RunningFormInfo & runningFormInfo)317 int32_t JsFormStateObserver::OnRemoveForm(const std::string &bundleName,
318     const AppExecFwk::RunningFormInfo &runningFormInfo)
319 {
320     HILOG_DEBUG("call");
321 
322     std::lock_guard<std::mutex> lock(removeFormCallbackMutex_);
323     auto callbackClient = formRemoveCallbackMap_.find(bundleName);
324     if (callbackClient != formRemoveCallbackMap_.end()) {
325         for (auto iter : callbackClient->second) {
326             iter->ProcessFormRemove(bundleName, runningFormInfo);
327         }
328     }
329     return ERR_OK;
330 }
331 
RegisterFormInstanceCallback(napi_env env,napi_value jsObserverObject,bool isVisibility,std::string & bundleName,sptr<JsFormStateObserver> & formObserver)332 int JsFormStateObserver::RegisterFormInstanceCallback(napi_env env, napi_value jsObserverObject,
333     bool isVisibility, std::string &bundleName, sptr<JsFormStateObserver> &formObserver)
334 {
335     HILOG_DEBUG("call");
336     if (env_ == nullptr) {
337         env_ = env;
338     }
339     std::string specialFlag = "#";
340     std::lock_guard<std::mutex> lock(formIsvisibleCallbackMutex_);
341     napi_ref ref = nullptr;
342     if (isVisibility) {
343         auto visibleCallback = formVisibleCallbackMap_.find(bundleName);
344         if (visibleCallback != formVisibleCallbackMap_.end()) {
345             HILOG_ERROR("bundleName is already in the map,bundleName id %{public}s", bundleName.c_str());
346             return ERR_APPEXECFWK_FORM_GET_BUNDLE_FAILED;
347         }
348         napi_create_reference(env, jsObserverObject, 1, &ref);
349         formVisibleCallbackMap_.emplace(
350             bundleName, std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference *>(ref)));
351     } else {
352         auto invisibleCallback = formInvisibleCallbackMap_.find(bundleName);
353         if (invisibleCallback != formInvisibleCallbackMap_.end()) {
354             HILOG_ERROR("bundleName is already in the map,bundleName id %{public}s", bundleName.c_str());
355             return ERR_APPEXECFWK_FORM_GET_BUNDLE_FAILED;
356         }
357         napi_create_reference(env, jsObserverObject, 1, &ref);
358         formInvisibleCallbackMap_.emplace(
359             bundleName, std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference *>(ref)));
360     }
361     AppExecFwk::FormMgr::GetInstance().RegisterAddObserver(bundleName + specialFlag + std::to_string(isVisibility),
362         formObserver);
363     return ERR_OK;
364 }
365 
ClearFormNotifyVisibleCallbackByBundle(const std::string bundleName,bool isVisibility,sptr<JsFormStateObserver> & formObserver)366 ErrCode JsFormStateObserver::ClearFormNotifyVisibleCallbackByBundle(const std::string bundleName,
367     bool isVisibility, sptr<JsFormStateObserver> &formObserver)
368 {
369     HILOG_DEBUG("call");
370     std::lock_guard<std::mutex> lock(formIsvisibleCallbackMutex_);
371     std::string specialFlag = "#";
372     if (isVisibility) {
373         auto visibleCallback = formVisibleCallbackMap_.find(bundleName);
374         if (visibleCallback != formVisibleCallbackMap_.end()) {
375             AppExecFwk::FormMgr::GetInstance().RegisterRemoveObserver(
376                 bundleName + specialFlag + std::to_string(isVisibility), formObserver);
377             formVisibleCallbackMap_.erase(visibleCallback);
378             return ERR_OK;
379         } else {
380             HILOG_ERROR("There is no formVisibleCallbackMap_ has been register");
381             return ERR_APPEXECFWK_FORM_GET_BUNDLE_FAILED;
382         }
383     } else {
384         auto invisibleCallback = formInvisibleCallbackMap_.find(bundleName);
385         if (invisibleCallback != formInvisibleCallbackMap_.end()) {
386             AppExecFwk::FormMgr::GetInstance().RegisterRemoveObserver(
387                 bundleName + specialFlag + std::to_string(isVisibility), formObserver);
388             formInvisibleCallbackMap_.erase(invisibleCallback);
389             return ERR_OK;
390         } else {
391             HILOG_ERROR("There is no formInvisibleCallbackMap_ has been register");
392             return ERR_APPEXECFWK_FORM_GET_BUNDLE_FAILED;
393         }
394     }
395 }
396 
DelFormNotifyVisibleCallbackByBundle(const std::string bundleName,bool isVisibility,napi_value jsObserverObject,sptr<JsFormStateObserver> & formObserver)397 ErrCode JsFormStateObserver::DelFormNotifyVisibleCallbackByBundle(const std::string bundleName,
398     bool isVisibility, napi_value jsObserverObject, sptr<JsFormStateObserver> &formObserver)
399 {
400     HILOG_DEBUG("call");
401     std::lock_guard<std::mutex> lock(formIsvisibleCallbackMutex_);
402     std::string specialFlag = "#";
403     if (isVisibility) {
404         auto visibleCallback = formVisibleCallbackMap_.find(bundleName);
405         if (visibleCallback != formVisibleCallbackMap_.end()) {
406             napi_value value = visibleCallback->second->GetNapiValue();
407             bool isEqual = false;
408             napi_strict_equals(env_, value, jsObserverObject, &isEqual);
409             if (isEqual) {
410                 AppExecFwk::FormMgr::GetInstance().RegisterRemoveObserver(
411                     bundleName + specialFlag + std::to_string(isVisibility), formObserver);
412                 formVisibleCallbackMap_.erase(visibleCallback);
413                 return ERR_OK;
414             } else {
415                 HILOG_ERROR("There is no formVisibleCallbackMap_ has been register");
416                 return ERR_APPEXECFWK_FORM_GET_BUNDLE_FAILED;
417             }
418         } else {
419             HILOG_ERROR("There is no formVisibleCallbackMap_ has been register");
420             return ERR_APPEXECFWK_FORM_GET_BUNDLE_FAILED;
421         }
422     } else {
423         auto invisibleCallback = formInvisibleCallbackMap_.find(bundleName);
424         if (invisibleCallback != formInvisibleCallbackMap_.end()) {
425             napi_value value = invisibleCallback->second->GetNapiValue();
426             bool isEqual = false;
427             napi_strict_equals(env_, value, jsObserverObject, &isEqual);
428             if (isEqual) {
429                 AppExecFwk::FormMgr::GetInstance().RegisterRemoveObserver(
430                     bundleName + specialFlag + std::to_string(isVisibility), formObserver);
431                 formInvisibleCallbackMap_.erase(invisibleCallback);
432                 return ERR_OK;
433             } else {
434                 HILOG_ERROR("There is no formInvisibleCallbackMap_ has been register");
435                 return ERR_APPEXECFWK_FORM_GET_BUNDLE_FAILED;
436             }
437         } else {
438             HILOG_ERROR("There is no formInvisibleCallbackMap_ has been register");
439             return ERR_APPEXECFWK_FORM_GET_BUNDLE_FAILED;
440         }
441     }
442 }
443 
NotifyWhetherFormsVisible(const AppExecFwk::FormVisibilityType visibleType,const std::string & bundleName,std::vector<AppExecFwk::FormInstance> & formInstances)444 int32_t JsFormStateObserver::NotifyWhetherFormsVisible(const AppExecFwk::FormVisibilityType visibleType,
445     const std::string &bundleName, std::vector<AppExecFwk::FormInstance> &formInstances)
446 {
447     handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
448     HILOG_DEBUG("call");
449     std::lock_guard<std::mutex> lock(formIsvisibleCallbackMutex_);
450     if (handler_) {
451         wptr<JsFormStateObserver> weakObserver = this;
452         handler_->PostSyncTask([weakObserver, visibleType, formInstances, bundleName]() {
453             std::string specialFlag = "#";
454             bool isVisibleTypeFlag = false;
455             auto sharedThis = weakObserver.promote();
456             if (sharedThis == nullptr) {
457                 HILOG_ERROR("null sharedThis");
458                 return;
459             }
460             napi_handle_scope scope = nullptr;
461             napi_open_handle_scope(sharedThis->env_, &scope);
462             if (scope == nullptr) {
463                 HILOG_ERROR("null scope");
464                 return;
465             }
466             if (visibleType == AppExecFwk::FormVisibilityType::VISIBLE) {
467                 isVisibleTypeFlag = true;
468                 if (bundleName.find((specialFlag + std::to_string(isVisibleTypeFlag))) != std::string::npos) {
469                     std::string bundleNameNew =
470                         std::regex_replace(bundleName, std::regex(specialFlag + std::to_string(isVisibleTypeFlag)), "");
471                     auto visibleCallback = sharedThis->formVisibleCallbackMap_.find(bundleNameNew);
472                     if (visibleCallback != sharedThis->formVisibleCallbackMap_.end()) {
473                         napi_value res = visibleCallback->second->GetNapiValue();
474                         napi_value argv[] = { CreateFormInstances(sharedThis->env_, formInstances) };
475                         napi_call_function(sharedThis->env_, res, res, sizeof(argv) / sizeof(argv[0]), argv, nullptr);
476                     }
477                 }
478             } else {
479                 isVisibleTypeFlag = false;
480                 if (bundleName.find((specialFlag + std::to_string(isVisibleTypeFlag))) != std::string::npos) {
481                     std::string bundleNameNew =
482                         std::regex_replace(bundleName, std::regex(specialFlag + std::to_string(isVisibleTypeFlag)), "");
483                     auto invisibleCallback = sharedThis->formInvisibleCallbackMap_.find(bundleNameNew);
484                     if (invisibleCallback != sharedThis->formInvisibleCallbackMap_.end()) {
485                         napi_value res = invisibleCallback->second->GetNapiValue();
486                         napi_value argv[] = { CreateFormInstances(sharedThis->env_, formInstances) };
487                         napi_call_function(sharedThis->env_, res, res, sizeof(argv) / sizeof(argv[0]), argv, nullptr);
488                     }
489                 }
490             }
491             napi_close_handle_scope(sharedThis->env_, scope);
492         });
493     }
494     return ERR_OK;
495 }
496 
OnFormClickEvent(const std::string & bundleName,const std::string & callType,const AppExecFwk::RunningFormInfo & runningFormInfo)497 ErrCode JsFormStateObserver::OnFormClickEvent(
498     const std::string &bundleName, const std::string &callType, const AppExecFwk::RunningFormInfo &runningFormInfo)
499 {
500     HILOG_DEBUG("call");
501     if (callType.empty()) {
502         HILOG_ERROR("empty Calltype");
503         return ERR_INVALID_VALUE;
504     }
505     if (handler_ == nullptr) {
506         handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
507         if (handler_ == nullptr) {
508             HILOG_ERROR("null Handler");
509             return ERR_INVALID_VALUE;
510         }
511     }
512 
513     wptr<JsFormStateObserver> weakObserver = this;
514     auto notify = [bundleName, callType, runningFormInfo, weakObserver]() {
515         auto self = weakObserver.promote();
516         if (self == nullptr) {
517             HILOG_ERROR("null Self");
518             return;
519         }
520         std::unique_lock<std::mutex> lock(self->formEventMapMutex_);
521         auto formEventCallbackListIter = self->formEventMap_.find(bundleName);
522         if (formEventCallbackListIter != self->formEventMap_.end()) {
523             auto &callbackListVec = formEventCallbackListIter->second;
524             auto callBackListIter = std::find_if(callbackListVec.begin(), callbackListVec.end(),
525             [bundleName, callType](auto &iter) {
526                 return iter != nullptr &&
527                        iter->BindFormEventType() == callType &&
528                        iter->BindHostBundleName() == bundleName;
529             });
530             if (callBackListIter != callbackListVec.end() && (*callBackListIter) != nullptr) {
531                 (*callBackListIter)->HandleFormEvent(runningFormInfo);
532             }
533         }
534     };
535 
536     handler_->PostSyncTask(notify);
537     return ERR_OK;
538 }
539 
RegisterClickEventCallback(const napi_env env,const std::string & bundleName,const napi_value callback,const std::string & type)540 ErrCode JsFormStateObserver::RegisterClickEventCallback(
541     const napi_env env, const std::string &bundleName, const napi_value callback, const std::string &type)
542 {
543     HILOG_DEBUG("call");
544     auto record = std::make_shared<FormEventCallbackList>(bundleName, type, env);
545     if (record == nullptr) {
546         HILOG_ERROR("New obj error");
547         return ERR_INVALID_VALUE;
548     }
549     record->PushCallback(callback);
550 
551     std::unique_lock<std::mutex> lock(formEventMapMutex_);
552 
553     auto formEventCallbackListIter = formEventMap_.find(bundleName);
554     if (formEventCallbackListIter == formEventMap_.end()) {
555         std::vector<std::shared_ptr<FormEventCallbackList>> formEventCallbackListVector {record};
556         formEventMap_.emplace(bundleName, formEventCallbackListVector);
557         AppExecFwk::FormMgr::GetInstance().RegisterClickEventObserver(
558             bundleName, type, JsFormStateObserver::GetInstance());
559         return ERR_OK;
560     }
561 
562     auto &callbackListVec = formEventCallbackListIter->second;
563     auto callBackListIter = std::find_if(
564         callbackListVec.begin(), callbackListVec.end(), [bundleName, type](auto &iter) {
565             return iter != nullptr && iter->BindFormEventType() == type && iter->BindHostBundleName() == bundleName;
566         });
567     if (callBackListIter != callbackListVec.end() && (*callBackListIter) != nullptr) {
568         (*callBackListIter)->PushCallback(callback);
569         return ERR_OK;
570     }
571 
572     formEventCallbackListIter->second.emplace_back(record);
573     AppExecFwk::FormMgr::GetInstance().RegisterClickEventObserver(bundleName, type, JsFormStateObserver::GetInstance());
574     return ERR_OK;
575 }
576 
ClearFormClickCallbackByBundleName(const std::string & type,const std::string & bundleName)577 ErrCode JsFormStateObserver::ClearFormClickCallbackByBundleName(const std::string &type, const std::string &bundleName)
578 {
579     HILOG_DEBUG("call");
580     std::unique_lock<std::mutex> lock(formEventMapMutex_);
581     auto formEventCallbackListIter = formEventMap_.find(bundleName);
582     if (formEventCallbackListIter == formEventMap_.end()) {
583         HILOG_ERROR("Invalid bundleName");
584         return ERR_INVALID_VALUE;
585     }
586 
587     auto &callbackListVec = formEventCallbackListIter->second;
588     auto callBackListIter = std::find_if(
589         callbackListVec.begin(), callbackListVec.end(), [bundleName, type](auto &iter) {
590             return iter != nullptr && iter->BindFormEventType() == type && iter->BindHostBundleName() == bundleName;
591         });
592     if (callBackListIter == callbackListVec.end()) {
593         HILOG_ERROR("This bundle hasn't registered any callback of this type");
594         return ERR_INVALID_VALUE;
595     }
596     callbackListVec.erase(callBackListIter);
597     AppExecFwk::FormMgr::GetInstance().UnregisterClickEventObserver(
598         bundleName, type, JsFormStateObserver::GetInstance());
599     return ERR_OK;
600 }
601 
ClearFormClickCallback(const std::string & type,const std::string & bundleName,const napi_value & callback)602 ErrCode JsFormStateObserver::ClearFormClickCallback(
603     const std::string &type, const std::string &bundleName, const napi_value &callback)
604 {
605     HILOG_DEBUG("call");
606     std::unique_lock<std::mutex> lock(formEventMapMutex_);
607     auto formEventCallbackListIter = formEventMap_.find(bundleName);
608     if (formEventCallbackListIter == formEventMap_.end()) {
609         HILOG_ERROR("Invalid bundleName");
610         return ERR_INVALID_VALUE;
611     }
612 
613     auto &callbackListVec = formEventCallbackListIter->second;
614     auto callBackListIter = std::find_if(
615         callbackListVec.begin(), callbackListVec.end(), [bundleName, type](auto &iter) {
616             return iter != nullptr && iter->BindFormEventType() == type && iter->BindHostBundleName() == bundleName;
617         });
618     if (callBackListIter == callbackListVec.end()) {
619         HILOG_ERROR("This bundle hasn't registered any callback of this type");
620         return ERR_INVALID_VALUE;
621     }
622 
623     auto sharedItem = *callBackListIter;
624     if (sharedItem == nullptr) {
625         HILOG_ERROR("Holding empty objects");
626         return ERR_INVALID_VALUE;
627     }
628 
629     sharedItem->RemoveCallback(callback);
630     if (sharedItem->IsEmpty()) {
631         callbackListVec.erase(callBackListIter);
632         // Need to notify fms
633         AppExecFwk::FormMgr::GetInstance().UnregisterClickEventObserver(
634             bundleName, type, JsFormStateObserver::GetInstance());
635     }
636     return ERR_OK;
637 }
638 
~FormEventCallbackList()639 FormEventCallbackList::~FormEventCallbackList()
640 {
641     for (auto &iter : callbacks_) {
642         napi_delete_reference(env_, iter);
643     }
644 }
645 
ContainEqualCallback(napi_value callback) const646 bool FormEventCallbackList::ContainEqualCallback(napi_value callback) const
647 {
648     HILOG_DEBUG("call");
649     if (env_ == nullptr) {
650         HILOG_ERROR("null env");
651         return false;
652     }
653     bool ref = false;
654     napi_value compareCallback = nullptr;
655     for (auto &call : callbacks_) {
656         napi_get_reference_value(env_, call, &compareCallback);
657         napi_strict_equals(env_, compareCallback, callback, &ref);
658         if (ref) {
659             return ref;
660         }
661     }
662     return ref;
663 }
664 
PushCallback(napi_value call)665 void FormEventCallbackList::PushCallback(napi_value call)
666 {
667     HILOG_DEBUG("call");
668     if (env_ == nullptr) {
669         HILOG_ERROR("null env");
670         return;
671     }
672     if (!ContainEqualCallback(call)) {
673         napi_ref callbackRef;
674         napi_create_reference(env_, call, REF_COUNT, &callbackRef);
675         if (callbackRef != nullptr) {
676             callbacks_.emplace_back(callbackRef);
677         }
678     }
679 }
680 
RemoveCallback(napi_value call)681 void FormEventCallbackList::RemoveCallback(napi_value call)
682 {
683     HILOG_DEBUG("call");
684     if (env_ == nullptr) {
685         HILOG_ERROR("null env");
686         return;
687     }
688     auto iter = std::find_if(callbacks_.begin(), callbacks_.end(), [env = env_, callback = call](auto &item) {
689         bool equal = false;
690         napi_value callbackFun = nullptr;
691         napi_get_reference_value(env, item, &callbackFun);
692         if (callbackFun != nullptr) {
693             napi_strict_equals(env, callbackFun, callback, &equal);
694         }
695         return equal;
696     });
697     if (iter != callbacks_.end()) {
698         napi_delete_reference(env_, *iter);
699         callbacks_.erase(iter);
700     }
701 }
702 
HandleFormEvent(const AppExecFwk::RunningFormInfo & runningFormInfo) const703 void FormEventCallbackList::HandleFormEvent(const AppExecFwk::RunningFormInfo &runningFormInfo) const
704 {
705     HILOG_DEBUG("call");
706     if (env_ == nullptr) {
707         HILOG_ERROR("null env");
708         return;
709     }
710     napi_value formInfo = nullptr;
711     napi_create_object(env_, &formInfo);
712     ParseRunningFormInfoIntoNapi(env_, runningFormInfo, formInfo);
713     napi_value callResult;
714     napi_value callbackfun = nullptr;
715     for (auto &iter : callbacks_) {
716         napi_get_reference_value(env_, iter, &callbackfun);
717         if (callbackfun != nullptr) {
718             napi_call_function(env_, nullptr, callbackfun, ARGS_ONE, &formInfo, &callResult);
719         }
720     }
721 }
722 }  // namespace AbilityRuntime
723 }  // namespace OHOS
724