• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "interfaces/inner_api/ui_session/ui_session_manager.h"
19 
20 #include "base/log/ace_checker.h"
21 #include "base/perfmonitor/perf_constants.h"
22 #include "base/perfmonitor/perf_monitor.h"
23 #include "core/common/ime/input_method_manager.h"
24 #include "base/ressched/ressched_report.h"
25 
26 #if !defined(ACE_UNITTEST)
27 #include "core/components_ng/base/transparent_node_detector.h"
28 #endif
29 
30 #include "core/components_ng/pattern/stage/page_pattern.h"
31 
32 namespace OHOS::Ace::NG {
33 std::string KEY_PAGE_TRANSITION_PROPERTY = "pageTransitionProperty";
34 namespace {
35 constexpr char EMPTY_PAGE_INFO[] = "NA";
36 
FirePageTransition(const RefPtr<FrameNode> & page,PageTransitionType transitionType)37 void FirePageTransition(const RefPtr<FrameNode>& page, PageTransitionType transitionType)
38 {
39     CHECK_NULL_VOID(page);
40     auto pagePattern = page->GetPattern<PagePattern>();
41     CHECK_NULL_VOID(pagePattern);
42     auto eventHub = page->GetOrCreateEventHub<EventHub>();
43     CHECK_NULL_VOID(eventHub);
44     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
45         if (transitionType == PageTransitionType::EXIT_POP) {
46             eventHub->SetEnabled(false);
47         }
48     } else {
49         eventHub->SetEnabled(false);
50     }
51     pagePattern->SetPageInTransition(true);
52     auto context = PipelineContext::GetCurrentContext();
53     CHECK_NULL_VOID(context);
54     auto stageManager = context->GetStageManager();
55     CHECK_NULL_VOID(stageManager);
56     stageManager->SetStageInTrasition(true);
57     pagePattern->SetAnimationId(stageManager->GetAnimationId());
58     if (transitionType == PageTransitionType::EXIT_PUSH || transitionType == PageTransitionType::EXIT_POP) {
59         pagePattern->TriggerPageTransition([weakPattern = WeakPtr<PagePattern>(pagePattern),
60             animationId = stageManager->GetAnimationId(), transitionType]() {
61                 auto pagePattern = weakPattern.Upgrade();
62                 CHECK_NULL_VOID(pagePattern);
63                 pagePattern->FinishOutPage(animationId, transitionType);
64             }, transitionType);
65         pagePattern->RemoveJsChildImmediately(page, transitionType);
66         return;
67     }
68     ACE_SCOPED_TRACE_COMMERCIAL("Router Page Transition Start");
69     PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
70     pagePattern->TriggerPageTransition(
71         [weak = WeakPtr<PagePattern>(pagePattern), animationId = stageManager->GetAnimationId(), transitionType]() {
72             auto pagePattern = weak.Upgrade();
73             CHECK_NULL_VOID(pagePattern);
74             auto page = pagePattern->GetHost();
75             CHECK_NULL_VOID(page);
76             TAG_LOGI(AceLogTag::ACE_ANIMATION, "pageTransition in finish, nodeId:%{public}d", page->GetId());
77             pagePattern->FinishInPage(animationId, transitionType);
78         }, transitionType);
79 }
80 } // namespace
81 
StartTransition(const RefPtr<FrameNode> & srcPage,const RefPtr<FrameNode> & destPage,RouteType type)82 void StageManager::StartTransition(const RefPtr<FrameNode>& srcPage, const RefPtr<FrameNode>& destPage, RouteType type)
83 {
84     auto pipeline = PipelineContext::GetCurrentContext();
85     CHECK_NULL_VOID(pipeline);
86     auto sharedManager = pipeline->GetSharedOverlayManager();
87     CHECK_NULL_VOID(sharedManager);
88     sharedManager->StartSharedTransition(srcPage, destPage);
89     animationSrcPage_ = srcPage;
90     destPageNode_ = destPage;
91     TAG_LOGI(AceLogTag::ACE_ANIMATION, "start pageTransition, from node %{public}d to %{public}d",
92         srcPage ? srcPage->GetId() : -1, destPage ? destPage->GetId() : -1);
93     // don't need to add animation id when routeType is none
94     if (type == RouteType::NONE) {
95         return;
96     }
97     if (srcPage) {
98         srcPage->SetNodeFreeze(true);
99     }
100     if (destPage) {
101         destPage->SetNodeFreeze(false);
102         auto pagePattern = destPage->GetPattern<NG::PagePattern>();
103         CHECK_NULL_VOID(pagePattern);
104         auto pageInfo = pagePattern->GetPageInfo();
105         CHECK_NULL_VOID(pageInfo);
106         auto pagePath = pageInfo->GetFullPath();
107         std::string routeType("routerPageChange");
108         if (type == RouteType::PUSH) {
109             routeType = "routerPushPage";
110         } else if (type == RouteType::POP) {
111             routeType = "routerPopPage";
112         }
113         UiSessionManager::GetInstance()->OnRouterChange(pagePath, routeType);
114     }
115     animationId_++;
116     if (type == RouteType::PUSH) {
117         pushAnimations_.clear();
118         FirePageTransition(srcPage, PageTransitionType::EXIT_PUSH);
119         FirePageTransition(destPage, PageTransitionType::ENTER_PUSH);
120     } else if (type == RouteType::POP) {
121         popAnimations_.clear();
122         FirePageTransition(srcPage, PageTransitionType::EXIT_POP);
123         FirePageTransition(destPage, PageTransitionType::ENTER_POP);
124     }
125 }
126 
StageManager(const RefPtr<FrameNode> & stage)127 StageManager::StageManager(const RefPtr<FrameNode>& stage) : stageNode_(stage)
128 {
129     CHECK_NULL_VOID(stageNode_);
130     stagePattern_ = DynamicCast<StagePattern>(stageNode_->GetPattern());
131 }
132 
PageChangeCloseKeyboard()133 void StageManager::PageChangeCloseKeyboard()
134 {
135     // close keyboard
136 #if defined (ENABLE_STANDARD_INPUT)
137     if (Container::CurrentId() == CONTAINER_ID_DIVIDE_SIZE) {
138         TAG_LOGI(AceLogTag::ACE_KEYBOARD, "StageManager FrameNode notNeedSoftKeyboard.");
139         auto container = Container::Current();
140         if (!container) {
141             return;
142         }
143         if (!container->IsSceneBoardWindow()) {
144             TAG_LOGI(AceLogTag::ACE_KEYBOARD, "Container not SceneBoardWindow.");
145             InputMethodManager::GetInstance()->CloseKeyboard(false);
146         }
147     }
148 #endif
149 }
150 
UpdateColorModeForPage(const RefPtr<FrameNode> & page)151 void StageManager::UpdateColorModeForPage(const RefPtr<FrameNode>& page)
152 {
153     if (SystemProperties::ConfigChangePerform()) {
154         CHECK_NULL_VOID(page);
155         auto pipelineContext = page->GetContext();
156         CHECK_NULL_VOID(pipelineContext);
157 
158         auto colorMode = pipelineContext->GetColorMode() == ColorMode::DARK ? true : false;
159         if (page->CheckIsDarkMode() == colorMode) {
160             return;
161         }
162         pipelineContext->SetIsSystemColorChange(false);
163         page->SetRerenderable(true);
164         page->NotifyColorModeChange(colorMode);
165     }
166 }
167 
PushPage(const RefPtr<FrameNode> & node,bool needHideLast,bool needTransition,const std::function<bool ()> && pushIntentPageCallback)168 bool StageManager::PushPage(const RefPtr<FrameNode>& node, bool needHideLast, bool needTransition,
169     const std::function<bool()>&& pushIntentPageCallback)
170 {
171     CHECK_NULL_RETURN(stageNode_, false);
172     CHECK_NULL_RETURN(node, false);
173     int64_t startTime = GetSysTimestamp();
174     auto pipeline = AceType::DynamicCast<NG::PipelineContext>(PipelineBase::GetCurrentContext());
175     CHECK_NULL_RETURN(pipeline, false);
176     StopPageTransition(needTransition);
177     const auto& children = stageNode_->GetChildren();
178     RefPtr<FrameNode> outPageNode;
179     needTransition &= !children.empty();
180     if (children.empty()) {
181         auto pagePattern = node->GetPattern<NG::PagePattern>();
182         CHECK_NULL_RETURN(pagePattern, false);
183         auto pageInfo = pagePattern->GetPageInfo();
184         CHECK_NULL_RETURN(pageInfo, false);
185         auto pagePath = pageInfo->GetFullPath();
186         ACE_SCOPED_TRACE_COMMERCIAL("Router Main Page: %s", pagePath.c_str());
187         UiSessionManager::GetInstance()->OnRouterChange(pagePath, "routerPushPage");
188     }
189     if (needTransition) {
190         pipeline->FlushPipelineImmediately();
191     }
192     RefPtr<UINode> hidePageNode;
193     auto isNewLifecycle = AceApplicationInfo::GetInstance()
194         .GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE);
195     if (!children.empty() && needHideLast) {
196         hidePageNode = srcPageNode_.Upgrade();
197         outPageNode = AceType::DynamicCast<FrameNode>(hidePageNode);
198         FireAutoSave(outPageNode, node);
199         if (!isNewLifecycle) {
200             FirePageHide(hidePageNode, needTransition ? PageTransitionType::EXIT_PUSH : PageTransitionType::NONE);
201         }
202 
203     }
204     auto rect = stageNode_->GetGeometryNode()->GetFrameRect();
205     rect.SetOffset({});
206     node->GetRenderContext()->SyncGeometryProperties(rect);
207     // mount to parent and mark build render tree.
208     node->MountToParent(stageNode_);
209     // then build the total child. Build will trigger page create and onAboutToAppear
210     node->Build(nullptr);
211     // after new page aboutToAppear, jump to intentPage
212     if (pushIntentPageCallback && pushIntentPageCallback()) {
213         return true;
214     }
215     // fire new lifecycle
216     if (hidePageNode && needHideLast && isNewLifecycle) {
217         FirePageHide(hidePageNode, needTransition ? PageTransitionType::EXIT_PUSH : PageTransitionType::NONE);
218     }
219     stageNode_->RebuildRenderContextTree();
220     UpdateColorModeForPage(node);
221     FirePageShow(node, needTransition ? PageTransitionType::ENTER_PUSH : PageTransitionType::NONE);
222 
223     auto pagePattern = node->GetPattern<PagePattern>();
224     CHECK_NULL_RETURN(pagePattern, false);
225     stagePattern_->SetCurrentPageIndex(pagePattern->GetPageInfo()->GetPageId());
226     if (AceChecker::IsPerformanceCheckEnabled()) {
227         // After completing layout tasks at all nodes on the page, perform performance testing and management
228         pipeline->AddAfterLayoutTask([weakStage = WeakClaim(this), weakNode = WeakPtr<FrameNode>(node), startTime]() {
229             auto stage = weakStage.Upgrade();
230             CHECK_NULL_VOID(stage);
231             auto pageNode = weakNode.Upgrade();
232             int64_t endTime = GetSysTimestamp();
233             auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
234             CHECK_NULL_VOID(pagePattern);
235             auto pageInfo = pagePattern->GetPageInfo();
236             CHECK_NULL_VOID(pageInfo);
237             auto pagePath = pageInfo->GetFullPath();
238             stage->PerformanceCheck(pageNode, endTime - startTime, pagePath);
239         });
240     }
241 #if !defined(ACE_UNITTEST)
242     auto pageInfo = pagePattern->GetPageInfo();
243     std::string pageUrl = "";
244     if (pageInfo) {
245         pageUrl = pageInfo->GetFullPath();
246     }
247     TransparentNodeDetector::GetInstance().PostCheckNodeTransparentTask(node, pageUrl);
248 #endif
249 
250     // close keyboard
251     PageChangeCloseKeyboard();
252     AddPageTransitionTrace(outPageNode, node);
253     if (needTransition) {
254         pipeline->AddAfterLayoutTask([weakStage = WeakClaim(this), weakIn = WeakPtr<FrameNode>(node),
255                                          weakOut = WeakPtr<FrameNode>(outPageNode)]() {
256             auto stage = weakStage.Upgrade();
257             CHECK_NULL_VOID(stage);
258             auto inPageNode = weakIn.Upgrade();
259             auto outPageNode = weakOut.Upgrade();
260             stage->StartTransition(outPageNode, inPageNode, RouteType::PUSH);
261         });
262     }
263 
264     // flush layout task.
265     if (!stageNode_->GetGeometryNode()->GetMarginFrameSize().IsPositive()) {
266         // in first load case, wait for window size.
267         return true;
268     }
269     stageNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
270     node->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
271 
272     return true;
273 }
274 
InsertPage(const RefPtr<FrameNode> & node,bool bellowTopOrBottom)275 bool StageManager::InsertPage(const RefPtr<FrameNode>& node, bool bellowTopOrBottom)
276 {
277     CHECK_NULL_RETURN(stageNode_, false);
278     CHECK_NULL_RETURN(node, false);
279 
280     const auto& children = stageNode_->GetChildren();
281     if (children.empty()) {
282         return false;
283     }
284 
285     RefPtr<FrameNode> targetNode = nullptr;
286     if (bellowTopOrBottom) {
287         targetNode = AceType::DynamicCast<FrameNode>(children.back());
288     } else {
289         targetNode = AceType::DynamicCast<FrameNode>(children.front());
290     }
291     auto rect = stageNode_->GetGeometryNode()->GetFrameRect();
292     rect.SetOffset({});
293     node->GetRenderContext()->SyncGeometryProperties(rect);
294     // mount to parent and mark build render tree.
295     stageNode_->AddChildBefore(node, targetNode);
296     // then build the total child. Build will trigger page create and onAboutToAppear
297     node->Build(nullptr);
298 
299     stageNode_->RebuildRenderContextTree();
300 
301     stageNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
302     node->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
303     return true;
304 }
305 
PerformanceCheck(const RefPtr<FrameNode> & pageNode,int64_t vsyncTimeout,std::string path)306 void StageManager::PerformanceCheck(const RefPtr<FrameNode>& pageNode, int64_t vsyncTimeout, std::string path)
307 {
308     CHECK_NULL_VOID(pageNode);
309     PerformanceCheckNodeMap nodeMap;
310     pageNode->GetPerformanceCheckData(nodeMap);
311     AceScopedPerformanceCheck::RecordPerformanceCheckData(nodeMap, vsyncTimeout, path);
312 }
313 
PopPage(const RefPtr<FrameNode> & inPage,bool needShowNext,bool needTransition)314 bool StageManager::PopPage(const RefPtr<FrameNode>& inPage, bool needShowNext, bool needTransition)
315 {
316     auto pipeline = PipelineContext::GetCurrentContext();
317     CHECK_NULL_RETURN(pipeline, false);
318     CHECK_NULL_RETURN(stageNode_, false);
319     StopPageTransition(needTransition);
320     const auto& children = stageNode_->GetChildren();
321     if (children.empty()) {
322         TAG_LOGI(AceLogTag::ACE_ROUTER, "router pop page start, children is empty");
323         return false;
324     }
325     auto pageNode = srcPageNode_.Upgrade();
326     const size_t transitionPageSize = 2;
327     needTransition &= (children.size() >= transitionPageSize);
328     if (needTransition) {
329         pipeline->FlushPipelineImmediately();
330     }
331     auto outPageNode = AceType::DynamicCast<FrameNode>(pageNode);
332     auto inPageNode = needShowNext ? inPage : nullptr;
333     pipeline->GetMemoryManager()->RebuildImageByPage(inPageNode);
334     FireAutoSave(outPageNode, inPageNode);
335     FirePageHide(pageNode, needTransition ? PageTransitionType::EXIT_POP : PageTransitionType::NONE);
336     FirePageShow(inPageNode, needTransition ? PageTransitionType::ENTER_POP : PageTransitionType::NONE);
337     UpdateColorModeForPage(inPageNode);
338     // close keyboard
339     PageChangeCloseKeyboard();
340 
341     AddPageTransitionTrace(outPageNode, inPageNode);
342     if (needTransition) {
343         StartTransition(outPageNode, inPageNode, RouteType::POP);
344         if (inPageNode) {
345             inPageNode->OnAccessibilityEvent(AccessibilityEventType::CHANGE);
346         }
347         return true;
348     }
349     if (pageNode) {
350         stageNode_->RemoveChild(pageNode);
351         pageNode->SetChildrenInDestroying();
352     }
353     stageNode_->RebuildRenderContextTree();
354     pipeline->RequestFrame();
355     return true;
356 }
357 
PopPageToIndex(int32_t index,bool needShowNext,bool needTransition)358 bool StageManager::PopPageToIndex(int32_t index, bool needShowNext, bool needTransition)
359 {
360     auto pipeline = PipelineContext::GetCurrentContext();
361     CHECK_NULL_RETURN(pipeline, false);
362     CHECK_NULL_RETURN(stageNode_, false);
363     StopPageTransition(needTransition);
364     const auto& children = stageNode_->GetChildren();
365     if (children.empty()) {
366         return false;
367     }
368     int32_t popSize = static_cast<int32_t>(children.size()) - index - 1;
369     if (popSize < 0) {
370         return false;
371     }
372     if (popSize == 0) {
373         return true;
374     }
375 
376     if (needTransition) {
377         pipeline->FlushPipelineImmediately();
378     }
379     bool firstPageTransition = true;
380     auto outPageNode = AceType::DynamicCast<FrameNode>(srcPageNode_.Upgrade());
381     auto iter = children.rbegin();
382     for (int32_t current = 0; current < popSize; ++current) {
383         auto pageNode = *iter;
384         if (!needTransition|| !CheckPageInTransition(pageNode)) {
385             FirePageHide(
386                 pageNode,
387                 firstPageTransition && needTransition ?PageTransitionType::EXIT_POP : PageTransitionType::NONE);
388             firstPageTransition = false;
389         }
390         ++iter;
391     }
392 
393     RefPtr<FrameNode> inPageNode;
394     if (needShowNext) {
395         const auto& newPageNode = *iter;
396         FirePageShow(newPageNode, needTransition ? PageTransitionType::ENTER_POP : PageTransitionType::NONE);
397         inPageNode = AceType::DynamicCast<FrameNode>(newPageNode);
398         pipeline->GetMemoryManager()->RebuildImageByPage(inPageNode);
399     }
400     UpdateColorModeForPage(inPageNode);
401     PageChangeCloseKeyboard();
402     AddPageTransitionTrace(outPageNode, inPageNode);
403 
404     FireAutoSave(outPageNode, inPageNode);
405     if (needTransition) {
406         // from the penultimate node, (popSize - 1) nodes are deleted.
407         // the last node will be deleted after pageTransition
408         for (int32_t current = 1; current < popSize; ++current) {
409             auto pageNode = *(++children.rbegin());
410             if (CheckPageInTransition(pageNode)) {
411                 UpdatePageNeedRemove(pageNode);
412             } else {
413                 stageNode_->RemoveChild(pageNode);
414             }
415         }
416         stageNode_->RebuildRenderContextTree();
417         StartTransition(outPageNode, inPageNode, RouteType::POP);
418         if (inPageNode) {
419             inPageNode->OnAccessibilityEvent(AccessibilityEventType::CHANGE);
420         }
421         return true;
422     }
423     for (int32_t current = 0; current < popSize; ++current) {
424         auto pageNode = children.back();
425         stageNode_->RemoveChild(pageNode);
426     }
427     stageNode_->RebuildRenderContextTree();
428     pipeline->RequestFrame();
429     return true;
430 }
431 
CleanPageStack()432 bool StageManager::CleanPageStack()
433 {
434     auto pipeline = PipelineContext::GetCurrentContext();
435     CHECK_NULL_RETURN(pipeline, false);
436     CHECK_NULL_RETURN(stageNode_, false);
437     const auto& children = stageNode_->GetChildren();
438     if (children.size() <= 1) {
439         return false;
440     }
441     auto popSize = static_cast<int32_t>(children.size()) - 1;
442     for (int32_t count = 1; count <= popSize; ++count) {
443         auto pageNode = children.front();
444         // mark pageNode child as destroying
445         pageNode->SetChildrenInDestroying();
446         stageNode_->RemoveChild(pageNode);
447     }
448     pipeline->GetMemoryManager()->RebuildImageByPage(AceType::DynamicCast<FrameNode>(children.back()));
449     stageNode_->RebuildRenderContextTree();
450     pipeline->RequestFrame();
451     return true;
452 }
453 
MovePageToFront(const RefPtr<FrameNode> & node,bool needHideLast,bool needTransition)454 bool StageManager::MovePageToFront(const RefPtr<FrameNode>& node, bool needHideLast, bool needTransition)
455 {
456     auto pipeline = PipelineContext::GetCurrentContext();
457     CHECK_NULL_RETURN(pipeline, false);
458     CHECK_NULL_RETURN(stageNode_, false);
459     StopPageTransition(needTransition);
460     const auto& children = stageNode_->GetChildren();
461     if (children.empty()) {
462         return false;
463     }
464     const auto& lastPage = children.back();
465     if (lastPage == node) {
466         return true;
467     }
468     if (needTransition) {
469         pipeline->FlushPipelineImmediately();
470     }
471     if (needHideLast) {
472         FirePageHide(lastPage, needTransition ? PageTransitionType::EXIT_PUSH : PageTransitionType::NONE);
473     }
474     node->MovePosition(static_cast<int32_t>(stageNode_->GetChildren().size()) - 1);
475     auto pattern = node->GetPattern<PagePattern>();
476     if  (pattern) {
477         pattern->ResetPageTransitionEffect();
478     }
479     UpdateColorModeForPage(node);
480     FirePageShow(node, needTransition ? PageTransitionType::ENTER_PUSH : PageTransitionType::NONE);
481 
482     stageNode_->RebuildRenderContextTree();
483     auto outPageNode = AceType::DynamicCast<FrameNode>(lastPage);
484     AddPageTransitionTrace(outPageNode, node);
485     FireAutoSave(outPageNode, node);
486     if (needTransition) {
487         StartTransition(outPageNode, node, RouteType::PUSH);
488         if (node) {
489             node->OnAccessibilityEvent(AccessibilityEventType::CHANGE);
490         }
491     }
492     pipeline->RequestFrame();
493     return true;
494 }
495 
FirePageHide(const RefPtr<UINode> & node,PageTransitionType transitionType)496 void StageManager::FirePageHide(const RefPtr<UINode>& node, PageTransitionType transitionType)
497 {
498     auto pageNode = DynamicCast<FrameNode>(node);
499     CHECK_NULL_VOID(pageNode);
500     auto pagePattern = pageNode->GetPattern<PagePattern>();
501     CHECK_NULL_VOID(pagePattern);
502     pagePattern->FocusViewHide();
503     pagePattern->OnHide();
504     if (transitionType == PageTransitionType::NONE) {
505         // If there is a page transition, this function should execute after page transition,
506         // otherwise the page will not be visible
507         pagePattern->ProcessHideState();
508     }
509 
510     auto context = PipelineContext::GetCurrentContext();
511     CHECK_NULL_VOID(context);
512     context->MarkNeedFlushMouseEvent();
513 }
514 
FirePageShow(const RefPtr<UINode> & node,PageTransitionType transitionType,bool needFocus)515 void StageManager::FirePageShow(const RefPtr<UINode>& node, PageTransitionType transitionType, bool needFocus)
516 {
517     auto pageNode = DynamicCast<FrameNode>(node);
518     CHECK_NULL_VOID(pageNode);
519     auto layoutProperty = pageNode->GetLayoutProperty();
520 
521     auto pagePattern = pageNode->GetPattern<PagePattern>();
522     CHECK_NULL_VOID(pagePattern);
523     if (needFocus) {
524         pagePattern->FocusViewShow();
525     }
526     pagePattern->OnShow();
527     // With or without a page transition, we need to make the coming page visible first
528     pagePattern->ProcessShowState();
529 
530     auto context = PipelineContext::GetCurrentContext();
531     CHECK_NULL_VOID(context);
532     context->MarkNeedFlushMouseEvent();
533 #ifdef UICAST_COMPONENT_SUPPORTED
534     do {
535         auto container = Container::Current();
536         CHECK_NULL_BREAK(container);
537         auto distributedUI = container->GetDistributedUI();
538         CHECK_NULL_BREAK(distributedUI);
539         distributedUI->OnPageChanged(node->GetPageId());
540     } while (false);
541 #endif
542 }
543 
FireAutoSave(const RefPtr<FrameNode> & outPageNode,const RefPtr<FrameNode> & inPageNode)544 void StageManager::FireAutoSave(const RefPtr<FrameNode>& outPageNode, const RefPtr<FrameNode>& inPageNode)
545 {
546     CHECK_NULL_VOID(outPageNode);
547     auto outPagePattern = outPageNode->GetPattern<PagePattern>();
548     CHECK_NULL_VOID(outPagePattern);
549     auto onUIExtNodeDestroy = [weak = WeakPtr<FrameNode>(inPageNode)]() {
550         TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "UIExtNodeDestroy called.");
551         auto page = weak.Upgrade();
552         CHECK_NULL_VOID(page);
553         auto pattern = page->GetPattern<PagePattern>();
554         CHECK_NULL_VOID(pattern);
555         pattern->SetIsModalCovered(false);
556     };
557     auto onUIExtNodeBindingCompleted = [weak = WeakPtr<FrameNode>(inPageNode)]() {
558         TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "UIExtNodeBindingCompleted called.");
559         auto page = weak.Upgrade();
560         CHECK_NULL_VOID(page);
561         auto pattern = page->GetPattern<PagePattern>();
562         CHECK_NULL_VOID(pattern);
563         pattern->SetIsModalCovered(true);
564     };
565     outPagePattern->ProcessAutoSave(onUIExtNodeDestroy, onUIExtNodeBindingCompleted);
566 }
567 
GetLastPage() const568 RefPtr<FrameNode> StageManager::GetLastPage() const
569 {
570     CHECK_NULL_RETURN(stageNode_, nullptr);
571     const auto& children = stageNode_->GetChildren();
572     if (children.empty()) {
573         return nullptr;
574     }
575     return DynamicCast<FrameNode>(children.back());
576 }
577 
GetPageById(int32_t pageId)578 RefPtr<FrameNode> StageManager::GetPageById(int32_t pageId)
579 {
580     CHECK_NULL_RETURN(stageNode_, nullptr);
581     const auto& children = stageNode_->GetChildren();
582     for (const auto& child : children) {
583         if (child->GetPageId() == pageId) {
584             return DynamicCast<FrameNode>(child);
585         }
586     }
587     return nullptr;
588 }
589 
ReloadStage()590 void StageManager::ReloadStage()
591 {
592     CHECK_NULL_VOID(stageNode_);
593     const auto& children = stageNode_->GetChildren();
594     for (const auto& child : children) {
595         auto frameNode = DynamicCast<FrameNode>(child);
596         if (!frameNode) {
597             continue;
598         }
599         auto pagePattern = frameNode->GetPattern<PagePattern>();
600         if (!pagePattern) {
601             continue;
602         }
603         pagePattern->ReloadPage();
604     }
605 }
606 
GetLastPageWithTransition() const607 RefPtr<FrameNode> StageManager::GetLastPageWithTransition() const
608 {
609     CHECK_NULL_RETURN(stageNode_, nullptr);
610     const auto& children = stageNode_->GetChildren();
611     if (children.empty()) {
612         return nullptr;
613     }
614     auto lastChildFrame = DynamicCast<FrameNode>(children.back());
615     CHECK_NULL_RETURN(lastChildFrame, nullptr);
616     auto pagePattern = lastChildFrame->GetPattern<PagePattern>();
617     if (pagePattern && pagePattern->GetPageInTransition()) {
618         return DynamicCast<FrameNode>(destPageNode_.Upgrade());
619     }
620     return lastChildFrame;
621 }
622 
GetPrevPageWithTransition() const623 RefPtr<FrameNode> StageManager::GetPrevPageWithTransition() const
624 {
625     CHECK_NULL_RETURN(stageNode_, nullptr);
626     const auto& children = stageNode_->GetChildren();
627     if (children.empty()) {
628         return nullptr;
629     }
630     if (stageInTrasition_) {
631         return DynamicCast<FrameNode>(srcPageNode_.Upgrade());
632     }
633     return DynamicCast<FrameNode>(children.front());
634 }
635 
AddPageTransitionTrace(const RefPtr<FrameNode> & srcPage,const RefPtr<FrameNode> & destPage)636 void StageManager::AddPageTransitionTrace(const RefPtr<FrameNode>& srcPage, const RefPtr<FrameNode>& destPage)
637 {
638     if (!destPage) {
639         CHECK_NULL_VOID(srcPage);
640         // when replace with pop first, destPage node info is empty, record srcPage info and use it when push happen.
641         auto srcPattern = srcPage->GetPattern<NG::PagePattern>();
642         CHECK_NULL_VOID(srcPattern);
643         auto srcPageInfo = srcPattern->GetPageInfo();
644         CHECK_NULL_VOID(srcPageInfo);
645         replaceSrcPageInfo_ = srcPageInfo->GetFullPath();
646         TAG_LOGD(AceLogTag::ACE_ROUTER, "replace router page with pop first, record srcPage info %{public}s",
647             replaceSrcPageInfo_.c_str());
648         return;
649     }
650 
651     std::string srcFullPath = GetSrcPageInfo(srcPage);
652     if (srcFullPath.empty()) {
653         srcFullPath = replaceSrcPageInfo_.empty() ? EMPTY_PAGE_INFO : replaceSrcPageInfo_;
654         replaceSrcPageInfo_.clear();
655     }
656 
657     auto destPattern = destPage->GetPattern<NG::PagePattern>();
658     CHECK_NULL_VOID(destPattern);
659     auto destPageInfo = destPattern->GetPageInfo();
660     CHECK_NULL_VOID(destPageInfo);
661     auto destFullPath = destPageInfo->GetFullPath();
662 
663     ResSchedReport::GetInstance().HandlePageTransition(srcFullPath, destFullPath, "Router");
664     ACE_SCOPED_TRACE_COMMERCIAL("Router Page from %s to %s", srcFullPath.c_str(), destFullPath.c_str());
665 }
666 
SyncPageSafeArea(bool keyboardSafeArea)667 void StageManager::SyncPageSafeArea(bool keyboardSafeArea)
668 {
669     auto changeType = keyboardSafeArea ? PROPERTY_UPDATE_LAYOUT : PROPERTY_UPDATE_MEASURE;
670     auto lastPage = GetLastPageWithTransition();
671     CHECK_NULL_VOID(lastPage);
672     lastPage->MarkDirtyNode(changeType);
673     auto lastPageOverlay = lastPage->GetPattern<PagePattern>();
674     CHECK_NULL_VOID(lastPageOverlay);
675     lastPageOverlay->MarkDirtyOverlay();
676 
677     auto prevPage = GetPrevPageWithTransition();
678     CHECK_NULL_VOID(prevPage);
679     auto prevPageOverlay = prevPage->GetPattern<PagePattern>();
680     CHECK_NULL_VOID(prevPageOverlay);
681     prevPageOverlay->MarkDirtyOverlay();
682 }
683 
CheckPageFocus()684 bool StageManager::CheckPageFocus()
685 {
686     auto pageNode = GetLastPage();
687     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
688         pageNode = GetLastPageWithTransition();
689     }
690     CHECK_NULL_RETURN(pageNode, true);
691     return pageNode->GetFocusHub() && pageNode->GetFocusHub()->IsCurrentFocus();
692 }
693 
AbortAnimation()694 void StageManager::AbortAnimation()
695 {
696     if (!pushAnimations_.empty()) {
697         for (const auto& animation : pushAnimations_) {
698             if (animation) {
699                 AnimationUtils::StopAnimation(animation);
700             }
701         }
702         pushAnimations_.clear();
703     }
704     if (!popAnimations_.empty()) {
705         for (const auto& animation : popAnimations_) {
706             if (animation) {
707                 AnimationUtils::StopAnimation(animation);
708             }
709         }
710         popAnimations_.clear();
711     }
712 }
713 
GetSrcPageInfo(const RefPtr<FrameNode> & srcPage)714 std::string StageManager::GetSrcPageInfo(const RefPtr<FrameNode>& srcPage)
715 {
716     CHECK_NULL_RETURN(srcPage, "");
717     auto srcPattern = srcPage->GetPattern<NG::PagePattern>();
718     CHECK_NULL_RETURN(srcPattern, "");
719     auto srcPageInfo = srcPattern->GetPageInfo();
720     CHECK_NULL_RETURN(srcPageInfo, "");
721     return srcPageInfo->GetFullPath();
722 }
723 
CheckPageInTransition(const RefPtr<UINode> & pageNode)724 bool StageManager::CheckPageInTransition(const RefPtr<UINode>& pageNode)
725 {
726     auto frameNode = AceType::DynamicCast<FrameNode>(pageNode);
727     CHECK_NULL_RETURN(frameNode, false);
728     auto pagePattern = frameNode->GetPattern<PagePattern>();
729     CHECK_NULL_RETURN(pagePattern, false);
730     return pagePattern->GetPageInTransition();
731 }
732 
UpdatePageNeedRemove(const RefPtr<UINode> & pageNode)733 void StageManager::UpdatePageNeedRemove(const RefPtr<UINode>& pageNode)
734 {
735     auto frameNode = AceType::DynamicCast<FrameNode>(pageNode);
736     CHECK_NULL_VOID(frameNode);
737     auto pagePattern = frameNode->GetPattern<PagePattern>();
738     CHECK_NULL_VOID(pagePattern);
739     pagePattern->SetIsNeedRemove(true);
740 }
741 
StopPageTransition(bool needTransition)742 void StageManager::StopPageTransition(bool needTransition)
743 {
744     if (needTransition) {
745         return;
746     }
747     auto srcNode = animationSrcPage_.Upgrade();
748     if (srcNode) {
749         auto pattern = srcNode->GetPattern<PagePattern>();
750         pattern->StopPageTransition();
751         animationSrcPage_ = nullptr;
752     }
753     auto destNode = destPageNode_.Upgrade();
754     if (destNode) {
755         auto pattern = destNode->GetPattern<PagePattern>();
756         pattern->StopPageTransition();
757         destPageNode_ = nullptr;
758     }
759 }
760 
GetTopPagesWithTransition() const761 std::vector<RefPtr<FrameNode>> StageManager::GetTopPagesWithTransition() const
762 {
763     std::vector<RefPtr<FrameNode>> pages;
764     auto page = GetLastPageWithTransition();
765     if (page) {
766         pages.emplace_back(page);
767     }
768     return pages;
769 }
770 
GetTopPagePaths() const771 std::vector<std::string> StageManager::GetTopPagePaths() const
772 {
773     std::vector<std::string> paths;
774     auto pages = GetTopPagesWithTransition();
775     for (auto& page : pages) {
776         paths.emplace_back("");
777         CHECK_NULL_CONTINUE(page);
778         auto pattern = page->GetPattern<PagePattern>();
779         CHECK_NULL_CONTINUE(pattern);
780         auto info = pattern->GetPageInfo();
781         CHECK_NULL_CONTINUE(info);
782         CHECK_NULL_CONTINUE(getPagePathCallback_);
783         paths.back() = getPagePathCallback_(info->GetPageUrl());
784     }
785     return paths;
786 }
787 
GetPagePath(const RefPtr<FrameNode> & pageNode)788 std::string StageManager::GetPagePath(const RefPtr<FrameNode>& pageNode)
789 {
790     CHECK_NULL_RETURN(pageNode, "");
791     auto pattern = pageNode->GetPattern<NG::PagePattern>();
792     CHECK_NULL_RETURN(pattern, "");
793     auto info = pattern->GetPageInfo();
794     CHECK_NULL_RETURN(info, "");
795     return info->GetPagePath();
796 }
797 
SetForceSplitEnable(bool isForceSplit,const std::string & homePage,bool ignoreOrientation)798 void StageManager::SetForceSplitEnable(bool isForceSplit, const std::string& homePage, bool ignoreOrientation)
799 {
800     TAG_LOGI(AceLogTag::ACE_ROUTER, "SetForceSplitEnable, isForceSplit: %{public}u, homePage: %{public}s, "
801         "ignoreOrientation: %{public}d", isForceSplit, homePage.c_str(), ignoreOrientation);
802     //app support split mode, whether force split is enable or disable, the homepage will be recognized
803     isDetectPrimaryPage_ = true;
804     if (isForceSplit_ == isForceSplit && homePageConfig_ == homePage && ignoreOrientation_ == ignoreOrientation) {
805         return;
806     }
807     isForceSplit_ = isForceSplit;
808     homePageConfig_ = homePage;
809     ignoreOrientation_ = ignoreOrientation;
810     OnForceSplitConfigUpdate();
811 }
812 
813 } // namespace OHOS::Ace::NG
814