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