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