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