1 /*
2  * Copyright (c) 2022-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 "core/components_ng/pattern/stage/stage_manager.h"
17 
18 #include <unordered_map>
19 
20 #include "base/geometry/ng/size_t.h"
21 #include "base/log/ace_checker.h"
22 #include "base/log/ace_performance_check.h"
23 #include "base/perfmonitor/perf_monitor.h"
24 #include "base/perfmonitor/perf_constants.h"
25 #include "base/memory/referenced.h"
26 #include "base/utils/time_util.h"
27 #include "base/utils/utils.h"
28 #include "core/animation/page_transition_common.h"
29 #include "core/common/container.h"
30 #include "core/common/ime/input_method_manager.h"
31 #include "core/components/common/layout/constants.h"
32 #include "core/components_ng/base/frame_node.h"
33 
34 #if !defined(ACE_UNITTEST)
35 #include "core/components_ng/base/transparent_node_detector.h"
36 #endif
37 
38 #if !defined(PREVIEW) && !defined(ACE_UNITTEST) && defined(OHOS_PLATFORM)
39 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
40 #endif
41 
42 #include "core/components_ng/base/ui_node.h"
43 #include "core/components_ng/event/focus_hub.h"
44 #include "core/components_ng/manager/shared_overlay/shared_overlay_manager.h"
45 #include "core/components_ng/pattern/overlay/overlay_manager.h"
46 #include "core/components_ng/pattern/stage/page_pattern.h"
47 #include "core/components_ng/pattern/stage/stage_pattern.h"
48 #include "core/components_ng/property/property.h"
49 #include "core/components_v2/inspector/inspector_constants.h"
50 #include "core/pipeline_ng/pipeline_context.h"
51 #include "core/pipeline_ng/ui_task_scheduler.h"
52 
53 namespace OHOS::Ace::NG {
54 
55 namespace {
FirePageTransition(const RefPtr<FrameNode> & page,PageTransitionType transitionType)56 void FirePageTransition(const RefPtr<FrameNode>& page, PageTransitionType transitionType)
57 {
58     CHECK_NULL_VOID(page);
59     auto pagePattern = page->GetPattern<PagePattern>();
60     CHECK_NULL_VOID(pagePattern);
61     page->GetEventHub<EventHub>()->SetEnabled(false);
62     pagePattern->SetPageInTransition(true);
63     auto context = PipelineContext::GetCurrentContext();
64     CHECK_NULL_VOID(context);
65     auto stageManager = context->GetStageManager();
66     CHECK_NULL_VOID(stageManager);
67     stageManager->SetStageInTrasition(true);
68     if (transitionType == PageTransitionType::EXIT_PUSH || transitionType == PageTransitionType::EXIT_POP) {
69         pagePattern->TriggerPageTransition(
70             transitionType, [weak = WeakPtr<FrameNode>(page), transitionType]() {
71                 auto context = PipelineContext::GetCurrentContext();
72                 CHECK_NULL_VOID(context);
73                 auto page = weak.Upgrade();
74                 CHECK_NULL_VOID(page);
75                 TAG_LOGI(AceLogTag::ACE_ANIMATION, "pageTransition exit finish, nodeId:%{public}d", page->GetId());
76                 auto pattern = page->GetPattern<PagePattern>();
77                 CHECK_NULL_VOID(pattern);
78                 pattern->FocusViewHide();
79                 if (transitionType == PageTransitionType::EXIT_POP && page->GetParent()) {
80                     auto stageNode = page->GetParent();
81                     stageNode->RemoveChild(page);
82                     stageNode->RebuildRenderContextTree();
83                     context->RequestFrame();
84                     return;
85                 }
86                 page->GetEventHub<EventHub>()->SetEnabled(true);
87                 pattern->SetPageInTransition(false);
88                 pattern->ProcessHideState();
89                 context->MarkNeedFlushMouseEvent();
90                 auto stageManager = context->GetStageManager();
91                 CHECK_NULL_VOID(stageManager);
92                 stageManager->SetStageInTrasition(false);
93                 page->GetRenderContext()->RemoveClipWithRRect();
94                 page->GetRenderContext()->ResetPageTransitionEffect();
95             });
96         return;
97     }
98     ACE_SCOPED_TRACE_COMMERCIAL("Router Page Transition Start");
99     PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
100     pagePattern->TriggerPageTransition(
101         transitionType, [weak = WeakPtr<FrameNode>(page)]() {
102             auto page = weak.Upgrade();
103             CHECK_NULL_VOID(page);
104             TAG_LOGI(AceLogTag::ACE_ANIMATION, "pageTransition in finish, nodeId:%{public}d", page->GetId());
105             page->GetEventHub<EventHub>()->SetEnabled(true);
106             auto pattern = page->GetPattern<PagePattern>();
107             CHECK_NULL_VOID(pattern);
108             pattern->SetPageInTransition(false);
109 
110             pattern->FocusViewShow();
111             auto context = PipelineContext::GetCurrentContext();
112             CHECK_NULL_VOID(context);
113             context->MarkNeedFlushMouseEvent();
114             page->GetRenderContext()->RemoveClipWithRRect();
115             auto stageManager = context->GetStageManager();
116             CHECK_NULL_VOID(stageManager);
117             stageManager->SetStageInTrasition(false);
118         });
119 }
120 } // namespace
121 
StartTransition(const RefPtr<FrameNode> & srcPage,const RefPtr<FrameNode> & destPage,RouteType type)122 void StageManager::StartTransition(const RefPtr<FrameNode>& srcPage, const RefPtr<FrameNode>& destPage, RouteType type)
123 {
124     auto pipeline = PipelineContext::GetCurrentContext();
125     CHECK_NULL_VOID(pipeline);
126     auto sharedManager = pipeline->GetSharedOverlayManager();
127     CHECK_NULL_VOID(sharedManager);
128     sharedManager->StartSharedTransition(srcPage, destPage);
129     srcPageNode_ = srcPage;
130     destPageNode_ = destPage;
131     TAG_LOGI(AceLogTag::ACE_ANIMATION, "start pageTransition, from node %{public}d to %{public}d",
132         srcPage ? srcPage->GetId() : -1, destPage ? destPage->GetId() : -1);
133     if (type == RouteType::PUSH) {
134         FirePageTransition(srcPage, PageTransitionType::EXIT_PUSH);
135         FirePageTransition(destPage, PageTransitionType::ENTER_PUSH);
136     } else if (type == RouteType::POP) {
137         FirePageTransition(srcPage, PageTransitionType::EXIT_POP);
138         FirePageTransition(destPage, PageTransitionType::ENTER_POP);
139     }
140 }
141 
StageManager(const RefPtr<FrameNode> & stage)142 StageManager::StageManager(const RefPtr<FrameNode>& stage) : stageNode_(stage)
143 {
144     CHECK_NULL_VOID(stageNode_);
145     stagePattern_ = DynamicCast<StagePattern>(stageNode_->GetPattern());
146 }
147 
StopPageTransition()148 void StageManager::StopPageTransition()
149 {
150     auto srcNode = srcPageNode_.Upgrade();
151     if (srcNode) {
152         auto pattern = srcNode->GetPattern<PagePattern>();
153         pattern->StopPageTransition();
154         srcPageNode_ = nullptr;
155     }
156     auto destNode = destPageNode_.Upgrade();
157     if (destNode) {
158         auto pattern = destNode->GetPattern<PagePattern>();
159         pattern->StopPageTransition();
160         destPageNode_ = nullptr;
161     }
162 }
163 
PageChangeCloseKeyboard()164 void StageManager::PageChangeCloseKeyboard()
165 {
166     // close keyboard
167 #if defined (ENABLE_STANDARD_INPUT)
168     // If pushpage, close it
169     if (Container::CurrentId() == CONTAINER_ID_DIVIDE_SIZE) {
170         TAG_LOGI(AceLogTag::ACE_KEYBOARD, "StageManager FrameNode notNeedSoftKeyboard.");
171         auto container = Container::Current();
172         if (!container) {
173             return;
174         }
175         if (!container->IsScenceBoardWindow()) {
176             TAG_LOGI(AceLogTag::ACE_KEYBOARD, "Container not ScenceBoardWindow.");
177             InputMethodManager::GetInstance()->CloseKeyboard();
178         }
179     }
180 #endif
181 }
182 
PushPage(const RefPtr<FrameNode> & node,bool needHideLast,bool needTransition)183 bool StageManager::PushPage(const RefPtr<FrameNode>& node, bool needHideLast, bool needTransition)
184 {
185     CHECK_NULL_RETURN(stageNode_, false);
186     CHECK_NULL_RETURN(node, false);
187     int64_t startTime = GetSysTimestamp();
188     auto pipeline = AceType::DynamicCast<NG::PipelineContext>(PipelineBase::GetCurrentContext());
189     CHECK_NULL_RETURN(pipeline, false);
190     StopPageTransition();
191 
192     const auto& children = stageNode_->GetChildren();
193     RefPtr<FrameNode> outPageNode;
194     needTransition &= !children.empty();
195     if (children.empty()) {
196         auto pagePattern = node->GetPattern<NG::PagePattern>();
197         CHECK_NULL_RETURN(pagePattern, false);
198         auto pageInfo = pagePattern->GetPageInfo();
199         CHECK_NULL_RETURN(pageInfo, false);
200         auto pagePath = pageInfo->GetFullPath();
201         ACE_SCOPED_TRACE_COMMERCIAL("Router Main Page: %s", pagePath.c_str());
202 #if !defined(PREVIEW) && !defined(ACE_UNITTEST) && defined(OHOS_PLATFORM)
203         UiSessionManager::GetInstance().OnRouterChange(pagePath, "routerPushPage");
204 #endif
205     }
206     if (needTransition) {
207         pipeline->FlushPipelineImmediately();
208     }
209     RefPtr<UINode> hidePageNode;
210     auto isNewLifecycle = AceApplicationInfo::GetInstance()
211         .GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE);
212     if (!children.empty() && needHideLast) {
213         hidePageNode = children.back();
214         outPageNode = AceType::DynamicCast<FrameNode>(hidePageNode);
215         FireAutoSave(outPageNode, node);
216         if (!isNewLifecycle) {
217             FirePageHide(hidePageNode, needTransition ? PageTransitionType::EXIT_PUSH : PageTransitionType::NONE);
218         }
219     }
220     auto rect = stageNode_->GetGeometryNode()->GetFrameRect();
221     rect.SetOffset({});
222     node->GetRenderContext()->SyncGeometryProperties(rect);
223     // mount to parent and mark build render tree.
224     node->MountToParent(stageNode_);
225     // then build the total child. Build will trigger page create and onAboutToAppear
226     node->Build(nullptr);
227     // fire new lifecycle
228     if (hidePageNode && needHideLast && isNewLifecycle) {
229         FirePageHide(hidePageNode, needTransition ? PageTransitionType::EXIT_PUSH : PageTransitionType::NONE);
230     }
231     stageNode_->RebuildRenderContextTree();
232     FirePageShow(node, needTransition ? PageTransitionType::ENTER_PUSH : PageTransitionType::NONE);
233 
234     auto pagePattern = node->GetPattern<PagePattern>();
235     CHECK_NULL_RETURN(pagePattern, false);
236     stagePattern_->SetCurrentPageIndex(pagePattern->GetPageInfo()->GetPageId());
237     if (AceChecker::IsPerformanceCheckEnabled()) {
238         // After completing layout tasks at all nodes on the page, perform performance testing and management
239         pipeline->AddAfterLayoutTask([weakStage = WeakClaim(this), weakNode = WeakPtr<FrameNode>(node), startTime]() {
240             auto stage = weakStage.Upgrade();
241             CHECK_NULL_VOID(stage);
242             auto pageNode = weakNode.Upgrade();
243             int64_t endTime = GetSysTimestamp();
244             auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
245             CHECK_NULL_VOID(pagePattern);
246             auto pageInfo = pagePattern->GetPageInfo();
247             CHECK_NULL_VOID(pageInfo);
248             auto pagePath = pageInfo->GetFullPath();
249             stage->PerformanceCheck(pageNode, endTime - startTime, pagePath);
250         });
251     }
252 #if !defined(ACE_UNITTEST)
253     TransparentNodeDetector::GetInstance().PostCheckNodeTransparentTask(node);
254 #endif
255 
256     // close keyboard
257     PageChangeCloseKeyboard();
258     AddPageTransitionTrace(outPageNode, node);
259     if (needTransition) {
260         pipeline->AddAfterLayoutTask([weakStage = WeakClaim(this), weakIn = WeakPtr<FrameNode>(node),
261                                          weakOut = WeakPtr<FrameNode>(outPageNode)]() {
262             auto stage = weakStage.Upgrade();
263             CHECK_NULL_VOID(stage);
264             auto inPageNode = weakIn.Upgrade();
265             auto outPageNode = weakOut.Upgrade();
266             stage->StartTransition(outPageNode, inPageNode, RouteType::PUSH);
267         });
268     }
269 
270     // flush layout task.
271     if (!stageNode_->GetGeometryNode()->GetMarginFrameSize().IsPositive()) {
272         // in first load case, wait for window size.
273         return true;
274     }
275     stageNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
276     node->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
277 
278     return true;
279 }
280 
InsertPage(const RefPtr<FrameNode> & node,bool bellowTopOrBottom)281 bool StageManager::InsertPage(const RefPtr<FrameNode>& node, bool bellowTopOrBottom)
282 {
283     CHECK_NULL_RETURN(stageNode_, false);
284     CHECK_NULL_RETURN(node, false);
285     StopPageTransition();
286 
287     const auto& children = stageNode_->GetChildren();
288     if (children.empty()) {
289         return false;
290     }
291 
292     RefPtr<FrameNode> targetNode = nullptr;
293     if (bellowTopOrBottom) {
294         targetNode = AceType::DynamicCast<FrameNode>(children.back());
295     } else {
296         targetNode = AceType::DynamicCast<FrameNode>(children.front());
297     }
298     auto rect = stageNode_->GetGeometryNode()->GetFrameRect();
299     rect.SetOffset({});
300     node->GetRenderContext()->SyncGeometryProperties(rect);
301     // mount to parent and mark build render tree.
302     stageNode_->AddChildBefore(node, targetNode);
303     // then build the total child. Build will trigger page create and onAboutToAppear
304     node->Build(nullptr);
305 
306     stageNode_->RebuildRenderContextTree();
307 
308     stageNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
309     node->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
310     return true;
311 }
312 
PerformanceCheck(const RefPtr<FrameNode> & pageNode,int64_t vsyncTimeout,std::string path)313 void StageManager::PerformanceCheck(const RefPtr<FrameNode>& pageNode, int64_t vsyncTimeout, std::string path)
314 {
315     CHECK_NULL_VOID(pageNode);
316     PerformanceCheckNodeMap nodeMap;
317     pageNode->GetPerformanceCheckData(nodeMap);
318     AceScopedPerformanceCheck::RecordPerformanceCheckData(nodeMap, vsyncTimeout, path);
319 }
320 
PopPage(bool needShowNext,bool needTransition)321 bool StageManager::PopPage(bool needShowNext, bool needTransition)
322 {
323     auto pipeline = PipelineContext::GetCurrentContext();
324     CHECK_NULL_RETURN(pipeline, false);
325     CHECK_NULL_RETURN(stageNode_, false);
326     StopPageTransition();
327     const auto& children = stageNode_->GetChildren();
328     if (children.empty()) {
329         TAG_LOGI(AceLogTag::ACE_ROUTER, "router pop page start, children is empty");
330         return false;
331     }
332     auto pageNode = children.back();
333     const size_t transitionPageSize = 2;
334     needTransition &= (children.size() >= transitionPageSize);
335     if (needTransition) {
336         pipeline->FlushPipelineImmediately();
337     }
338     auto outPageNode = AceType::DynamicCast<FrameNode>(pageNode);
339     RefPtr<FrameNode> inPageNode;
340     if (needShowNext && children.size() >= transitionPageSize) {
341         auto newPageNode = *(++children.rbegin());
342         inPageNode = AceType::DynamicCast<FrameNode>(newPageNode);
343     }
344     FireAutoSave(outPageNode, inPageNode);
345     FirePageHide(pageNode, needTransition ? PageTransitionType::EXIT_POP : PageTransitionType::NONE);
346     FirePageShow(inPageNode, needTransition ? PageTransitionType::ENTER_POP : PageTransitionType::NONE);
347 
348     // close keyboard
349     PageChangeCloseKeyboard();
350 
351     AddPageTransitionTrace(outPageNode, inPageNode);
352     if (needTransition) {
353         StartTransition(outPageNode, inPageNode, RouteType::POP);
354         inPageNode->OnAccessibilityEvent(AccessibilityEventType::CHANGE);
355         return true;
356     }
357     stageNode_->RemoveChild(pageNode);
358     pageNode->SetChildrenInDestroying();
359     stageNode_->RebuildRenderContextTree();
360     pipeline->RequestFrame();
361     return true;
362 }
363 
PopPageToIndex(int32_t index,bool needShowNext,bool needTransition)364 bool StageManager::PopPageToIndex(int32_t index, bool needShowNext, bool needTransition)
365 {
366     auto pipeline = PipelineContext::GetCurrentContext();
367     CHECK_NULL_RETURN(pipeline, false);
368     CHECK_NULL_RETURN(stageNode_, false);
369     StopPageTransition();
370     const auto& children = stageNode_->GetChildren();
371     if (children.empty()) {
372         return false;
373     }
374     int32_t popSize = static_cast<int32_t>(children.size()) - index - 1;
375     if (popSize < 0) {
376         return false;
377     }
378     if (popSize == 0) {
379         return true;
380     }
381 
382     if (needTransition) {
383         pipeline->FlushPipelineImmediately();
384     }
385     bool firstPageTransition = true;
386     auto outPageNode = AceType::DynamicCast<FrameNode>(children.back());
387     auto iter = children.rbegin();
388     for (int32_t current = 0; current < popSize; ++current) {
389         auto pageNode = *iter;
390         FirePageHide(
391             pageNode, firstPageTransition && needTransition ? PageTransitionType::EXIT_POP : PageTransitionType::NONE);
392         firstPageTransition = false;
393         ++iter;
394     }
395 
396     RefPtr<FrameNode> inPageNode;
397     if (needShowNext) {
398         const auto& newPageNode = *iter;
399         FirePageShow(newPageNode, needTransition ? PageTransitionType::ENTER_POP : PageTransitionType::NONE);
400         inPageNode = AceType::DynamicCast<FrameNode>(newPageNode);
401     }
402     PageChangeCloseKeyboard();
403     AddPageTransitionTrace(outPageNode, inPageNode);
404 
405     FireAutoSave(outPageNode, inPageNode);
406     if (needTransition) {
407         // from the penultimate node, (popSize - 1) nodes are deleted.
408         // the last node will be deleted after pageTransition
409         for (int32_t current = 1; current < popSize; ++current) {
410             auto pageNode = *(++children.rbegin());
411             stageNode_->RemoveChild(pageNode);
412         }
413         stageNode_->RebuildRenderContextTree();
414         StartTransition(outPageNode, inPageNode, RouteType::POP);
415         return true;
416     }
417     for (int32_t current = 0; current < popSize; ++current) {
418         auto pageNode = children.back();
419         stageNode_->RemoveChild(pageNode);
420     }
421     stageNode_->RebuildRenderContextTree();
422     pipeline->RequestFrame();
423     return true;
424 }
425 
CleanPageStack()426 bool StageManager::CleanPageStack()
427 {
428     auto pipeline = PipelineContext::GetCurrentContext();
429     CHECK_NULL_RETURN(pipeline, false);
430     CHECK_NULL_RETURN(stageNode_, false);
431     const auto& children = stageNode_->GetChildren();
432     if (children.size() <= 1) {
433         return false;
434     }
435     auto popSize = static_cast<int32_t>(children.size()) - 1;
436     for (int32_t count = 1; count <= popSize; ++count) {
437         auto pageNode = children.front();
438         // mark pageNode child as destroying
439         pageNode->SetChildrenInDestroying();
440         stageNode_->RemoveChild(pageNode);
441     }
442     stageNode_->RebuildRenderContextTree();
443     pipeline->RequestFrame();
444     return true;
445 }
446 
MovePageToFront(const RefPtr<FrameNode> & node,bool needHideLast,bool needTransition)447 bool StageManager::MovePageToFront(const RefPtr<FrameNode>& node, bool needHideLast, bool needTransition)
448 {
449     auto pipeline = PipelineContext::GetCurrentContext();
450     CHECK_NULL_RETURN(pipeline, false);
451     CHECK_NULL_RETURN(stageNode_, false);
452     StopPageTransition();
453     const auto& children = stageNode_->GetChildren();
454     if (children.empty()) {
455         return false;
456     }
457     const auto& lastPage = children.back();
458     if (lastPage == node) {
459         return true;
460     }
461     if (needTransition) {
462         pipeline->FlushPipelineImmediately();
463     }
464     if (needHideLast) {
465         FirePageHide(lastPage, needTransition ? PageTransitionType::EXIT_PUSH : PageTransitionType::NONE);
466     }
467     node->MovePosition(static_cast<int32_t>(stageNode_->GetChildren().size()) - 1);
468     node->GetRenderContext()->ResetPageTransitionEffect();
469     FirePageShow(node, needTransition ? PageTransitionType::ENTER_PUSH : PageTransitionType::NONE);
470 
471     stageNode_->RebuildRenderContextTree();
472     auto outPageNode = AceType::DynamicCast<FrameNode>(lastPage);
473     AddPageTransitionTrace(outPageNode, node);
474     FireAutoSave(outPageNode, node);
475     if (needTransition) {
476         StartTransition(outPageNode, node, RouteType::PUSH);
477     }
478     pipeline->RequestFrame();
479     return true;
480 }
481 
FirePageHide(const RefPtr<UINode> & node,PageTransitionType transitionType)482 void StageManager::FirePageHide(const RefPtr<UINode>& node, PageTransitionType transitionType)
483 {
484     auto pageNode = DynamicCast<FrameNode>(node);
485     CHECK_NULL_VOID(pageNode);
486     auto pagePattern = pageNode->GetPattern<PagePattern>();
487     CHECK_NULL_VOID(pagePattern);
488     pagePattern->FocusViewHide();
489     pagePattern->OnHide();
490     if (transitionType == PageTransitionType::NONE) {
491         // If there is a page transition, this function should execute after page transition,
492         // otherwise the page will not be visible
493         pagePattern->ProcessHideState();
494     }
495 
496     auto context = PipelineContext::GetCurrentContext();
497     CHECK_NULL_VOID(context);
498     context->MarkNeedFlushMouseEvent();
499 }
500 
FirePageShow(const RefPtr<UINode> & node,PageTransitionType transitionType,bool needFocus)501 void StageManager::FirePageShow(const RefPtr<UINode>& node, PageTransitionType transitionType, bool needFocus)
502 {
503     auto pageNode = DynamicCast<FrameNode>(node);
504     CHECK_NULL_VOID(pageNode);
505     auto layoutProperty = pageNode->GetLayoutProperty();
506 
507     auto pagePattern = pageNode->GetPattern<PagePattern>();
508     CHECK_NULL_VOID(pagePattern);
509     if (needFocus) {
510         pagePattern->FocusViewShow();
511     }
512     pagePattern->OnShow();
513     // With or without a page transition, we need to make the coming page visible first
514     pagePattern->ProcessShowState();
515 
516     auto context = PipelineContext::GetCurrentContext();
517     CHECK_NULL_VOID(context);
518     context->MarkNeedFlushMouseEvent();
519 #ifdef UICAST_COMPONENT_SUPPORTED
520     do {
521         auto container = Container::Current();
522         CHECK_NULL_BREAK(container);
523         auto distributedUI = container->GetDistributedUI();
524         CHECK_NULL_BREAK(distributedUI);
525         distributedUI->OnPageChanged(node->GetPageId());
526     } while (false);
527 #endif
528 }
529 
FireAutoSave(const RefPtr<FrameNode> & outPageNode,const RefPtr<FrameNode> & inPageNode)530 void StageManager::FireAutoSave(const RefPtr<FrameNode>& outPageNode, const RefPtr<FrameNode>& inPageNode)
531 {
532     CHECK_NULL_VOID(outPageNode);
533     auto outPagePattern = outPageNode->GetPattern<PagePattern>();
534     CHECK_NULL_VOID(outPagePattern);
535     auto onUIExtNodeDestroy = [weak = WeakPtr<FrameNode>(inPageNode)]() {
536         TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "called.");
537         auto page = weak.Upgrade();
538         CHECK_NULL_VOID(page);
539         auto pattern = page->GetPattern<PagePattern>();
540         CHECK_NULL_VOID(pattern);
541         pattern->SetIsModalCovered(false);
542     };
543     auto onUIExtNodeBindingCompleted = [weak = WeakPtr<FrameNode>(inPageNode)]() {
544         TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "called.");
545         auto page = weak.Upgrade();
546         CHECK_NULL_VOID(page);
547         auto pattern = page->GetPattern<PagePattern>();
548         CHECK_NULL_VOID(pattern);
549         pattern->SetIsModalCovered(true);
550     };
551     outPagePattern->ProcessAutoSave(onUIExtNodeDestroy, onUIExtNodeBindingCompleted);
552 }
553 
GetLastPage() const554 RefPtr<FrameNode> StageManager::GetLastPage() const
555 {
556     CHECK_NULL_RETURN(stageNode_, nullptr);
557     const auto& children = stageNode_->GetChildren();
558     if (children.empty()) {
559         return nullptr;
560     }
561     return DynamicCast<FrameNode>(children.back());
562 }
563 
GetPageById(int32_t pageId)564 RefPtr<FrameNode> StageManager::GetPageById(int32_t pageId)
565 {
566     CHECK_NULL_RETURN(stageNode_, nullptr);
567     const auto& children = stageNode_->GetChildren();
568     for (const auto& child : children) {
569         if (child->GetPageId() == pageId) {
570             return DynamicCast<FrameNode>(child);
571         }
572     }
573     return nullptr;
574 }
575 
ReloadStage()576 void StageManager::ReloadStage()
577 {
578     CHECK_NULL_VOID(stageNode_);
579     const auto& children = stageNode_->GetChildren();
580     for (const auto& child : children) {
581         auto frameNode = DynamicCast<FrameNode>(child);
582         if (!frameNode) {
583             continue;
584         }
585         auto pagePattern = frameNode->GetPattern<PagePattern>();
586         if (!pagePattern) {
587             continue;
588         }
589         pagePattern->ReloadPage();
590     }
591 }
592 
GetLastPageWithTransition() const593 RefPtr<FrameNode> StageManager::GetLastPageWithTransition() const
594 {
595     CHECK_NULL_RETURN(stageNode_, nullptr);
596     const auto& children = stageNode_->GetChildren();
597     if (children.empty()) {
598         return nullptr;
599     }
600     auto lastChildFrame = DynamicCast<FrameNode>(children.back());
601     auto pagePattern = lastChildFrame->GetPattern<PagePattern>();
602     if (pagePattern && pagePattern->GetPageInTransition()) {
603         return DynamicCast<FrameNode>(destPageNode_.Upgrade());
604     }
605     return lastChildFrame;
606 }
607 
GetPrevPageWithTransition() const608 RefPtr<FrameNode> StageManager::GetPrevPageWithTransition() const
609 {
610     CHECK_NULL_RETURN(stageNode_, nullptr);
611     const auto& children = stageNode_->GetChildren();
612     if (children.empty()) {
613         return nullptr;
614     }
615     if (stageInTrasition_) {
616         return DynamicCast<FrameNode>(srcPageNode_.Upgrade());
617     }
618     return DynamicCast<FrameNode>(children.front());
619 }
620 
AddPageTransitionTrace(const RefPtr<FrameNode> & srcPage,const RefPtr<FrameNode> & destPage)621 void StageManager::AddPageTransitionTrace(const RefPtr<FrameNode>& srcPage, const RefPtr<FrameNode>& destPage)
622 {
623     CHECK_NULL_VOID(srcPage);
624     CHECK_NULL_VOID(destPage);
625 
626     auto srcPattern = srcPage->GetPattern<NG::PagePattern>();
627     CHECK_NULL_VOID(srcPattern);
628     auto srcPageInfo = srcPattern->GetPageInfo();
629     CHECK_NULL_VOID(srcPageInfo);
630     auto srcFullPath = srcPageInfo->GetFullPath();
631 
632     auto destPattern = destPage->GetPattern<NG::PagePattern>();
633     CHECK_NULL_VOID(destPattern);
634     auto destPageInfo = destPattern->GetPageInfo();
635     CHECK_NULL_VOID(destPageInfo);
636     auto destFullPath = destPageInfo->GetFullPath();
637 
638     ACE_SCOPED_TRACE_COMMERCIAL("Router Page from %s to %s", srcFullPath.c_str(), destFullPath.c_str());
639 }
640 
SyncPageSafeArea(bool keyboardSafeArea)641 void StageManager::SyncPageSafeArea(bool keyboardSafeArea)
642 {
643     auto changeType = keyboardSafeArea ? PROPERTY_UPDATE_LAYOUT : PROPERTY_UPDATE_MEASURE;
644     auto lastPage = GetLastPageWithTransition();
645     CHECK_NULL_VOID(lastPage);
646     lastPage->MarkDirtyNode(changeType);
647     auto lastPageOverlay = lastPage->GetPattern<PagePattern>();
648     CHECK_NULL_VOID(lastPageOverlay);
649     lastPageOverlay->MarkDirtyOverlay();
650 
651     auto prevPage = GetPrevPageWithTransition();
652     CHECK_NULL_VOID(prevPage);
653     auto prevPageOverlay = prevPage->GetPattern<PagePattern>();
654     CHECK_NULL_VOID(prevPageOverlay);
655     prevPageOverlay->MarkDirtyOverlay();
656 }
657 
CheckPageFocus()658 bool StageManager::CheckPageFocus()
659 {
660     auto pageNode = GetLastPage();
661     CHECK_NULL_RETURN(pageNode, true);
662     return pageNode->GetFocusHub() && pageNode->GetFocusHub()->IsCurrentFocus();
663 }
664 } // namespace OHOS::Ace::NG
665