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