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 #include <algorithm>
21
22 namespace OHOS::Ace::Napi {
23 std::list<std::shared_ptr<UIObserverListener>> UIObserver::unspecifiedNavigationListeners_;
24 std::unordered_map<std::string, std::list<std::shared_ptr<UIObserverListener>>>
25 UIObserver::specifiedCNavigationListeners_;
26
27 std::list<std::shared_ptr<UIObserverListener>> UIObserver::scrollEventListeners_;
28 std::unordered_map<std::string, std::list<std::shared_ptr<UIObserverListener>>>
29 UIObserver::specifiedScrollEventListeners_;
30
31 std::unordered_map<napi_ref, std::list<std::shared_ptr<UIObserverListener>>>
32 UIObserver::abilityContextRouterPageListeners_;
33 std::unordered_map<int32_t, std::list<std::shared_ptr<UIObserverListener>>>
34 UIObserver::specifiedRouterPageListeners_;
35 std::unordered_map<napi_ref, NG::AbilityContextInfo> UIObserver::infosForRouterPage_;
36
37 std::unordered_map<int32_t, std::list<std::shared_ptr<UIObserverListener>>>
38 UIObserver::specifiedDensityListeners_;
39 std::unordered_map<int32_t, std::list<std::shared_ptr<UIObserverListener>>> UIObserver::specifiedDrawListeners_;
40 std::unordered_map<int32_t, std::list<std::shared_ptr<UIObserverListener>>> UIObserver::specifiedLayoutListeners_;
41
42 std::unordered_map<napi_ref, UIObserver::NavIdAndListenersMap> UIObserver::abilityUIContextNavDesSwitchListeners_;
43 std::unordered_map<int32_t, UIObserver::NavIdAndListenersMap> UIObserver::uiContextNavDesSwitchListeners_;
44 std::unordered_map<napi_ref, NG::AbilityContextInfo> UIObserver::infosForNavDesSwitch_;
45
46 std::unordered_map<napi_ref, std::list<std::shared_ptr<UIObserverListener>>>
47 UIObserver::abilityContextWillClickListeners_;
48 std::unordered_map<int32_t, std::list<std::shared_ptr<UIObserverListener>>>
49 UIObserver::specifiedWillClickListeners_;
50 std::unordered_map<napi_ref, NG::AbilityContextInfo> UIObserver::willClickInfos_;
51
52 std::unordered_map<napi_ref, std::list<std::shared_ptr<UIObserverListener>>>
53 UIObserver::abilityContextDidClickListeners_;
54 std::unordered_map<int32_t, std::list<std::shared_ptr<UIObserverListener>>>
55 UIObserver::specifiedDidClickListeners_;
56 std::unordered_map<napi_ref, NG::AbilityContextInfo> UIObserver::didClickInfos_;
57
58 std::list<std::shared_ptr<UIObserverListener>> UIObserver::tabContentStateListeners_;
59 std::unordered_map<std::string, std::list<std::shared_ptr<UIObserverListener>>>
60 UIObserver::specifiedTabContentStateListeners_;
61
62 // UIObserver.on(type: "navDestinationUpdate", callback)
63 // register a global listener without options
RegisterNavigationCallback(const std::shared_ptr<UIObserverListener> & listener)64 void UIObserver::RegisterNavigationCallback(const std::shared_ptr<UIObserverListener>& listener)
65 {
66 if (std::find(unspecifiedNavigationListeners_.begin(), unspecifiedNavigationListeners_.end(), listener) !=
67 unspecifiedNavigationListeners_.end()) {
68 return;
69 }
70 unspecifiedNavigationListeners_.emplace_back(listener);
71 }
72
73 // UIObserver.on(type: "navDestinationUpdate", options, callback)
74 // register a listener on a specified Navigation
RegisterNavigationCallback(std::string navigationId,const std::shared_ptr<UIObserverListener> & listener)75 void UIObserver::RegisterNavigationCallback(
76 std::string navigationId, const std::shared_ptr<UIObserverListener>& listener)
77 {
78 auto iter = specifiedCNavigationListeners_.find(navigationId);
79 if (iter == specifiedCNavigationListeners_.end()) {
80 specifiedCNavigationListeners_.emplace(
81 navigationId, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
82 return;
83 }
84 auto& holder = iter->second;
85 if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
86 return;
87 }
88 holder.emplace_back(listener);
89 }
90
91 // UIObserver.off(type: "navDestinationUpdate", callback)
UnRegisterNavigationCallback(napi_value cb)92 void UIObserver::UnRegisterNavigationCallback(napi_value cb)
93 {
94 if (cb == nullptr) {
95 unspecifiedNavigationListeners_.clear();
96 return;
97 }
98
99 unspecifiedNavigationListeners_.erase(
100 std::remove_if(
101 unspecifiedNavigationListeners_.begin(),
102 unspecifiedNavigationListeners_.end(),
103 [cb](const std::shared_ptr<UIObserverListener>& registeredListener) {
104 return registeredListener->NapiEqual(cb);
105 }
106 ),
107 unspecifiedNavigationListeners_.end()
108 );
109 }
110
111 // UIObserver.off(type: "navDestinationUpdate", options, callback)
UnRegisterNavigationCallback(std::string navigationId,napi_value cb)112 void UIObserver::UnRegisterNavigationCallback(std::string navigationId, napi_value cb)
113 {
114 auto iter = specifiedCNavigationListeners_.find(navigationId);
115 if (iter == specifiedCNavigationListeners_.end()) {
116 return;
117 }
118 auto& holder = iter->second;
119 if (cb == nullptr) {
120 holder.clear();
121 return;
122 }
123 holder.erase(
124 std::remove_if(
125 holder.begin(),
126 holder.end(),
127 [cb](const std::shared_ptr<UIObserverListener>& registeredListener) {
128 return registeredListener->NapiEqual(cb);
129 }
130 ),
131 holder.end()
132 );
133 }
134
HandleNavigationStateChange(const NG::NavDestinationInfo & info)135 void UIObserver::HandleNavigationStateChange(const NG::NavDestinationInfo& info)
136 {
137 auto unspecifiedHolder = unspecifiedNavigationListeners_;
138 for (const auto& listener : unspecifiedHolder) {
139 listener->OnNavigationStateChange(info);
140 }
141 auto iter = specifiedCNavigationListeners_.find(info.navigationId);
142 if (iter == specifiedCNavigationListeners_.end()) {
143 return;
144 }
145
146 auto holder = iter->second;
147
148 for (const auto& listener : holder) {
149 listener->OnNavigationStateChange(info);
150 }
151 }
152
153 // UIObserver.on(type: "scrollEvent", callback)
154 // register a global listener without options
RegisterScrollEventCallback(const std::shared_ptr<UIObserverListener> & listener)155 void UIObserver::RegisterScrollEventCallback(const std::shared_ptr<UIObserverListener>& listener)
156 {
157 if (std::find(scrollEventListeners_.begin(), scrollEventListeners_.end(), listener) !=
158 scrollEventListeners_.end()) {
159 return;
160 }
161 scrollEventListeners_.emplace_back(listener);
162 }
163
164 // UIObserver.on(type: "scrollEvent", options, callback)
165 // register a listener on a specified scrollEvent
RegisterScrollEventCallback(const std::string & id,const std::shared_ptr<UIObserverListener> & listener)166 void UIObserver::RegisterScrollEventCallback(
167 const std::string& id, const std::shared_ptr<UIObserverListener>& listener)
168 {
169 if (specifiedScrollEventListeners_.find(id) == specifiedScrollEventListeners_.end()) {
170 specifiedScrollEventListeners_[id] = std::list<std::shared_ptr<UIObserverListener>>({ listener });
171 return;
172 }
173 auto& holder = specifiedScrollEventListeners_[id];
174 if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
175 return;
176 }
177 holder.emplace_back(listener);
178 }
179
180 // UIObserver.off(type: "scrollEvent", callback)
UnRegisterScrollEventCallback(napi_value cb)181 void UIObserver::UnRegisterScrollEventCallback(napi_value cb)
182 {
183 if (cb == nullptr) {
184 scrollEventListeners_.clear();
185 return;
186 }
187
188 scrollEventListeners_.erase(
189 std::remove_if(
190 scrollEventListeners_.begin(),
191 scrollEventListeners_.end(),
192 [cb](const std::shared_ptr<UIObserverListener>& registeredListener) {
193 return registeredListener->NapiEqual(cb);
194 }),
195 scrollEventListeners_.end()
196 );
197 }
198
199 // UIObserver.off(type: "scrollEvent", options, callback)
UnRegisterScrollEventCallback(const std::string & id,napi_value cb)200 void UIObserver::UnRegisterScrollEventCallback(const std::string& id, napi_value cb)
201 {
202 auto iter = specifiedScrollEventListeners_.find(id);
203 if (iter == specifiedScrollEventListeners_.end()) {
204 return;
205 }
206 auto& holder = iter->second;
207 if (cb == nullptr) {
208 holder.clear();
209 return;
210 }
211 holder.erase(
212 std::remove_if(
213 holder.begin(),
214 holder.end(),
215 [cb](const std::shared_ptr<UIObserverListener>& registeredListener) {
216 return registeredListener->NapiEqual(cb);
217 }),
218 holder.end()
219 );
220 }
221
HandleScrollEventStateChange(const std::string & id,int32_t uniqueId,NG::ScrollEventType eventType,float offset)222 void UIObserver::HandleScrollEventStateChange(const std::string& id, int32_t uniqueId,
223 NG::ScrollEventType eventType, float offset)
224 {
225 for (const auto& listener : scrollEventListeners_) {
226 listener->OnScrollEventStateChange(id, uniqueId, eventType, offset);
227 }
228
229 auto iter = specifiedScrollEventListeners_.find(id);
230 if (iter == specifiedScrollEventListeners_.end()) {
231 return;
232 }
233
234 auto& holder = iter->second;
235
236 for (const auto& listener : holder) {
237 listener->OnScrollEventStateChange(id, uniqueId, eventType, offset);
238 }
239 }
240
241 // UIObserver.on(type: "routerPageUpdate", UIAbilityContext, callback)
242 // register a listener on current page
RegisterRouterPageCallback(napi_env env,napi_value uiAbilityContext,const std::shared_ptr<UIObserverListener> & listener)243 void UIObserver::RegisterRouterPageCallback(
244 napi_env env, napi_value uiAbilityContext, const std::shared_ptr<UIObserverListener>& listener)
245 {
246 NG::AbilityContextInfo info;
247 GetAbilityInfos(env, uiAbilityContext, info);
248 for (auto listenerPair : abilityContextRouterPageListeners_) {
249 auto ref = listenerPair.first;
250 auto localInfo = infosForRouterPage_[ref];
251 if (info.IsEqual(localInfo)) {
252 auto& holder = abilityContextRouterPageListeners_[ref];
253 if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
254 return;
255 }
256 holder.emplace_back(listener);
257 return;
258 }
259 }
260 napi_ref newRef = nullptr;
261 napi_create_reference(env, uiAbilityContext, 1, &newRef);
262 abilityContextRouterPageListeners_[newRef] = std::list<std::shared_ptr<UIObserverListener>>({ listener });
263 infosForRouterPage_[newRef] = info;
264 }
265
266 // UIObserver.on(type: "routerPageUpdate", uiContext | null, callback)
267 // register a listener on current page
RegisterRouterPageCallback(int32_t uiContextInstanceId,const std::shared_ptr<UIObserverListener> & listener)268 void UIObserver::RegisterRouterPageCallback(
269 int32_t uiContextInstanceId, const std::shared_ptr<UIObserverListener>& listener)
270 {
271 if (uiContextInstanceId == 0) {
272 uiContextInstanceId = Container::CurrentId();
273 }
274 auto iter = specifiedRouterPageListeners_.find(uiContextInstanceId);
275 if (iter == specifiedRouterPageListeners_.end()) {
276 specifiedRouterPageListeners_.emplace(
277 uiContextInstanceId, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
278 return;
279 }
280 auto& holder = iter->second;
281 if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
282 return;
283 }
284 holder.emplace_back(listener);
285 }
286
287 // UIObserver.off(type: "routerPageUpdate", uiAbilityContext, callback)
UnRegisterRouterPageCallback(napi_env env,napi_value uiAbilityContext,napi_value callback)288 void UIObserver::UnRegisterRouterPageCallback(napi_env env, napi_value uiAbilityContext, napi_value callback)
289 {
290 NG::AbilityContextInfo info;
291 GetAbilityInfos(env, uiAbilityContext, info);
292 for (auto listenerPair : abilityContextRouterPageListeners_) {
293 auto ref = listenerPair.first;
294 auto localInfo = infosForRouterPage_[ref];
295 if (info.IsEqual(localInfo)) {
296 auto& holder = abilityContextRouterPageListeners_[listenerPair.first];
297 if (callback == nullptr) {
298 holder.clear();
299 } else {
300 holder.erase(
301 std::remove_if(
302 holder.begin(),
303 holder.end(),
304 [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
305 return registeredListener->NapiEqual(callback);
306 }),
307 holder.end());
308 }
309 if (holder.empty()) {
310 infosForRouterPage_.erase(ref);
311 abilityContextRouterPageListeners_.erase(ref);
312 napi_delete_reference(env, ref);
313 }
314 return;
315 }
316 }
317 }
318
319 // UIObserver.off(type: "routerPageUpdate", uiContext | null, callback)
UnRegisterRouterPageCallback(int32_t uiContextInstanceId,napi_value callback)320 void UIObserver::UnRegisterRouterPageCallback(int32_t uiContextInstanceId, napi_value callback)
321 {
322 if (uiContextInstanceId == 0) {
323 uiContextInstanceId = Container::CurrentId();
324 }
325 auto iter = specifiedRouterPageListeners_.find(uiContextInstanceId);
326 if (iter == specifiedRouterPageListeners_.end()) {
327 return;
328 }
329 auto& holder = iter->second;
330 if (callback == nullptr) {
331 holder.clear();
332 return;
333 }
334 holder.erase(
335 std::remove_if(
336 holder.begin(),
337 holder.end(),
338 [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
339 return registeredListener->NapiEqual(callback);
340 }),
341 holder.end());
342 }
343
344 // UIObserver.on(type: "willDraw", uiContext | null, callback)
345 // register a listener on current page
RegisterDrawCallback(int32_t uiContextInstanceId,const std::shared_ptr<UIObserverListener> & listener)346 void UIObserver::RegisterDrawCallback(int32_t uiContextInstanceId, const std::shared_ptr<UIObserverListener>& listener)
347 {
348 if (uiContextInstanceId == 0) {
349 uiContextInstanceId = Container::CurrentId();
350 }
351 if (specifiedDrawListeners_.find(uiContextInstanceId) == specifiedDrawListeners_.end()) {
352 specifiedDrawListeners_[uiContextInstanceId] = std::list<std::shared_ptr<UIObserverListener>>({ listener });
353 return;
354 }
355 auto& holder = specifiedDrawListeners_[uiContextInstanceId];
356 if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
357 return;
358 }
359 holder.emplace_back(listener);
360 }
361
362 // UIObserver.off(type: "willDraw", uiContext | null, callback)
UnRegisterDrawCallback(int32_t uiContextInstanceId,napi_value callback)363 void UIObserver::UnRegisterDrawCallback(int32_t uiContextInstanceId, napi_value callback)
364 {
365 if (uiContextInstanceId == 0) {
366 uiContextInstanceId = Container::CurrentId();
367 }
368 if (specifiedDrawListeners_.find(uiContextInstanceId) == specifiedDrawListeners_.end()) {
369 return;
370 }
371 auto& holder = specifiedDrawListeners_[uiContextInstanceId];
372 if (callback == nullptr) {
373 holder.clear();
374 return;
375 }
376 holder.erase(
377 std::remove_if(
378 holder.begin(),
379 holder.end(),
380 [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
381 return registeredListener->NapiEqual(callback);
382 }),
383 holder.end());
384 }
385
386 // UIObserver.on(type: "didLayout", uiContext | null, callback)
387 // register a listener on current page
RegisterLayoutCallback(int32_t uiContextInstanceId,const std::shared_ptr<UIObserverListener> & listener)388 void UIObserver::RegisterLayoutCallback(
389 int32_t uiContextInstanceId, const std::shared_ptr<UIObserverListener>& listener)
390 {
391 if (uiContextInstanceId == 0) {
392 uiContextInstanceId = Container::CurrentId();
393 }
394 if (specifiedLayoutListeners_.find(uiContextInstanceId) == specifiedLayoutListeners_.end()) {
395 specifiedLayoutListeners_[uiContextInstanceId] = std::list<std::shared_ptr<UIObserverListener>>({ listener });
396 return;
397 }
398 auto& holder = specifiedLayoutListeners_[uiContextInstanceId];
399 if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
400 return;
401 }
402 holder.emplace_back(listener);
403 }
404
405 // UIObserver.off(type: "didLayout", uiContext | null, callback)
UnRegisterLayoutCallback(int32_t uiContextInstanceId,napi_value callback)406 void UIObserver::UnRegisterLayoutCallback(int32_t uiContextInstanceId, napi_value callback)
407 {
408 if (uiContextInstanceId == 0) {
409 uiContextInstanceId = Container::CurrentId();
410 }
411 if (specifiedLayoutListeners_.find(uiContextInstanceId) == specifiedLayoutListeners_.end()) {
412 return;
413 }
414 auto& holder = specifiedLayoutListeners_[uiContextInstanceId];
415 if (callback == nullptr) {
416 holder.clear();
417 return;
418 }
419 holder.erase(
420 std::remove_if(
421 holder.begin(),
422 holder.end(),
423 [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
424 return registeredListener->NapiEqual(callback);
425 }),
426 holder.end());
427 }
428
HandleRouterPageStateChange(NG::AbilityContextInfo & info,const NG::RouterPageInfoNG & pageInfo)429 void UIObserver::HandleRouterPageStateChange(NG::AbilityContextInfo& info, const NG::RouterPageInfoNG& pageInfo)
430 {
431 for (auto listenerPair : abilityContextRouterPageListeners_) {
432 auto ref = listenerPair.first;
433 auto localInfo = infosForRouterPage_[ref];
434 if (info.IsEqual(localInfo)) {
435 auto env = GetCurrentNapiEnv();
436 napi_value abilityContext = nullptr;
437 napi_get_reference_value(env, ref, &abilityContext);
438
439 NG::RouterPageInfoNG abilityPageInfo(
440 abilityContext, pageInfo.index, pageInfo.name, pageInfo.path, pageInfo.state, pageInfo.pageId);
441 auto holder = abilityContextRouterPageListeners_[ref];
442 for (const auto& listener : holder) {
443 listener->OnRouterPageStateChange(abilityPageInfo);
444 }
445 break;
446 }
447 }
448
449 auto currentId = Container::CurrentId();
450 auto iter = specifiedRouterPageListeners_.find(currentId);
451 if (iter == specifiedRouterPageListeners_.end()) {
452 return;
453 }
454 auto holder = iter->second;
455 for (const auto& listener : holder) {
456 listener->OnRouterPageStateChange(pageInfo);
457 }
458 }
459
460 // UIObserver.on(type: "densityUpdate", uiContext | null, callback)
461 // register a listener on current page
RegisterDensityCallback(int32_t uiContextInstanceId,const std::shared_ptr<UIObserverListener> & listener)462 void UIObserver::RegisterDensityCallback(
463 int32_t uiContextInstanceId, const std::shared_ptr<UIObserverListener>& listener)
464 {
465 if (uiContextInstanceId == 0) {
466 uiContextInstanceId = Container::CurrentId();
467 }
468 if (specifiedDensityListeners_.find(uiContextInstanceId) == specifiedDensityListeners_.end()) {
469 specifiedDensityListeners_[uiContextInstanceId] =
470 std::list<std::shared_ptr<UIObserverListener>>({ listener });
471 return;
472 }
473 auto& holder = specifiedDensityListeners_[uiContextInstanceId];
474 if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
475 return;
476 }
477 holder.emplace_back(listener);
478 }
479
480 // UIObserver.off(type: "densityUpdate", uiContext | null, callback)
UnRegisterDensityCallback(int32_t uiContextInstanceId,napi_value callback)481 void UIObserver::UnRegisterDensityCallback(int32_t uiContextInstanceId, napi_value callback)
482 {
483 if (uiContextInstanceId == 0) {
484 uiContextInstanceId = Container::CurrentId();
485 }
486 if (specifiedDensityListeners_.find(uiContextInstanceId) == specifiedDensityListeners_.end()) {
487 return;
488 }
489 auto& holder = specifiedDensityListeners_[uiContextInstanceId];
490 if (callback == nullptr) {
491 holder.clear();
492 return;
493 }
494 holder.erase(
495 std::remove_if(
496 holder.begin(),
497 holder.end(),
498 [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
499 return registeredListener->NapiEqual(callback);
500 }),
501 holder.end());
502 }
503
HandleDensityChange(NG::AbilityContextInfo & info,double density)504 void UIObserver::HandleDensityChange(NG::AbilityContextInfo& info, double density)
505 {
506 auto currentId = Container::CurrentId();
507 if (specifiedDensityListeners_.find(currentId) == specifiedDensityListeners_.end()) {
508 return;
509 }
510 auto& holder = specifiedDensityListeners_[currentId];
511 for (const auto& listener : holder) {
512 listener->OnDensityChange(density);
513 }
514 }
515
HandDrawCommandSendChange()516 void UIObserver::HandDrawCommandSendChange()
517 {
518 auto currentId = Container::CurrentId();
519 if (specifiedDrawListeners_.find(currentId) == specifiedDrawListeners_.end()) {
520 return;
521 }
522 auto& holder = specifiedDrawListeners_[currentId];
523 for (const auto& listener : holder) {
524 listener->OnDrawOrLayout();
525 }
526 }
527
HandLayoutDoneChange()528 void UIObserver::HandLayoutDoneChange()
529 {
530 auto currentId = Container::CurrentId();
531 if (specifiedLayoutListeners_.find(currentId) == specifiedLayoutListeners_.end()) {
532 return;
533 }
534 auto& holder = specifiedLayoutListeners_[currentId];
535 for (const auto& listener : holder) {
536 listener->OnDrawOrLayout();
537 }
538 }
539
540 /**
541 * observer.on('navDestinationSwitch', context: UIAbilityContext, callback)
542 * observer.on('navDestinationSwitch', context: UIAbilityContext, { navigationId: navId }, callback)
543 */
RegisterNavDestinationSwitchCallback(napi_env env,napi_value uiAbilityContext,const std::optional<std::string> & navigationId,const std::shared_ptr<UIObserverListener> & listener)544 void UIObserver::RegisterNavDestinationSwitchCallback(napi_env env, napi_value uiAbilityContext,
545 const std::optional<std::string>& navigationId, const std::shared_ptr<UIObserverListener>& listener)
546 {
547 NG::AbilityContextInfo info;
548 GetAbilityInfos(env, uiAbilityContext, info);
549 for (auto& listenerPair : abilityUIContextNavDesSwitchListeners_) {
550 auto ref = listenerPair.first;
551 auto localInfo = infosForNavDesSwitch_[ref];
552 if (!info.IsEqual(localInfo)) {
553 continue;
554 }
555
556 auto& listenersMap = listenerPair.second;
557 auto it = listenersMap.find(navigationId);
558 if (it == listenersMap.end()) {
559 listenersMap[navigationId] = std::list<std::shared_ptr<UIObserverListener>>({listener});
560 return;
561 }
562 if (std::find(it->second.begin(), it->second.end(), listener) == it->second.end()) {
563 it->second.emplace_back(listener);
564 }
565 return;
566 }
567 napi_ref newRef = nullptr;
568 napi_create_reference(env, uiAbilityContext, 1, &newRef);
569 NavIdAndListenersMap listenersMap;
570 listenersMap.emplace(navigationId, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
571 abilityUIContextNavDesSwitchListeners_[newRef] = listenersMap;
572 infosForNavDesSwitch_[newRef] = info;
573 }
574
575 /**
576 * UIObserver.on('navDestinationSwitch', { navigationId: navId }, callback)
577 * UIObserver.on('navDestinationSwitch', callback)
578 * observer.on('navDestinationSwitch', context: UIContext, { navigationId?: navId }, callback)
579 */
RegisterNavDestinationSwitchCallback(int32_t uiContextInstanceId,const std::optional<std::string> & navigationId,const std::shared_ptr<UIObserverListener> & listener)580 void UIObserver::RegisterNavDestinationSwitchCallback(int32_t uiContextInstanceId,
581 const std::optional<std::string>& navigationId, const std::shared_ptr<UIObserverListener>& listener)
582 {
583 if (uiContextInstanceId == 0) {
584 uiContextInstanceId = Container::CurrentId();
585 }
586 auto listenersMapIter = uiContextNavDesSwitchListeners_.find(uiContextInstanceId);
587 if (listenersMapIter == uiContextNavDesSwitchListeners_.end()) {
588 NavIdAndListenersMap listenersMap;
589 listenersMap.emplace(navigationId, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
590 uiContextNavDesSwitchListeners_[uiContextInstanceId] = listenersMap;
591 return;
592 }
593
594 auto& listenersMap = listenersMapIter->second;
595 auto it = listenersMap.find(navigationId);
596 if (it == listenersMap.end()) {
597 listenersMap[navigationId] = std::list<std::shared_ptr<UIObserverListener>>({listener});
598 return;
599 }
600
601 if (std::find(it->second.begin(), it->second.end(), listener) == it->second.end()) {
602 it->second.emplace_back(listener);
603 }
604 }
605
606 /**
607 * observer.off('navDestinationSwitch', context: AbilityUIContext})
608 * observer.off('navDestinationSwitch', context: AbilityUIContext, callback })
609 * observer.off('navDestinationSwitch', context: AbilityUIContext, { navigationId: navId } })
610 * observer.off('navDestinationSwitch', context: AbilityUIContext, { navigationId: navId }, callback })
611 */
UnRegisterNavDestinationSwitchCallback(napi_env env,napi_value uiAbilityContext,const std::optional<std::string> & navigationId,napi_value callback)612 void UIObserver::UnRegisterNavDestinationSwitchCallback(napi_env env, napi_value uiAbilityContext,
613 const std::optional<std::string>& navigationId, napi_value callback)
614 {
615 NG::AbilityContextInfo info;
616 GetAbilityInfos(env, uiAbilityContext, info);
617 for (auto listenerPair : abilityUIContextNavDesSwitchListeners_) {
618 auto ref = listenerPair.first;
619 auto localInfo = infosForNavDesSwitch_[ref];
620 if (!info.IsEqual(localInfo)) {
621 continue;
622 }
623
624 auto& listenersMap = listenerPair.second;
625 auto it = listenersMap.find(navigationId);
626 if (it == listenersMap.end()) {
627 return;
628 }
629 auto& listeners = it->second;
630 if (callback == nullptr) {
631 listeners.clear();
632 } else {
633 listeners.erase(std::remove_if(listeners.begin(), listeners.end(),
634 [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
635 return registeredListener->NapiEqual(callback);
636 }), listeners.end());
637 }
638 if (listeners.empty()) {
639 listenersMap.erase(it);
640 }
641 if (listenersMap.empty()) {
642 infosForNavDesSwitch_.erase(ref);
643 abilityUIContextNavDesSwitchListeners_.erase(ref);
644 napi_delete_reference(env, ref);
645 }
646 return;
647 }
648 }
649
650 /**
651 * observer.off('navDestinationSwitch', context: UIContext})
652 * observer.off('navDestinationSwitch', context: UIContext, callback })
653 * observer.off('navDestinationSwitch', context: UIContext, { navigationId: navId })
654 * observer.off('navDestinationSwitch', context: UIContext, { navigationId: navId }, callback )
655 * UIObserver.off('navDestinationSwitch')
656 * UIObserver.off('navDestinationSwitch', callback)
657 * UIObserver.off('navDestinationSwitch', { navigationId: navId })
658 * UIObserver.off('navDestinationSwitch', { navigationId: navId }, callback )
659 */
UnRegisterNavDestinationSwitchCallback(int32_t uiContextInstanceId,const std::optional<std::string> & navigationId,napi_value callback)660 void UIObserver::UnRegisterNavDestinationSwitchCallback(int32_t uiContextInstanceId,
661 const std::optional<std::string>& navigationId, napi_value callback)
662 {
663 if (uiContextInstanceId == 0) {
664 uiContextInstanceId = Container::CurrentId();
665 }
666 auto listenersMapIter = uiContextNavDesSwitchListeners_.find(uiContextInstanceId);
667 if (listenersMapIter == uiContextNavDesSwitchListeners_.end()) {
668 return;
669 }
670 auto& listenersMap = listenersMapIter->second;
671 auto it = listenersMap.find(navigationId);
672 if (it == listenersMap.end()) {
673 return;
674 }
675 auto& listeners = it->second;
676 if (callback == nullptr) {
677 listeners.clear();
678 } else {
679 listeners.erase(std::remove_if(listeners.begin(), listeners.end(),
680 [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
681 return registeredListener->NapiEqual(callback);
682 }), listeners.end());
683 }
684 if (listeners.empty()) {
685 listenersMap.erase(it);
686 }
687 if (listenersMap.empty()) {
688 uiContextNavDesSwitchListeners_.erase(listenersMapIter);
689 }
690 }
691
HandleNavDestinationSwitch(const NG::AbilityContextInfo & info,NG::NavDestinationSwitchInfo & switchInfo)692 void UIObserver::HandleNavDestinationSwitch(
693 const NG::AbilityContextInfo& info, NG::NavDestinationSwitchInfo& switchInfo)
694 {
695 HandleAbilityUIContextNavDestinationSwitch(info, switchInfo);
696 HandleUIContextNavDestinationSwitch(switchInfo);
697 }
698
HandleAbilityUIContextNavDestinationSwitch(const NG::AbilityContextInfo & info,NG::NavDestinationSwitchInfo & switchInfo)699 void UIObserver::HandleAbilityUIContextNavDestinationSwitch(
700 const NG::AbilityContextInfo& info, NG::NavDestinationSwitchInfo& switchInfo)
701 {
702 napi_value uiContextBackup = switchInfo.context;
703 for (auto listenerPair : abilityUIContextNavDesSwitchListeners_) {
704 auto ref = listenerPair.first;
705 auto localInfo = infosForNavDesSwitch_[ref];
706 if (!info.IsEqual(localInfo)) {
707 continue;
708 }
709
710 auto env = GetCurrentNapiEnv();
711 napi_value abilityContext = nullptr;
712 napi_get_reference_value(env, ref, &abilityContext);
713
714 switchInfo.context = abilityContext;
715 auto listenersMap = listenerPair.second;
716 HandleListenersWithEmptyNavigationId(listenersMap, switchInfo);
717 HandleListenersWithSpecifiedNavigationId(listenersMap, switchInfo);
718 break;
719 }
720 switchInfo.context = uiContextBackup;
721 }
722
HandleUIContextNavDestinationSwitch(const NG::NavDestinationSwitchInfo & switchInfo)723 void UIObserver::HandleUIContextNavDestinationSwitch(const NG::NavDestinationSwitchInfo& switchInfo)
724 {
725 auto currentId = Container::CurrentId();
726 auto listenersMapIter = uiContextNavDesSwitchListeners_.find(currentId);
727 if (listenersMapIter == uiContextNavDesSwitchListeners_.end()) {
728 return;
729 }
730 auto listenersMap = listenersMapIter->second;
731 HandleListenersWithEmptyNavigationId(listenersMap, switchInfo);
732 HandleListenersWithSpecifiedNavigationId(listenersMap, switchInfo);
733 }
734
HandleListenersWithEmptyNavigationId(const NavIdAndListenersMap & listenersMap,const NG::NavDestinationSwitchInfo & switchInfo)735 void UIObserver::HandleListenersWithEmptyNavigationId(
736 const NavIdAndListenersMap& listenersMap, const NG::NavDestinationSwitchInfo& switchInfo)
737 {
738 std::optional<std::string> navId;
739 auto it = listenersMap.find(navId);
740 if (it != listenersMap.end()) {
741 const auto listeners = it->second;
742 for (const auto& listener : listeners) {
743 listener->OnNavDestinationSwitch(switchInfo);
744 }
745 }
746 }
747
HandleListenersWithSpecifiedNavigationId(const NavIdAndListenersMap & listenersMap,const NG::NavDestinationSwitchInfo & switchInfo)748 void UIObserver::HandleListenersWithSpecifiedNavigationId(
749 const NavIdAndListenersMap& listenersMap, const NG::NavDestinationSwitchInfo& switchInfo)
750 {
751 std::string navigationId;
752 if (switchInfo.from.has_value()) {
753 navigationId = switchInfo.from.value().navigationId;
754 } else if (switchInfo.to.has_value()) {
755 navigationId = switchInfo.to.value().navigationId;
756 }
757 if (!navigationId.empty()) {
758 std::optional<std::string> navId{navigationId};
759 auto it = listenersMap.find(navId);
760 if (it != listenersMap.end()) {
761 const auto listeners = it->second;
762 for (const auto& listener : listeners) {
763 listener->OnNavDestinationSwitch(switchInfo);
764 }
765 }
766 }
767 }
768
RegisterWillClickCallback(napi_env env,napi_value uiAbilityContext,const std::shared_ptr<UIObserverListener> & listener)769 void UIObserver::RegisterWillClickCallback(
770 napi_env env, napi_value uiAbilityContext, const std::shared_ptr<UIObserverListener>& listener)
771 {
772 napi_handle_scope scope = nullptr;
773 auto status = napi_open_handle_scope(env, &scope);
774 if (status != napi_ok) {
775 return;
776 }
777 NG::AbilityContextInfo info;
778 GetAbilityInfos(env, uiAbilityContext, info);
779 for (auto listenerPair : abilityContextWillClickListeners_) {
780 auto ref = listenerPair.first;
781 auto localInfo = willClickInfos_[ref];
782 if (info.IsEqual(localInfo)) {
783 auto& holder = abilityContextWillClickListeners_[ref];
784 if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
785 napi_close_handle_scope(env, scope);
786 return;
787 }
788 holder.emplace_back(listener);
789 napi_close_handle_scope(env, scope);
790 return;
791 }
792 }
793 napi_ref newRef = nullptr;
794 napi_create_reference(env, uiAbilityContext, 1, &newRef);
795 abilityContextWillClickListeners_[newRef] = std::list<std::shared_ptr<UIObserverListener>>({ listener });
796 willClickInfos_[newRef] = info;
797 napi_close_handle_scope(env, scope);
798 }
799
RegisterWillClickCallback(int32_t uiContextInstanceId,const std::shared_ptr<UIObserverListener> & listener)800 void UIObserver::RegisterWillClickCallback(
801 int32_t uiContextInstanceId, const std::shared_ptr<UIObserverListener>& listener)
802 {
803 if (uiContextInstanceId == 0) {
804 uiContextInstanceId = Container::CurrentId();
805 }
806 auto iter = specifiedWillClickListeners_.find(uiContextInstanceId);
807 if (iter == specifiedWillClickListeners_.end()) {
808 specifiedWillClickListeners_.emplace(
809 uiContextInstanceId, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
810 return;
811 }
812 auto& holder = iter->second;
813 if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
814 return;
815 }
816 holder.emplace_back(listener);
817 }
818
UnRegisterWillClickCallback(napi_env env,napi_value uiAbilityContext,napi_value callback)819 void UIObserver::UnRegisterWillClickCallback(napi_env env, napi_value uiAbilityContext, napi_value callback)
820 {
821 napi_handle_scope scope = nullptr;
822 auto status = napi_open_handle_scope(env, &scope);
823 if (status != napi_ok) {
824 return;
825 }
826 NG::AbilityContextInfo info;
827 GetAbilityInfos(env, uiAbilityContext, info);
828 for (auto listenerPair : abilityContextWillClickListeners_) {
829 auto ref = listenerPair.first;
830 auto localInfo = willClickInfos_[ref];
831 if (!info.IsEqual(localInfo)) {
832 continue;
833 }
834 auto& holder = abilityContextWillClickListeners_[listenerPair.first];
835 if (callback == nullptr) {
836 holder.clear();
837 } else {
838 holder.erase(
839 std::remove_if(
840 holder.begin(),
841 holder.end(),
842 [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
843 return registeredListener->NapiEqual(callback);
844 }),
845 holder.end());
846 }
847 if (holder.empty()) {
848 willClickInfos_.erase(ref);
849 abilityContextWillClickListeners_.erase(ref);
850 napi_delete_reference(env, ref);
851 }
852 }
853 napi_close_handle_scope(env, scope);
854 }
855
UnRegisterWillClickCallback(int32_t uiContextInstanceId,napi_value callback)856 void UIObserver::UnRegisterWillClickCallback(int32_t uiContextInstanceId, napi_value callback)
857 {
858 if (uiContextInstanceId == 0) {
859 uiContextInstanceId = Container::CurrentId();
860 }
861 auto iter = specifiedWillClickListeners_.find(uiContextInstanceId);
862 if (iter == specifiedWillClickListeners_.end()) {
863 return;
864 }
865 auto& holder = iter->second;
866 if (callback == nullptr) {
867 holder.clear();
868 return;
869 }
870 holder.erase(
871 std::remove_if(
872 holder.begin(),
873 holder.end(),
874 [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
875 return registeredListener->NapiEqual(callback);
876 }),
877 holder.end());
878 }
879
HandleWillClick(NG::AbilityContextInfo & info,const GestureEvent & gestureEventInfo,const ClickInfo & clickInfo,const RefPtr<NG::FrameNode> & frameNode)880 void UIObserver::HandleWillClick(NG::AbilityContextInfo& info, const GestureEvent& gestureEventInfo,
881 const ClickInfo& clickInfo, const RefPtr<NG::FrameNode>& frameNode)
882 {
883 auto env = GetCurrentNapiEnv();
884 napi_handle_scope scope = nullptr;
885 auto status = napi_open_handle_scope(env, &scope);
886 if (status != napi_ok) {
887 return;
888 }
889 for (auto listenerPair : abilityContextWillClickListeners_) {
890 auto ref = listenerPair.first;
891 auto localInfo = willClickInfos_[ref];
892 if (info.IsEqual(localInfo)) {
893 napi_value abilityContext = nullptr;
894 napi_get_reference_value(env, ref, &abilityContext);
895
896 auto& holder = abilityContextWillClickListeners_[ref];
897 for (const auto& listener : holder) {
898 listener->OnWillClick(gestureEventInfo, clickInfo, frameNode);
899 }
900 break;
901 }
902 }
903
904 auto currentId = Container::CurrentId();
905 auto iter = specifiedWillClickListeners_.find(currentId);
906 if (iter == specifiedWillClickListeners_.end()) {
907 napi_close_handle_scope(env, scope);
908 return;
909 }
910 auto& holder = iter->second;
911 for (const auto& listener : holder) {
912 listener->OnWillClick(gestureEventInfo, clickInfo, frameNode);
913 }
914 napi_close_handle_scope(env, scope);
915 }
916
RegisterDidClickCallback(napi_env env,napi_value uiAbilityContext,const std::shared_ptr<UIObserverListener> & listener)917 void UIObserver::RegisterDidClickCallback(
918 napi_env env, napi_value uiAbilityContext, const std::shared_ptr<UIObserverListener>& listener)
919 {
920 napi_handle_scope scope = nullptr;
921 auto status = napi_open_handle_scope(env, &scope);
922 if (status != napi_ok) {
923 return;
924 }
925 NG::AbilityContextInfo info;
926 GetAbilityInfos(env, uiAbilityContext, info);
927 for (auto listenerPair : abilityContextDidClickListeners_) {
928 auto ref = listenerPair.first;
929 auto localInfo = didClickInfos_[ref];
930 if (info.IsEqual(localInfo)) {
931 auto& holder = abilityContextDidClickListeners_[ref];
932 if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
933 napi_close_handle_scope(env, scope);
934 return;
935 }
936 holder.emplace_back(listener);
937 napi_close_handle_scope(env, scope);
938 return;
939 }
940 }
941 napi_ref newRef = nullptr;
942 napi_create_reference(env, uiAbilityContext, 1, &newRef);
943 abilityContextDidClickListeners_[newRef] = std::list<std::shared_ptr<UIObserverListener>>({ listener });
944 didClickInfos_[newRef] = info;
945 napi_close_handle_scope(env, scope);
946 }
947
RegisterDidClickCallback(int32_t uiContextInstanceId,const std::shared_ptr<UIObserverListener> & listener)948 void UIObserver::RegisterDidClickCallback(
949 int32_t uiContextInstanceId, const std::shared_ptr<UIObserverListener>& listener)
950 {
951 if (uiContextInstanceId == 0) {
952 uiContextInstanceId = Container::CurrentId();
953 }
954 auto iter = specifiedDidClickListeners_.find(uiContextInstanceId);
955 if (iter == specifiedDidClickListeners_.end()) {
956 specifiedDidClickListeners_.emplace(
957 uiContextInstanceId, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
958 return;
959 }
960 auto& holder = iter->second;
961 if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
962 return;
963 }
964 holder.emplace_back(listener);
965 }
966
UnRegisterDidClickCallback(napi_env env,napi_value uiAbilityContext,napi_value callback)967 void UIObserver::UnRegisterDidClickCallback(napi_env env, napi_value uiAbilityContext, napi_value callback)
968 {
969 napi_handle_scope scope = nullptr;
970 auto status = napi_open_handle_scope(env, &scope);
971 if (status != napi_ok) {
972 return;
973 }
974 NG::AbilityContextInfo info;
975 GetAbilityInfos(env, uiAbilityContext, info);
976 for (auto listenerPair : abilityContextDidClickListeners_) {
977 auto ref = listenerPair.first;
978 auto localInfo = didClickInfos_[ref];
979 if (!info.IsEqual(localInfo)) {
980 continue;
981 }
982 auto& holder = abilityContextDidClickListeners_[listenerPair.first];
983 if (callback == nullptr) {
984 holder.clear();
985 } else {
986 holder.erase(
987 std::remove_if(
988 holder.begin(),
989 holder.end(),
990 [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
991 return registeredListener->NapiEqual(callback);
992 }),
993 holder.end());
994 }
995 if (holder.empty()) {
996 didClickInfos_.erase(ref);
997 abilityContextDidClickListeners_.erase(ref);
998 napi_delete_reference(env, ref);
999 }
1000 }
1001 napi_close_handle_scope(env, scope);
1002 }
1003
UnRegisterDidClickCallback(int32_t uiContextInstanceId,napi_value callback)1004 void UIObserver::UnRegisterDidClickCallback(int32_t uiContextInstanceId, napi_value callback)
1005 {
1006 if (uiContextInstanceId == 0) {
1007 uiContextInstanceId = Container::CurrentId();
1008 }
1009 auto iter = specifiedDidClickListeners_.find(uiContextInstanceId);
1010 if (iter == specifiedDidClickListeners_.end()) {
1011 return;
1012 }
1013 auto& holder = iter->second;
1014 if (callback == nullptr) {
1015 holder.clear();
1016 return;
1017 }
1018 holder.erase(
1019 std::remove_if(
1020 holder.begin(),
1021 holder.end(),
1022 [callback](const std::shared_ptr<UIObserverListener>& registeredListener) {
1023 return registeredListener->NapiEqual(callback);
1024 }),
1025 holder.end());
1026 }
1027
HandleDidClick(NG::AbilityContextInfo & info,const GestureEvent & gestureEventInfo,const ClickInfo & clickInfo,const RefPtr<NG::FrameNode> & frameNode)1028 void UIObserver::HandleDidClick(NG::AbilityContextInfo& info, const GestureEvent& gestureEventInfo,
1029 const ClickInfo& clickInfo, const RefPtr<NG::FrameNode>& frameNode)
1030 {
1031 auto env = GetCurrentNapiEnv();
1032 napi_handle_scope scope = nullptr;
1033 auto status = napi_open_handle_scope(env, &scope);
1034 if (status != napi_ok) {
1035 return;
1036 }
1037 for (auto listenerPair : abilityContextDidClickListeners_) {
1038 auto ref = listenerPair.first;
1039 auto localInfo = didClickInfos_[ref];
1040 if (info.IsEqual(localInfo)) {
1041 napi_value abilityContext = nullptr;
1042 napi_get_reference_value(env, ref, &abilityContext);
1043
1044 auto& holder = abilityContextDidClickListeners_[ref];
1045 for (const auto& listener : holder) {
1046 listener->OnDidClick(gestureEventInfo, clickInfo, frameNode);
1047 }
1048 break;
1049 }
1050 }
1051
1052 auto currentId = Container::CurrentId();
1053 auto iter = specifiedDidClickListeners_.find(currentId);
1054 if (iter == specifiedDidClickListeners_.end()) {
1055 napi_close_handle_scope(env, scope);
1056 return;
1057 }
1058 auto& holder = iter->second;
1059 for (const auto& listener : holder) {
1060 listener->OnDidClick(gestureEventInfo, clickInfo, frameNode);
1061 }
1062 napi_close_handle_scope(env, scope);
1063 }
1064
1065 // UIObserver.on(type: "tabContentState", callback)
1066 // register a global listener without options
RegisterTabContentStateCallback(const std::shared_ptr<UIObserverListener> & listener)1067 void UIObserver::RegisterTabContentStateCallback(const std::shared_ptr<UIObserverListener>& listener)
1068 {
1069 if (std::find(tabContentStateListeners_.begin(), tabContentStateListeners_.end(), listener) !=
1070 tabContentStateListeners_.end()) {
1071 return;
1072 }
1073 tabContentStateListeners_.emplace_back(listener);
1074 }
1075
1076 // UIObserver.on(type: "tabContentState", options, callback)
1077 // register a listener on a specified tabContentState
RegisterTabContentStateCallback(const std::string & id,const std::shared_ptr<UIObserverListener> & listener)1078 void UIObserver::RegisterTabContentStateCallback(
1079 const std::string& id, const std::shared_ptr<UIObserverListener>& listener)
1080 {
1081 auto iter = specifiedTabContentStateListeners_.find(id);
1082 if (iter == specifiedTabContentStateListeners_.end()) {
1083 specifiedTabContentStateListeners_.emplace(id, std::list<std::shared_ptr<UIObserverListener>>({ listener }));
1084 return;
1085 }
1086 auto& holder = iter->second;
1087 if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
1088 return;
1089 }
1090 holder.emplace_back(listener);
1091 }
1092
1093 // UIObserver.off(type: "tabContentState", callback)
UnRegisterTabContentStateCallback(napi_value cb)1094 void UIObserver::UnRegisterTabContentStateCallback(napi_value cb)
1095 {
1096 if (cb == nullptr) {
1097 tabContentStateListeners_.clear();
1098 return;
1099 }
1100
1101 tabContentStateListeners_.erase(
1102 std::remove_if(
1103 tabContentStateListeners_.begin(),
1104 tabContentStateListeners_.end(),
1105 [cb](const std::shared_ptr<UIObserverListener>& registeredListener) {
1106 return registeredListener->NapiEqual(cb);
1107 }),
1108 tabContentStateListeners_.end()
1109 );
1110 }
1111
1112 // UIObserver.off(type: "tabContentState", options, callback)
UnRegisterTabContentStateCallback(const std::string & id,napi_value cb)1113 void UIObserver::UnRegisterTabContentStateCallback(const std::string& id, napi_value cb)
1114 {
1115 auto iter = specifiedTabContentStateListeners_.find(id);
1116 if (iter == specifiedTabContentStateListeners_.end()) {
1117 return;
1118 }
1119 auto& holder = iter->second;
1120 if (cb == nullptr) {
1121 holder.clear();
1122 return;
1123 }
1124 holder.erase(
1125 std::remove_if(
1126 holder.begin(),
1127 holder.end(),
1128 [cb](const std::shared_ptr<UIObserverListener>& registeredListener) {
1129 return registeredListener->NapiEqual(cb);
1130 }),
1131 holder.end()
1132 );
1133 }
1134
HandleTabContentStateChange(const NG::TabContentInfo & tabContentInfo)1135 void UIObserver::HandleTabContentStateChange(const NG::TabContentInfo& tabContentInfo)
1136 {
1137 for (const auto& listener : tabContentStateListeners_) {
1138 listener->OnTabContentStateChange(tabContentInfo);
1139 }
1140
1141 auto iter = specifiedTabContentStateListeners_.find(tabContentInfo.id);
1142 if (iter == specifiedTabContentStateListeners_.end()) {
1143 return;
1144 }
1145
1146 auto& holder = iter->second;
1147
1148 for (const auto& listener : holder) {
1149 listener->OnTabContentStateChange(tabContentInfo);
1150 }
1151 }
1152
GetAbilityInfos(napi_env env,napi_value abilityContext,NG::AbilityContextInfo & info)1153 void UIObserver::GetAbilityInfos(napi_env env, napi_value abilityContext, NG::AbilityContextInfo& info)
1154 {
1155 if (!env || !abilityContext) {
1156 return;
1157 }
1158 napi_value napiInfo = nullptr;
1159 napi_get_named_property(env, abilityContext, "abilityInfo", &napiInfo);
1160 CHECK_NULL_VOID(napiInfo);
1161 napi_value name = nullptr;
1162 napi_get_named_property(env, napiInfo, "name", &name);
1163 ParseStringFromNapi(env, name, info.name);
1164 napi_get_named_property(env, napiInfo, "bundleName", &name);
1165 ParseStringFromNapi(env, name, info.bundleName);
1166 napi_get_named_property(env, napiInfo, "moduleName", &name);
1167 ParseStringFromNapi(env, name, info.moduleName);
1168 }
1169
ParseStringFromNapi(napi_env env,napi_value val,std::string & str)1170 bool UIObserver::ParseStringFromNapi(napi_env env, napi_value val, std::string& str)
1171 {
1172 if (!val || !MatchValueType(env, val, napi_string)) {
1173 return false;
1174 }
1175 size_t len = 0;
1176 napi_get_value_string_utf8(env, val, nullptr, 0, &len);
1177 std::unique_ptr<char[]> result = std::make_unique<char[]>(len + 1);
1178 napi_get_value_string_utf8(env, val, result.get(), len + 1, &len);
1179 str = result.get();
1180 return true;
1181 }
1182
MatchValueType(napi_env env,napi_value value,napi_valuetype targetType)1183 bool UIObserver::MatchValueType(napi_env env, napi_value value, napi_valuetype targetType)
1184 {
1185 napi_valuetype valueType = napi_undefined;
1186 napi_typeof(env, value, &valueType);
1187 return valueType == targetType;
1188 }
1189
GetCurrentNapiEnv()1190 napi_env UIObserver::GetCurrentNapiEnv()
1191 {
1192 auto engine = EngineHelper::GetCurrentEngine();
1193 CHECK_NULL_RETURN(engine, nullptr);
1194 NativeEngine* nativeEngine = engine->GetNativeEngine();
1195 CHECK_NULL_RETURN(nativeEngine, nullptr);
1196 return reinterpret_cast<napi_env>(nativeEngine);
1197 }
1198 } // namespace OHOS::Ace::Napi
1199