• 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 "ui_observer.h"
17 
18 #include "bridge/common/utils/engine_helper.h"
19 
20 
21 namespace OHOS::Ace::Napi {
22 std::list<std::shared_ptr<UIObserverListener>> UIObserver::unspecifiedNavigationListeners_;
23 std::unordered_map<std::string, std::list<std::shared_ptr<UIObserverListener>>>
24     UIObserver::specifiedCNavigationListeners_;
25 
26 std::list<std::shared_ptr<UIObserverListener>> UIObserver::scrollEventListeners_;
27 std::unordered_map<std::string, std::list<std::shared_ptr<UIObserverListener>>>
28     UIObserver::specifiedScrollEventListeners_;
29 
30 std::unordered_map<napi_ref, std::list<std::shared_ptr<UIObserverListener>>>
31     UIObserver::abilityContextRouterPageListeners_;
32 std::unordered_map<int32_t, std::list<std::shared_ptr<UIObserverListener>>>
33     UIObserver::specifiedRouterPageListeners_;
34 std::unordered_map<napi_ref, NG::AbilityContextInfo> UIObserver::infosForRouterPage_;
35 
36 std::unordered_map<int32_t, std::list<std::shared_ptr<UIObserverListener>>>
37     UIObserver::specifiedDensityListeners_;
38 std::unordered_map<int32_t, std::list<std::shared_ptr<UIObserverListener>>> UIObserver::specifiedDrawListeners_;
39 std::unordered_map<int32_t, std::list<std::shared_ptr<UIObserverListener>>> UIObserver::specifiedLayoutListeners_;
40 
41 std::unordered_map<napi_ref, UIObserver::NavIdAndListenersMap> UIObserver::abilityUIContextNavDesSwitchListeners_;
42 std::unordered_map<int32_t, UIObserver::NavIdAndListenersMap> UIObserver::uiContextNavDesSwitchListeners_;
43 std::unordered_map<napi_ref, NG::AbilityContextInfo> UIObserver::infosForNavDesSwitch_;
44 
45 std::unordered_map<napi_ref, std::list<std::shared_ptr<UIObserverListener>>>
46     UIObserver::abilityContextWillClickListeners_;
47 std::unordered_map<int32_t, std::list<std::shared_ptr<UIObserverListener>>>
48     UIObserver::specifiedWillClickListeners_;
49 std::unordered_map<napi_ref, NG::AbilityContextInfo> UIObserver::willClickInfos_;
50 
51 std::unordered_map<napi_ref, std::list<std::shared_ptr<UIObserverListener>>>
52     UIObserver::abilityContextDidClickListeners_;
53 std::unordered_map<int32_t, std::list<std::shared_ptr<UIObserverListener>>>
54     UIObserver::specifiedDidClickListeners_;
55 std::unordered_map<napi_ref, NG::AbilityContextInfo> UIObserver::didClickInfos_;
56 
57 std::list<std::shared_ptr<UIObserverListener>> UIObserver::tabContentStateListeners_;
58 std::unordered_map<std::string, std::list<std::shared_ptr<UIObserverListener>>>
59     UIObserver::specifiedTabContentStateListeners_;
60 
61 std::unordered_map<napi_ref, std::list<std::shared_ptr<UIObserverListener>>>
62     UIObserver::abilityContextBeforePanStartListeners_;
63 std::unordered_map<int32_t, std::list<std::shared_ptr<UIObserverListener>>>
64     UIObserver::specifiedBeforePanStartListeners_;
65 std::unordered_map<napi_ref, NG::AbilityContextInfo> UIObserver::beforePanStartInfos_;
66 std::unordered_map<napi_ref, std::list<std::shared_ptr<UIObserverListener>>>
67     UIObserver::abilityContextBeforePanEndListeners_;
68 std::unordered_map<int32_t, std::list<std::shared_ptr<UIObserverListener>>>
69     UIObserver::specifiedBeforePanEndListeners_;
70 std::unordered_map<napi_ref, NG::AbilityContextInfo> UIObserver::beforePanEndInfos_;
71 
72 std::unordered_map<napi_ref, std::list<std::shared_ptr<UIObserverListener>>>
73     UIObserver::abilityContextAfterPanStartListeners_;
74 std::unordered_map<int32_t, std::list<std::shared_ptr<UIObserverListener>>>
75     UIObserver::specifiedAfterPanStartListeners_;
76 std::unordered_map<napi_ref, NG::AbilityContextInfo> UIObserver::afterPanStartInfos_;
77 std::unordered_map<napi_ref, std::list<std::shared_ptr<UIObserverListener>>>
78     UIObserver::abilityContextAfterPanEndListeners_;
79 std::unordered_map<int32_t, std::list<std::shared_ptr<UIObserverListener>>>
80     UIObserver::specifiedAfterPanEndListeners_;
81 std::unordered_map<napi_ref, NG::AbilityContextInfo> UIObserver::afterPanEndInfos_;
82 std::unordered_map<napi_ref, NG::AbilityContextInfo> UIObserver::PanGestureInfos_;
83 
84 // UIObserver.on(type: "navDestinationUpdate", callback)
85 // register a global listener without options
RegisterNavigationCallback(const std::shared_ptr<UIObserverListener> & listener)86 void UIObserver::RegisterNavigationCallback(const std::shared_ptr<UIObserverListener>& listener)
87 {
88     if (std::find(unspecifiedNavigationListeners_.begin(), unspecifiedNavigationListeners_.end(), listener) !=
89         unspecifiedNavigationListeners_.end()) {
90         return;
91     }
92     unspecifiedNavigationListeners_.emplace_back(listener);
93 }
94 
95 // UIObserver.on(type: "navDestinationUpdate", options, callback)
96 // register a listener on a specified Navigation
RegisterNavigationCallback(std::string navigationId,const std::shared_ptr<UIObserverListener> & listener)97 void UIObserver::RegisterNavigationCallback(
98     std::string navigationId, const std::shared_ptr<UIObserverListener>& listener)
99 {
100     auto iter = specifiedCNavigationListeners_.find(navigationId);
101     if (iter == specifiedCNavigationListeners_.end()) {
102         specifiedCNavigationListeners_.emplace(
103             navigationId, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
104         return;
105     }
106     auto& holder = iter->second;
107     if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
108         return;
109     }
110     holder.emplace_back(listener);
111 }
112 
113 // UIObserver.off(type: "navDestinationUpdate", callback)
UnRegisterNavigationCallback(napi_value cb)114 void UIObserver::UnRegisterNavigationCallback(napi_value cb)
115 {
116     if (cb == nullptr) {
117         unspecifiedNavigationListeners_.clear();
118         return;
119     }
120 
121     unspecifiedNavigationListeners_.erase(
122         std::remove_if(
123             unspecifiedNavigationListeners_.begin(),
124             unspecifiedNavigationListeners_.end(),
125             [cb](const std::shared_ptr<UIObserverListener>& registeredListener) {
126                 return registeredListener->NapiEqual(cb);
127             }
128         ),
129         unspecifiedNavigationListeners_.end()
130     );
131 }
132 
133 // UIObserver.off(type: "navDestinationUpdate", options, callback)
UnRegisterNavigationCallback(std::string navigationId,napi_value cb)134 void UIObserver::UnRegisterNavigationCallback(std::string navigationId, napi_value cb)
135 {
136     auto iter = specifiedCNavigationListeners_.find(navigationId);
137     if (iter == specifiedCNavigationListeners_.end()) {
138         return;
139     }
140     auto& holder = iter->second;
141     if (cb == nullptr) {
142         holder.clear();
143         return;
144     }
145     holder.erase(
146         std::remove_if(
147             holder.begin(),
148             holder.end(),
149             [cb](const std::shared_ptr<UIObserverListener>& registeredListener) {
150                 return registeredListener->NapiEqual(cb);
151             }
152         ),
153         holder.end()
154     );
155 }
156 
HandleNavigationStateChange(const NG::NavDestinationInfo & info)157 void UIObserver::HandleNavigationStateChange(const NG::NavDestinationInfo& info)
158 {
159     auto unspecifiedHolder = unspecifiedNavigationListeners_;
160     for (const auto& listener : unspecifiedHolder) {
161         listener->OnNavigationStateChange(info);
162     }
163     auto iter = specifiedCNavigationListeners_.find(info.navigationId);
164     if (iter == specifiedCNavigationListeners_.end()) {
165         return;
166     }
167 
168     auto holder = iter->second;
169 
170     for (const auto& listener : holder) {
171         listener->OnNavigationStateChange(info);
172     }
173 }
174 
175 // UIObserver.on(type: "scrollEvent", callback)
176 // register a global listener without options
RegisterScrollEventCallback(const std::shared_ptr<UIObserverListener> & listener)177 void UIObserver::RegisterScrollEventCallback(const std::shared_ptr<UIObserverListener>& listener)
178 {
179     if (std::find(scrollEventListeners_.begin(), scrollEventListeners_.end(), listener) !=
180         scrollEventListeners_.end()) {
181         return;
182     }
183     scrollEventListeners_.emplace_back(listener);
184 }
185 
186 // UIObserver.on(type: "scrollEvent", options, callback)
187 // register a listener on a specified scrollEvent
RegisterScrollEventCallback(const std::string & id,const std::shared_ptr<UIObserverListener> & listener)188 void UIObserver::RegisterScrollEventCallback(
189     const std::string& id, const std::shared_ptr<UIObserverListener>& listener)
190 {
191     auto iter = specifiedScrollEventListeners_.find(id);
192     if (iter == specifiedScrollEventListeners_.end()) {
193         specifiedScrollEventListeners_.emplace(id, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
194         return;
195     }
196     auto& holder = iter->second;
197     if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
198         return;
199     }
200     holder.emplace_back(listener);
201 }
202 
203 // UIObserver.off(type: "scrollEvent", callback)
UnRegisterScrollEventCallback(napi_value cb)204 void UIObserver::UnRegisterScrollEventCallback(napi_value cb)
205 {
206     if (cb == nullptr) {
207         scrollEventListeners_.clear();
208         return;
209     }
210 
211     scrollEventListeners_.erase(
212         std::remove_if(
213             scrollEventListeners_.begin(),
214             scrollEventListeners_.end(),
215             [cb](const std::shared_ptr<UIObserverListener>& registeredListener) {
216                 return registeredListener->NapiEqual(cb);
217             }),
218         scrollEventListeners_.end()
219     );
220 }
221 
222 // UIObserver.off(type: "scrollEvent", options, callback)
UnRegisterScrollEventCallback(const std::string & id,napi_value cb)223 void UIObserver::UnRegisterScrollEventCallback(const std::string& id, napi_value cb)
224 {
225     auto iter = specifiedScrollEventListeners_.find(id);
226     if (iter == specifiedScrollEventListeners_.end()) {
227         return;
228     }
229     auto& holder = iter->second;
230     if (cb == nullptr) {
231         holder.clear();
232         return;
233     }
234     holder.erase(
235         std::remove_if(
236             holder.begin(),
237             holder.end(),
238             [cb](const std::shared_ptr<UIObserverListener>& registeredListener) {
239                 return registeredListener->NapiEqual(cb);
240             }),
241         holder.end()
242     );
243 }
244 
HandleScrollEventStateChange(const std::string & id,int32_t uniqueId,NG::ScrollEventType eventType,float offset)245 void UIObserver::HandleScrollEventStateChange(const std::string& id, int32_t uniqueId,
246     NG::ScrollEventType eventType, float offset)
247 {
248     for (const auto& listener : scrollEventListeners_) {
249         listener->OnScrollEventStateChange(id, uniqueId, eventType, offset);
250     }
251 
252     auto iter = specifiedScrollEventListeners_.find(id);
253     if (iter == specifiedScrollEventListeners_.end()) {
254         return;
255     }
256 
257     auto& holder = iter->second;
258 
259     for (const auto& listener : holder) {
260         listener->OnScrollEventStateChange(id, uniqueId, eventType, offset);
261     }
262 }
263 
264 // UIObserver.on(type: "routerPageUpdate", UIAbilityContext, callback)
265 // register a listener on current page
RegisterRouterPageCallback(napi_env env,napi_value uiAbilityContext,const std::shared_ptr<UIObserverListener> & listener)266 void UIObserver::RegisterRouterPageCallback(
267     napi_env env, napi_value uiAbilityContext, const std::shared_ptr<UIObserverListener>& listener)
268 {
269     NG::AbilityContextInfo info;
270     GetAbilityInfos(env, uiAbilityContext, info);
271     for (auto listenerPair : abilityContextRouterPageListeners_) {
272         auto ref = listenerPair.first;
273         auto localInfo = infosForRouterPage_[ref];
274         if (info.IsEqual(localInfo)) {
275             auto& holder = abilityContextRouterPageListeners_[ref];
276             if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
277                 return;
278             }
279             holder.emplace_back(listener);
280             return;
281         }
282     }
283     napi_ref newRef = nullptr;
284     napi_create_reference(env, uiAbilityContext, 1, &newRef);
285     abilityContextRouterPageListeners_[newRef] = std::list<std::shared_ptr<UIObserverListener>>({ listener });
286     infosForRouterPage_[newRef] = info;
287 }
288 
289 // UIObserver.on(type: "routerPageUpdate", uiContext | null, callback)
290 // register a listener on current page
RegisterRouterPageCallback(int32_t uiContextInstanceId,const std::shared_ptr<UIObserverListener> & listener)291 void UIObserver::RegisterRouterPageCallback(
292     int32_t uiContextInstanceId, const std::shared_ptr<UIObserverListener>& listener)
293 {
294     if (uiContextInstanceId == 0) {
295         uiContextInstanceId = Container::CurrentId();
296     }
297     auto iter = specifiedRouterPageListeners_.find(uiContextInstanceId);
298     if (iter == specifiedRouterPageListeners_.end()) {
299         specifiedRouterPageListeners_.emplace(
300             uiContextInstanceId, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
301         return;
302     }
303     auto& holder = iter->second;
304     if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
305         return;
306     }
307     holder.emplace_back(listener);
308 }
309 
310 // UIObserver.off(type: "routerPageUpdate", uiAbilityContext, callback)
UnRegisterRouterPageCallback(napi_env env,napi_value uiAbilityContext,napi_value callback)311 void UIObserver::UnRegisterRouterPageCallback(napi_env env, napi_value uiAbilityContext, napi_value callback)
312 {
313     NG::AbilityContextInfo info;
314     GetAbilityInfos(env, uiAbilityContext, info);
315     for (auto listenerPair : abilityContextRouterPageListeners_) {
316         auto ref = listenerPair.first;
317         auto localInfo = infosForRouterPage_[ref];
318         if (info.IsEqual(localInfo)) {
319             auto& holder = abilityContextRouterPageListeners_[listenerPair.first];
320             if (callback == nullptr) {
321                 holder.clear();
322             } else {
323                 holder.erase(
324                     std::remove_if(
325                         holder.begin(),
326                         holder.end(),
327                         [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
328                             return registeredListener->NapiEqual(callback);
329                         }),
330                     holder.end());
331             }
332             if (holder.empty()) {
333                 infosForRouterPage_.erase(ref);
334                 abilityContextRouterPageListeners_.erase(ref);
335                 napi_delete_reference(env, ref);
336             }
337             return;
338         }
339     }
340 }
341 
342 // UIObserver.off(type: "routerPageUpdate", uiContext | null, callback)
UnRegisterRouterPageCallback(int32_t uiContextInstanceId,napi_value callback)343 void UIObserver::UnRegisterRouterPageCallback(int32_t uiContextInstanceId, napi_value callback)
344 {
345     if (uiContextInstanceId == 0) {
346         uiContextInstanceId = Container::CurrentId();
347     }
348     auto iter = specifiedRouterPageListeners_.find(uiContextInstanceId);
349     if (iter == specifiedRouterPageListeners_.end()) {
350         return;
351     }
352     auto& holder = iter->second;
353     if (callback == nullptr) {
354         holder.clear();
355         return;
356     }
357     holder.erase(
358         std::remove_if(
359             holder.begin(),
360             holder.end(),
361             [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
362                 return registeredListener->NapiEqual(callback);
363             }),
364         holder.end());
365 }
366 
367 // UIObserver.on(type: "willDraw", uiContext | null, callback)
368 // register a listener on current page
RegisterDrawCallback(int32_t uiContextInstanceId,const std::shared_ptr<UIObserverListener> & listener)369 void UIObserver::RegisterDrawCallback(int32_t uiContextInstanceId, const std::shared_ptr<UIObserverListener>& listener)
370 {
371     if (uiContextInstanceId == 0) {
372         uiContextInstanceId = Container::CurrentId();
373     }
374     if (specifiedDrawListeners_.find(uiContextInstanceId) == specifiedDrawListeners_.end()) {
375         specifiedDrawListeners_[uiContextInstanceId] = std::list<std::shared_ptr<UIObserverListener>>({ listener });
376         return;
377     }
378     auto& holder = specifiedDrawListeners_[uiContextInstanceId];
379     if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
380         return;
381     }
382     holder.emplace_back(listener);
383 }
384 
385 // UIObserver.off(type: "willDraw", uiContext | null, callback)
UnRegisterDrawCallback(int32_t uiContextInstanceId,napi_value callback)386 void UIObserver::UnRegisterDrawCallback(int32_t uiContextInstanceId, napi_value callback)
387 {
388     if (uiContextInstanceId == 0) {
389         uiContextInstanceId = Container::CurrentId();
390     }
391     if (specifiedDrawListeners_.find(uiContextInstanceId) == specifiedDrawListeners_.end()) {
392         return;
393     }
394     auto& holder = specifiedDrawListeners_[uiContextInstanceId];
395     if (callback == nullptr) {
396         auto container = Container::GetContainer(uiContextInstanceId);
397         CHECK_NULL_VOID(container);
398         auto taskExecutor = container->GetTaskExecutor();
399         CHECK_NULL_VOID(taskExecutor);
400         taskExecutor->PostTask([&holder]() { holder.clear(); }, TaskExecutor::TaskType::UI, "ArkUIClearListener");
401         return;
402     }
403     holder.erase(
404         std::remove_if(
405             holder.begin(),
406             holder.end(),
407             [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
408                 return registeredListener->NapiEqual(callback);
409             }),
410         holder.end());
411 }
412 
413 // UIObserver.on(type: "didLayout", uiContext | null, callback)
414 // register a listener on current page
RegisterLayoutCallback(int32_t uiContextInstanceId,const std::shared_ptr<UIObserverListener> & listener)415 void UIObserver::RegisterLayoutCallback(
416     int32_t uiContextInstanceId, const std::shared_ptr<UIObserverListener>& listener)
417 {
418     if (uiContextInstanceId == 0) {
419         uiContextInstanceId = Container::CurrentId();
420     }
421     if (specifiedLayoutListeners_.find(uiContextInstanceId) == specifiedLayoutListeners_.end()) {
422         specifiedLayoutListeners_[uiContextInstanceId] = std::list<std::shared_ptr<UIObserverListener>>({ listener });
423         return;
424     }
425     auto& holder = specifiedLayoutListeners_[uiContextInstanceId];
426     if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
427         return;
428     }
429     holder.emplace_back(listener);
430 }
431 
432 // UIObserver.off(type: "didLayout", uiContext | null, callback)
UnRegisterLayoutCallback(int32_t uiContextInstanceId,napi_value callback)433 void UIObserver::UnRegisterLayoutCallback(int32_t uiContextInstanceId, napi_value callback)
434 {
435     if (uiContextInstanceId == 0) {
436         uiContextInstanceId = Container::CurrentId();
437     }
438     if (specifiedLayoutListeners_.find(uiContextInstanceId) == specifiedLayoutListeners_.end()) {
439         return;
440     }
441     auto& holder = specifiedLayoutListeners_[uiContextInstanceId];
442     if (callback == nullptr) {
443         auto container = Container::GetContainer(uiContextInstanceId);
444         CHECK_NULL_VOID(container);
445         auto taskExecutor = container->GetTaskExecutor();
446         CHECK_NULL_VOID(taskExecutor);
447         taskExecutor->PostTask([&holder]() { holder.clear(); }, TaskExecutor::TaskType::UI, "ArkUIClearListener");
448         return;
449     }
450     holder.erase(
451         std::remove_if(
452             holder.begin(),
453             holder.end(),
454             [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
455                 return registeredListener->NapiEqual(callback);
456             }),
457         holder.end());
458 }
459 
HandleRouterPageStateChange(NG::AbilityContextInfo & info,const NG::RouterPageInfoNG & pageInfo)460 void UIObserver::HandleRouterPageStateChange(NG::AbilityContextInfo& info, const NG::RouterPageInfoNG& pageInfo)
461 {
462     for (auto listenerPair : abilityContextRouterPageListeners_) {
463         auto ref = listenerPair.first;
464         auto localInfo = infosForRouterPage_[ref];
465         if (info.IsEqual(localInfo)) {
466             auto env = GetCurrentNapiEnv();
467             napi_value abilityContext = nullptr;
468             napi_get_reference_value(env, ref, &abilityContext);
469 
470             NG::RouterPageInfoNG abilityPageInfo(
471                 abilityContext, pageInfo.index, pageInfo.name, pageInfo.path, pageInfo.state, pageInfo.pageId);
472             auto holder = abilityContextRouterPageListeners_[ref];
473             for (const auto& listener : holder) {
474                 listener->OnRouterPageStateChange(abilityPageInfo);
475             }
476             break;
477         }
478     }
479 
480     auto currentId = Container::CurrentId();
481     auto iter = specifiedRouterPageListeners_.find(currentId);
482     if (iter == specifiedRouterPageListeners_.end()) {
483         return;
484     }
485     auto holder = iter->second;
486     for (const auto& listener : holder) {
487         listener->OnRouterPageStateChange(pageInfo);
488     }
489 }
490 
491 // UIObserver.on(type: "densityUpdate", uiContext | null, callback)
492 // register a listener on current page
RegisterDensityCallback(int32_t uiContextInstanceId,const std::shared_ptr<UIObserverListener> & listener)493 void UIObserver::RegisterDensityCallback(
494     int32_t uiContextInstanceId, const std::shared_ptr<UIObserverListener>& listener)
495 {
496     if (uiContextInstanceId == 0) {
497         uiContextInstanceId = Container::CurrentId();
498     }
499     auto iter = specifiedDensityListeners_.find(uiContextInstanceId);
500     if (iter == specifiedDensityListeners_.end()) {
501         specifiedDensityListeners_.emplace(
502             uiContextInstanceId, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
503         return;
504     }
505     auto& holder = iter->second;
506     if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
507         return;
508     }
509     holder.emplace_back(listener);
510 }
511 
512 // UIObserver.off(type: "densityUpdate", uiContext | null, callback)
UnRegisterDensityCallback(int32_t uiContextInstanceId,napi_value callback)513 void UIObserver::UnRegisterDensityCallback(int32_t uiContextInstanceId, napi_value callback)
514 {
515     if (uiContextInstanceId == 0) {
516         uiContextInstanceId = Container::CurrentId();
517     }
518     auto iter = specifiedDensityListeners_.find(uiContextInstanceId);
519     if (iter == specifiedDensityListeners_.end()) {
520         return;
521     }
522     auto& holder = iter->second;
523     if (callback == nullptr) {
524         holder.clear();
525         return;
526     }
527     holder.erase(
528         std::remove_if(
529             holder.begin(),
530             holder.end(),
531             [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
532                 return registeredListener->NapiEqual(callback);
533             }),
534         holder.end());
535 }
536 
HandleDensityChange(NG::AbilityContextInfo & info,double density)537 void UIObserver::HandleDensityChange(NG::AbilityContextInfo& info, double density)
538 {
539     auto currentId = Container::CurrentId();
540     auto iter = specifiedDensityListeners_.find(currentId);
541     if (iter == specifiedDensityListeners_.end()) {
542         return;
543     }
544     auto& holder = iter->second;
545     for (const auto& listener : holder) {
546         listener->OnDensityChange(density);
547     }
548 }
549 
HandDrawCommandSendChange()550 void UIObserver::HandDrawCommandSendChange()
551 {
552     auto currentId = Container::CurrentId();
553     if (specifiedDrawListeners_.find(currentId) == specifiedDrawListeners_.end()) {
554         return;
555     }
556     auto& holder = specifiedDrawListeners_[currentId];
557     for (const auto& listener : holder) {
558         listener->OnDrawOrLayout();
559     }
560 }
561 
HandLayoutDoneChange()562 void UIObserver::HandLayoutDoneChange()
563 {
564     auto currentId = Container::CurrentId();
565     if (specifiedLayoutListeners_.find(currentId) == specifiedLayoutListeners_.end()) {
566         return;
567     }
568     auto& holder = specifiedLayoutListeners_[currentId];
569     for (const auto& listener : holder) {
570         listener->OnDrawOrLayout();
571     }
572 }
573 
574 /**
575  * observer.on('navDestinationSwitch', context: UIAbilityContext, callback)
576  * observer.on('navDestinationSwitch', context: UIAbilityContext, { navigationId: navId }, callback)
577  */
RegisterNavDestinationSwitchCallback(napi_env env,napi_value uiAbilityContext,const std::optional<std::string> & navigationId,const std::shared_ptr<UIObserverListener> & listener)578 void UIObserver::RegisterNavDestinationSwitchCallback(napi_env env, napi_value uiAbilityContext,
579     const std::optional<std::string>& navigationId, const std::shared_ptr<UIObserverListener>& listener)
580 {
581     NG::AbilityContextInfo info;
582     GetAbilityInfos(env, uiAbilityContext, info);
583     for (auto& listenerPair : abilityUIContextNavDesSwitchListeners_) {
584         auto ref = listenerPair.first;
585         auto localInfo = infosForNavDesSwitch_[ref];
586         if (!info.IsEqual(localInfo)) {
587             continue;
588         }
589 
590         auto& listenersMap = listenerPair.second;
591         auto it = listenersMap.find(navigationId);
592         if (it == listenersMap.end()) {
593             listenersMap[navigationId] = std::list<std::shared_ptr<UIObserverListener>>({listener});
594             return;
595         }
596         if (std::find(it->second.begin(), it->second.end(), listener) == it->second.end()) {
597             it->second.emplace_back(listener);
598         }
599         return;
600     }
601     napi_ref newRef = nullptr;
602     napi_create_reference(env, uiAbilityContext, 1, &newRef);
603     NavIdAndListenersMap listenersMap;
604     listenersMap.emplace(navigationId, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
605     abilityUIContextNavDesSwitchListeners_[newRef] = listenersMap;
606     infosForNavDesSwitch_[newRef] = info;
607 }
608 
609 /**
610  * UIObserver.on('navDestinationSwitch', { navigationId: navId }, callback)
611  * UIObserver.on('navDestinationSwitch', callback)
612  * observer.on('navDestinationSwitch', context: UIContext, { navigationId?: navId }, callback)
613  */
RegisterNavDestinationSwitchCallback(int32_t uiContextInstanceId,const std::optional<std::string> & navigationId,const std::shared_ptr<UIObserverListener> & listener)614 void UIObserver::RegisterNavDestinationSwitchCallback(int32_t uiContextInstanceId,
615     const std::optional<std::string>& navigationId, const std::shared_ptr<UIObserverListener>& listener)
616 {
617     if (uiContextInstanceId == 0) {
618         uiContextInstanceId = Container::CurrentId();
619     }
620     auto listenersMapIter = uiContextNavDesSwitchListeners_.find(uiContextInstanceId);
621     if (listenersMapIter == uiContextNavDesSwitchListeners_.end()) {
622         NavIdAndListenersMap listenersMap;
623         listenersMap.emplace(navigationId, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
624         uiContextNavDesSwitchListeners_[uiContextInstanceId] = listenersMap;
625         return;
626     }
627 
628     auto& listenersMap = listenersMapIter->second;
629     auto it = listenersMap.find(navigationId);
630     if (it == listenersMap.end()) {
631         listenersMap[navigationId] = std::list<std::shared_ptr<UIObserverListener>>({listener});
632         return;
633     }
634 
635     if (std::find(it->second.begin(), it->second.end(), listener) == it->second.end()) {
636         it->second.emplace_back(listener);
637     }
638 }
639 
640 /**
641  * observer.off('navDestinationSwitch', context: AbilityUIContext})
642  * observer.off('navDestinationSwitch', context: AbilityUIContext, callback })
643  * observer.off('navDestinationSwitch', context: AbilityUIContext, { navigationId: navId } })
644  * observer.off('navDestinationSwitch', context: AbilityUIContext, { navigationId: navId }, callback })
645  */
UnRegisterNavDestinationSwitchCallback(napi_env env,napi_value uiAbilityContext,const std::optional<std::string> & navigationId,napi_value callback)646 void UIObserver::UnRegisterNavDestinationSwitchCallback(napi_env env, napi_value uiAbilityContext,
647     const std::optional<std::string>& navigationId, napi_value callback)
648 {
649     NG::AbilityContextInfo info;
650     GetAbilityInfos(env, uiAbilityContext, info);
651     for (auto listenerPair : abilityUIContextNavDesSwitchListeners_) {
652         auto ref = listenerPair.first;
653         auto localInfo = infosForNavDesSwitch_[ref];
654         if (!info.IsEqual(localInfo)) {
655             continue;
656         }
657 
658         auto& listenersMap = listenerPair.second;
659         auto it = listenersMap.find(navigationId);
660         if (it == listenersMap.end()) {
661             return;
662         }
663         auto& listeners = it->second;
664         if (callback == nullptr) {
665             listeners.clear();
666         } else {
667             listeners.erase(std::remove_if(listeners.begin(), listeners.end(),
668                 [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
669                     return registeredListener->NapiEqual(callback);
670                 }), listeners.end());
671         }
672         if (listeners.empty()) {
673             listenersMap.erase(it);
674         }
675         if (listenersMap.empty()) {
676             infosForNavDesSwitch_.erase(ref);
677             abilityUIContextNavDesSwitchListeners_.erase(ref);
678             napi_delete_reference(env, ref);
679         }
680         return;
681     }
682 }
683 
684 /**
685  * observer.off('navDestinationSwitch', context: UIContext})
686  * observer.off('navDestinationSwitch', context: UIContext, callback })
687  * observer.off('navDestinationSwitch', context: UIContext, { navigationId: navId })
688  * observer.off('navDestinationSwitch', context: UIContext, { navigationId: navId }, callback )
689  * UIObserver.off('navDestinationSwitch')
690  * UIObserver.off('navDestinationSwitch', callback)
691  * UIObserver.off('navDestinationSwitch', { navigationId: navId })
692  * UIObserver.off('navDestinationSwitch', { navigationId: navId }, callback )
693  */
UnRegisterNavDestinationSwitchCallback(int32_t uiContextInstanceId,const std::optional<std::string> & navigationId,napi_value callback)694 void UIObserver::UnRegisterNavDestinationSwitchCallback(int32_t uiContextInstanceId,
695     const std::optional<std::string>& navigationId, napi_value callback)
696 {
697     if (uiContextInstanceId == 0) {
698         uiContextInstanceId = Container::CurrentId();
699     }
700     auto listenersMapIter = uiContextNavDesSwitchListeners_.find(uiContextInstanceId);
701     if (listenersMapIter == uiContextNavDesSwitchListeners_.end()) {
702         return;
703     }
704     auto& listenersMap = listenersMapIter->second;
705     auto it = listenersMap.find(navigationId);
706     if (it == listenersMap.end()) {
707         return;
708     }
709     auto& listeners = it->second;
710     if (callback == nullptr) {
711         listeners.clear();
712     } else {
713         listeners.erase(std::remove_if(listeners.begin(), listeners.end(),
714             [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
715                 return registeredListener->NapiEqual(callback);
716             }), listeners.end());
717     }
718     if (listeners.empty()) {
719         listenersMap.erase(it);
720     }
721     if (listenersMap.empty()) {
722         uiContextNavDesSwitchListeners_.erase(listenersMapIter);
723     }
724 }
725 
HandleNavDestinationSwitch(const NG::AbilityContextInfo & info,NG::NavDestinationSwitchInfo & switchInfo)726 void UIObserver::HandleNavDestinationSwitch(
727     const NG::AbilityContextInfo& info, NG::NavDestinationSwitchInfo& switchInfo)
728 {
729     HandleAbilityUIContextNavDestinationSwitch(info, switchInfo);
730     HandleUIContextNavDestinationSwitch(switchInfo);
731 }
732 
HandleAbilityUIContextNavDestinationSwitch(const NG::AbilityContextInfo & info,NG::NavDestinationSwitchInfo & switchInfo)733 void UIObserver::HandleAbilityUIContextNavDestinationSwitch(
734     const NG::AbilityContextInfo& info, NG::NavDestinationSwitchInfo& switchInfo)
735 {
736     napi_value uiContextBackup = switchInfo.context;
737     for (auto listenerPair : abilityUIContextNavDesSwitchListeners_) {
738         auto ref = listenerPair.first;
739         auto localInfo = infosForNavDesSwitch_[ref];
740         if (!info.IsEqual(localInfo)) {
741             continue;
742         }
743 
744         auto env = GetCurrentNapiEnv();
745         napi_value abilityContext = nullptr;
746         napi_get_reference_value(env, ref, &abilityContext);
747 
748         switchInfo.context = abilityContext;
749         auto listenersMap = listenerPair.second;
750         HandleListenersWithEmptyNavigationId(listenersMap, switchInfo);
751         HandleListenersWithSpecifiedNavigationId(listenersMap, switchInfo);
752         break;
753     }
754     switchInfo.context = uiContextBackup;
755 }
756 
HandleUIContextNavDestinationSwitch(const NG::NavDestinationSwitchInfo & switchInfo)757 void UIObserver::HandleUIContextNavDestinationSwitch(const NG::NavDestinationSwitchInfo& switchInfo)
758 {
759     auto currentId = Container::CurrentId();
760     auto listenersMapIter = uiContextNavDesSwitchListeners_.find(currentId);
761     if (listenersMapIter == uiContextNavDesSwitchListeners_.end()) {
762         return;
763     }
764     auto listenersMap = listenersMapIter->second;
765     HandleListenersWithEmptyNavigationId(listenersMap, switchInfo);
766     HandleListenersWithSpecifiedNavigationId(listenersMap, switchInfo);
767 }
768 
HandleListenersWithEmptyNavigationId(const NavIdAndListenersMap & listenersMap,const NG::NavDestinationSwitchInfo & switchInfo)769 void UIObserver::HandleListenersWithEmptyNavigationId(
770     const NavIdAndListenersMap& listenersMap, const NG::NavDestinationSwitchInfo& switchInfo)
771 {
772     std::optional<std::string> navId;
773     auto it = listenersMap.find(navId);
774     if (it != listenersMap.end()) {
775         const auto listeners = it->second;
776         for (const auto& listener : listeners) {
777             listener->OnNavDestinationSwitch(switchInfo);
778         }
779     }
780 }
781 
HandleListenersWithSpecifiedNavigationId(const NavIdAndListenersMap & listenersMap,const NG::NavDestinationSwitchInfo & switchInfo)782 void UIObserver::HandleListenersWithSpecifiedNavigationId(
783     const NavIdAndListenersMap& listenersMap, const NG::NavDestinationSwitchInfo& switchInfo)
784 {
785     std::string navigationId;
786     if (switchInfo.from.has_value()) {
787         navigationId = switchInfo.from.value().navigationId;
788     } else if (switchInfo.to.has_value()) {
789         navigationId = switchInfo.to.value().navigationId;
790     }
791     if (!navigationId.empty()) {
792         std::optional<std::string> navId{navigationId};
793         auto it = listenersMap.find(navId);
794         if (it != listenersMap.end()) {
795             const auto listeners = it->second;
796             for (const auto& listener : listeners) {
797                 listener->OnNavDestinationSwitch(switchInfo);
798             }
799         }
800     }
801 }
802 
RegisterWillClickCallback(napi_env env,napi_value uiAbilityContext,const std::shared_ptr<UIObserverListener> & listener)803 void UIObserver::RegisterWillClickCallback(
804     napi_env env, napi_value uiAbilityContext, const std::shared_ptr<UIObserverListener>& listener)
805 {
806     napi_handle_scope scope = nullptr;
807     auto status = napi_open_handle_scope(env, &scope);
808     if (status != napi_ok) {
809         return;
810     }
811     NG::AbilityContextInfo info;
812     GetAbilityInfos(env, uiAbilityContext, info);
813     for (auto listenerPair : abilityContextWillClickListeners_) {
814         auto ref = listenerPair.first;
815         auto localInfo = willClickInfos_[ref];
816         if (info.IsEqual(localInfo)) {
817             auto& holder = abilityContextWillClickListeners_[ref];
818             if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
819                 napi_close_handle_scope(env, scope);
820                 return;
821             }
822             holder.emplace_back(listener);
823             napi_close_handle_scope(env, scope);
824             return;
825         }
826     }
827     napi_ref newRef = nullptr;
828     napi_create_reference(env, uiAbilityContext, 1, &newRef);
829     abilityContextWillClickListeners_[newRef] = std::list<std::shared_ptr<UIObserverListener>>({ listener });
830     willClickInfos_[newRef] = info;
831     napi_close_handle_scope(env, scope);
832 }
833 
RegisterWillClickCallback(int32_t uiContextInstanceId,const std::shared_ptr<UIObserverListener> & listener)834 void UIObserver::RegisterWillClickCallback(
835     int32_t uiContextInstanceId, const std::shared_ptr<UIObserverListener>& listener)
836 {
837     if (uiContextInstanceId == 0) {
838         uiContextInstanceId = Container::CurrentId();
839     }
840     auto iter = specifiedWillClickListeners_.find(uiContextInstanceId);
841     if (iter == specifiedWillClickListeners_.end()) {
842         specifiedWillClickListeners_.emplace(
843             uiContextInstanceId, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
844         return;
845     }
846     auto& holder = iter->second;
847     if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
848         return;
849     }
850     holder.emplace_back(listener);
851 }
852 
UnRegisterWillClickCallback(napi_env env,napi_value uiAbilityContext,napi_value callback)853 void UIObserver::UnRegisterWillClickCallback(napi_env env, napi_value uiAbilityContext, napi_value callback)
854 {
855     napi_handle_scope scope = nullptr;
856     auto status = napi_open_handle_scope(env, &scope);
857     if (status != napi_ok) {
858         return;
859     }
860     NG::AbilityContextInfo info;
861     GetAbilityInfos(env, uiAbilityContext, info);
862     for (auto listenerPair : abilityContextWillClickListeners_) {
863         auto ref = listenerPair.first;
864         auto localInfo = willClickInfos_[ref];
865         if (!info.IsEqual(localInfo)) {
866             continue;
867         }
868         auto& holder = abilityContextWillClickListeners_[listenerPair.first];
869         if (callback == nullptr) {
870             holder.clear();
871         } else {
872             holder.erase(
873                 std::remove_if(
874                     holder.begin(),
875                     holder.end(),
876                     [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
877                         return registeredListener->NapiEqual(callback);
878                     }),
879                 holder.end());
880         }
881         if (holder.empty()) {
882             willClickInfos_.erase(ref);
883             abilityContextWillClickListeners_.erase(ref);
884             napi_delete_reference(env, ref);
885         }
886     }
887     napi_close_handle_scope(env, scope);
888 }
889 
UnRegisterWillClickCallback(int32_t uiContextInstanceId,napi_value callback)890 void UIObserver::UnRegisterWillClickCallback(int32_t uiContextInstanceId, napi_value callback)
891 {
892     if (uiContextInstanceId == 0) {
893         uiContextInstanceId = Container::CurrentId();
894     }
895     auto iter = specifiedWillClickListeners_.find(uiContextInstanceId);
896     if (iter == specifiedWillClickListeners_.end()) {
897         return;
898     }
899     auto& holder = iter->second;
900     if (callback == nullptr) {
901         holder.clear();
902         return;
903     }
904     holder.erase(
905         std::remove_if(
906             holder.begin(),
907             holder.end(),
908             [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
909                 return registeredListener->NapiEqual(callback);
910             }),
911         holder.end());
912 }
913 
HandleWillClick(NG::AbilityContextInfo & info,const GestureEvent & gestureEventInfo,const ClickInfo & clickInfo,const RefPtr<NG::FrameNode> & frameNode)914 void UIObserver::HandleWillClick(NG::AbilityContextInfo& info, const GestureEvent& gestureEventInfo,
915     const ClickInfo& clickInfo, const RefPtr<NG::FrameNode>& frameNode)
916 {
917     auto env = GetCurrentNapiEnv();
918     napi_handle_scope scope = nullptr;
919     auto status = napi_open_handle_scope(env, &scope);
920     if (status != napi_ok) {
921         return;
922     }
923     for (auto listenerPair : abilityContextWillClickListeners_) {
924         auto ref = listenerPair.first;
925         auto localInfo = willClickInfos_[ref];
926         if (info.IsEqual(localInfo)) {
927             napi_value abilityContext = nullptr;
928             napi_get_reference_value(env, ref, &abilityContext);
929 
930             auto& holder = abilityContextWillClickListeners_[ref];
931             for (const auto& listener : holder) {
932                 listener->OnWillClick(gestureEventInfo, clickInfo, frameNode);
933             }
934             break;
935         }
936     }
937 
938     auto currentId = Container::CurrentId();
939     auto iter = specifiedWillClickListeners_.find(currentId);
940     if (iter == specifiedWillClickListeners_.end()) {
941         napi_close_handle_scope(env, scope);
942         return;
943     }
944     auto& holder = iter->second;
945     for (const auto& listener : holder) {
946         listener->OnWillClick(gestureEventInfo, clickInfo, frameNode);
947     }
948     napi_close_handle_scope(env, scope);
949 }
950 
RegisterDidClickCallback(napi_env env,napi_value uiAbilityContext,const std::shared_ptr<UIObserverListener> & listener)951 void UIObserver::RegisterDidClickCallback(
952     napi_env env, napi_value uiAbilityContext, const std::shared_ptr<UIObserverListener>& listener)
953 {
954     napi_handle_scope scope = nullptr;
955     auto status = napi_open_handle_scope(env, &scope);
956     if (status != napi_ok) {
957         return;
958     }
959     NG::AbilityContextInfo info;
960     GetAbilityInfos(env, uiAbilityContext, info);
961     for (auto listenerPair : abilityContextDidClickListeners_) {
962         auto ref = listenerPair.first;
963         auto localInfo = didClickInfos_[ref];
964         if (info.IsEqual(localInfo)) {
965             auto& holder = abilityContextDidClickListeners_[ref];
966             if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
967                 napi_close_handle_scope(env, scope);
968                 return;
969             }
970             holder.emplace_back(listener);
971             napi_close_handle_scope(env, scope);
972             return;
973         }
974     }
975     napi_ref newRef = nullptr;
976     napi_create_reference(env, uiAbilityContext, 1, &newRef);
977     abilityContextDidClickListeners_[newRef] = std::list<std::shared_ptr<UIObserverListener>>({ listener });
978     didClickInfos_[newRef] = info;
979     napi_close_handle_scope(env, scope);
980 }
981 
RegisterDidClickCallback(int32_t uiContextInstanceId,const std::shared_ptr<UIObserverListener> & listener)982 void UIObserver::RegisterDidClickCallback(
983     int32_t uiContextInstanceId, const std::shared_ptr<UIObserverListener>& listener)
984 {
985     if (uiContextInstanceId == 0) {
986         uiContextInstanceId = Container::CurrentId();
987     }
988     auto iter = specifiedDidClickListeners_.find(uiContextInstanceId);
989     if (iter == specifiedDidClickListeners_.end()) {
990         specifiedDidClickListeners_.emplace(
991             uiContextInstanceId, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
992         return;
993     }
994     auto& holder = iter->second;
995     if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
996         return;
997     }
998     holder.emplace_back(listener);
999 }
1000 
UnRegisterDidClickCallback(napi_env env,napi_value uiAbilityContext,napi_value callback)1001 void UIObserver::UnRegisterDidClickCallback(napi_env env, napi_value uiAbilityContext, napi_value callback)
1002 {
1003     napi_handle_scope scope = nullptr;
1004     auto status = napi_open_handle_scope(env, &scope);
1005     if (status != napi_ok) {
1006         return;
1007     }
1008     NG::AbilityContextInfo info;
1009     GetAbilityInfos(env, uiAbilityContext, info);
1010     for (auto listenerPair : abilityContextDidClickListeners_) {
1011         auto ref = listenerPair.first;
1012         auto localInfo = didClickInfos_[ref];
1013         if (!info.IsEqual(localInfo)) {
1014             continue;
1015         }
1016         auto& holder = abilityContextDidClickListeners_[listenerPair.first];
1017         if (callback == nullptr) {
1018             holder.clear();
1019         } else {
1020             holder.erase(
1021                 std::remove_if(
1022                     holder.begin(),
1023                     holder.end(),
1024                     [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
1025                         return registeredListener->NapiEqual(callback);
1026                     }),
1027                 holder.end());
1028         }
1029         if (holder.empty()) {
1030             didClickInfos_.erase(ref);
1031             abilityContextDidClickListeners_.erase(ref);
1032             napi_delete_reference(env, ref);
1033         }
1034     }
1035     napi_close_handle_scope(env, scope);
1036 }
1037 
UnRegisterDidClickCallback(int32_t uiContextInstanceId,napi_value callback)1038 void UIObserver::UnRegisterDidClickCallback(int32_t uiContextInstanceId, napi_value callback)
1039 {
1040     if (uiContextInstanceId == 0) {
1041         uiContextInstanceId = Container::CurrentId();
1042     }
1043     auto iter = specifiedDidClickListeners_.find(uiContextInstanceId);
1044     if (iter == specifiedDidClickListeners_.end()) {
1045         return;
1046     }
1047     auto& holder = iter->second;
1048     if (callback == nullptr) {
1049         holder.clear();
1050         return;
1051     }
1052     holder.erase(
1053         std::remove_if(
1054             holder.begin(),
1055             holder.end(),
1056             [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
1057                 return registeredListener->NapiEqual(callback);
1058             }),
1059         holder.end());
1060 }
1061 
HandleDidClick(NG::AbilityContextInfo & info,const GestureEvent & gestureEventInfo,const ClickInfo & clickInfo,const RefPtr<NG::FrameNode> & frameNode)1062 void UIObserver::HandleDidClick(NG::AbilityContextInfo& info, const GestureEvent& gestureEventInfo,
1063     const ClickInfo& clickInfo, const RefPtr<NG::FrameNode>& frameNode)
1064 {
1065     auto env = GetCurrentNapiEnv();
1066     napi_handle_scope scope = nullptr;
1067     auto status = napi_open_handle_scope(env, &scope);
1068     if (status != napi_ok) {
1069         return;
1070     }
1071     for (auto listenerPair : abilityContextDidClickListeners_) {
1072         auto ref = listenerPair.first;
1073         auto localInfo = didClickInfos_[ref];
1074         if (info.IsEqual(localInfo)) {
1075             napi_value abilityContext = nullptr;
1076             napi_get_reference_value(env, ref, &abilityContext);
1077 
1078             auto& holder = abilityContextDidClickListeners_[ref];
1079             for (const auto& listener : holder) {
1080                 listener->OnDidClick(gestureEventInfo, clickInfo, frameNode);
1081             }
1082             break;
1083         }
1084     }
1085 
1086     auto currentId = Container::CurrentId();
1087     auto iter = specifiedDidClickListeners_.find(currentId);
1088     if (iter == specifiedDidClickListeners_.end()) {
1089         napi_close_handle_scope(env, scope);
1090         return;
1091     }
1092     auto& holder = iter->second;
1093     for (const auto& listener : holder) {
1094         listener->OnDidClick(gestureEventInfo, clickInfo, frameNode);
1095     }
1096     napi_close_handle_scope(env, scope);
1097 }
1098 
RegisterBeforePanStartCallback(napi_env env,napi_value uiAbilityContext,const std::shared_ptr<UIObserverListener> & listener)1099 void UIObserver::RegisterBeforePanStartCallback(
1100     napi_env env, napi_value uiAbilityContext, const std::shared_ptr<UIObserverListener>& listener)
1101 {
1102     napi_handle_scope scope = nullptr;
1103     auto status = napi_open_handle_scope(env, &scope);
1104     if (status != napi_ok) {
1105         return;
1106     }
1107     NG::AbilityContextInfo info;
1108     GetAbilityInfos(env, uiAbilityContext, info);
1109     for (auto listenerPair : abilityContextBeforePanStartListeners_) {
1110         auto ref = listenerPair.first;
1111         auto localInfo = beforePanStartInfos_[ref];
1112         if (info.IsEqual(localInfo)) {
1113             auto& holder = listenerPair.second;
1114             if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
1115                 napi_close_handle_scope(env, scope);
1116                 return;
1117             }
1118             holder.emplace_back(listener);
1119             napi_close_handle_scope(env, scope);
1120             return;
1121         }
1122     }
1123     napi_ref newRef = nullptr;
1124     napi_create_reference(env, uiAbilityContext, 1, &newRef);
1125     abilityContextBeforePanStartListeners_[newRef] = std::list<std::shared_ptr<UIObserverListener>>({ listener });
1126     beforePanStartInfos_[newRef] = info;
1127     napi_close_handle_scope(env, scope);
1128 }
1129 
RegisterBeforePanStartCallback(int32_t uiContextInstanceId,const std::shared_ptr<UIObserverListener> & listener)1130 void UIObserver::RegisterBeforePanStartCallback(
1131     int32_t uiContextInstanceId, const std::shared_ptr<UIObserverListener>& listener)
1132 {
1133     if (uiContextInstanceId == 0) {
1134         uiContextInstanceId = Container::CurrentId();
1135     }
1136     auto iter = specifiedBeforePanStartListeners_.find(uiContextInstanceId);
1137     if (iter == specifiedBeforePanStartListeners_.end()) {
1138         specifiedBeforePanStartListeners_.emplace(
1139             uiContextInstanceId, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
1140         return;
1141     }
1142     auto& holder = iter->second;
1143     if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
1144         return;
1145     }
1146     holder.emplace_back(listener);
1147 }
1148 
UnRegisterBeforePanStartCallback(napi_env env,napi_value uiAbilityContext,napi_value callback)1149 void UIObserver::UnRegisterBeforePanStartCallback(napi_env env, napi_value uiAbilityContext, napi_value callback)
1150 {
1151     napi_handle_scope scope = nullptr;
1152     auto status = napi_open_handle_scope(env, &scope);
1153     if (status != napi_ok) {
1154         return;
1155     }
1156     NG::AbilityContextInfo info;
1157     GetAbilityInfos(env, uiAbilityContext, info);
1158     for (auto listenerPair : abilityContextBeforePanStartListeners_) {
1159         auto ref = listenerPair.first;
1160         auto localInfo = beforePanStartInfos_[ref];
1161         if (!info.IsEqual(localInfo)) {
1162             continue;
1163         }
1164         auto& holder = listenerPair.second;
1165         if (callback == nullptr) {
1166             holder.clear();
1167         } else {
1168             holder.erase(
1169                 std::remove_if(
1170                     holder.begin(),
1171                     holder.end(),
1172                     [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
1173                         return registeredListener->NapiEqual(callback);
1174                     }),
1175                 holder.end());
1176         }
1177         if (holder.empty()) {
1178             beforePanStartInfos_.erase(ref);
1179             abilityContextBeforePanStartListeners_.erase(ref);
1180             napi_delete_reference(env, ref);
1181         }
1182     }
1183     napi_close_handle_scope(env, scope);
1184 }
1185 
UnRegisterBeforePanStartCallback(int32_t uiContextInstanceId,napi_value callback)1186 void UIObserver::UnRegisterBeforePanStartCallback(int32_t uiContextInstanceId, napi_value callback)
1187 {
1188     if (uiContextInstanceId == 0) {
1189         uiContextInstanceId = Container::CurrentId();
1190     }
1191     auto iter = specifiedBeforePanStartListeners_.find(uiContextInstanceId);
1192     if (iter == specifiedBeforePanStartListeners_.end()) {
1193         return;
1194     }
1195     auto& holder = iter->second;
1196     if (callback == nullptr) {
1197         holder.clear();
1198         return;
1199     }
1200     holder.erase(
1201         std::remove_if(
1202             holder.begin(),
1203             holder.end(),
1204             [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
1205                 return registeredListener->NapiEqual(callback);
1206             }),
1207         holder.end());
1208 }
1209 
RegisterBeforePanEndCallback(napi_env env,napi_value uiAbilityContext,const std::shared_ptr<UIObserverListener> & listener)1210 void UIObserver::RegisterBeforePanEndCallback(
1211     napi_env env, napi_value uiAbilityContext, const std::shared_ptr<UIObserverListener>& listener)
1212 {
1213     napi_handle_scope scope = nullptr;
1214     auto status = napi_open_handle_scope(env, &scope);
1215     if (status != napi_ok) {
1216         return;
1217     }
1218     NG::AbilityContextInfo info;
1219     GetAbilityInfos(env, uiAbilityContext, info);
1220     for (auto listenerPair : abilityContextBeforePanEndListeners_) {
1221         auto ref = listenerPair.first;
1222         auto localInfo = beforePanEndInfos_[ref];
1223         if (info.IsEqual(localInfo)) {
1224             auto& holder = listenerPair.second;
1225             if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
1226                 napi_close_handle_scope(env, scope);
1227                 return;
1228             }
1229             holder.emplace_back(listener);
1230             napi_close_handle_scope(env, scope);
1231             return;
1232         }
1233     }
1234     napi_ref newRef = nullptr;
1235     napi_create_reference(env, uiAbilityContext, 1, &newRef);
1236     abilityContextBeforePanEndListeners_[newRef] = std::list<std::shared_ptr<UIObserverListener>>({ listener });
1237     beforePanEndInfos_[newRef] = info;
1238     napi_close_handle_scope(env, scope);
1239 }
1240 
RegisterBeforePanEndCallback(int32_t uiContextInstanceId,const std::shared_ptr<UIObserverListener> & listener)1241 void UIObserver::RegisterBeforePanEndCallback(
1242     int32_t uiContextInstanceId, const std::shared_ptr<UIObserverListener>& listener)
1243 {
1244     if (uiContextInstanceId == 0) {
1245         uiContextInstanceId = Container::CurrentId();
1246     }
1247     auto iter = specifiedBeforePanEndListeners_.find(uiContextInstanceId);
1248     if (iter == specifiedBeforePanEndListeners_.end()) {
1249         specifiedBeforePanEndListeners_.emplace(
1250             uiContextInstanceId, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
1251         return;
1252     }
1253     auto& holder = iter->second;
1254     if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
1255         return;
1256     }
1257     holder.emplace_back(listener);
1258 }
1259 
UnRegisterBeforePanEndCallback(napi_env env,napi_value uiAbilityContext,napi_value callback)1260 void UIObserver::UnRegisterBeforePanEndCallback(napi_env env, napi_value uiAbilityContext, napi_value callback)
1261 {
1262     napi_handle_scope scope = nullptr;
1263     auto status = napi_open_handle_scope(env, &scope);
1264     if (status != napi_ok) {
1265         return;
1266     }
1267     NG::AbilityContextInfo info;
1268     GetAbilityInfos(env, uiAbilityContext, info);
1269     for (auto listenerPair : abilityContextBeforePanEndListeners_) {
1270         auto ref = listenerPair.first;
1271         auto localInfo = beforePanEndInfos_[ref];
1272         if (!info.IsEqual(localInfo)) {
1273             continue;
1274         }
1275         auto& holder = listenerPair.second;
1276         if (callback == nullptr) {
1277             holder.clear();
1278         } else {
1279             holder.erase(
1280                 std::remove_if(
1281                     holder.begin(),
1282                     holder.end(),
1283                     [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
1284                         return registeredListener->NapiEqual(callback);
1285                     }),
1286                 holder.end());
1287         }
1288         if (holder.empty()) {
1289             beforePanEndInfos_.erase(ref);
1290             abilityContextBeforePanEndListeners_.erase(ref);
1291             napi_delete_reference(env, ref);
1292         }
1293     }
1294     napi_close_handle_scope(env, scope);
1295 }
1296 
UnRegisterBeforePanEndCallback(int32_t uiContextInstanceId,napi_value callback)1297 void UIObserver::UnRegisterBeforePanEndCallback(int32_t uiContextInstanceId, napi_value callback)
1298 {
1299     if (uiContextInstanceId == 0) {
1300         uiContextInstanceId = Container::CurrentId();
1301     }
1302     auto iter = specifiedBeforePanEndListeners_.find(uiContextInstanceId);
1303     if (iter == specifiedBeforePanEndListeners_.end()) {
1304         return;
1305     }
1306     auto& holder = iter->second;
1307     if (callback == nullptr) {
1308         holder.clear();
1309         return;
1310     }
1311     holder.erase(
1312         std::remove_if(
1313             holder.begin(),
1314             holder.end(),
1315             [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
1316                 return registeredListener->NapiEqual(callback);
1317             }),
1318         holder.end());
1319 }
1320 
RegisterAfterPanStartCallback(napi_env env,napi_value uiAbilityContext,const std::shared_ptr<UIObserverListener> & listener)1321 void UIObserver::RegisterAfterPanStartCallback(
1322     napi_env env, napi_value uiAbilityContext, const std::shared_ptr<UIObserverListener>& listener)
1323 {
1324     napi_handle_scope scope = nullptr;
1325     auto status = napi_open_handle_scope(env, &scope);
1326     if (status != napi_ok) {
1327         return;
1328     }
1329     NG::AbilityContextInfo info;
1330     GetAbilityInfos(env, uiAbilityContext, info);
1331     for (auto listenerPair : abilityContextAfterPanStartListeners_) {
1332         auto ref = listenerPair.first;
1333         auto localInfo = afterPanStartInfos_[ref];
1334         if (info.IsEqual(localInfo)) {
1335             auto& holder = listenerPair.second;
1336             if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
1337                 napi_close_handle_scope(env, scope);
1338                 return;
1339             }
1340             holder.emplace_back(listener);
1341             napi_close_handle_scope(env, scope);
1342             return;
1343         }
1344     }
1345     napi_ref newRef = nullptr;
1346     napi_create_reference(env, uiAbilityContext, 1, &newRef);
1347     abilityContextAfterPanStartListeners_[newRef] = std::list<std::shared_ptr<UIObserverListener>>({ listener });
1348     afterPanStartInfos_[newRef] = info;
1349     napi_close_handle_scope(env, scope);
1350 }
1351 
RegisterAfterPanStartCallback(int32_t uiContextInstanceId,const std::shared_ptr<UIObserverListener> & listener)1352 void UIObserver::RegisterAfterPanStartCallback(
1353     int32_t uiContextInstanceId, const std::shared_ptr<UIObserverListener>& listener)
1354 {
1355     if (uiContextInstanceId == 0) {
1356         uiContextInstanceId = Container::CurrentId();
1357     }
1358     auto iter = specifiedAfterPanStartListeners_.find(uiContextInstanceId);
1359     if (iter == specifiedAfterPanStartListeners_.end()) {
1360         specifiedAfterPanStartListeners_.emplace(
1361             uiContextInstanceId, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
1362         return;
1363     }
1364     auto& holder = iter->second;
1365     if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
1366         return;
1367     }
1368     holder.emplace_back(listener);
1369 }
1370 
UnRegisterAfterPanStartCallback(napi_env env,napi_value uiAbilityContext,napi_value callback)1371 void UIObserver::UnRegisterAfterPanStartCallback(napi_env env, napi_value uiAbilityContext, napi_value callback)
1372 {
1373     napi_handle_scope scope = nullptr;
1374     auto status = napi_open_handle_scope(env, &scope);
1375     if (status != napi_ok) {
1376         return;
1377     }
1378     NG::AbilityContextInfo info;
1379     GetAbilityInfos(env, uiAbilityContext, info);
1380     for (auto listenerPair : abilityContextAfterPanStartListeners_) {
1381         auto ref = listenerPair.first;
1382         auto localInfo = afterPanStartInfos_[ref];
1383         if (!info.IsEqual(localInfo)) {
1384             continue;
1385         }
1386         auto& holder = listenerPair.second;
1387         if (callback == nullptr) {
1388             holder.clear();
1389         } else {
1390             holder.erase(
1391                 std::remove_if(
1392                     holder.begin(),
1393                     holder.end(),
1394                     [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
1395                         return registeredListener->NapiEqual(callback);
1396                     }),
1397                 holder.end());
1398         }
1399         if (holder.empty()) {
1400             afterPanStartInfos_.erase(ref);
1401             abilityContextAfterPanStartListeners_.erase(ref);
1402             napi_delete_reference(env, ref);
1403         }
1404     }
1405     napi_close_handle_scope(env, scope);
1406 }
1407 
UnRegisterAfterPanStartCallback(int32_t uiContextInstanceId,napi_value callback)1408 void UIObserver::UnRegisterAfterPanStartCallback(int32_t uiContextInstanceId, napi_value callback)
1409 {
1410     if (uiContextInstanceId == 0) {
1411         uiContextInstanceId = Container::CurrentId();
1412     }
1413     auto iter = specifiedAfterPanStartListeners_.find(uiContextInstanceId);
1414     if (iter == specifiedAfterPanStartListeners_.end()) {
1415         return;
1416     }
1417     auto& holder = iter->second;
1418     if (callback == nullptr) {
1419         holder.clear();
1420         return;
1421     }
1422     holder.erase(
1423         std::remove_if(
1424             holder.begin(),
1425             holder.end(),
1426             [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
1427                 return registeredListener->NapiEqual(callback);
1428             }),
1429         holder.end());
1430 }
1431 
RegisterAfterPanEndCallback(napi_env env,napi_value uiAbilityContext,const std::shared_ptr<UIObserverListener> & listener)1432 void UIObserver::RegisterAfterPanEndCallback(
1433     napi_env env, napi_value uiAbilityContext, const std::shared_ptr<UIObserverListener>& listener)
1434 {
1435     napi_handle_scope scope = nullptr;
1436     auto status = napi_open_handle_scope(env, &scope);
1437     if (status != napi_ok) {
1438         return;
1439     }
1440     NG::AbilityContextInfo info;
1441     GetAbilityInfos(env, uiAbilityContext, info);
1442     for (auto listenerPair : abilityContextAfterPanEndListeners_) {
1443         auto ref = listenerPair.first;
1444         auto localInfo = afterPanEndInfos_[ref];
1445         if (info.IsEqual(localInfo)) {
1446             auto& holder = listenerPair.second;
1447             if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
1448                 napi_close_handle_scope(env, scope);
1449                 return;
1450             }
1451             holder.emplace_back(listener);
1452             napi_close_handle_scope(env, scope);
1453             return;
1454         }
1455     }
1456     napi_ref newRef = nullptr;
1457     napi_create_reference(env, uiAbilityContext, 1, &newRef);
1458     abilityContextAfterPanEndListeners_[newRef] = std::list<std::shared_ptr<UIObserverListener>>({ listener });
1459     afterPanEndInfos_[newRef] = info;
1460     napi_close_handle_scope(env, scope);
1461 }
1462 
RegisterAfterPanEndCallback(int32_t uiContextInstanceId,const std::shared_ptr<UIObserverListener> & listener)1463 void UIObserver::RegisterAfterPanEndCallback(
1464     int32_t uiContextInstanceId, const std::shared_ptr<UIObserverListener>& listener)
1465 {
1466     if (uiContextInstanceId == 0) {
1467         uiContextInstanceId = Container::CurrentId();
1468     }
1469     auto iter = specifiedAfterPanEndListeners_.find(uiContextInstanceId);
1470     if (iter == specifiedAfterPanEndListeners_.end()) {
1471         specifiedAfterPanEndListeners_.emplace(
1472             uiContextInstanceId, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
1473         return;
1474     }
1475     auto& holder = iter->second;
1476     if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
1477         return;
1478     }
1479     holder.emplace_back(listener);
1480 }
1481 
UnRegisterAfterPanEndCallback(napi_env env,napi_value uiAbilityContext,napi_value callback)1482 void UIObserver::UnRegisterAfterPanEndCallback(napi_env env, napi_value uiAbilityContext, napi_value callback)
1483 {
1484     napi_handle_scope scope = nullptr;
1485     auto status = napi_open_handle_scope(env, &scope);
1486     if (status != napi_ok) {
1487         return;
1488     }
1489     NG::AbilityContextInfo info;
1490     GetAbilityInfos(env, uiAbilityContext, info);
1491     for (auto listenerPair : abilityContextAfterPanEndListeners_) {
1492         auto ref = listenerPair.first;
1493         auto localInfo = afterPanEndInfos_[ref];
1494         if (!info.IsEqual(localInfo)) {
1495             continue;
1496         }
1497         auto& holder = listenerPair.second;
1498         if (callback == nullptr) {
1499             holder.clear();
1500         } else {
1501             holder.erase(
1502                 std::remove_if(
1503                     holder.begin(),
1504                     holder.end(),
1505                     [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
1506                         return registeredListener->NapiEqual(callback);
1507                     }),
1508                 holder.end());
1509         }
1510         if (holder.empty()) {
1511             afterPanEndInfos_.erase(ref);
1512             abilityContextAfterPanEndListeners_.erase(ref);
1513             napi_delete_reference(env, ref);
1514         }
1515     }
1516     napi_close_handle_scope(env, scope);
1517 }
1518 
UnRegisterAfterPanEndCallback(int32_t uiContextInstanceId,napi_value callback)1519 void UIObserver::UnRegisterAfterPanEndCallback(int32_t uiContextInstanceId, napi_value callback)
1520 {
1521     if (uiContextInstanceId == 0) {
1522         uiContextInstanceId = Container::CurrentId();
1523     }
1524     auto iter = specifiedAfterPanEndListeners_.find(uiContextInstanceId);
1525     if (iter == specifiedAfterPanEndListeners_.end()) {
1526         return;
1527     }
1528     auto& holder = iter->second;
1529     if (callback == nullptr) {
1530         holder.clear();
1531         return;
1532     }
1533     holder.erase(
1534         std::remove_if(
1535             holder.begin(),
1536             holder.end(),
1537             [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
1538                 return registeredListener->NapiEqual(callback);
1539             }),
1540         holder.end());
1541 }
1542 
HandlePanGestureAccept(NG::AbilityContextInfo & info,const GestureEvent & gestureEventInfo,const RefPtr<NG::PanRecognizer> & current,const RefPtr<NG::FrameNode> & frameNode,const NG::PanGestureInfo & panGestureInfo)1543 void UIObserver::HandlePanGestureAccept(NG::AbilityContextInfo& info, const GestureEvent& gestureEventInfo,
1544     const RefPtr<NG::PanRecognizer>& current, const RefPtr<NG::FrameNode>& frameNode,
1545     const NG::PanGestureInfo& panGestureInfo)
1546 {
1547     auto env = GetCurrentNapiEnv();
1548     napi_handle_scope scope = nullptr;
1549     auto status = napi_open_handle_scope(env, &scope);
1550     if (status != napi_ok) {
1551         return;
1552     }
1553 
1554     auto [listeners, specifiedListeners] = GetPanGestureListeners(panGestureInfo);
1555     if (listeners.empty() && specifiedListeners.empty()) {
1556         napi_close_handle_scope(env, scope);
1557         return;
1558     }
1559     for (auto& listenerPair : listeners) {
1560         auto ref = listenerPair.first;
1561         auto localInfo = PanGestureInfos_[ref];
1562         if (info.IsEqual(localInfo)) {
1563             napi_value abilityContext = nullptr;
1564             napi_get_reference_value(env, ref, &abilityContext);
1565 
1566             auto& holder = listenerPair.second;
1567             for (const auto& listener : holder) {
1568                 listener->OnPanGestureStateChange(gestureEventInfo, current, frameNode);
1569             }
1570             break;
1571         }
1572     }
1573 
1574     auto currentId = Container::CurrentId();
1575     auto iter = specifiedListeners.find(currentId);
1576     if (iter == specifiedListeners.end()) {
1577         napi_close_handle_scope(env, scope);
1578         return;
1579     }
1580     auto& holder = iter->second;
1581     for (const auto& listener : holder) {
1582         listener->OnPanGestureStateChange(gestureEventInfo, current, frameNode);
1583     }
1584     napi_close_handle_scope(env, scope);
1585 }
1586 
GetPanGestureListeners(const NG::PanGestureInfo & panGestureInfo)1587 UIObserver::PanGestureListenersPair UIObserver::GetPanGestureListeners(const NG::PanGestureInfo& panGestureInfo)
1588 {
1589     static std::unordered_map<napi_ref, std::list<std::shared_ptr<UIObserverListener>>> emptyListeners;
1590     static std::unordered_map<int32_t, std::list<std::shared_ptr<UIObserverListener>>> emptySpecifiedListeners;
1591     if (panGestureInfo.callbackState == NG::CurrentCallbackState::START &&
1592         panGestureInfo.gestureState == NG::PanGestureState::BEFORE) {
1593         return { abilityContextBeforePanStartListeners_, specifiedBeforePanStartListeners_ };
1594     } else if (panGestureInfo.callbackState == NG::CurrentCallbackState::END &&
1595                panGestureInfo.gestureState == NG::PanGestureState::BEFORE) {
1596         return { abilityContextBeforePanEndListeners_, specifiedBeforePanEndListeners_ };
1597     } else if (panGestureInfo.callbackState == NG::CurrentCallbackState::START &&
1598                panGestureInfo.gestureState == NG::PanGestureState::AFTER) {
1599         return { abilityContextAfterPanStartListeners_, specifiedAfterPanStartListeners_ };
1600     } else if (panGestureInfo.callbackState == NG::CurrentCallbackState::END &&
1601                panGestureInfo.gestureState == NG::PanGestureState::AFTER) {
1602         return { abilityContextAfterPanEndListeners_, specifiedAfterPanEndListeners_ };
1603     } else {
1604         return { emptyListeners, emptySpecifiedListeners };
1605     }
1606 }
1607 
1608 // UIObserver.on(type: "tabContentState", callback)
1609 // register a global listener without options
RegisterTabContentStateCallback(const std::shared_ptr<UIObserverListener> & listener)1610 void UIObserver::RegisterTabContentStateCallback(const std::shared_ptr<UIObserverListener>& listener)
1611 {
1612     if (std::find(tabContentStateListeners_.begin(), tabContentStateListeners_.end(), listener) !=
1613         tabContentStateListeners_.end()) {
1614         return;
1615     }
1616     tabContentStateListeners_.emplace_back(listener);
1617 }
1618 
1619 // UIObserver.on(type: "tabContentState", options, callback)
1620 // register a listener on a specified tabContentState
RegisterTabContentStateCallback(const std::string & id,const std::shared_ptr<UIObserverListener> & listener)1621 void UIObserver::RegisterTabContentStateCallback(
1622     const std::string& id, const std::shared_ptr<UIObserverListener>& listener)
1623 {
1624     auto iter = specifiedTabContentStateListeners_.find(id);
1625     if (iter == specifiedTabContentStateListeners_.end()) {
1626         specifiedTabContentStateListeners_.emplace(id, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
1627         return;
1628     }
1629     auto& holder = iter->second;
1630     if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
1631         return;
1632     }
1633     holder.emplace_back(listener);
1634 }
1635 
1636 // UIObserver.off(type: "tabContentState", callback)
UnRegisterTabContentStateCallback(napi_value cb)1637 void UIObserver::UnRegisterTabContentStateCallback(napi_value cb)
1638 {
1639     if (cb == nullptr) {
1640         tabContentStateListeners_.clear();
1641         return;
1642     }
1643 
1644     tabContentStateListeners_.erase(
1645         std::remove_if(
1646             tabContentStateListeners_.begin(),
1647             tabContentStateListeners_.end(),
1648             [cb](const std::shared_ptr<UIObserverListener>& registeredListener) {
1649                 return registeredListener->NapiEqual(cb);
1650             }),
1651         tabContentStateListeners_.end()
1652     );
1653 }
1654 
1655 // UIObserver.off(type: "tabContentState", options, callback)
UnRegisterTabContentStateCallback(const std::string & id,napi_value cb)1656 void UIObserver::UnRegisterTabContentStateCallback(const std::string& id, napi_value cb)
1657 {
1658     auto iter = specifiedTabContentStateListeners_.find(id);
1659     if (iter == specifiedTabContentStateListeners_.end()) {
1660         return;
1661     }
1662     auto& holder = iter->second;
1663     if (cb == nullptr) {
1664         holder.clear();
1665         return;
1666     }
1667     holder.erase(
1668         std::remove_if(
1669             holder.begin(),
1670             holder.end(),
1671             [cb](const std::shared_ptr<UIObserverListener>& registeredListener) {
1672                 return registeredListener->NapiEqual(cb);
1673             }),
1674         holder.end()
1675     );
1676 }
1677 
HandleTabContentStateChange(const NG::TabContentInfo & tabContentInfo)1678 void UIObserver::HandleTabContentStateChange(const NG::TabContentInfo& tabContentInfo)
1679 {
1680     for (const auto& listener : tabContentStateListeners_) {
1681         listener->OnTabContentStateChange(tabContentInfo);
1682     }
1683 
1684     auto iter = specifiedTabContentStateListeners_.find(tabContentInfo.id);
1685     if (iter == specifiedTabContentStateListeners_.end()) {
1686         return;
1687     }
1688 
1689     auto& holder = iter->second;
1690 
1691     for (const auto& listener : holder) {
1692         listener->OnTabContentStateChange(tabContentInfo);
1693     }
1694 }
1695 
GetAbilityInfos(napi_env env,napi_value abilityContext,NG::AbilityContextInfo & info)1696 void UIObserver::GetAbilityInfos(napi_env env, napi_value abilityContext, NG::AbilityContextInfo& info)
1697 {
1698     if (!env || !abilityContext) {
1699         return;
1700     }
1701     napi_value napiInfo = nullptr;
1702     napi_get_named_property(env, abilityContext, "abilityInfo", &napiInfo);
1703     CHECK_NULL_VOID(napiInfo);
1704     napi_value name = nullptr;
1705     napi_get_named_property(env, napiInfo, "name", &name);
1706     ParseStringFromNapi(env, name, info.name);
1707     napi_get_named_property(env, napiInfo, "bundleName", &name);
1708     ParseStringFromNapi(env, name, info.bundleName);
1709     napi_get_named_property(env, napiInfo, "moduleName", &name);
1710     ParseStringFromNapi(env, name, info.moduleName);
1711 }
1712 
ParseStringFromNapi(napi_env env,napi_value val,std::string & str)1713 bool UIObserver::ParseStringFromNapi(napi_env env, napi_value val, std::string& str)
1714 {
1715     if (!val || !MatchValueType(env, val, napi_string)) {
1716         return false;
1717     }
1718     size_t len = 0;
1719     napi_get_value_string_utf8(env, val, nullptr, 0, &len);
1720     std::unique_ptr<char[]> result = std::make_unique<char[]>(len + 1);
1721     napi_get_value_string_utf8(env, val, result.get(), len + 1, &len);
1722     str = result.get();
1723     return true;
1724 }
1725 
MatchValueType(napi_env env,napi_value value,napi_valuetype targetType)1726 bool UIObserver::MatchValueType(napi_env env, napi_value value, napi_valuetype targetType)
1727 {
1728     napi_valuetype valueType = napi_undefined;
1729     napi_typeof(env, value, &valueType);
1730     return valueType == targetType;
1731 }
1732 
GetCurrentNapiEnv()1733 napi_env UIObserver::GetCurrentNapiEnv()
1734 {
1735     auto engine = EngineHelper::GetCurrentEngine();
1736     CHECK_NULL_RETURN(engine, nullptr);
1737     NativeEngine* nativeEngine = engine->GetNativeEngine();
1738     CHECK_NULL_RETURN(nativeEngine, nullptr);
1739     return reinterpret_cast<napi_env>(nativeEngine);
1740 }
1741 } // namespace OHOS::Ace::Napi
1742