1 /*
2 * Copyright (c) 2022 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/navigation/navigation_pattern.h"
17 #include <string>
18
19 #include "base/geometry/dimension.h"
20 #include "base/log/dump_log.h"
21 #include "base/log/event_report.h"
22 #include "base/perfmonitor/perf_constants.h"
23 #include "base/perfmonitor/perf_monitor.h"
24 #include "core/common/container.h"
25 #include "core/common/ime/input_method_manager.h"
26 #include "core/common/manager_interface.h"
27 #include "core/components_ng/base/observer_handler.h"
28 #include "core/components_ng/pattern/navigation/nav_bar_layout_property.h"
29 #include "core/components_ng/pattern/navigation/nav_bar_pattern.h"
30 #include "core/components_ng/pattern/navigation/nav_bar_node.h"
31 #include "core/components_ng/pattern/navigation/navigation_drag_bar_pattern.h"
32 #include "core/components_ng/pattern/navigation/navigation_model_data.h"
33 #include "core/components_ng/pattern/navigation/title_bar_pattern.h"
34 #include "core/components_ng/pattern/stage/page_pattern.h"
35 #include "core/components_ng/pattern/text_field/text_field_manager.h"
36
37 namespace OHOS::Ace::NG {
38
39 constexpr int32_t NAVIMODE_CHANGE_ANIMATION_DURATION = 250;
40 constexpr int32_t OPACITY_ANIMATION_DURATION_APPEAR = 150;
41 constexpr int32_t OPACITY_ANIMATION_DURATION_DISAPPEAR = 250;
42 constexpr int32_t EMPTY_DESTINATION_CHILD_SIZE = 1;
43 constexpr Dimension DEFAULT_DRAG_REGION = 12.0_vp;
44 constexpr Dimension DEFAULT_DRAG_BAR_HOT_ZONE = 12.0_vp;
45 constexpr float DEFAULT_HALF = 2.0f;
46 const Color MASK_COLOR = Color::FromARGB(25, 0, 0, 0);
47 constexpr int32_t PAGE_NODES = 1000;
48 constexpr int32_t PAGE_DEPTH = 300;
49 constexpr int32_t HALF_POSITION = 50;
50 constexpr int32_t END_POSITION = 100;
51 constexpr Dimension DRAG_BAR_RADIUS = 6.0_vp;
52 constexpr Dimension DRAG_BAR_BLUR_RADIUS = 20.0_vp;
53 constexpr Dimension DRAG_BAR_ITEM_RADIUS = 1.0_vp;
54 constexpr int32_t SECOND_ZINDEX_VALUE = 2;
55 constexpr int32_t INVALID_ANIMATION_ID = -1;
56 namespace {
57 constexpr int32_t MODE_SWITCH_ANIMATION_DURATION = 500; // ms
58 const RefPtr<CubicCurve> MODE_SWITCH_CURVE = AceType::MakeRefPtr<CubicCurve>(0.2f, 0.2f, 0.1f, 1.0f);
59
CreatePercentGradientColor(int32_t percent,Color color)60 GradientColor CreatePercentGradientColor(int32_t percent, Color color)
61 {
62 NG::GradientColor gredient = GradientColor(color);
63 gredient.SetDimension(CalcDimension(percent, DimensionUnit::PERCENT));
64 return gredient;
65 }
66
BuildNavDestinationInfoFromContext(const std::string & navigationId,NavDestinationState state,const RefPtr<NavDestinationContext> & context,bool isFrom,std::optional<NavDestinationInfo> & info)67 void BuildNavDestinationInfoFromContext(const std::string& navigationId, NavDestinationState state,
68 const RefPtr<NavDestinationContext>& context, bool isFrom, std::optional<NavDestinationInfo>& info)
69 {
70 if (!context) {
71 info.reset();
72 return;
73 }
74
75 int32_t index = isFrom ? context->GetPreIndex() : context->GetIndex();
76 std::string navDestinationId = std::to_string(context->GetNavDestinationId());
77 std::string name;
78 napi_value param = nullptr;
79 auto pathInfo = context->GetNavPathInfo();
80 if (pathInfo) {
81 name = pathInfo->GetName();
82 param = pathInfo->GetParamObj();
83 }
84 NavDestinationMode mode = context->GetMode();
85 int32_t uniqueId = context->GetUniqueId();
86 info = std::make_optional<NavDestinationInfo>(navigationId, name, state, index, param,
87 navDestinationId, mode, uniqueId);
88 }
89
TriggerNavDestinationTransition(const RefPtr<NavDestinationGroupNode> & navDestination,NavigationOperation operation,bool isEnter)90 int32_t TriggerNavDestinationTransition(const RefPtr<NavDestinationGroupNode>& navDestination,
91 NavigationOperation operation, bool isEnter)
92 {
93 CHECK_NULL_RETURN(navDestination, INVALID_ANIMATION_ID);
94 return navDestination->DoTransition(operation, isEnter);
95 }
96 } // namespace
97
NavigationPattern()98 NavigationPattern::NavigationPattern()
99 {
100 navigationController_ = std::make_shared<InnerNavigationController>(WeakClaim(this), Container::CurrentId());
101 }
102
GetTitleBarRenderContext()103 RefPtr<RenderContext> NavigationPattern::GetTitleBarRenderContext()
104 {
105 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
106 CHECK_NULL_RETURN(hostNode, nullptr);
107 auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
108 CHECK_NULL_RETURN(layoutProperty, nullptr);
109 auto contentNode = AceType::DynamicCast<FrameNode>(hostNode->GetContentNode());
110 CHECK_NULL_RETURN(contentNode, nullptr);
111 if (contentNode->FindChildNodeOfClass<NavDestinationGroupNode>()) {
112 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
113 CHECK_NULL_RETURN(navBarNode, nullptr);
114 auto renderContext = navBarNode->GetRenderContext();
115 return renderContext;
116 } else {
117 auto renderContext = contentNode->GetRenderContext();
118 return renderContext;
119 }
120 }
121
DoAnimation(NavigationMode usrNavigationMode)122 void NavigationPattern::DoAnimation(NavigationMode usrNavigationMode)
123 {
124 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
125 CHECK_NULL_VOID(hostNode);
126 auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
127 CHECK_NULL_VOID(layoutProperty);
128
129 auto context = PipelineContext::GetCurrentContext();
130 CHECK_NULL_VOID(context);
131 layoutProperty->UpdateNavigationMode(navigationMode_);
132 hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
133 AnimationOption option = AnimationOption();
134 option.SetDuration(NAVIMODE_CHANGE_ANIMATION_DURATION);
135 option.SetCurve(Curves::FRICTION);
136 option.SetFillMode(FillMode::FORWARDS);
137 AnimationOption optionAlpha = AnimationOption();
138 optionAlpha.SetCurve(Curves::SHARP);
139 optionAlpha.SetFillMode(FillMode::FORWARDS);
140 auto renderContext = GetTitleBarRenderContext();
141 CHECK_NULL_VOID(renderContext);
142
143 std::function<void()> finishCallback = [optionAlpha, renderContext, hostNode]() {
144 renderContext->OpacityAnimation(optionAlpha, 0, 1);
145 hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
146 };
147
148 context->OpenImplicitAnimation(option, option.GetCurve(), finishCallback);
149 layoutProperty->UpdateNavigationMode(usrNavigationMode);
150 hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
151 context->FlushUITasks();
152 if (usrNavigationMode == NavigationMode::STACK || navigationMode_ == NavigationMode::SPLIT) {
153 optionAlpha.SetDuration(OPACITY_ANIMATION_DURATION_DISAPPEAR);
154 renderContext->OpacityAnimation(optionAlpha, 1, 0);
155 } else if (usrNavigationMode == NavigationMode::SPLIT || navigationMode_ == NavigationMode::STACK) {
156 optionAlpha.SetDuration(OPACITY_ANIMATION_DURATION_APPEAR);
157 renderContext->OpacityAnimation(optionAlpha, 0, 1);
158 }
159 context->CloseImplicitAnimation();
160 navigationMode_ = usrNavigationMode;
161 }
162
OnAttachToFrameNode()163 void NavigationPattern::OnAttachToFrameNode()
164 {
165 auto host = GetHost();
166 CHECK_NULL_VOID(host);
167 auto pipelineContext = PipelineContext::GetCurrentContext();
168 CHECK_NULL_VOID(pipelineContext);
169 pipelineContext->AddWindowStateChangedCallback(host->GetId());
170 pipelineContext->AddWindowSizeChangeCallback(host->GetId());
171
172 auto theme = NavigationGetTheme();
173 if (theme && theme->GetNavBarUnfocusEffectEnable()) {
174 pipelineContext->AddWindowFocusChangedCallback(host->GetId());
175 }
176 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
177 SafeAreaExpandOpts opts = { .type = SAFE_AREA_TYPE_ALL, .edges = SAFE_AREA_EDGE_ALL };
178 host->GetLayoutProperty()->UpdateSafeAreaExpandOpts(opts);
179 }
180 }
181
OnDetachFromFrameNode(FrameNode * frameNode)182 void NavigationPattern::OnDetachFromFrameNode(FrameNode* frameNode)
183 {
184 auto id = frameNode->GetId();
185 auto pipeline = AceType::DynamicCast<PipelineContext>(PipelineBase::GetCurrentContext());
186 CHECK_NULL_VOID(pipeline);
187 pipeline->RemoveWindowStateChangedCallback(id);
188 pipeline->RemoveWindowSizeChangeCallback(id);
189 }
190
191
DoNavbarHideAnimation(const RefPtr<NavigationGroupNode> & hostNode)192 void NavigationPattern::DoNavbarHideAnimation(const RefPtr<NavigationGroupNode>& hostNode)
193 {
194 AnimationOption option;
195 option.SetCurve(MODE_SWITCH_CURVE);
196 option.SetFillMode(FillMode::FORWARDS);
197 option.SetDuration(MODE_SWITCH_ANIMATION_DURATION);
198 AnimationUtils::Animate(option, [weakHost = WeakPtr<NavigationGroupNode>(hostNode)]() {
199 auto hostNode = weakHost.Upgrade();
200 CHECK_NULL_VOID(hostNode);
201 auto layoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(hostNode->GetLayoutProperty());
202 CHECK_NULL_VOID(layoutProperty);
203 bool hideNavBar = layoutProperty->GetHideNavBarValue(false);
204 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
205 CHECK_NULL_VOID(navBarNode);
206 auto navBarLayoutProperty = navBarNode->GetLayoutProperty();
207 CHECK_NULL_VOID(navBarLayoutProperty);
208 navBarLayoutProperty->UpdateVisibility(hideNavBar ? VisibleType::INVISIBLE : VisibleType::VISIBLE, true);
209 hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
210 hostNode->GetContext()->FlushUITasks();
211 });
212 }
213
InitDragBarEvent()214 void NavigationPattern::InitDragBarEvent()
215 {
216 auto dragBarNode = AceType::DynamicCast<FrameNode>(GetDragBarNode());
217 CHECK_NULL_VOID(dragBarNode);
218 auto dragGestureHub = dragBarNode->GetOrCreateGestureEventHub();
219 CHECK_NULL_VOID(dragGestureHub);
220 InitDragBarPanEvent(dragGestureHub);
221 InitTouchEvent(dragGestureHub);
222
223 // clear divider hover and pan event
224 auto dividerNode = GetDividerNode();
225 CHECK_NULL_VOID(dividerNode);
226 auto dividerGestureHub = dividerNode->GetOrCreateGestureEventHub();
227 CHECK_NULL_VOID(dividerGestureHub);
228 auto dividerInputHub = dividerNode->GetOrCreateInputEventHub();
229 CHECK_NULL_VOID(dividerInputHub);
230 if (hoverEvent_) {
231 dividerInputHub->RemoveOnHoverEvent(hoverEvent_);
232 hoverEvent_.Reset();
233 }
234 if (panEvent_) {
235 dividerGestureHub->RemovePanEvent(panEvent_);
236 panEvent_.Reset();
237 }
238 }
239
ClearDragBarEvent()240 void NavigationPattern::ClearDragBarEvent()
241 {
242 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
243 CHECK_NULL_VOID(hostNode);
244 auto dragBarNode = AceType::DynamicCast<FrameNode>(GetDragBarNode());
245 CHECK_NULL_VOID(dragBarNode);
246 auto dragGestureHub = dragBarNode->GetOrCreateGestureEventHub();
247 CHECK_NULL_VOID(dragGestureHub);
248
249 // clear drag bar touch and pan event
250 if (touchEvent_) {
251 dragGestureHub->RemoveTouchEvent(touchEvent_);
252 touchEvent_.Reset();
253 }
254 if (dragBarPanEvent_) {
255 dragGestureHub->RemovePanEvent(dragBarPanEvent_);
256 dragBarPanEvent_.Reset();
257 }
258
259 hostNode->RemoveChild(dragBarNode);
260 hostNode->SetDragBarNode(nullptr);
261 }
262
BuildDragBar()263 void NavigationPattern::BuildDragBar()
264 {
265 if (!AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TEN)) {
266 return;
267 }
268 if (enableDragBar_) {
269 if (GetDragBarNode()) {
270 // if dragBar is already in navigation, do nothing
271 return;
272 }
273 // create drag bar and init drag bar gesture event
274 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
275 CHECK_NULL_VOID(hostNode);
276 CreateDragBarNode(hostNode);
277 InitDragBarEvent();
278 return;
279 }
280 auto dividerNode = GetDividerNode();
281 CHECK_NULL_VOID(dividerNode);
282 auto dividerGestureHub = dividerNode->GetOrCreateGestureEventHub();
283 CHECK_NULL_VOID(dividerGestureHub);
284 auto dividerInputHub = dividerNode->GetOrCreateInputEventHub();
285 CHECK_NULL_VOID(dividerInputHub);
286 InitDividerPanEvent(dividerGestureHub);
287 InitDividerMouseEvent(dividerInputHub);
288 if (GetDragBarNode()) {
289 // clear drag bar gesture event and remove dragBar
290 ClearDragBarEvent();
291 }
292 }
293
OnModifyDone()294 void NavigationPattern::OnModifyDone()
295 {
296 // !!! Do not add operations about NavPathStack here, see @SyncWithJsStackIfNeeded
297 Pattern::OnModifyDone();
298 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
299 CHECK_NULL_VOID(hostNode);
300 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
301 CHECK_NULL_VOID(navBarNode);
302 navBarNode->MarkModifyDone();
303 isRightToLeft_ = AceApplicationInfo::GetInstance().IsRightToLeft();
304
305 auto pipeline = PipelineContext::GetCurrentContext();
306 CHECK_NULL_VOID(pipeline);
307 BuildDragBar();
308
309 auto layoutProperty = hostNode->GetLayoutProperty<NavigationLayoutProperty>();
310 CHECK_NULL_VOID(layoutProperty);
311 auto&& opts = layoutProperty->GetSafeAreaExpandOpts();
312 if (opts) {
313 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "Navigation SafArea expand as %{public}s", opts->ToString().c_str());
314 uint8_t ignoreExpandKeyboard = 0x11;
315 SafeAreaExpandOpts optsExceptKeyboard = { .type = opts->type & ignoreExpandKeyboard,
316 .edges = opts->edges };
317 navBarNode->GetLayoutProperty()->UpdateSafeAreaExpandOpts(optsExceptKeyboard);
318 navBarNode->MarkModifyDone();
319
320 auto navigationContentNode = AceType::DynamicCast<FrameNode>(hostNode->GetContentNode());
321 CHECK_NULL_VOID(navigationContentNode);
322 navigationContentNode->GetLayoutProperty()->UpdateSafeAreaExpandOpts(optsExceptKeyboard);
323 navigationContentNode->MarkModifyDone();
324
325 auto dividerNode = AceType::DynamicCast<FrameNode>(hostNode->GetDividerNode());
326 CHECK_NULL_VOID(dividerNode);
327 dividerNode->GetLayoutProperty()->UpdateSafeAreaExpandOpts(optsExceptKeyboard);
328 dividerNode->MarkModifyDone();
329 }
330
331 bool enableModeChangeAnimation = layoutProperty->GetEnableModeChangeAnimation().value_or(true);
332 if (enableModeChangeAnimation && GetNavigationMode() == NavigationMode::SPLIT && GetNavBarVisibilityChange()) {
333 DoNavbarHideAnimation(hostNode);
334 }
335
336 // AddRecoverableNavigation function will check inside whether current navigation can be recovered
337 pipeline->GetNavigationManager()->AddRecoverableNavigation(hostNode->GetCurId(), hostNode);
338 RestoreJsStackIfNeeded();
339 }
340
SetSystemBarStyle(const RefPtr<SystemBarStyle> & style)341 void NavigationPattern::SetSystemBarStyle(const RefPtr<SystemBarStyle>& style)
342 {
343 auto host = GetHost();
344 CHECK_NULL_VOID(host);
345 auto pipeline = host->GetContext();
346 CHECK_NULL_VOID(pipeline);
347 auto windowManager = pipeline->GetWindowManager();
348 CHECK_NULL_VOID(windowManager);
349 if (!backupStyle_.has_value()) {
350 backupStyle_ = windowManager->GetSystemBarStyle();
351 }
352 currStyle_ = style;
353
354 // The systemBarStyle may only take effect when navigation fills the entire page.
355 if (!isFullPageNavigation_) {
356 return;
357 }
358
359 // When there is NavDestination in the stack, the systemBarStyle set for Navigation does not take effect.
360 do {
361 if (!navigationStack_) {
362 break;
363 }
364 auto topPath = navigationStack_->GetTopNavPath();
365 if (!topPath.has_value()) {
366 break;
367 }
368 auto topNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
369 NavigationGroupNode::GetNavDestinationNode(topPath->second));
370 if (topNavDestination) {
371 return;
372 }
373 } while (false);
374
375 /**
376 * When developers provide a valid style to systemBarStyle, we should set the style to window;
377 * when 'undefined' was provided, we should restore the style.
378 */
379 if (currStyle_.value() != nullptr) {
380 windowManager->SetSystemBarStyle(currStyle_.value());
381 } else {
382 TryRestoreSystemBarStyle(windowManager);
383 }
384 }
385
OnAttachToMainTree()386 void NavigationPattern::OnAttachToMainTree()
387 {
388 auto host = GetHost();
389 CHECK_NULL_VOID(host);
390 InitPageNode(host);
391 InitFoldState();
392 }
393
InitFoldState()394 void NavigationPattern::InitFoldState()
395 {
396 auto container = Container::Current();
397 CHECK_NULL_VOID(container);
398 container->InitIsFoldable();
399 if (container->IsFoldable()) {
400 currentFoldStatus_ = container->GetCurrentFoldStatus();
401 }
402 }
403
OnDetachFromMainTree()404 void NavigationPattern::OnDetachFromMainTree()
405 {
406 isFullPageNavigation_ = false;
407 auto host = GetHost();
408 CHECK_NULL_VOID(host);
409 auto pipeline = host->GetContext();
410 CHECK_NULL_VOID(pipeline);
411 auto windowManager = pipeline->GetWindowManager();
412 CHECK_NULL_VOID(windowManager);
413 TryRestoreSystemBarStyle(windowManager);
414 backupStyle_.reset();
415 currStyle_.reset();
416 pageNode_ = nullptr;
417 }
418
IsTopNavDestination(const RefPtr<UINode> & node) const419 bool NavigationPattern::IsTopNavDestination(const RefPtr<UINode>& node) const
420 {
421 if (!navigationStack_) {
422 return false;
423 }
424 auto topPath = navigationStack_->GetTopNavPath();
425 if (!topPath.has_value()) {
426 return false;
427 }
428 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(
429 NavigationGroupNode::GetNavDestinationNode(topPath->second));
430 return navDestination == node;
431 }
432
JudgeFoldStateChangeAndUpdateState()433 bool NavigationPattern::JudgeFoldStateChangeAndUpdateState()
434 {
435 auto container = Container::Current();
436 CHECK_NULL_RETURN(container, false);
437 auto foldStatus = container->GetCurrentFoldStatus();
438 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "newFoldStatus: %{public}d, currentFoldStatus: %{public}d.",
439 static_cast<int32_t>(foldStatus), static_cast<int32_t>(currentFoldStatus_));
440 if (foldStatus != currentFoldStatus_) {
441 currentFoldStatus_ = foldStatus;
442 return true;
443 }
444 return false;
445 }
446
UpdateIsFullPageNavigation(const RefPtr<FrameNode> & host)447 void NavigationPattern::UpdateIsFullPageNavigation(const RefPtr<FrameNode>& host)
448 {
449 CHECK_NULL_VOID(host);
450 auto geometryNode = host->GetGeometryNode();
451 CHECK_NULL_VOID(geometryNode);
452 auto frame = geometryNode->GetFrameRect();
453 auto pipeline = host->GetContext();
454 CHECK_NULL_VOID(pipeline);
455 auto windowManager = pipeline->GetWindowManager();
456 CHECK_NULL_VOID(windowManager);
457
458 bool isFullPage = false;
459 auto pageNode = pageNode_.Upgrade();
460 if (pageNode) {
461 auto pageNodeGeometryNode = pageNode->GetGeometryNode();
462 if (pageNodeGeometryNode) {
463 auto pageFrame = pageNodeGeometryNode->GetFrameRect();
464 isFullPage = pageFrame.GetSize() == frame.GetSize();
465 }
466 }
467 pageNode = nullptr;
468
469 if (isFullPage == isFullPageNavigation_) {
470 return;
471 }
472
473 isFullPageNavigation_ = isFullPage;
474 UpdateSystemBarStyleOnFullPageStateChange(windowManager);
475 if (isFullPageNavigation_) {
476 RegisterPageVisibilityChangeCallback();
477 }
478 }
479
UpdateSystemBarStyleOnFullPageStateChange(const RefPtr<WindowManager> & windowManager)480 void NavigationPattern::UpdateSystemBarStyleOnFullPageStateChange(const RefPtr<WindowManager>& windowManager)
481 {
482 // full page -> partial page
483 if (!isFullPageNavigation_) {
484 TryRestoreSystemBarStyle(windowManager);
485 return;
486 }
487
488 // partial page -> full page
489 auto topPath = navigationStack_->GetTopNavPath();
490 UpdateSystemBarStyleWithTopNavPath(windowManager, topPath);
491 }
492
UpdateSystemBarStyleOnTopNavPathChange(const std::optional<std::pair<std::string,RefPtr<UINode>>> & newTopNavPath)493 void NavigationPattern::UpdateSystemBarStyleOnTopNavPathChange(
494 const std::optional<std::pair<std::string, RefPtr<UINode>>>& newTopNavPath)
495 {
496 if (!isFullPageNavigation_) {
497 return;
498 }
499
500 auto host = GetHost();
501 CHECK_NULL_VOID(host);
502 auto pipeline = host->GetContext();
503 CHECK_NULL_VOID(pipeline);
504 auto windowManager = pipeline->GetWindowManager();
505 CHECK_NULL_VOID(windowManager);
506 UpdateSystemBarStyleWithTopNavPath(windowManager, newTopNavPath);
507 }
508
UpdateSystemBarStyleWithTopNavPath(const RefPtr<WindowManager> & windowManager,const std::optional<std::pair<std::string,RefPtr<UINode>>> & topNavPath)509 void NavigationPattern::UpdateSystemBarStyleWithTopNavPath(const RefPtr<WindowManager>& windowManager,
510 const std::optional<std::pair<std::string, RefPtr<UINode>>>& topNavPath)
511 {
512 if (ApplyTopNavPathSystemBarStyleOrRestore(windowManager, topNavPath)) {
513 return;
514 }
515
516 if (currStyle_.has_value() && currStyle_.value() != nullptr) {
517 windowManager->SetSystemBarStyle(currStyle_.value());
518 } else {
519 TryRestoreSystemBarStyle(windowManager);
520 }
521 }
522
TryRestoreSystemBarStyle(const RefPtr<WindowManager> & windowManager)523 void NavigationPattern::TryRestoreSystemBarStyle(const RefPtr<WindowManager>& windowManager)
524 {
525 if (backupStyle_.has_value()) {
526 windowManager->SetSystemBarStyle(backupStyle_.value());
527 }
528 }
529
UpdateSystemBarStyleOnPageVisibilityChange(bool show)530 void NavigationPattern::UpdateSystemBarStyleOnPageVisibilityChange(bool show)
531 {
532 if (!isFullPageNavigation_) {
533 return;
534 }
535
536 CHECK_NULL_VOID(navigationStack_);
537 auto host = GetHost();
538 CHECK_NULL_VOID(host);
539 auto pipeline = host->GetContext();
540 CHECK_NULL_VOID(pipeline);
541 auto windowManager = pipeline->GetWindowManager();
542 CHECK_NULL_VOID(windowManager);
543 if (show) {
544 // page containing Navigation, hide -> show
545 auto topPath = navigationStack_->GetTopNavPath();
546 UpdateSystemBarStyleWithTopNavPath(windowManager, topPath);
547 } else {
548 // page containing Navigation, show -> hide
549 TryRestoreSystemBarStyle(windowManager);
550 }
551 }
552
RegisterPageVisibilityChangeCallback()553 void NavigationPattern::RegisterPageVisibilityChangeCallback()
554 {
555 auto pageNode = pageNode_.Upgrade();
556 CHECK_NULL_VOID(pageNode);
557 RefPtr<PagePattern> pagePattern = pageNode->GetPattern<PagePattern>();
558 CHECK_NULL_VOID(pagePattern);
559 auto callback = [weak = WeakClaim(this)](bool show) {
560 auto pattern = weak.Upgrade();
561 CHECK_NULL_VOID(pattern);
562 // we need update the "systemBarStyle" at the beginning of the transition animation on the router page
563 pattern->UpdateSystemBarStyleOnPageVisibilityChange(show);
564 };
565 pagePattern->SetPageVisibilityChangeCallback(std::move(callback));
566 }
567
ApplyTopNavPathSystemBarStyleOrRestore(const RefPtr<WindowManager> & windowManager,const std::optional<std::pair<std::string,RefPtr<UINode>>> & topNavPath)568 bool NavigationPattern::ApplyTopNavPathSystemBarStyleOrRestore(
569 const RefPtr<WindowManager>& windowManager,
570 const std::optional<std::pair<std::string, RefPtr<UINode>>>& topNavPath)
571 {
572 if (!topNavPath.has_value()) {
573 return false;
574 }
575
576 auto topNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
577 NavigationGroupNode::GetNavDestinationNode(topNavPath->second));
578 if (!topNavDestination) {
579 return false;
580 }
581
582 auto navDestinationPattern = topNavDestination->GetPattern<NavDestinationPattern>();
583 if (!navDestinationPattern) {
584 return false;
585 }
586 /**
587 * Backup is only performed when the developer sets the "systemBarStyle" attribute,
588 * and the entire Navigation is only backed up once.
589 * Therefore, when developer only set the "systemBarStyle" attribute to NavDestination, we need to
590 * save the attribute to Navigation.
591 */
592 auto backupFromNavDestination = navDestinationPattern->GetBackupStyle();
593 if (!backupStyle_.has_value() && backupFromNavDestination.has_value()) {
594 backupStyle_ = backupFromNavDestination;
595 }
596
597 auto destCurrStyle = navDestinationPattern->GetCurrentStyle();
598 if (destCurrStyle.has_value() && destCurrStyle.value() != nullptr) {
599 windowManager->SetSystemBarStyle(destCurrStyle.value());
600 } else {
601 TryRestoreSystemBarStyle(windowManager);
602 }
603 return true;
604 }
605
InitPageNode(const RefPtr<FrameNode> & host)606 void NavigationPattern::InitPageNode(const RefPtr<FrameNode>& host)
607 {
608 CHECK_NULL_VOID(host);
609 auto parent = host->GetParent();
610 CHECK_NULL_VOID(parent);
611 RefPtr<FrameNode> pageNode = nullptr;
612 while (parent) {
613 if (parent->GetTag() == V2::PAGE_ETS_TAG) {
614 pageNode = AceType::DynamicCast<FrameNode>(parent);
615 break;
616 }
617 parent = parent->GetParent();
618 }
619 if (!pageNode) {
620 TAG_LOGE(AceLogTag::ACE_NAVIGATION, "Failed to find PageNode of Navigation");
621 } else {
622 pageNode_ = WeakPtr<FrameNode>(pageNode);
623 }
624 }
625
OnLanguageConfigurationUpdate()626 void NavigationPattern::OnLanguageConfigurationUpdate()
627 {
628 bool isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft();
629 if (isRightToLeft != isRightToLeft_) {
630 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
631 CHECK_NULL_VOID(hostNode);
632 hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
633 isRightToLeft_ = isRightToLeft;
634 }
635 }
636
SyncWithJsStackIfNeeded()637 void NavigationPattern::SyncWithJsStackIfNeeded()
638 {
639 if (!needSyncWithJsStack_) {
640 TAG_LOGI(AceLogTag::ACE_NAVIGATION,
641 "not need SyncWithJsStack, needSyncWithJsStack_ %{public}d", needSyncWithJsStack_);
642 return;
643 }
644 CHECK_NULL_VOID(navigationStack_);
645 needSyncWithJsStack_ = false;
646 if (!isFinishInteractiveAnimation_) {
647 TAG_LOGI(AceLogTag::ACE_NAVIGATION,
648 "not need SyncWithJsStack, interactive animation: %{public}d", isFinishInteractiveAnimation_);
649 return;
650 }
651 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "sync with js stack");
652 preTopNavPath_ = navigationStack_->GetPreTopNavPath();
653 preStackSize_ = navigationStack_->PreSize();
654
655 preContext_ = nullptr;
656 if (preTopNavPath_.has_value()) {
657 auto preDestination = AceType::DynamicCast<NavDestinationGroupNode>(
658 NavigationGroupNode::GetNavDestinationNode(preTopNavPath_->second));
659 if (preDestination) {
660 auto pattern = AceType::DynamicCast<NavDestinationPattern>(preDestination->GetPattern());
661 preContext_ = pattern->GetNavDestinationContext();
662 if (preContext_) {
663 preContext_->SetPreIndex(preStackSize_ - 1);
664 }
665 }
666 }
667 if (isCustomAnimation_) {
668 navigationStack_->UpdateRecoveryList();
669 }
670 UpdateNavPathList();
671 auto newTopNavPath = navigationStack_->GetTopNavPath();
672 auto replaceValue = navigationStack_->GetReplaceValue();
673 if (preTopNavPath_ != newTopNavPath || replaceValue == 1) {
674 isReplace_ = replaceValue != 0;
675 UpdateIsAnimation(preTopNavPath_);
676 lastPreIndex_ = 0;
677 if (preTopNavPath_.has_value()) {
678 lastPreIndex_ = navigationStack_->FindIndex(preTopNavPath_->first,
679 preTopNavPath_->second, true);
680 }
681 FireInterceptionEvent(true, newTopNavPath);
682 if (needSyncWithJsStack_) {
683 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "sync with js stack in before interception");
684 UpdateNavPathList();
685 needSyncWithJsStack_ = false;
686 }
687 }
688 RefreshNavDestination();
689 }
690
UpdateNavPathList()691 void NavigationPattern::UpdateNavPathList()
692 {
693 CHECK_NULL_VOID(navigationStack_);
694 auto pathNames = navigationStack_->GetAllPathName();
695 auto indexes = navigationStack_->GetAllPathIndex();
696 auto cacheNodes = navigationStack_->GetAllCacheNodes();
697 NavPathList navPathList;
698 int32_t pathListSize = static_cast<int32_t>(pathNames.size());
699 isCurTopNewInstance_ = false;
700 // lastRecoveredStandardIndex will be only used in recovery case
701 int32_t lastRecoveredStandardIndex = 0;
702 for (int32_t index = 0; index < pathListSize; ++index) {
703 auto pathName = pathNames[index];
704 RefPtr<UINode> uiNode = nullptr;
705 if (navigationStack_->IsFromRecovery(index)) {
706 if (navigationStack_->GetRecoveredDestinationMode(index) ==
707 static_cast<int32_t>(NavDestinationMode::STANDARD)) {
708 lastRecoveredStandardIndex = index;
709 }
710 navPathList.emplace_back(std::make_pair(pathName, uiNode));
711 // only create recovery node when it is at top
712 if (index == pathListSize - 1) {
713 GenerateUINodeFromRecovery(lastRecoveredStandardIndex, navPathList);
714 }
715 continue;
716 }
717 auto pathIndex = indexes[index];
718 if (navigationStack_->NeedBuildNewInstance(index)) {
719 // if marked NEW_INSTANCE when push/replace in frontend, build a new instance anyway
720 uiNode = GenerateUINodeByIndex(index);
721 navPathList.emplace_back(std::make_pair(pathName, uiNode));
722 navigationStack_->SetNeedBuildNewInstance(index, false);
723 if (index == pathListSize - 1) {
724 isCurTopNewInstance_ = true;
725 }
726 continue;
727 }
728 if (index == pathListSize - 1 && addByNavRouter_) {
729 addByNavRouter_ = false;
730 uiNode = navigationStack_->Get();
731 } else {
732 uiNode = navigationStack_->Get(pathIndex);
733 }
734 if (uiNode) {
735 TAG_LOGD(AceLogTag::ACE_NAVIGATION, "find in list, navigation stack reserve node, "
736 "old index: %{public}d, index: %{public}d, name: %{public}s.",
737 pathIndex, index, pathName.c_str());
738 /**
739 * If we call the function pushPath/pushDestination with singleton mode(
740 * LaunchMode == MOVE_TO_TOP_SINGLETON/POP_TO_SINGLETON), and the top NavDestination of stack
741 * is the NavDestination which we need to push(NavDestination's name == NavPathInfo's name),
742 * then wee need to update the NavDestination's parameters.
743 */
744 navigationStack_->UpdatePathInfoIfNeeded(uiNode, index);
745 auto navDestinationGroupNode = AceType::DynamicCast<NavDestinationGroupNode>(
746 NavigationGroupNode::GetNavDestinationNode(uiNode));
747 if (navDestinationGroupNode && navDestinationGroupNode->GetCanReused()) {
748 navPathList.emplace_back(std::make_pair(pathName, uiNode));
749 continue;
750 }
751 }
752 uiNode = navigationStack_->GetFromCacheNode(cacheNodes, pathName);
753 if (uiNode) {
754 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "find in cached node, navigation stack reserve node, "
755 "index: %{public}d, name: %{public}s.", index, pathName.c_str());
756 navPathList.emplace_back(std::make_pair(pathName, uiNode));
757 navigationStack_->RemoveCacheNode(cacheNodes, pathName, uiNode);
758 auto navDestination =
759 DynamicCast<NavDestinationGroupNode>(NavigationGroupNode::GetNavDestinationNode(uiNode));
760 if (navDestination) {
761 auto eventHub = navDestination->GetEventHub<EventHub>();
762 CHECK_NULL_VOID(eventHub);
763 eventHub->SetEnabledInternal(true);
764 }
765 continue;
766 }
767 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "find in nowhere, navigation stack create new node, "
768 "index: %{public}d, name: %{public}s.", index, pathName.c_str());
769 uiNode = GenerateUINodeByIndex(index);
770 navPathList.emplace_back(std::make_pair(pathName, uiNode));
771 }
772 navigationStack_->ClearPreBuildNodeList();
773 navigationStack_->SetNavPathList(navPathList);
774 navigationStack_->InitNavPathIndex(pathNames);
775 }
776
RefreshNavDestination()777 void NavigationPattern::RefreshNavDestination()
778 {
779 isChanged_ = false;
780 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
781 CHECK_NULL_VOID(hostNode);
782 auto pipeline = PipelineContext::GetCurrentContext();
783 CHECK_NULL_VOID(pipeline);
784 auto preTopNavPath = std::move(preTopNavPath_);
785 auto preLastStandardIndex = hostNode->GetLastStandardIndex();
786 auto& navPathList = navigationStack_->GetAllNavDestinationNodes();
787 hostNode->UpdateNavDestinationNodeWithoutMarkDirty(
788 preTopNavPath.has_value() ? preTopNavPath->second : nullptr, navigationModeChange_);
789 auto newTopNavPath = navigationStack_->GetTopNavPath();
790 #if defined(ENABLE_NAV_SPLIT_MODE)
791 isBackPage_ = newTopNavPath.has_value() ?
792 navigationStack_->isLastListContains(newTopNavPath->first, newTopNavPath->second) : false;
793 #endif
794 std::string navDestinationName = "";
795 CheckTopNavPathChange(preTopNavPath, newTopNavPath, preLastStandardIndex);
796
797 // close keyboard
798 #if defined(ENABLE_STANDARD_INPUT)
799 RefPtr<FrameNode> targetNode = newTopNavPath.has_value() ? AceType::DynamicCast<FrameNode>(
800 NavigationGroupNode::GetNavDestinationNode(newTopNavPath->second)) :
801 AceType::DynamicCast<FrameNode>(hostNode->GetNavBarNode());
802 if (isChanged_ && GetIsFocusable(targetNode)) {
803 InputMethodManager::GetInstance()->CloseKeyboard();
804 }
805 #endif
806
807 #if defined(ENABLE_NAV_SPLIT_MODE)
808 navigationStack_->SetLastNavPathList(navPathList);
809 #endif
810
811 /* if first navDestination is removed, the new one will be refreshed */
812 if (!navPathList.empty()) {
813 auto firstNavDesNode = AceType::DynamicCast<NavDestinationGroupNode>(
814 NavigationGroupNode::GetNavDestinationNode(navPathList.front().second));
815 CHECK_NULL_VOID(firstNavDesNode);
816 firstNavDesNode->MarkModifyDone();
817 }
818
819 if (newTopNavPath.has_value()) {
820 navDestinationName = newTopNavPath->first;
821 }
822 pipeline->AddPredictTask([weak = WeakClaim(this), weakNode = WeakPtr<FrameNode>(hostNode),
823 navDestinationName](int64_t deadline, bool canUseLongPredictTask) {
824 auto navigationPattern = weak.Upgrade();
825 CHECK_NULL_VOID(navigationPattern);
826 auto navigationNode = weakNode.Upgrade();
827 CHECK_NULL_VOID(navigationNode);
828 int32_t count = 0;
829 int32_t depth = 0;
830 navigationNode->GetPageNodeCountAndDepth(&count, &depth);
831 navigationPattern->PerformanceEventReport(count, depth, navDestinationName);
832 });
833 }
834
CheckTopNavPathChange(const std::optional<std::pair<std::string,RefPtr<UINode>>> & preTopNavPath,const std::optional<std::pair<std::string,RefPtr<UINode>>> & newTopNavPath,int32_t preLastStandardIndex)835 void NavigationPattern::CheckTopNavPathChange(
836 const std::optional<std::pair<std::string, RefPtr<UINode>>>& preTopNavPath,
837 const std::optional<std::pair<std::string, RefPtr<UINode>>>& newTopNavPath,
838 int32_t preLastStandardIndex)
839 {
840 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
841 CHECK_NULL_VOID(hostNode);
842 if (preTopNavPath != newTopNavPath) {
843 UpdateSystemBarStyleOnTopNavPathChange(newTopNavPath);
844 }
845 auto replaceValue = navigationStack_->GetReplaceValue();
846 if (preTopNavPath == newTopNavPath && replaceValue != 1) {
847 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "page is not change. don't transition");
848 auto currentProxy = GetTopNavigationProxy();
849 if (currentProxy) {
850 currentProxy->SetIsSuccess(false);
851 }
852 hostNode->FireHideNodeChange(NavDestinationLifecycle::ON_WILL_HIDE);
853 NotifyDialogChange(NavDestinationLifecycle::ON_WILL_SHOW, true, true);
854 auto pipeline = PipelineContext::GetCurrentContext();
855 CHECK_NULL_VOID(pipeline);
856 pipeline->AddAfterLayoutTask([weakPattern = WeakClaim(this)]() {
857 auto pattern = weakPattern.Upgrade();
858 CHECK_NULL_VOID(pattern);
859 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(pattern->GetHost());
860 CHECK_NULL_VOID(hostNode);
861 hostNode->FireHideNodeChange(NavDestinationLifecycle::ON_HIDE);
862 hostNode->FireHideNodeChange(NavDestinationLifecycle::ON_WILL_DISAPPEAR);
863 pattern->NotifyDialogChange(NavDestinationLifecycle::ON_SHOW, true, true);
864 hostNode->RemoveDialogDestination();
865 });
866 navigationStack_->ClearRecoveryList();
867 return;
868 }
869
870 isChanged_ = true;
871 UpdateIsAnimation(preTopNavPath);
872 isReplace_ = replaceValue != 0;
873 if (replaceValue == 1) {
874 const int32_t replaceAnimation = 2;
875 navigationStack_->UpdateReplaceValue(replaceAnimation);
876 }
877 auto contentNode = hostNode->GetContentNode();
878 CHECK_NULL_VOID(contentNode);
879 auto context = PipelineContext::GetCurrentContext();
880 CHECK_NULL_VOID(context);
881 // close the text selection menu before transition.
882 auto selectOverlayManager = context->GetSelectOverlayManager();
883 if (selectOverlayManager) {
884 selectOverlayManager->ResetSelectionAndDestroySelectOverlay();
885 }
886 // fire onHidden and lostFocus event
887 RefPtr<NavDestinationGroupNode> preTopNavDestination;
888 int32_t lastPreIndex = -1;
889 bool isPopPage = false;
890 if (preTopNavPath.has_value()) {
891 // pre page is not in the current stack
892 lastPreIndex = navigationStack_->FindIndex(preTopNavPath->first, preTopNavPath->second, true);
893 isPopPage |= lastPreIndex == -1;
894 preTopNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
895 NavigationGroupNode::GetNavDestinationNode(preTopNavPath->second));
896 }
897 if (isCurTopNewInstance_) {
898 isPopPage = false;
899 }
900 RefPtr<NavDestinationGroupNode> newTopNavDestination;
901 if (newTopNavPath.has_value()) {
902 newTopNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
903 NavigationGroupNode::GetNavDestinationNode(newTopNavPath->second));
904 do {
905 if (!newTopNavDestination) {
906 break;
907 }
908 if (!GetIsFocusable(newTopNavDestination)) {
909 break;
910 }
911 auto navDestinationPattern = newTopNavDestination->GetPattern<NavDestinationPattern>();
912 auto navDestinationFocusView = AceType::DynamicCast<FocusView>(navDestinationPattern);
913 CHECK_NULL_VOID(navDestinationFocusView);
914 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TWELVE)) {
915 navDestinationFocusView->SetIsViewRootScopeFocused(false);
916 }
917 navDestinationFocusView->FocusViewShow();
918 } while (0);
919 } else {
920 // back to navBar case
921 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
922 CHECK_NULL_VOID(navBarNode);
923 auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(hostNode->GetLayoutProperty());
924 if (!navigationLayoutProperty->GetHideNavBarValue(false)) {
925 navBarNode->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
926 navBarNode->SetJSViewActive(true);
927 }
928 auto stageManager = context->GetStageManager();
929 if (stageManager != nullptr) {
930 RefPtr<FrameNode> pageNode = stageManager->GetLastPage();
931 CHECK_NULL_VOID(pageNode);
932 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
933 CHECK_NULL_VOID(pagePattern);
934 auto pageInfo = pagePattern->GetPageInfo();
935 NotifyPageShow(pageInfo->GetPageUrl());
936 }
937 navBarNode->GetEventHub<EventHub>()->SetEnabledInternal(true);
938 if (GetIsFocusable(navBarNode)) {
939 auto navBarFocusView = navBarNode->GetPattern<FocusView>();
940 CHECK_NULL_VOID(navBarFocusView);
941 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TWELVE)) {
942 navBarFocusView->SetIsViewRootScopeFocused(false);
943 }
944 navBarFocusView->FocusViewShow();
945 }
946 }
947 bool isShow = false;
948 bool isDialog =
949 (preTopNavDestination && preTopNavDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG) ||
950 (newTopNavDestination && newTopNavDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG);
951 if (preTopNavDestination && isDialog) {
952 auto lastStandardIndex = hostNode->GetLastStandardIndex();
953 isShow = (lastPreIndex != -1) && (lastPreIndex >= lastStandardIndex);
954 hostNode->SetNeedSetInvisible(lastStandardIndex >= 0);
955 if (lastStandardIndex < 0) {
956 auto navBarNode = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarNode());
957 auto layoutProperty = navBarNode->GetLayoutProperty();
958 layoutProperty->UpdateVisibility(VisibleType::VISIBLE, true);
959 navBarNode->SetJSViewActive(true);
960 }
961 }
962 bool disableAllAnimation = navigationStack_->GetDisableAnimation();
963 bool animated = navigationStack_->GetAnimatedValue();
964 TAG_LOGI(AceLogTag::ACE_NAVIGATION,
965 "transition start, disableAllAnimation: %{public}d, animated: %{public}d, isPopPage: %{public}d, isDialog: "
966 "%{public}d",
967 disableAllAnimation, animated, isPopPage, isDialog);
968 if (disableAllAnimation || !animated) {
969 // transition without animation need to run before layout for geometryTransition.
970 StartTransition(preTopNavDestination, newTopNavDestination, false, isPopPage, isShow);
971 navigationStack_->UpdateAnimatedValue(true);
972 hostNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
973 return;
974 }
975 if (isDialog && !isCustomAnimation_) {
976 bool isNeedAnimation =
977 AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_THIRTEEN) ?
978 true : false;
979 StartTransition(preTopNavDestination, newTopNavDestination, isNeedAnimation, isPopPage, isShow);
980 hostNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
981 return;
982 }
983
984 // before the animation of navDes replacing, update the zIndex of the previous navDes node
985 UpdatePreNavDesZIndex(preTopNavDestination, newTopNavDestination, preLastStandardIndex);
986 // transition with animation need to run after layout task
987 StartTransition(preTopNavDestination, newTopNavDestination, true, isPopPage, isShow);
988 hostNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
989 }
990
FireNavDestinationStateChange(NavDestinationLifecycle lifecycle)991 int32_t NavigationPattern::FireNavDestinationStateChange(NavDestinationLifecycle lifecycle)
992 {
993 const auto& navDestinationNodes = navigationStack_->GetAllNavDestinationNodes();
994 auto errIndex = static_cast<int32_t>(navDestinationNodes.size());
995 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
996 CHECK_NULL_RETURN(hostNode, errIndex);
997 NotifyDialogChange(lifecycle, false, true);
998 return hostNode->GetLastStandardIndex();
999 }
1000
CheckParentDestinationIsOnhide(const RefPtr<NavDestinationGroupNode> & destinationNode)1001 bool NavigationPattern::CheckParentDestinationIsOnhide(const RefPtr<NavDestinationGroupNode>& destinationNode)
1002 {
1003 CHECK_NULL_RETURN(destinationNode, false);
1004 auto destinationNodePattern = destinationNode->GetPattern<NavDestinationPattern>();
1005 CHECK_NULL_RETURN(destinationNodePattern, false);
1006 return !destinationNodePattern->GetIsOnShow();
1007 }
1008
CheckDestinationIsPush(const RefPtr<NavDestinationGroupNode> & destinationNode)1009 bool NavigationPattern::CheckDestinationIsPush(const RefPtr<NavDestinationGroupNode>& destinationNode)
1010 {
1011 CHECK_NULL_RETURN(destinationNode, false);
1012 return destinationNode->GetIndex() != -1 || destinationNode->GetNavDestinationCustomNode();
1013 }
1014
FireNavigationInner(const RefPtr<UINode> & node,bool isOnShow)1015 void NavigationPattern::FireNavigationInner(const RefPtr<UINode>& node, bool isOnShow)
1016 {
1017 CHECK_NULL_VOID(node);
1018 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(node);
1019 if (!navigationNode) {
1020 NavigationPattern::FireNavigationChange(node, isOnShow, false);
1021 return;
1022 }
1023 auto navigationPattern = navigationNode->GetPattern<NavigationPattern>();
1024 CHECK_NULL_VOID(navigationPattern);
1025 CHECK_NULL_VOID(navigationPattern->navigationStack_);
1026 const auto& navDestinationNodes = navigationPattern->navigationStack_->GetAllNavDestinationNodes();
1027 auto lastStandardIndex = navigationNode->GetLastStandardIndex();
1028 int32_t standardIndex = lastStandardIndex >= 0 ? lastStandardIndex : 0;
1029 int32_t start = standardIndex;
1030 int32_t end = navigationPattern->navigationStack_->Size();
1031 auto pipeline = PipelineContext::GetCurrentContext();
1032 CHECK_NULL_VOID(pipeline);
1033 auto overlayManager = pipeline->GetOverlayManager();
1034 if (isOnShow) {
1035 if (overlayManager && overlayManager->HasModalPage()) {
1036 return;
1037 }
1038 for (int32_t index = start; index < end; index++) {
1039 const auto& curPath = navDestinationNodes[index];
1040 auto curDestination = AceType::DynamicCast<NavDestinationGroupNode>(
1041 navigationNode->GetNavDestinationNode(curPath.second));
1042 if (!curDestination || !curDestination->GetLayoutProperty()) {
1043 continue;
1044 }
1045 auto navDestinationPattern = curDestination->GetPattern<NavDestinationPattern>();
1046 CHECK_NULL_VOID(navDestinationPattern);
1047 auto property = curDestination->GetLayoutProperty();
1048 if (property->GetVisibilityValue(VisibleType::VISIBLE) != VisibleType::VISIBLE ||
1049 !curDestination->IsActive() || navDestinationPattern->GetIsOnShow() == isOnShow) {
1050 continue;
1051 }
1052 auto eventHub = curDestination->GetEventHub<NavDestinationEventHub>();
1053 CHECK_NULL_VOID(eventHub);
1054 auto param = Recorder::EventRecorder::Get().IsPageParamRecordEnable() ?
1055 navigationPattern->navigationStack_->GetRouteParam() : "";
1056 eventHub->FireOnShownEvent(navDestinationPattern->GetName(), param);
1057 navDestinationPattern->SetIsOnShow(true);
1058 NavigationPattern::FireNavigationChange(curDestination, true, false);
1059 NavigationPattern::NotifyPerfMonitorPageMsg(navDestinationPattern->GetName());
1060 }
1061 return;
1062 }
1063 for (int32_t index = end - 1; index >= 0 && index >= start; index--) {
1064 const auto& curPath = navDestinationNodes[index];
1065 auto curDestination = AceType::DynamicCast<NavDestinationGroupNode>(
1066 navigationNode->GetNavDestinationNode(curPath.second));
1067 if (!curDestination || !curDestination->GetLayoutProperty()) {
1068 continue;
1069 }
1070 auto navDestinationPattern = curDestination->GetPattern<NavDestinationPattern>();
1071 CHECK_NULL_VOID(navDestinationPattern);
1072 auto property = curDestination->GetLayoutProperty();
1073 if (property->GetVisibilityValue(VisibleType::VISIBLE) != VisibleType::VISIBLE ||
1074 !curDestination->IsActive() || navDestinationPattern->GetIsOnShow() == isOnShow) {
1075 continue;
1076 }
1077 auto eventHub = curDestination->GetEventHub<NavDestinationEventHub>();
1078 CHECK_NULL_VOID(eventHub);
1079 eventHub->FireOnHiddenEvent(navDestinationPattern->GetName());
1080 navDestinationPattern->SetIsOnShow(false);
1081 NavigationPattern::FireNavigationChange(curDestination, false, false);
1082 }
1083 }
1084
FireNavigationChange(const RefPtr<UINode> & node,bool isOnShow,bool isFirst)1085 void NavigationPattern::FireNavigationChange(const RefPtr<UINode>& node, bool isOnShow, bool isFirst)
1086 {
1087 CHECK_NULL_VOID(node);
1088 if (isFirst) {
1089 FireNavigationInner(node, isOnShow);
1090 return;
1091 }
1092 const auto& children = node->GetChildren();
1093 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
1094 auto& child = *iter;
1095 FireNavigationInner(child, isOnShow);
1096 }
1097 }
1098
FireNavigationStateChange(const RefPtr<UINode> & node,bool isShow)1099 void NavigationPattern::FireNavigationStateChange(const RefPtr<UINode>& node, bool isShow)
1100 {
1101 if (isShow) {
1102 NavigationPattern::FireNavigationLifecycleChange(node, NavDestinationLifecycle::ON_SHOW);
1103 return;
1104 }
1105 NavigationPattern::FireNavigationLifecycleChange(node, NavDestinationLifecycle::ON_HIDE);
1106 }
1107
FireNavigationLifecycleChange(const RefPtr<UINode> & node,NavDestinationLifecycle lifecycle)1108 void NavigationPattern::FireNavigationLifecycleChange(const RefPtr<UINode>& node, NavDestinationLifecycle lifecycle)
1109 {
1110 CHECK_NULL_VOID(node);
1111 const auto& children = node->GetChildren();
1112 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
1113 auto& child = *iter;
1114 auto navigation = AceType::DynamicCast<NavigationGroupNode>(child);
1115 if (navigation) {
1116 auto destinationNode = navigation->GetParentDestinationNode().Upgrade();
1117 if ((lifecycle == NavDestinationLifecycle::ON_SHOW) && CheckParentDestinationIsOnhide(destinationNode) &&
1118 CheckDestinationIsPush(destinationNode)) {
1119 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation parent is onhide");
1120 continue;
1121 }
1122 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(navigation->GetPattern());
1123 CHECK_NULL_VOID(navigationPattern);
1124 navigationPattern->FireNavDestinationStateChange(lifecycle);
1125 } else {
1126 NavigationPattern::FireNavigationLifecycleChange(child, lifecycle);
1127 }
1128 }
1129 }
1130
NotifyPageHide(const std::string & pageName)1131 void NavigationPattern::NotifyPageHide(const std::string& pageName)
1132 {
1133 auto container = Container::Current();
1134 CHECK_NULL_VOID(container);
1135 auto pageUrlChecker = container->GetPageUrlChecker();
1136 CHECK_NULL_VOID(pageUrlChecker);
1137 pageUrlChecker->NotifyPageHide(pageName);
1138 }
1139
NotifyPageShow(const std::string & pageName)1140 void NavigationPattern::NotifyPageShow(const std::string& pageName)
1141 {
1142 auto container = Container::Current();
1143 CHECK_NULL_VOID(container);
1144 auto pageUrlChecker = container->GetPageUrlChecker();
1145 CHECK_NULL_VOID(pageUrlChecker);
1146 pageUrlChecker->NotifyPageShow(pageName);
1147 if (PerfMonitor::GetPerfMonitor() != nullptr) {
1148 PerfMonitor::GetPerfMonitor()->SetPageName(pageName);
1149 }
1150 }
1151
ReplaceAnimation(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination)1152 void NavigationPattern::ReplaceAnimation(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
1153 const RefPtr<NavDestinationGroupNode>& newTopNavDestination)
1154 {
1155 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1156 CHECK_NULL_VOID(navigationNode);
1157 auto navBarNode = AceType::DynamicCast<NavBarNode>(navigationNode->GetNavBarNode());
1158 CHECK_NULL_VOID(navBarNode);
1159 bool preUseCustomTransition = TriggerNavDestinationTransition(
1160 preTopNavDestination, NavigationOperation::REPLACE, false) != INVALID_ANIMATION_ID;
1161 TriggerNavDestinationTransition(newTopNavDestination, NavigationOperation::REPLACE, true);
1162 if (newTopNavDestination && preTopNavDestination && !preUseCustomTransition) {
1163 navigationNode->DealNavigationExit(preTopNavDestination, false, false);
1164 } else if (newTopNavDestination && navigationMode_ == NavigationMode::STACK) {
1165 navigationNode->DealNavigationExit(navBarNode, true, false);
1166 }
1167 navigationNode->RemoveDialogDestination();
1168 auto id = navigationNode->GetTopDestination() ? navigationNode->GetTopDestination()->GetAccessibilityId() : -1;
1169 navigationNode->OnAccessibilityEvent(
1170 AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
1171 navigationStack_->UpdateReplaceValue(0);
1172 }
1173
TransitionWithOutAnimation(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage,bool needVisible)1174 void NavigationPattern::TransitionWithOutAnimation(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
1175 const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage, bool needVisible)
1176 {
1177 navigationStack_->ClearRecoveryList();
1178 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1179 CHECK_NULL_VOID(navigationNode);
1180 auto navBarNode = AceType::DynamicCast<NavBarNode>(navigationNode->GetNavBarNode());
1181 CHECK_NULL_VOID(navBarNode);
1182 auto pipeline = PipelineContext::GetCurrentContext();
1183 CHECK_NULL_VOID(pipeline);
1184
1185 // replace
1186 auto replaceVal = navigationStack_->GetReplaceValue();
1187 if (replaceVal != 0) {
1188 ReplaceAnimation(preTopNavDestination, newTopNavDestination);
1189 return;
1190 }
1191
1192 // navDestination push/pop navDestination
1193 if (newTopNavDestination && preTopNavDestination) {
1194 if (isPopPage) {
1195 newTopNavDestination->SetTransitionType(PageTransitionType::ENTER_POP);
1196 preTopNavDestination->CleanContent();
1197 auto parent = preTopNavDestination->GetParent();
1198 CHECK_NULL_VOID(parent);
1199 parent->RemoveChild(preTopNavDestination, true);
1200 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1201 } else {
1202 preTopNavDestination->GetRenderContext()->RemoveClipWithRRect();
1203 preTopNavDestination->SetTransitionType(PageTransitionType::EXIT_PUSH);
1204 newTopNavDestination->SetTransitionType(PageTransitionType::ENTER_PUSH);
1205 DealTransitionVisibility(preTopNavDestination, needVisible, false);
1206 if (preTopNavDestination->NeedRemoveInPush()) {
1207 preTopNavDestination->CleanContent();
1208 auto parent = preTopNavDestination->GetParent();
1209 CHECK_NULL_VOID(parent);
1210 parent->RemoveChild(preTopNavDestination, true);
1211 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1212 }
1213 }
1214 navigationNode->RemoveDialogDestination();
1215 auto id = navigationNode->GetTopDestination() ? navigationNode->GetTopDestination()->GetAccessibilityId() : -1;
1216 navigationNode->OnAccessibilityEvent(
1217 AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
1218 return;
1219 }
1220
1221 // navBar push navDestination
1222 if (newTopNavDestination && newTopNavDestination->GetNavDestinationMode() == NavDestinationMode::STANDARD) {
1223 newTopNavDestination->SetTransitionType(PageTransitionType::ENTER_PUSH);
1224 auto navBar = AceType::DynamicCast<NavBarNode>(navBarNode);
1225 // current mode is stack, set navBar invisible
1226 if (navigationMode_ == NavigationMode::STACK && navBar) {
1227 navBar->SetTransitionType(PageTransitionType::EXIT_PUSH);
1228 DealTransitionVisibility(navBarNode, false, true);
1229 }
1230 // if current mode is auto, need set navBar need set invisible true
1231 navigationNode->SetNeedSetInvisible(true);
1232 }
1233
1234 // navDestination pop to navBar
1235 if (preTopNavDestination) {
1236 preTopNavDestination->CleanContent();
1237 auto parent = preTopNavDestination->GetParent();
1238 CHECK_NULL_VOID(parent);
1239 parent->RemoveChild(preTopNavDestination, true);
1240 navigationNode->SetNeedSetInvisible(false);
1241 auto navBar = AceType::DynamicCast<NavBarNode>(navBarNode);
1242 if (navBar) {
1243 navBar->SetTransitionType(PageTransitionType::ENTER_POP);
1244 }
1245 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1246 }
1247 navigationNode->RemoveDialogDestination();
1248 auto id = navigationNode->GetTopDestination() ? navigationNode->GetTopDestination()->GetAccessibilityId() : -1;
1249 navigationNode->OnAccessibilityEvent(
1250 AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
1251 }
1252
TransitionWithAnimation(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage,bool isNeedVisible)1253 void NavigationPattern::TransitionWithAnimation(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
1254 const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage, bool isNeedVisible)
1255 {
1256 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1257 CHECK_NULL_VOID(navigationNode);
1258 auto pipeline = PipelineContext::GetCurrentContext();
1259 CHECK_NULL_VOID(pipeline);
1260 auto layoutProperty = navigationNode->GetLayoutProperty<NavigationLayoutProperty>();
1261 CHECK_NULL_VOID(layoutProperty);
1262 if (layoutProperty->GetHideNavBarValue(false) && (!newTopNavDestination || !preTopNavDestination)) {
1263 // hide navBarNode and need to do animation with navBarNode
1264 if (preTopNavDestination) {
1265 // remove preTopNavDestination node in pop
1266 auto parent = preTopNavDestination->GetParent();
1267 CHECK_NULL_VOID(parent);
1268 if (preTopNavDestination->GetContentNode()) {
1269 preTopNavDestination->GetContentNode()->Clean();
1270 }
1271 parent->RemoveChild(preTopNavDestination);
1272 auto preTopNavDestinationPattern = preTopNavDestination->GetPattern<NavDestinationPattern>();
1273 CHECK_NULL_VOID(preTopNavDestinationPattern);
1274 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1275 }
1276 navigationNode->RemoveDialogDestination();
1277 navigationStack_->ClearRecoveryList();
1278 return;
1279 }
1280 if (isCustomAnimation_ && TriggerCustomAnimation(preTopNavDestination, newTopNavDestination, isPopPage)) {
1281 auto operation = NavigationOperation::REPLACE;
1282 if (navigationStack_->GetReplaceValue() == 0) {
1283 operation = isPopPage ? NavigationOperation::POP : NavigationOperation::PUSH;
1284 }
1285 TriggerNavDestinationTransition(preTopNavDestination, operation, false);
1286 TriggerNavDestinationTransition(newTopNavDestination, operation, true);
1287 return;
1288 }
1289 StartDefaultAnimation(preTopNavDestination, newTopNavDestination, isPopPage, isNeedVisible);
1290 }
1291
DialogAnimation(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage,bool isNeedVisible)1292 void NavigationPattern::DialogAnimation(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
1293 const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage, bool isNeedVisible)
1294 {
1295 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_THIRTEEN)) {
1296 TransitionWithDialogAnimation(preTopNavDestination, newTopNavDestination, isPopPage);
1297 } else {
1298 TransitionWithOutAnimation(preTopNavDestination, newTopNavDestination, isPopPage, isNeedVisible);
1299 }
1300 }
1301
StartDefaultAnimation(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage,bool isNeedVisible)1302 void NavigationPattern::StartDefaultAnimation(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
1303 const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage, bool isNeedVisible)
1304 {
1305 auto currentProxy = GetTopNavigationProxy();
1306 if (currentProxy) {
1307 currentProxy->SetIsFinished(true);
1308 }
1309 navigationStack_->ClearRecoveryList();
1310 bool isPreDialog = preTopNavDestination &&
1311 preTopNavDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG;
1312 bool isNewDialog = newTopNavDestination &&
1313 newTopNavDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG;
1314 if (isPreDialog || isNewDialog) {
1315 DialogAnimation(preTopNavDestination, newTopNavDestination, isPopPage, isNeedVisible);
1316 return;
1317 }
1318 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1319 CHECK_NULL_VOID(navigationNode);
1320 auto navBarNode = AceType::DynamicCast<NavBarNode>(navigationNode->GetNavBarNode());
1321 CHECK_NULL_VOID(navBarNode);
1322 // replace
1323 auto replaceValue = navigationStack_->GetReplaceValue();
1324 if (replaceValue != 0) {
1325 if (newTopNavDestination && preTopNavDestination) {
1326 navigationNode->TransitionWithReplace(preTopNavDestination, newTopNavDestination, false);
1327 } else if (newTopNavDestination && navigationMode_ == NavigationMode::STACK) {
1328 navigationNode->TransitionWithReplace(navBarNode, newTopNavDestination, true);
1329 }
1330 navigationStack_->UpdateReplaceValue(0);
1331 return;
1332 }
1333 // navDestination push/pop navDestination
1334 if (newTopNavDestination && preTopNavDestination) {
1335 if (isPopPage) {
1336 navigationNode->TransitionWithPop(preTopNavDestination, newTopNavDestination);
1337 } else {
1338 navigationNode->TransitionWithPush(preTopNavDestination, newTopNavDestination);
1339 }
1340 return;
1341 }
1342 // navBar push navDestination
1343 if (newTopNavDestination && navigationMode_ == NavigationMode::STACK) {
1344 navigationNode->TransitionWithPush(navBarNode, newTopNavDestination, true);
1345 return;
1346 }
1347 // navDestination pop to navBar
1348 if (preTopNavDestination) {
1349 if (navigationMode_ == NavigationMode::SPLIT) {
1350 navigationNode->TransitionWithPop(preTopNavDestination, nullptr);
1351 }
1352 if (navigationMode_ == NavigationMode::STACK) {
1353 navigationNode->TransitionWithPop(preTopNavDestination, navBarNode, true);
1354 }
1355 }
1356 }
1357
OnVisibleChange(bool isVisible)1358 void NavigationPattern::OnVisibleChange(bool isVisible)
1359 {
1360 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1361 CHECK_NULL_VOID(hostNode);
1362 auto eventHub = hostNode->GetEventHub<NavigationEventHub>();
1363 CHECK_NULL_VOID(eventHub);
1364 eventHub->FireNavBarStateChangeEvent(isVisible);
1365 }
1366
OnNavBarStateChange(bool modeChange)1367 void NavigationPattern::OnNavBarStateChange(bool modeChange)
1368 {
1369 auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
1370 CHECK_NULL_VOID(layoutProperty);
1371 auto visibilityValue = layoutProperty->GetVisibilityValue(VisibleType::VISIBLE);
1372 if (visibilityValue != VisibleType::VISIBLE) {
1373 return;
1374 }
1375
1376 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1377 CHECK_NULL_VOID(hostNode);
1378 auto eventHub = hostNode->GetEventHub<NavigationEventHub>();
1379 CHECK_NULL_VOID(eventHub);
1380 auto currentNavigationMode = GetNavigationMode();
1381
1382 if (modeChange) {
1383 if (currentNavigationMode == NavigationMode::SPLIT) {
1384 if (layoutProperty->GetHideNavBarValue(false)) {
1385 eventHub->FireNavBarStateChangeEvent(false);
1386 } else {
1387 eventHub->FireNavBarStateChangeEvent(true);
1388 }
1389 } else {
1390 if (navigationStack_->Empty() && !layoutProperty->GetHideNavBarValue(false)) {
1391 eventHub->FireNavBarStateChangeEvent(true);
1392 } else {
1393 eventHub->FireNavBarStateChangeEvent(false);
1394 }
1395 }
1396 SetNavBarVisibilityChange(false);
1397 return;
1398 }
1399
1400 if (GetNavBarVisibilityChange()) {
1401 if (!layoutProperty->GetHideNavBarValue(false)) {
1402 eventHub->FireNavBarStateChangeEvent(true);
1403 } else {
1404 eventHub->FireNavBarStateChangeEvent(false);
1405 }
1406 SetNavBarVisibilityChange(false);
1407 return;
1408 }
1409
1410 if (currentNavigationMode == NavigationMode::STACK) {
1411 eventHub->FireNavBarStateChangeEvent(navigationStack_->Empty());
1412 }
1413 }
1414
OnNavigationModeChange(bool modeChange)1415 void NavigationPattern::OnNavigationModeChange(bool modeChange)
1416 {
1417 if (!modeChange) {
1418 return;
1419 }
1420 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1421 CHECK_NULL_VOID(hostNode);
1422 auto eventHub = hostNode->GetEventHub<NavigationEventHub>();
1423 CHECK_NULL_VOID(eventHub);
1424 eventHub->FireNavigationModeChangeEvent(navigationMode_);
1425 // fire navigation stack navigation mode change event
1426 navigationStack_->FireNavigationModeChange(navigationMode_);
1427 }
1428
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)1429 bool NavigationPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
1430 {
1431 if (config.skipMeasure && config.skipLayout) {
1432 return false;
1433 }
1434 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1435 CHECK_NULL_RETURN(hostNode, false);
1436 UpdateIsFullPageNavigation(hostNode);
1437 if (navigationModeChange_) {
1438 if (NavigationMode::STACK == navigationMode_) {
1439 // Set focus on navDestination when mode changes to STACK
1440 RefreshFocusToDestination();
1441 }
1442 AbortAnimation(hostNode);
1443 }
1444 auto context = PipelineContext::GetCurrentContext();
1445 if (context) {
1446 context->GetTaskExecutor()->PostTask(
1447 [weak = WeakClaim(this), navigationStackWeak = WeakPtr<NavigationStack>(navigationStack_),
1448 navigationWeak = WeakPtr<NavigationGroupNode>(hostNode)] {
1449 auto pattern = weak.Upgrade();
1450 CHECK_NULL_VOID(pattern);
1451 auto navigationGroupNode = navigationWeak.Upgrade();
1452 CHECK_NULL_VOID(navigationGroupNode);
1453 auto navigationLayoutProperty =
1454 AceType::DynamicCast<NavigationLayoutProperty>(navigationGroupNode->GetLayoutProperty());
1455 CHECK_NULL_VOID(navigationLayoutProperty);
1456 auto navigationStack = navigationStackWeak.Upgrade();
1457 CHECK_NULL_VOID(navigationStack);
1458 auto curTopNavPath = navigationStack->GetTopNavPath();
1459 if (curTopNavPath.has_value()) {
1460 // considering backButton visibility
1461 auto curTopNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
1462 NavigationGroupNode::GetNavDestinationNode(curTopNavPath->second));
1463 pattern->UpdateContextRect(curTopNavDestination, navigationGroupNode);
1464 }
1465 // considering navBar visibility
1466 auto navBarNode = AceType::DynamicCast<NavBarNode>(navigationGroupNode->GetNavBarNode());
1467 CHECK_NULL_VOID(navBarNode);
1468 auto navBarLayoutProperty = navBarNode->GetLayoutProperty<NavBarLayoutProperty>();
1469 CHECK_NULL_VOID(navBarLayoutProperty);
1470 bool isSetInvisible =
1471 (navigationGroupNode->GetNeedSetInvisible() && navigationStack->Size() != 0) ? true : false;
1472 if (navigationLayoutProperty->GetHideNavBar().value_or(false) ||
1473 (pattern->GetNavigationMode() == NavigationMode::STACK && isSetInvisible)) {
1474 navBarLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
1475 navBarNode->SetJSViewActive(false);
1476 } else {
1477 navBarNode->GetRenderContext()->UpdateOpacity(1.0f);
1478 navBarLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
1479 navBarNode->SetJSViewActive(true);
1480 }
1481 auto navigationContentNode = AceType::DynamicCast<FrameNode>(navigationGroupNode->GetContentNode());
1482 CHECK_NULL_VOID(navigationContentNode);
1483 auto navDestinationNode =
1484 AceType::DynamicCast<NavDestinationGroupNode>(navigationContentNode->GetLastChild());
1485 CHECK_NULL_VOID(navDestinationNode);
1486 auto navDestinationPattern = navDestinationNode->GetPattern<NavDestinationPattern>();
1487 auto navDestinationFocusHub = navDestinationNode->GetFocusHub();
1488 CHECK_NULL_VOID(navDestinationFocusHub);
1489 auto defaultFocusHub = navDestinationFocusHub->GetChildFocusNodeByType(FocusNodeType::DEFAULT);
1490 if (!defaultFocusHub && navDestinationNode->GetChildren().size() <= EMPTY_DESTINATION_CHILD_SIZE &&
1491 navDestinationPattern->GetBackButtonState()) {
1492 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navDestinationNode->GetTitleBarNode());
1493 CHECK_NULL_VOID(titleBarNode);
1494 auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
1495 backButtonNode->GetOrCreateFocusHub()->SetIsDefaultFocus(true);
1496 auto navigation = pattern->GetHost();
1497 CHECK_NULL_VOID(navigation);
1498 auto navigationFocusHub = navigation->GetFocusHub();
1499 CHECK_NULL_VOID(navigationFocusHub);
1500 auto navDestinationFocusView = navDestinationNode->GetPattern<FocusView>();
1501 if (navigationFocusHub->IsCurrentFocus() && navDestinationFocusView) {
1502 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TWELVE)) {
1503 navDestinationFocusView->SetIsViewRootScopeFocused(false);
1504 }
1505 navDestinationFocusView->FocusViewShow();
1506 }
1507 }
1508 },
1509 TaskExecutor::TaskType::UI, "ArkUINavigationDirtyLayoutWrapperSwap");
1510 }
1511 auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(hostNode->GetLayoutProperty());
1512 CHECK_NULL_RETURN(navigationLayoutProperty, false);
1513 UpdateTitleModeChangeEventHub(hostNode);
1514 AddDragBarHotZoneRect();
1515 AddDividerHotZoneRect();
1516 ifNeedInit_ = false;
1517 return false;
1518 }
1519
AbortAnimation(RefPtr<NavigationGroupNode> & hostNode)1520 void NavigationPattern::AbortAnimation(RefPtr<NavigationGroupNode>& hostNode)
1521 {
1522 TAG_LOGD(AceLogTag::ACE_NAVIGATION, "Aborting navigation animations");
1523 if (!hostNode->GetPushAnimations().empty()) {
1524 auto pushAnimations = hostNode->GetPushAnimations();
1525 for (const auto& animation : pushAnimations) {
1526 if (animation) {
1527 AnimationUtils::StopAnimation(animation);
1528 }
1529 }
1530 }
1531 if (!hostNode->GetPopAnimations().empty()) {
1532 auto popAnimations = hostNode->GetPopAnimations();
1533 for (const auto& animation : popAnimations) {
1534 if (animation) {
1535 AnimationUtils::StopAnimation(animation);
1536 }
1537 }
1538 }
1539 hostNode->CleanPushAnimations();
1540 hostNode->CleanPopAnimations();
1541 }
1542
UpdateContextRect(const RefPtr<NavDestinationGroupNode> & curDestination,const RefPtr<NavigationGroupNode> & hostNode)1543 void NavigationPattern::UpdateContextRect(
1544 const RefPtr<NavDestinationGroupNode>& curDestination, const RefPtr<NavigationGroupNode>& hostNode)
1545 {
1546 CHECK_NULL_VOID(curDestination);
1547 CHECK_NULL_VOID(hostNode);
1548 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
1549 CHECK_NULL_VOID(navBarNode);
1550 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
1551 CHECK_NULL_VOID(navigationPattern);
1552
1553 if (navigationPattern->GetNavigationMode() == NavigationMode::STACK) {
1554 curDestination->GetRenderContext()->SetActualForegroundColor(Color::TRANSPARENT);
1555 return;
1556 }
1557 auto navigationLayoutProperty = hostNode->GetLayoutProperty<NavigationLayoutProperty>();
1558 CHECK_NULL_VOID(navigationLayoutProperty);
1559 auto navBarProperty = navBarNode->GetLayoutProperty();
1560 navBarProperty->UpdateVisibility(VisibleType::VISIBLE);
1561 navBarNode->SetJSViewActive(true);
1562 if (!curDestination->IsOnAnimation()) {
1563 curDestination->GetRenderContext()->UpdateTranslateInXY(OffsetF { 0.0f, 0.0f });
1564 curDestination->GetRenderContext()->SetActualForegroundColor(Color::TRANSPARENT);
1565 navBarNode->GetEventHub<EventHub>()->SetEnabledInternal(true);
1566 auto titleBarNode = DynamicCast<TitleBarNode>(navBarNode->GetTitleBarNode());
1567 CHECK_NULL_VOID(titleBarNode);
1568 auto titleNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetTitle());
1569 CHECK_NULL_VOID(titleNode);
1570 titleNode->GetRenderContext()->UpdateTranslateInXY(OffsetF { 0.0f, 0.0f });
1571 }
1572 }
1573
UpdateTitleModeChangeEventHub(const RefPtr<NavigationGroupNode> & hostNode)1574 bool NavigationPattern::UpdateTitleModeChangeEventHub(const RefPtr<NavigationGroupNode>& hostNode)
1575 {
1576 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
1577 CHECK_NULL_RETURN(navBarNode, false);
1578 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navBarNode->GetTitleBarNode());
1579 CHECK_NULL_RETURN(titleBarNode, false);
1580 auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty<TitleBarLayoutProperty>();
1581 CHECK_NULL_RETURN(titleBarLayoutProperty, false);
1582 auto eventHub = hostNode->GetEventHub<NavigationEventHub>();
1583 CHECK_NULL_RETURN(eventHub, false);
1584 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::FREE) {
1585 auto titleBarPattern = AceType::DynamicCast<TitleBarPattern>(titleBarNode->GetPattern());
1586 CHECK_NULL_RETURN(titleBarPattern, false);
1587 NavigationTitleMode titleMode = titleBarPattern->GetNavigationTitleMode();
1588 if (titleMode != NavigationTitleMode::FREE && titleMode_ != titleMode) {
1589 NavigationTitleModeChangeEvent navigationTitleModeChange(titleMode == NavigationTitleMode::MINI);
1590 eventHub->FireChangeEvent(&navigationTitleModeChange);
1591 titleMode_ = titleMode;
1592 }
1593 }
1594 return true;
1595 }
1596
GenerateUINodeFromRecovery(int32_t lastStandardIndex,NavPathList & navPathList)1597 void NavigationPattern::GenerateUINodeFromRecovery(int32_t lastStandardIndex, NavPathList& navPathList)
1598 {
1599 /**
1600 * In case several pages at the top of stack are dialog pages.
1601 * We need to recovery node until a standard page created.
1602 * And the creation process should be bottom-up to satisfy the order of life-cycle.
1603 */
1604 int32_t jsStackSize = static_cast<int32_t>(navPathList.size());
1605 for (int32_t index = lastStandardIndex; index < jsStackSize; ++ index) {
1606 if (navPathList[index].second || !navigationStack_->IsFromRecovery(index)) {
1607 continue;
1608 }
1609 navPathList[index].second = GenerateUINodeByIndex(index);
1610 navigationStack_->SetFromRecovery(index, false);
1611 auto navdestination = AceType::DynamicCast<NavDestinationGroupNode>(
1612 NavigationGroupNode::GetNavDestinationNode(navPathList[index].second));
1613 navdestination->SetNeedAppearFromRecovery(true);
1614 }
1615 }
1616
GenerateUINodeByIndex(int32_t index)1617 RefPtr<UINode> NavigationPattern::GenerateUINodeByIndex(int32_t index)
1618 {
1619 auto node = navigationStack_->CreateNodeByIndex(index, parentNode_);
1620 auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(
1621 NavigationGroupNode::GetNavDestinationNode(node));
1622 CHECK_NULL_RETURN(navDestinationNode, node);
1623 // set navigation id
1624 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1625 auto navDestinationPattern = AceType::DynamicCast<NavDestinationPattern>(navDestinationNode->GetPattern());
1626 if (navigationNode && navDestinationPattern) {
1627 navDestinationPattern->SetNavigationNode(navigationNode);
1628 navDestinationPattern->SetNavigationId(navigationNode->GetInspectorId().value_or(""));
1629 navigationStack_->SetDestinationIdToJsStack(
1630 index, std::to_string(navDestinationPattern->GetNavDestinationId()));
1631 }
1632 auto eventHub = navDestinationNode->GetEventHub<NavDestinationEventHub>();
1633 CHECK_NULL_RETURN(eventHub, node);
1634 eventHub->FireOnWillAppear();
1635 return node;
1636 }
1637
InitDividerMouseEvent(const RefPtr<InputEventHub> & inputHub)1638 void NavigationPattern::InitDividerMouseEvent(const RefPtr<InputEventHub>& inputHub)
1639 {
1640 CHECK_NULL_VOID(inputHub);
1641 CHECK_NULL_VOID(!hoverEvent_);
1642
1643 auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
1644 auto pattern = weak.Upgrade();
1645 if (pattern) {
1646 pattern->OnHover(isHover);
1647 }
1648 };
1649 hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
1650 inputHub->AddOnHoverEvent(hoverEvent_);
1651 }
1652
HandleDragStart()1653 void NavigationPattern::HandleDragStart()
1654 {
1655 preNavBarWidth_ = realNavBarWidth_;
1656 if (!isDividerDraggable_) {
1657 return;
1658 }
1659 isInDividerDrag_ = true;
1660 if (!enableDragBar_) {
1661 auto pipeline = PipelineContext::GetCurrentContext();
1662 CHECK_NULL_VOID(pipeline);
1663 auto windowId = pipeline->GetWindowId();
1664 auto mouseStyle = MouseStyle::CreateMouseStyle();
1665 mouseStyle->SetPointerStyle(static_cast<int32_t>(windowId), MouseFormat::RESIZE_LEFT_RIGHT);
1666 }
1667 }
1668
HandleDragUpdate(float xOffset)1669 void NavigationPattern::HandleDragUpdate(float xOffset)
1670 {
1671 auto navigationLayoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
1672 CHECK_NULL_VOID(navigationLayoutProperty);
1673 auto host = GetHost();
1674 CHECK_NULL_VOID(host);
1675 auto geometryNode = host->GetGeometryNode();
1676 CHECK_NULL_VOID(geometryNode);
1677 auto frameSize = geometryNode->GetFrameSize();
1678 auto frameWidth = frameSize.Width();
1679 auto constraint = navigationLayoutProperty->GetLayoutConstraint();
1680 auto parentSize = CreateIdealSize(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
1681
1682 float minNavBarWidthPx = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
1683 float maxNavBarWidthPx = maxNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
1684 float minContentWidthPx = minContentWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
1685 auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
1686
1687 auto navigationPosition = navigationLayoutProperty->GetNavBarPosition().value_or(NavBarPosition::START);
1688 bool isNavBarStart = navigationPosition == NavBarPosition::START;
1689 auto navBarLine = isRightToLeft_ ? preNavBarWidth_ + (isNavBarStart ? -xOffset : xOffset)
1690 : preNavBarWidth_ + (isNavBarStart ? xOffset : -xOffset);
1691 float currentNavBarWidth = realNavBarWidth_;
1692
1693 if (maxNavBarWidthPx + dividerWidth + minContentWidthPx > frameWidth) {
1694 maxNavBarWidthPx = frameWidth - minContentWidthPx - dividerWidth;
1695 }
1696 navBarLine = std::min(navBarLine, maxNavBarWidthPx);
1697
1698 if (userSetMinContentFlag_ && !userSetNavBarRangeFlag_) {
1699 if (minContentWidthPx >= frameWidth) {
1700 realNavBarWidth_ = 0.0f;
1701 } else if (navBarLine + dividerWidth + minContentWidthPx <= frameWidth) {
1702 realNavBarWidth_ = navBarLine;
1703 } else {
1704 realNavBarWidth_ = frameWidth - minContentWidthPx - dividerWidth;
1705 }
1706 } else {
1707 realDividerWidth_ = dividerWidth;
1708 float remainingSpace = frameWidth - navBarLine - dividerWidth;
1709 if (remainingSpace >= minContentWidthPx) {
1710 realNavBarWidth_ = navBarLine;
1711 } else if (remainingSpace < minContentWidthPx && navBarLine > minNavBarWidthPx) {
1712 realNavBarWidth_ = frameWidth - minContentWidthPx - dividerWidth;
1713 } else {
1714 realNavBarWidth_ = minNavBarWidthPx;
1715 }
1716 }
1717 realNavBarWidth_ = std::min(realNavBarWidth_, frameWidth);
1718 realNavBarWidth_ = std::min(realNavBarWidth_, maxNavBarWidthPx);
1719 realNavBarWidth_ = std::max(realNavBarWidth_, minNavBarWidthPx);
1720 // MEASURE
1721 if (realNavBarWidth_ != currentNavBarWidth) {
1722 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
1723 }
1724 }
1725
HandleDragEnd()1726 void NavigationPattern::HandleDragEnd()
1727 {
1728 preNavBarWidth_ = realNavBarWidth_;
1729 if (!isDividerDraggable_) {
1730 return;
1731 }
1732 isInDividerDrag_ = false;
1733 auto pipeline = PipelineContext::GetCurrentContext();
1734 CHECK_NULL_VOID(pipeline);
1735 auto windowId = pipeline->GetWindowId();
1736 auto mouseStyle = MouseStyle::CreateMouseStyle();
1737 mouseStyle->SetPointerStyle(static_cast<int32_t>(windowId), MouseFormat::DEFAULT);
1738 }
1739
InitDividerPanEvent(const RefPtr<GestureEventHub> & gestureHub)1740 void NavigationPattern::InitDividerPanEvent(const RefPtr<GestureEventHub>& gestureHub)
1741 {
1742 CHECK_NULL_VOID(!panEvent_);
1743 auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1744 auto pattern = weak.Upgrade();
1745 CHECK_NULL_VOID(pattern);
1746 pattern->HandleDragStart();
1747 };
1748 auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1749 auto pattern = weak.Upgrade();
1750 CHECK_NULL_VOID(pattern);
1751 pattern->HandleDragUpdate(static_cast<float>(info.GetOffsetX()));
1752 };
1753 auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1754 auto pattern = weak.Upgrade();
1755 CHECK_NULL_VOID(pattern);
1756 pattern->HandleDragEnd();
1757 };
1758 auto actionCancelTask = [weak = WeakClaim(this)]() {
1759 auto pattern = weak.Upgrade();
1760 CHECK_NULL_VOID(pattern);
1761 pattern->HandleDragEnd();
1762 };
1763 panEvent_ = MakeRefPtr<PanEvent>(
1764 std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
1765 PanDirection panDirection = { .type = PanDirection::HORIZONTAL };
1766 gestureHub->AddPanEvent(panEvent_, panDirection, DEFAULT_PAN_FINGER, DEFAULT_PAN_DISTANCE);
1767 }
1768
InitDragBarPanEvent(const RefPtr<GestureEventHub> & gestureHub)1769 void NavigationPattern::InitDragBarPanEvent(const RefPtr<GestureEventHub>& gestureHub)
1770 {
1771 CHECK_NULL_VOID(!dragBarPanEvent_);
1772 auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1773 auto pattern = weak.Upgrade();
1774 CHECK_NULL_VOID(pattern);
1775 pattern->HandleDragStart();
1776 };
1777 auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1778 auto pattern = weak.Upgrade();
1779 CHECK_NULL_VOID(pattern);
1780 pattern->HandleDragUpdate(static_cast<float>(info.GetOffsetX()));
1781 };
1782 auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1783 auto pattern = weak.Upgrade();
1784 CHECK_NULL_VOID(pattern);
1785 pattern->HandleDragEnd();
1786 };
1787 auto actionCancelTask = [weak = WeakClaim(this)]() {
1788 auto pattern = weak.Upgrade();
1789 CHECK_NULL_VOID(pattern);
1790 pattern->HandleDragEnd();
1791 };
1792 dragBarPanEvent_ = MakeRefPtr<PanEvent>(
1793 std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
1794 PanDirection panDirection = { .type = PanDirection::HORIZONTAL };
1795 gestureHub->AddPanEvent(dragBarPanEvent_, panDirection, DEFAULT_PAN_FINGER, DEFAULT_PAN_DISTANCE);
1796 }
1797
OnHover(bool isHover)1798 void NavigationPattern::OnHover(bool isHover)
1799 {
1800 if (isInDividerDrag_) {
1801 return;
1802 }
1803 MouseFormat format = isHover ? MouseFormat::RESIZE_LEFT_RIGHT : MouseFormat::DEFAULT;
1804 auto pipeline = PipelineContext::GetCurrentContext();
1805 CHECK_NULL_VOID(pipeline);
1806 auto windowId = pipeline->GetWindowId();
1807 auto mouseStyle = MouseStyle::CreateMouseStyle();
1808 int32_t currentPointerStyle = 0;
1809 mouseStyle->GetPointerStyle(static_cast<int32_t>(windowId), currentPointerStyle);
1810 auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
1811 CHECK_NULL_VOID(layoutProperty);
1812 auto userSetMinNavBarWidthValue = layoutProperty->GetMinNavBarWidthValue(Dimension(0.0));
1813 auto userSetMaxNavBarWidthValue = layoutProperty->GetMaxNavBarWidthValue(Dimension(0.0));
1814 bool navBarWidthRangeEqual = userSetMinNavBarWidthValue.Value() >= userSetMaxNavBarWidthValue.Value();
1815 if ((userSetNavBarWidthFlag_ && !userSetNavBarRangeFlag_) || (userSetNavBarRangeFlag_ && navBarWidthRangeEqual)) {
1816 isDividerDraggable_ = false;
1817 return;
1818 }
1819 isDividerDraggable_ = true;
1820 if (currentPointerStyle != static_cast<int32_t>(format)) {
1821 mouseStyle->SetPointerStyle(static_cast<int32_t>(windowId), format);
1822 }
1823 }
1824
GetDividerNode() const1825 RefPtr<FrameNode> NavigationPattern::GetDividerNode() const
1826 {
1827 auto host = GetHost();
1828 CHECK_NULL_RETURN(host, nullptr);
1829 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(host);
1830 CHECK_NULL_RETURN(navigationNode, nullptr);
1831 auto dividerFrameNode = AceType::DynamicCast<FrameNode>(navigationNode->GetDividerNode());
1832 CHECK_NULL_RETURN(dividerFrameNode, nullptr);
1833 return dividerFrameNode;
1834 }
1835
GetDragBarNode() const1836 RefPtr<FrameNode> NavigationPattern::GetDragBarNode() const
1837 {
1838 auto host = GetHost();
1839 CHECK_NULL_RETURN(host, nullptr);
1840 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(host);
1841 CHECK_NULL_RETURN(navigationNode, nullptr);
1842 auto dragBarNode = AceType::DynamicCast<FrameNode>(navigationNode->GetDragBarNode());
1843 CHECK_NULL_RETURN(dragBarNode, nullptr);
1844 return dragBarNode;
1845 }
1846
BeforeSyncGeometryProperties(const DirtySwapConfig &)1847 void NavigationPattern::BeforeSyncGeometryProperties(const DirtySwapConfig& /* config */)
1848 {
1849 AddDividerHotZoneRect();
1850 }
1851
AddDividerHotZoneRect()1852 void NavigationPattern::AddDividerHotZoneRect()
1853 {
1854 if (NearZero(realDividerWidth_)) {
1855 return;
1856 }
1857 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1858 CHECK_NULL_VOID(hostNode);
1859 auto navBarNode = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarNode());
1860 CHECK_NULL_VOID(navBarNode);
1861 auto geometryNode = navBarNode->GetGeometryNode();
1862 CHECK_NULL_VOID(geometryNode);
1863
1864 OffsetF hotZoneOffset;
1865 hotZoneOffset.SetX(-DEFAULT_DIVIDER_HOT_ZONE_HORIZONTAL_PADDING.ConvertToPx());
1866 hotZoneOffset.SetY(DEFAULT_DIVIDER_START_MARGIN.ConvertToPx());
1867 SizeF hotZoneSize;
1868 hotZoneSize.SetWidth(realDividerWidth_ + DIVIDER_HOT_ZONE_HORIZONTAL_PADDING_NUM *
1869 DEFAULT_DIVIDER_HOT_ZONE_HORIZONTAL_PADDING.ConvertToPx());
1870 hotZoneSize.SetHeight(geometryNode->GetFrameSize().Height());
1871 DimensionRect hotZoneRegion;
1872 auto paintHeight = GetPaintRectHeight(navBarNode);
1873 if (navigationMode_ == NavigationMode::STACK || enableDragBar_) {
1874 hotZoneRegion.SetSize(DimensionSize(Dimension(0.0f), Dimension(0.0f)));
1875 } else {
1876 hotZoneRegion.SetSize(DimensionSize(
1877 Dimension(hotZoneSize.Width()), Dimension(NearZero(paintHeight) ? hotZoneSize.Height() : paintHeight)));
1878 }
1879 hotZoneRegion.SetOffset(DimensionOffset(Dimension(hotZoneOffset.GetX()), Dimension(hotZoneOffset.GetY())));
1880
1881 std::vector<DimensionRect> mouseRegion;
1882 mouseRegion.emplace_back(hotZoneRegion);
1883
1884 auto dividerFrameNode = GetDividerNode();
1885 CHECK_NULL_VOID(dividerFrameNode);
1886 auto dividerGestureHub = dividerFrameNode->GetOrCreateGestureEventHub();
1887 CHECK_NULL_VOID(dividerGestureHub);
1888 dividerGestureHub->SetMouseResponseRegion(mouseRegion);
1889
1890 auto dragRectOffset = geometryNode->GetMarginFrameOffset();
1891 dragRectOffset.SetX(-DEFAULT_DRAG_REGION.ConvertToPx());
1892 dragRect_.SetOffset(dragRectOffset);
1893 if (navigationMode_ == NavigationMode::STACK || enableDragBar_) {
1894 dragRect_.SetSize(SizeF(0.0f, 0.0f));
1895 } else {
1896 dragRect_.SetSize(SizeF(DEFAULT_DRAG_REGION.ConvertToPx() * DEFAULT_HALF + realDividerWidth_,
1897 NearZero(paintHeight) ? geometryNode->GetFrameSize().Height() : paintHeight));
1898 }
1899
1900 std::vector<DimensionRect> responseRegion;
1901 DimensionOffset responseOffset(dragRectOffset);
1902 DimensionRect responseRect(Dimension(dragRect_.Width(), DimensionUnit::PX),
1903 Dimension(dragRect_.Height(), DimensionUnit::PX), responseOffset);
1904 responseRegion.emplace_back(responseRect);
1905 dividerGestureHub->SetResponseRegion(responseRegion);
1906 }
1907
AddDragBarHotZoneRect()1908 void NavigationPattern::AddDragBarHotZoneRect()
1909 {
1910 if (NearZero(realDividerWidth_)) {
1911 return;
1912 }
1913 auto dargBarNode = GetDragBarNode();
1914 CHECK_NULL_VOID(dargBarNode);
1915 auto geometryNode = dargBarNode->GetGeometryNode();
1916 CHECK_NULL_VOID(geometryNode);
1917 auto dragBarGestureHub = dargBarNode->GetOrCreateGestureEventHub();
1918 CHECK_NULL_VOID(dragBarGestureHub);
1919
1920 auto dragRectOffset = geometryNode->GetMarginFrameOffset();
1921 dragRectOffset.SetX(-DEFAULT_DRAG_BAR_HOT_ZONE.ConvertToPx());
1922 dragRectOffset.SetY(0.0f);
1923 dragBarRect_.SetOffset(dragRectOffset);
1924 if (navigationMode_ == NavigationMode::STACK) {
1925 dragBarRect_.SetSize(SizeF(0.0f, 0.0f));
1926 } else {
1927 dragBarRect_.SetSize(SizeF(DEFAULT_DRAG_BAR_HOT_ZONE.ConvertToPx() * DEFAULT_HALF +
1928 geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height()));
1929 }
1930 std::vector<DimensionRect> responseRegion;
1931 DimensionOffset responseOffset(dragRectOffset);
1932 DimensionRect responseRect(Dimension(dragBarRect_.Width(), DimensionUnit::PX),
1933 Dimension(dragBarRect_.Height(), DimensionUnit::PX), responseOffset);
1934 responseRegion.emplace_back(responseRect);
1935 dragBarGestureHub->SetResponseRegion(responseRegion);
1936 }
1937
NotifyDialogChange(NavDestinationLifecycle lifecycle,bool isNavigationChanged,bool isFromStandardIndex)1938 void NavigationPattern::NotifyDialogChange(NavDestinationLifecycle lifecycle, bool isNavigationChanged,
1939 bool isFromStandardIndex)
1940 {
1941 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1942 const auto& navDestinationNodes = navigationStack_->GetAllNavDestinationNodes();
1943 int32_t lastStandardIndex = hostNode->GetLastStandardIndex();
1944 int32_t standardIndex = lastStandardIndex >= 0 ? lastStandardIndex : 0;
1945 int32_t start = isFromStandardIndex ? standardIndex : 0;
1946 int32_t end = isFromStandardIndex ? navigationStack_->Size() : standardIndex;
1947 bool isShow = lifecycle == NavDestinationLifecycle::ON_SHOW || (lifecycle == NavDestinationLifecycle::ON_WILL_SHOW);
1948 if (isShow) {
1949 for (int32_t index = start; index < end; index++) {
1950 NotifyDestinationLifecycle(navDestinationNodes[index].second, lifecycle);
1951 }
1952 } else {
1953 for (int32_t index = end - 1; index >= 0 && index >= start; index--) {
1954 NotifyDestinationLifecycle(navDestinationNodes[index].second, lifecycle);
1955 }
1956 }
1957 }
1958
DumpInfo()1959 void NavigationPattern::DumpInfo()
1960 {
1961 if (!navigationStack_) {
1962 return;
1963 }
1964 DumpLog::GetInstance().AddDesc(std::string("size").append(std::to_string(navigationStack_->Size())));
1965 }
1966
OnColorConfigurationUpdate()1967 void NavigationPattern::OnColorConfigurationUpdate()
1968 {
1969 auto dividerNode = GetDividerNode();
1970 CHECK_NULL_VOID(dividerNode);
1971 auto theme = NavigationGetTheme();
1972 CHECK_NULL_VOID(theme);
1973 dividerNode->GetRenderContext()->UpdateBackgroundColor(theme->GetNavigationDividerColor());
1974
1975 auto dragBarNode = GetDragBarNode();
1976 CHECK_NULL_VOID(dragBarNode);
1977 auto dragPattern = dragBarNode->GetPattern<NavigationDragBarPattern>();
1978 CHECK_NULL_VOID(dragPattern);
1979 dragPattern->UpdateDefaultColor();
1980 }
1981
TriggerCustomAnimation(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage)1982 bool NavigationPattern::TriggerCustomAnimation(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
1983 const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage)
1984 {
1985 if ((!preTopNavDestination && !newTopNavDestination) || !onTransition_) {
1986 return false;
1987 }
1988 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1989 hostNode->SetIsOnAnimation(true);
1990 if (!newTopNavDestination) {
1991 // pop animation with top navDestination, recover navBar visible tag
1992 hostNode->SetNeedSetInvisible(false);
1993 }
1994 auto proxy = AceType::MakeRefPtr<NavigationTransitionProxy>();
1995 proxy->SetPreDestination(preTopNavDestination);
1996 proxy->SetTopDestination(newTopNavDestination);
1997 auto proxyId = proxy->GetProxyId();
1998 proxyList_.emplace_back(proxy);
1999 auto navigationTransition = ExecuteTransition(preTopNavDestination, newTopNavDestination, isPopPage);
2000 if (!navigationTransition.isValid) {
2001 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "custom transition value is invalid, do default animation");
2002 return false;
2003 }
2004 ExecuteAddAnimation(preTopNavDestination, newTopNavDestination, isPopPage, proxy, navigationTransition);
2005 ACE_SCOPED_TRACE_COMMERCIAL("Navigation page custom transition start");
2006 if (navigationTransition.interactive) {
2007 PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH_INTERACTIVE,
2008 PerfActionType::FIRST_MOVE, "");
2009 auto finishCallback = [weakNavigation = WeakClaim(this),
2010 weakPreNavDestination = WeakPtr<NavDestinationGroupNode>(preTopNavDestination),
2011 weakNewNavDestination = WeakPtr<NavDestinationGroupNode>(newTopNavDestination),
2012 isPopPage, proxyId]() {
2013 auto pattern = weakNavigation.Upgrade();
2014 CHECK_NULL_VOID(pattern);
2015 auto proxy = pattern->GetProxyById(proxyId);
2016 if (proxy == nullptr) {
2017 return;
2018 }
2019 if (!proxy->GetInteractive()) {
2020 pattern->RemoveProxyById(proxyId);
2021 return;
2022 }
2023 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "interactive animation is finish: %{public}d", proxy->GetIsSuccess());
2024 pattern->isFinishInteractiveAnimation_ = true;
2025 auto preDestination = weakPreNavDestination.Upgrade();
2026 auto topDestination = weakNewNavDestination.Upgrade();
2027 proxy->SetIsFinished(true);
2028 // this flag will be update in cancelTransition or finishTransition
2029 ACE_SCOPED_TRACE_COMMERCIAL("navigation page custom transition end");
2030 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH_INTERACTIVE, true);
2031 if (proxy->GetIsSuccess()) {
2032 pattern->GetNavigationStack()->ClearRecoveryList();
2033 pattern->OnCustomAnimationFinish(preDestination, topDestination, isPopPage);
2034 } else {
2035 // fire page cancel transition
2036 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "interactive animation canceled");
2037 pattern->RecoveryToLastStack(preDestination, topDestination);
2038 pattern->SyncWithJsStackIfNeeded();
2039 }
2040 proxy->FireEndCallback();
2041 pattern->RemoveProxyById(proxyId);
2042 };
2043 auto pipelineContext = hostNode->GetContext();
2044 CHECK_NULL_RETURN(pipelineContext, false);
2045 auto navigationManager = pipelineContext->GetNavigationManager();
2046 CHECK_NULL_RETURN(navigationManager, false);
2047 navigationManager->SetInteractive(hostNode->GetId());
2048 proxy->SetInteractiveAnimation(AnimationUtils::CreateInteractiveAnimation(
2049 nullptr, finishCallback), finishCallback);
2050 navigationTransition.transition(proxy);
2051 isFinishInteractiveAnimation_ = false;
2052 navigationManager->FinishInteractiveAnimation();
2053 proxy->StartAnimation();
2054 } else {
2055 PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
2056 navigationStack_->ClearRecoveryList();
2057 navigationTransition.transition(proxy);
2058 // enable render group for text node during custom animation to reduce
2059 // unnecessary redrawing
2060 if (isPopPage && preTopNavDestination) {
2061 preTopNavDestination->UpdateTextNodeListAsRenderGroup(isPopPage, proxy);
2062 }
2063 if (!isPopPage && newTopNavDestination) {
2064 newTopNavDestination->UpdateTextNodeListAsRenderGroup(isPopPage, proxy);
2065 }
2066 }
2067
2068 RefPtr<EventHub> eventHub;
2069 if (!preTopNavDestination && navigationMode_ == NavigationMode::STACK) {
2070 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2071 CHECK_NULL_RETURN(hostNode, true);
2072 auto navBarNode = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarNode());
2073 CHECK_NULL_RETURN(navBarNode, true);
2074 eventHub = navBarNode->GetEventHub<EventHub>();
2075 }
2076 if (preTopNavDestination) {
2077 eventHub = preTopNavDestination->GetEventHub<EventHub>();
2078 }
2079 CHECK_NULL_RETURN(eventHub, true);
2080 eventHub->SetEnabledInternal(false);
2081 return true;
2082 }
2083
OnCustomAnimationFinish(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage)2084 void NavigationPattern::OnCustomAnimationFinish(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
2085 const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage)
2086 {
2087 if (!preTopNavDestination && !newTopNavDestination) {
2088 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "preDestination and topDestination is invalid");
2089 return;
2090 }
2091 ACE_SCOPED_TRACE_COMMERCIAL("Navigation page custom transition end");
2092 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
2093 auto replaceValue = navigationStack_->GetReplaceValue();
2094 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2095 CHECK_NULL_VOID(hostNode);
2096 hostNode->SetIsOnAnimation(false);
2097 if (preTopNavDestination) {
2098 preTopNavDestination->SetIsOnAnimation(false);
2099 }
2100 if (newTopNavDestination) {
2101 newTopNavDestination->SetIsOnAnimation(false);
2102 }
2103 auto id = hostNode->GetTopDestination() ? hostNode->GetTopDestination()->GetAccessibilityId() : -1;
2104 hostNode->OnAccessibilityEvent(
2105 AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
2106 do {
2107 if (replaceValue != 0) {
2108 hostNode->DealNavigationExit(preTopNavDestination, preTopNavDestination == nullptr);
2109 navigationStack_->UpdateReplaceValue(0);
2110 break;
2111 }
2112 if ((newTopNavDestination && preTopNavDestination && isPopPage) ||
2113 (preTopNavDestination && !newTopNavDestination)) {
2114 PageTransitionType preNodeTransitionType = preTopNavDestination->GetTransitionType();
2115 if (preNodeTransitionType != PageTransitionType::EXIT_POP) {
2116 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "previous destination node is executing another transition");
2117 return;
2118 }
2119 auto preDestinationPattern = preTopNavDestination->GetPattern<NavDestinationPattern>();
2120 CHECK_NULL_VOID(preDestinationPattern);
2121 auto shallowBuilder = preDestinationPattern->GetShallowBuilder();
2122 if (shallowBuilder) {
2123 shallowBuilder->MarkIsExecuteDeepRenderDone(false);
2124 }
2125 auto parent = preTopNavDestination->GetParent();
2126 CHECK_NULL_VOID(parent);
2127 parent->RemoveChild(preTopNavDestination);
2128 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2129 break;
2130 }
2131 if ((newTopNavDestination && preTopNavDestination && !isPopPage) ||
2132 (!preTopNavDestination && newTopNavDestination && navigationMode_ == NavigationMode::STACK)) {
2133 hostNode->SetNeedSetInvisible(true);
2134 RefPtr<FrameNode> node;
2135 PageTransitionType preNodeTransitionType;
2136 if (preTopNavDestination) {
2137 preNodeTransitionType = preTopNavDestination->GetTransitionType();
2138 node = preTopNavDestination;
2139 } else {
2140 // pre destination is nullptr, preNode is navBarNode
2141 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
2142 CHECK_NULL_VOID(navBarNode);
2143 preNodeTransitionType = navBarNode->GetTransitionType();
2144 node = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarNode());
2145 CHECK_NULL_VOID(node);
2146 }
2147 if (preNodeTransitionType != PageTransitionType::EXIT_PUSH) {
2148 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "previous destination node is executing another transition");
2149 return;
2150 }
2151 // recover event hub
2152 auto eventHub = node->GetEventHub<EventHub>();
2153 if (eventHub) {
2154 eventHub->SetEnabledInternal(true);
2155 }
2156 bool isDialog = newTopNavDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG;
2157 if (isDialog) {
2158 return;
2159 }
2160 auto property = node->GetLayoutProperty();
2161 property->UpdateVisibility(VisibleType::INVISIBLE);
2162 node->SetJSViewActive(false);
2163 if (!preTopNavDestination) {
2164 hostNode->NotifyPageHide();
2165 }
2166 }
2167 } while (0);
2168 hostNode->RemoveDialogDestination();
2169 auto context = PipelineContext::GetCurrentContext();
2170 CHECK_NULL_VOID(context);
2171 context->MarkNeedFlushMouseEvent();
2172 }
2173
ExecuteTransition(const RefPtr<NavDestinationGroupNode> & preTopDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage)2174 NavigationTransition NavigationPattern::ExecuteTransition(const RefPtr<NavDestinationGroupNode>& preTopDestination,
2175 const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage)
2176 {
2177 NavigationTransition navigationTransition;
2178 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2179 CHECK_NULL_RETURN(hostNode, navigationTransition);
2180 NavigationOperation operation;
2181 auto currentProxy = GetTopNavigationProxy();
2182 auto preInfo = currentProxy->GetPreDestinationContext();
2183 auto topInfo = currentProxy->GetTopDestinationContext();
2184 auto replaceValue = navigationStack_->GetReplaceValue();
2185 if (replaceValue != 0) {
2186 operation = NavigationOperation::REPLACE;
2187 } else if (!preTopDestination) {
2188 operation = NavigationOperation::PUSH;
2189 // if animated with navBarNode, recover navBar visibility
2190 hostNode->SetNeedSetInvisible(false);
2191 } else if (!newTopNavDestination) {
2192 operation = NavigationOperation::POP;
2193 } else if (isPopPage) {
2194 operation = NavigationOperation::POP;
2195 } else {
2196 operation = NavigationOperation::PUSH;
2197 }
2198
2199 /* set transition animation flag fro navBarNode or navDestinationNode */
2200 if (operation == NavigationOperation::PUSH) {
2201 if (preTopDestination != nullptr) {
2202 preTopDestination->SetTransitionType(PageTransitionType::EXIT_PUSH);
2203 } else {
2204 // preTopDestination is nullptr, previous node is navBar node
2205 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
2206 CHECK_NULL_RETURN(navBarNode, navigationTransition);
2207 navBarNode->SetTransitionType(PageTransitionType::EXIT_PUSH);
2208 }
2209
2210 if (newTopNavDestination != nullptr) {
2211 newTopNavDestination->SetTransitionType(PageTransitionType::ENTER_PUSH);
2212 }
2213 }
2214 if (operation == NavigationOperation::POP) {
2215 if (preTopDestination != nullptr) {
2216 preTopDestination->SetTransitionType(PageTransitionType::EXIT_POP);
2217 }
2218 if (newTopNavDestination != nullptr) {
2219 newTopNavDestination->SetTransitionType(PageTransitionType::ENTER_POP);
2220 } else {
2221 // newTopNavDestination is nullptr, current node is navBar node
2222 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
2223 CHECK_NULL_RETURN(navBarNode, navigationTransition);
2224 navBarNode->SetTransitionType(PageTransitionType::ENTER_POP);
2225 }
2226 }
2227 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "custom animation start: operation: %{public}d", operation);
2228 return onTransition_(preInfo, topInfo, operation);
2229 }
2230
UpdatePreNavDesZIndex(const RefPtr<FrameNode> & preTopNavDestination,const RefPtr<FrameNode> & newTopNavDestination,int32_t preLastStandardIndex)2231 void NavigationPattern::UpdatePreNavDesZIndex(const RefPtr<FrameNode> &preTopNavDestination,
2232 const RefPtr<FrameNode> &newTopNavDestination, int32_t preLastStandardIndex)
2233 {
2234 auto replaceVal = navigationStack_->GetReplaceValue();
2235 if (replaceVal != 0 && preTopNavDestination && newTopNavDestination) {
2236 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2237 CHECK_NULL_VOID(hostNode);
2238 auto navigationContentNode = AceType::DynamicCast<FrameNode>(hostNode->GetContentNode());
2239 CHECK_NULL_VOID(navigationContentNode);
2240 auto newDesNodeContext = newTopNavDestination->GetRenderContext();
2241 CHECK_NULL_VOID(newDesNodeContext);
2242 std::optional<int32_t> newNodeZIndex = newDesNodeContext->GetZIndex();
2243 int32_t standardIndex = newNodeZIndex.value_or(0) - 1;
2244 auto hideNodes = hostNode->GetHideNodes();
2245 for (auto iter = hideNodes.begin(); iter != hideNodes.end(); ++iter) {
2246 // if navdestination nodes is not need removed, default zIndex is satisfied, don't need change
2247 if (!iter->second) {
2248 continue;
2249 }
2250 auto navDestination = iter->first;
2251 if (!navDestination) {
2252 continue;
2253 }
2254 auto navDestinationContext = navDestination->GetRenderContext();
2255 if (!navDestinationContext) {
2256 continue;
2257 }
2258 // get navDestination index in hideNodes, use navdestination index in pre navigation stack
2259 int32_t hideNodesIndex =
2260 static_cast<int32_t>(hideNodes.size()) - (navDestination->GetIndex() - preLastStandardIndex);
2261 navDestinationContext->UpdateZIndex(standardIndex - hideNodesIndex);
2262 }
2263 auto preDesNodeContext = preTopNavDestination->GetRenderContext();
2264 CHECK_NULL_VOID(preDesNodeContext);
2265 preDesNodeContext->UpdateZIndex(standardIndex);
2266 navigationContentNode->RebuildRenderContextTree();
2267 auto context = PipelineContext::GetCurrentContext();
2268 CHECK_NULL_VOID(context);
2269 context->RequestFrame();
2270 }
2271 }
2272
SetNavigationStack(const RefPtr<NavigationStack> & navigationStack)2273 void NavigationPattern::SetNavigationStack(const RefPtr<NavigationStack>& navigationStack)
2274 {
2275 if (navigationStack_) {
2276 navigationStack_->SetOnStateChangedCallback(nullptr);
2277 }
2278 navigationStack_ = navigationStack;
2279 if (navigationStack_) {
2280 navigationStack_->SetNavigationNode(GetHost());
2281 WeakPtr<NavigationPattern> weakPattern = WeakClaim(this);
2282 auto id = Container::CurrentId();
2283 auto callback = [weakPattern, id]() {
2284 ContainerScope scope(id);
2285 auto pattern = weakPattern.Upgrade();
2286 CHECK_NULL_VOID(pattern);
2287 if (pattern->NeedSyncWithJsStackMarked()) {
2288 return;
2289 }
2290 pattern->MarkNeedSyncWithJsStack();
2291 auto context = PipelineContext::GetCurrentContext();
2292 CHECK_NULL_VOID(context);
2293 context->AddBuildFinishCallBack([weakPattern]() {
2294 auto pattern = weakPattern.Upgrade();
2295 CHECK_NULL_VOID(pattern);
2296 pattern->SyncWithJsStackIfNeeded();
2297 auto host = pattern->GetHost();
2298 CHECK_NULL_VOID(host);
2299 host->MarkDirtyNode();
2300 });
2301 context->RequestFrame();
2302 };
2303 navigationStack_->SetOnStateChangedCallback(callback);
2304 }
2305 }
2306
GetParentNavigationPattern()2307 RefPtr<NavigationPattern> NavigationPattern::GetParentNavigationPattern()
2308 {
2309 RefPtr<UINode> node = GetHost();
2310 CHECK_NULL_RETURN(node, nullptr);
2311 node = node->GetParent();
2312 while (node) {
2313 if (node->GetTag() == V2::NAVIGATION_VIEW_ETS_TAG) {
2314 break;
2315 }
2316 node = node->GetParent();
2317 }
2318 auto groupNode = AceType::DynamicCast<NavigationGroupNode>(node);
2319 CHECK_NULL_RETURN(groupNode, nullptr);
2320 return AceType::DynamicCast<NavigationPattern>(groupNode->GetPattern());
2321 }
2322
AttachNavigationStackToParent()2323 void NavigationPattern::AttachNavigationStackToParent()
2324 {
2325 CHECK_NULL_VOID(navigationStack_);
2326 auto parentPattern = GetParentNavigationPattern();
2327 CHECK_NULL_VOID(parentPattern);
2328 auto parentStack = parentPattern->GetNavigationStack();
2329 if (parentStack) {
2330 navigationStack_->OnAttachToParent(parentStack);
2331 }
2332 }
2333
DetachNavigationStackFromParent()2334 void NavigationPattern::DetachNavigationStackFromParent()
2335 {
2336 if (navigationStack_) {
2337 navigationStack_->OnDetachFromParent();
2338 }
2339 }
2340
DealTransitionVisibility(const RefPtr<FrameNode> & node,bool isVisible,bool isNavBar)2341 void NavigationPattern::DealTransitionVisibility(const RefPtr<FrameNode>& node, bool isVisible, bool isNavBar)
2342 {
2343 auto renderContext = node->GetRenderContext();
2344 if (!renderContext->HasDisappearTransition()) {
2345 auto layoutProperty = node->GetLayoutProperty();
2346 layoutProperty->UpdateVisibility(isVisible ? VisibleType::VISIBLE : VisibleType::INVISIBLE);
2347 node->SetJSViewActive(isVisible);
2348 return;
2349 }
2350 auto layoutProperty = node->GetLayoutProperty();
2351 layoutProperty->UpdateVisibility(isVisible ? VisibleType::VISIBLE : VisibleType::INVISIBLE, true);
2352 renderContext->SetTransitionOutCallback([weakNode = WeakPtr<FrameNode>(node), isVisible, isNavBar] {
2353 auto curNode = weakNode.Upgrade();
2354 CHECK_NULL_VOID(curNode);
2355 if (isNavBar) {
2356 auto navBarNode = AceType::DynamicCast<NavBarNode>(curNode);
2357 if (navBarNode->GetTransitionType() != PageTransitionType::EXIT_PUSH) {
2358 return;
2359 }
2360 } else {
2361 auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
2362 if (navDestinationNode->GetTransitionType() != PageTransitionType::EXIT_PUSH) {
2363 return;
2364 }
2365 }
2366 curNode->SetJSViewActive(isVisible);
2367 });
2368 }
2369
AddToDumpManager()2370 void NavigationPattern::AddToDumpManager()
2371 {
2372 auto node = GetHost();
2373 auto context = PipelineContext::GetCurrentContext();
2374 if (!node || !context) {
2375 return;
2376 }
2377 auto mgr = context->GetNavigationManager();
2378 if (!mgr) {
2379 return;
2380 }
2381 auto callback = [weakPattern = WeakClaim(this)](int depth) {
2382 auto pattern = weakPattern.Upgrade();
2383 if (!pattern) {
2384 return;
2385 }
2386 const auto& stack = pattern->GetNavigationStack();
2387 if (!stack) {
2388 return;
2389 }
2390 auto infos = stack->DumpStackInfo();
2391 for (const auto& info : infos) {
2392 DumpLog::GetInstance().Print(depth, info);
2393 }
2394 };
2395 mgr->AddNavigationDumpCallback(node->GetId(), node->GetDepth(), callback);
2396 }
2397
RemoveFromDumpManager()2398 void NavigationPattern::RemoveFromDumpManager()
2399 {
2400 auto node = GetHost();
2401 auto context = PipelineContext::GetCurrentContext();
2402 if (!node || !context) {
2403 return;
2404 }
2405 auto mgr = context->GetNavigationManager();
2406 if (mgr) {
2407 mgr->RemoveNavigationDumpCallback(node->GetId(), node->GetDepth());
2408 }
2409 }
2410
FireInterceptionEvent(bool isBefore,const std::optional<std::pair<std::string,RefPtr<UINode>>> & newTopPath)2411 void NavigationPattern::FireInterceptionEvent(bool isBefore,
2412 const std::optional<std::pair<std::string, RefPtr<UINode>>>& newTopPath)
2413 {
2414 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2415 RefPtr<NavDestinationContext> to;
2416 if (newTopPath.has_value()) {
2417 auto topDestination =
2418 AceType::DynamicCast<NavDestinationGroupNode>(hostNode->GetNavDestinationNode(newTopPath->second));
2419 if (topDestination) {
2420 auto pattern = AceType::DynamicCast<NavDestinationPattern>(topDestination->GetPattern());
2421 to = pattern->GetNavDestinationContext();
2422 }
2423 }
2424 NavigationOperation operation;
2425 if (isReplace_ != 0) {
2426 operation = NavigationOperation::REPLACE;
2427 } else {
2428 operation = lastPreIndex_ == -1 ? NavigationOperation::POP : NavigationOperation::PUSH;
2429 }
2430 auto layoutProperty = hostNode->GetLayoutProperty<NavigationLayoutProperty>();
2431 // mode is split and stack size is one,don't need to do animation.
2432 if ((layoutProperty->GetUsrNavigationModeValue(NavigationMode::AUTO) == NavigationMode::SPLIT
2433 || navigationMode_ == NavigationMode::SPLIT) && !preContext_) {
2434 isAnimated_ = false;
2435 }
2436 navigationStack_->FireNavigationInterception(isBefore, preContext_, to, operation,
2437 isAnimated_);
2438
2439 if (!isBefore) {
2440 NotifyNavDestinationSwitch(preContext_, to, operation);
2441 }
2442 }
2443
UpdateIsAnimation(const std::optional<std::pair<std::string,RefPtr<UINode>>> & preTopNavPath)2444 void NavigationPattern::UpdateIsAnimation(const std::optional<std::pair<std::string, RefPtr<UINode>>>& preTopNavPath)
2445 {
2446 auto disAbleAnimation = navigationStack_->GetDisableAnimation();
2447 auto animated = navigationStack_->GetAnimatedValue();
2448 // current animation flag is false
2449 if (disAbleAnimation || !animated) {
2450 isAnimated_ = false;
2451 return;
2452 }
2453 // check is dialog mode
2454 bool isDialog = false;
2455 if (preTopNavPath.has_value()) {
2456 auto preDestination = AceType::DynamicCast<NavDestinationGroupNode>(
2457 NavigationGroupNode::GetNavDestinationNode(preTopNavPath->second));
2458 if (preDestination) {
2459 isDialog = isDialog || (preDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG);
2460 }
2461 }
2462 auto topNode = navigationStack_->Get();
2463 if (topNode) {
2464 auto newTopDestination = AceType::DynamicCast<NavDestinationGroupNode>(
2465 NavigationGroupNode::GetNavDestinationNode(topNode));
2466 if (newTopDestination) {
2467 isDialog = isDialog || (newTopDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG);
2468 }
2469 }
2470 if (!isDialog) {
2471 isAnimated_ = true;
2472 return;
2473 }
2474 isAnimated_ = isCustomAnimation_;
2475 }
2476
NotifyNavDestinationSwitch(const RefPtr<NavDestinationContext> & from,const RefPtr<NavDestinationContext> & to,NavigationOperation operation)2477 void NavigationPattern::NotifyNavDestinationSwitch(const RefPtr<NavDestinationContext>& from,
2478 const RefPtr<NavDestinationContext>& to, NavigationOperation operation)
2479 {
2480 auto host = GetHost();
2481 auto NavdestinationSwitchFunc =
2482 UIObserverHandler::GetInstance().GetHandleNavDestinationSwitchFunc();
2483 if (!host || !NavdestinationSwitchFunc) {
2484 return;
2485 }
2486
2487 std::string navigationId = host->GetInspectorIdValue("");
2488 std::optional<NavDestinationInfo> fromInfo;
2489 std::optional<NavDestinationInfo> toInfo;
2490 BuildNavDestinationInfoFromContext(navigationId, NavDestinationState::ON_HIDDEN, from, true, fromInfo);
2491 BuildNavDestinationInfoFromContext(navigationId, NavDestinationState::ON_SHOWN, to, false, toInfo);
2492 UIObserverHandler::GetInstance().NotifyNavDestinationSwitch(
2493 std::move(fromInfo), std::move(toInfo), operation);
2494 }
2495
StartTransition(const RefPtr<NavDestinationGroupNode> & preDestination,const RefPtr<NavDestinationGroupNode> & topDestination,bool isAnimated,bool isPopPage,bool isNeedVisible)2496 void NavigationPattern::StartTransition(const RefPtr<NavDestinationGroupNode>& preDestination,
2497 const RefPtr<NavDestinationGroupNode>& topDestination,
2498 bool isAnimated, bool isPopPage, bool isNeedVisible)
2499 {
2500 std::string fromPathInfo;
2501 std::string toPathInfo;
2502 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2503 CHECK_NULL_VOID(hostNode);
2504 bool isNotNeedAnimation = !isAnimated;
2505 #if defined(ENABLE_NAV_SPLIT_MODE)
2506 isNotNeedAnimation = !isAnimated ||
2507 (navigationMode_ == NavigationMode::SPLIT && navigationStack_->Size() <= 1 &&
2508 !isBackPage_ && !isCustomAnimation_);
2509 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "StartTransition navigationMode_:%{public}d isNotNeedAnimation:%{public}d",
2510 navigationMode_, isNotNeedAnimation);
2511 #endif
2512
2513 if (preDestination) {
2514 fromPathInfo = preDestination->GetNavDestinationPathInfo();
2515 auto preDestinationPattern = preDestination->GetPattern<NavDestinationPattern>();
2516 CHECK_NULL_VOID(preDestinationPattern);
2517 auto navDestinationName = preDestinationPattern->GetName();
2518 fromPathInfo += ", navDesitinationName: " + navDestinationName;
2519 if ((isPopPage || preDestination->NeedRemoveInPush()) && isNotNeedAnimation) {
2520 /**
2521 * when transition without animation, 'pop' and 'push with remove' need to post
2522 * afterLayoutTask to delay old top's onDisappear. So set this flag to 'false'
2523 */
2524 preDestination->SetIsAnimated(false);
2525 }
2526 } else {
2527 fromPathInfo = hostNode->GetNavigationPathInfo();
2528 }
2529 if (topDestination) {
2530 toPathInfo = topDestination->GetNavDestinationPathInfo();
2531 auto topDestinationPattern = topDestination->GetPattern<NavDestinationPattern>();
2532 CHECK_NULL_VOID(topDestinationPattern);
2533 auto navDestinationName = topDestinationPattern->GetName();
2534 toPathInfo += ", navDesitinationName: " + navDestinationName;
2535 } else {
2536 toPathInfo = hostNode->GetNavigationPathInfo();
2537 }
2538 ACE_SCOPED_TRACE_COMMERCIAL("NavDestination Page from %s to %s", fromPathInfo.c_str(), toPathInfo.c_str());
2539
2540 // fire onWillHide
2541 if (!isPopPage && !preDestination && navigationMode_ == NavigationMode::STACK) {
2542 // NavBar will be covered in STACK mode
2543 auto navBarNode = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarNode());
2544 ProcessAutoSave(navBarNode);
2545 }
2546 if (isPopPage || (preDestination &&
2547 (hostNode->GetLastStandardIndex() > preDestination->GetIndex() || preDestination->NeedRemoveInPush()))) {
2548 NotifyDestinationLifecycle(preDestination, NavDestinationLifecycle::ON_WILL_HIDE);
2549 }
2550 hostNode->FireHideNodeChange(NavDestinationLifecycle::ON_WILL_HIDE);
2551 auto pipeline = PipelineContext::GetCurrentContext();
2552 CHECK_NULL_VOID(pipeline);
2553 auto navigationManager = pipeline->GetNavigationManager();
2554 navigationManager->FireNavigationUpdateCallback();
2555 auto overlayManager = pipeline->GetOverlayManager();
2556 if (overlayManager) {
2557 overlayManager->RemoveAllModalInOverlay(false);
2558 }
2559 if (topDestination) {
2560 NotifyDialogChange(NavDestinationLifecycle::ON_WILL_SHOW, false, true);
2561 }
2562 if (isNotNeedAnimation) {
2563 FireShowAndHideLifecycle(preDestination, topDestination, isPopPage, false);
2564 TransitionWithOutAnimation(preDestination, topDestination, isPopPage, isNeedVisible);
2565 return;
2566 }
2567 pipeline->AddAfterLayoutTask([weakNavigation = WeakClaim(this),
2568 weakPreDestination = WeakPtr<NavDestinationGroupNode>(preDestination),
2569 weakTopDestination = WeakPtr<NavDestinationGroupNode>(topDestination),
2570 isPopPage, isAnimated, isNeedVisible]() {
2571 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(weakNavigation.Upgrade());
2572 CHECK_NULL_VOID(navigationPattern);
2573 auto preDestination = weakPreDestination.Upgrade();
2574 auto topDestination = weakTopDestination.Upgrade();
2575 navigationPattern->FireShowAndHideLifecycle(preDestination, topDestination, isPopPage, true);
2576 navigationPattern->TransitionWithAnimation(preDestination, topDestination, isPopPage, isNeedVisible);
2577 });
2578 }
2579
ProcessAutoSave(const RefPtr<FrameNode> & node)2580 void NavigationPattern::ProcessAutoSave(const RefPtr<FrameNode>& node)
2581 {
2582 CHECK_NULL_VOID(node);
2583 if (!node->NeedRequestAutoSave()) {
2584 return;
2585 }
2586 auto container = Container::Current();
2587 CHECK_NULL_VOID(container);
2588 container->RequestAutoSave(node);
2589 }
2590
NotifyDestinationLifecycle(const RefPtr<UINode> & uiNode,NavDestinationLifecycle lifecycle)2591 void NavigationPattern::NotifyDestinationLifecycle(const RefPtr<UINode>& uiNode,
2592 NavDestinationLifecycle lifecycle)
2593 {
2594 auto curDestination =
2595 AceType::DynamicCast<NavDestinationGroupNode>(NavigationGroupNode::GetNavDestinationNode(uiNode));
2596 CHECK_NULL_VOID(curDestination);
2597 auto eventHub = curDestination->GetEventHub<NavDestinationEventHub>();
2598 CHECK_NULL_VOID(eventHub);
2599 if (lifecycle == NavDestinationLifecycle::ON_WILL_DISAPPEAR) {
2600 NavigationPattern::FireNavigationLifecycleChange(curDestination, lifecycle);
2601 eventHub->FireOnWillDisAppear();
2602 return;
2603 }
2604 auto navDestinationPattern = curDestination->GetPattern<NavDestinationPattern>();
2605 if ((navDestinationPattern->GetIsOnShow() && (lifecycle == NavDestinationLifecycle::ON_SHOW ||
2606 lifecycle == NavDestinationLifecycle::ON_WILL_SHOW)) ||
2607 (!navDestinationPattern->GetIsOnShow() && (lifecycle == NavDestinationLifecycle::ON_HIDE ||
2608 lifecycle == NavDestinationLifecycle::ON_WILL_HIDE))) {
2609 return;
2610 }
2611 if (lifecycle == NavDestinationLifecycle::ON_WILL_SHOW) {
2612 eventHub->FireOnWillShow();
2613 NavigationPattern::FireNavigationLifecycleChange(curDestination, lifecycle);
2614 return;
2615 }
2616 if (lifecycle == NavDestinationLifecycle::ON_SHOW) {
2617 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2618 CHECK_NULL_VOID(navigationNode);
2619 auto parentDestinationNode = navigationNode->GetParentDestinationNode().Upgrade();
2620 if (CheckParentDestinationIsOnhide(parentDestinationNode) && CheckDestinationIsPush(parentDestinationNode)) {
2621 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "parentDestinationNode is onhide");
2622 return;
2623 }
2624 auto param = Recorder::EventRecorder::Get().IsPageParamRecordEnable() ? navigationStack_->GetRouteParam() : "";
2625 eventHub->FireOnShownEvent(navDestinationPattern->GetName(), param);
2626 NotifyPageShow(navDestinationPattern->GetName());
2627 navDestinationPattern->SetIsOnShow(true);
2628 NavigationPattern::FireNavigationLifecycleChange(curDestination, lifecycle);
2629 return;
2630 }
2631 NavigationPattern::FireNavigationLifecycleChange(curDestination, lifecycle);
2632 if (lifecycle == NavDestinationLifecycle::ON_WILL_HIDE) {
2633 eventHub->FireOnWillHide();
2634 return;
2635 }
2636 if (lifecycle == NavDestinationLifecycle::ON_HIDE) {
2637 eventHub->FireOnHiddenEvent(navDestinationPattern->GetName());
2638 NotifyPageHide(navDestinationPattern->GetName());
2639 navDestinationPattern->SetIsOnShow(false);
2640 }
2641 }
2642
GetNavdestinationJsonArray()2643 std::unique_ptr<JsonValue> NavigationPattern::GetNavdestinationJsonArray()
2644 {
2645 auto allNavdestinationInfo = JsonUtil::CreateArray(true);
2646 const auto& navdestinationNodes = GetAllNavDestinationNodes();
2647 for (auto iter : navdestinationNodes) {
2648 auto navdestinationInfo = JsonUtil::Create(true);
2649 auto navdestinationNode =
2650 AceType::DynamicCast<NavDestinationGroupNode>(NavigationGroupNode::GetNavDestinationNode(iter.second));
2651 if (!navdestinationNode) {
2652 continue;
2653 }
2654 if (!navdestinationNode->CanRecovery()) {
2655 continue;
2656 }
2657 auto navdestinationPattern = navdestinationNode->GetPattern<NavDestinationPattern>();
2658 if (!navdestinationPattern) {
2659 continue;
2660 }
2661 auto name = navdestinationPattern->GetName();
2662 auto param = navigationStack_->GetStringifyParamByIndex(navdestinationNode->GetIndex());
2663 auto mode = static_cast<int32_t>(navdestinationNode->GetNavDestinationMode());
2664 navdestinationInfo->Put("name", name.c_str());
2665 navdestinationInfo->Put("param", param.c_str());
2666 navdestinationInfo->Put("mode", mode);
2667 allNavdestinationInfo->Put(navdestinationInfo);
2668 }
2669 return allNavdestinationInfo;
2670 }
2671
RestoreJsStackIfNeeded()2672 void NavigationPattern::RestoreJsStackIfNeeded()
2673 {
2674 auto pipeline = PipelineContext::GetCurrentContext();
2675 CHECK_NULL_VOID(pipeline);
2676 auto navigationManager = pipeline->GetNavigationManager();
2677 CHECK_NULL_VOID(navigationManager);
2678 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2679 CHECK_NULL_VOID(hostNode);
2680 auto navdestinationsInfo = navigationManager->GetNavigationRecoveryInfo(hostNode->GetCurId());
2681 if (navdestinationsInfo.empty()) {
2682 return;
2683 }
2684 navigationStack_->SetPathArray(navdestinationsInfo);
2685 }
2686
PerformanceEventReport(int32_t nodeCount,int32_t depth,const std::string & navDestinationName)2687 void NavigationPattern::PerformanceEventReport(int32_t nodeCount, int32_t depth, const std::string& navDestinationName)
2688 {
2689 if (nodeCount >= PAGE_NODES) {
2690 EventReport::ReportPageNodeOverflow(navDestinationName, nodeCount, PAGE_NODES);
2691 }
2692 if (depth >= PAGE_DEPTH) {
2693 EventReport::ReportPageDepthOverflow(navDestinationName, depth, PAGE_DEPTH);
2694 }
2695 }
2696
FireShowAndHideLifecycle(const RefPtr<NavDestinationGroupNode> & preDestination,const RefPtr<NavDestinationGroupNode> & topDestination,bool isPopPage,bool isAnimated)2697 void NavigationPattern::FireShowAndHideLifecycle(const RefPtr<NavDestinationGroupNode>& preDestination,
2698 const RefPtr<NavDestinationGroupNode>& topDestination, bool isPopPage, bool isAnimated)
2699 {
2700 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2701 // don't move position hide lifecycle is from top to end
2702 if (preDestination) {
2703 auto lastStandardIndex = hostNode->GetLastStandardIndex();
2704 if (isPopPage || lastStandardIndex > preDestination->GetIndex() || preDestination->NeedRemoveInPush()) {
2705 // fire preTop Destination lifecycle
2706 NotifyDestinationLifecycle(preDestination, NavDestinationLifecycle::ON_HIDE);
2707 }
2708 }
2709 // fire remove navDestination and invisible navDestination lifecycle for pop or clear
2710 hostNode->FireHideNodeChange(NavDestinationLifecycle::ON_HIDE);
2711 if (isPopPage || (preDestination && preDestination->NeedRemoveInPush())) {
2712 // fire removed preDestination lifecycle for pop many times or clear
2713 NotifyDestinationLifecycle(preDestination, NavDestinationLifecycle::ON_WILL_DISAPPEAR);
2714 }
2715 // fire removed navDestination lifecycle
2716 hostNode->FireHideNodeChange(NavDestinationLifecycle::ON_WILL_DISAPPEAR);
2717 if (!isAnimated) {
2718 auto pipelineContext = PipelineContext::GetCurrentContext();
2719 CHECK_NULL_VOID(pipelineContext);
2720 pipelineContext->AddAfterLayoutTask([weakNavigation = WeakClaim(this)]() {
2721 auto navigation = weakNavigation.Upgrade();
2722 CHECK_NULL_VOID(navigation);
2723 navigation->NotifyDialogChange(NavDestinationLifecycle::ON_SHOW, false, true);
2724 });
2725 } else {
2726 NotifyDialogChange(NavDestinationLifecycle::ON_SHOW, false, true);
2727 }
2728 FireInterceptionEvent(false, navigationStack_->GetTopNavPath());
2729 }
2730
OnWindowSizeChanged(int32_t,int32_t,WindowSizeChangeReason type)2731 void NavigationPattern::OnWindowSizeChanged(int32_t /*width*/, int32_t /*height*/, WindowSizeChangeReason type)
2732 {
2733 if (WindowSizeChangeReason::ROTATION == type) {
2734 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2735 CHECK_NULL_VOID(hostNode);
2736 AbortAnimation(hostNode);
2737 }
2738 }
2739
OnWindowHide()2740 void NavigationPattern::OnWindowHide()
2741 {
2742 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2743 CHECK_NULL_VOID(hostNode);
2744 auto navigationPattern = hostNode->GetPattern<NavigationPattern>();
2745 CHECK_NULL_VOID(navigationPattern);
2746 navigationPattern->SyncWithJsStackIfNeeded();
2747 }
2748
NotifyPerfMonitorPageMsg(const std::string & pageName)2749 void NavigationPattern::NotifyPerfMonitorPageMsg(const std::string& pageName)
2750 {
2751 auto container = Container::Current();
2752 if (container != nullptr && PerfMonitor::GetPerfMonitor() != nullptr) {
2753 std::string bundleName = container->GetBundleName();
2754 PerfMonitor::GetPerfMonitor()->ReportPageShowMsg("", bundleName, pageName);
2755 }
2756 }
2757
RefreshFocusToDestination()2758 void NavigationPattern::RefreshFocusToDestination()
2759 {
2760 auto newTopNavPath = navigationStack_->GetTopNavPath();
2761 if (!newTopNavPath.has_value()) {
2762 return;
2763 }
2764 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2765 CHECK_NULL_VOID(hostNode);
2766 auto navBarNode = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarNode());
2767 CHECK_NULL_VOID(navBarNode);
2768 auto navBarFocus = navBarNode->GetFocusHub();
2769 CHECK_NULL_VOID(navBarFocus);
2770 if (!navBarFocus->IsCurrentFocus()) {
2771 return;
2772 }
2773 auto newTopNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
2774 NavigationGroupNode::GetNavDestinationNode(newTopNavPath->second));
2775 CHECK_NULL_VOID(newTopNavDestination);
2776 if (!GetIsFocusable(newTopNavDestination)) {
2777 return;
2778 }
2779 auto navDestinationFocusView = newTopNavDestination->GetPattern<FocusView>();
2780 CHECK_NULL_VOID(navDestinationFocusView);
2781 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TWELVE)) {
2782 navDestinationFocusView->SetIsViewRootScopeFocused(false);
2783 }
2784 navDestinationFocusView->FocusViewShow();
2785 }
2786
RecoveryToLastStack(const RefPtr<NavDestinationGroupNode> & preTopDestination,const RefPtr<NavDestinationGroupNode> & newTopDestination)2787 void NavigationPattern::RecoveryToLastStack(
2788 const RefPtr<NavDestinationGroupNode>& preTopDestination,
2789 const RefPtr<NavDestinationGroupNode>& newTopDestination)
2790 {
2791 if (preTopDestination) {
2792 preTopDestination->SetIsOnAnimation(false);
2793 }
2794 if (newTopDestination) {
2795 newTopDestination->SetIsOnAnimation(false);
2796 }
2797 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2798 CHECK_NULL_VOID(hostNode);
2799 hostNode->CleanHideNodes();
2800 CHECK_NULL_VOID(navigationStack_);
2801 navigationStack_->SetNavPathList(navigationStack_->GetRecoveryList());
2802
2803 // update cached node
2804 auto destinationNodes = navigationStack_->GetAllNavDestinationNodes();
2805 for (uint32_t index = 0; index < destinationNodes.size(); index++) {
2806 auto childNode = destinationNodes[index];
2807 if (!childNode.second) {
2808 continue;
2809 }
2810 auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(
2811 NavigationGroupNode::GetNavDestinationNode(childNode.second));
2812 if (!navDestinationNode) {
2813 continue;
2814 }
2815 // update pre cache node to cache node list
2816 auto cacheNode = navigationStack_->GetFromCacheNode(childNode.first);
2817 if (cacheNode && cacheNode == childNode.second) {
2818 navigationStack_->AddCacheNode(childNode.first, childNode.second);
2819 }
2820 }
2821 hostNode->UpdateNavDestinationNodeWithoutMarkDirty(nullptr, navigationModeChange_);
2822
2823 // recover lifecycle state before transition
2824 hostNode->FireHideNodeChange(NavDestinationLifecycle::ON_HIDE);
2825 hostNode->FireHideNodeChange(NavDestinationLifecycle::ON_WILL_DISAPPEAR);
2826 NotifyDialogChange(NavDestinationLifecycle::ON_SHOW, true, true);
2827 hostNode->RemoveDialogDestination();
2828 hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
2829
2830 // update name index
2831 navigationStack_->RecoveryNavigationStack();
2832 ACE_SCOPED_TRACE_COMMERCIAL("Navigation page transition end");
2833 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
2834 hostNode->SetIsOnAnimation(false);
2835 auto id = hostNode->GetTopDestination() ? hostNode->GetTopDestination()->GetAccessibilityId() : -1;
2836 hostNode->OnAccessibilityEvent(
2837 AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
2838 }
2839
ExecuteAddAnimation(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage,const RefPtr<NavigationTransitionProxy> & proxy,NavigationTransition navigationTransition)2840 bool NavigationPattern::ExecuteAddAnimation(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
2841 const RefPtr<NavDestinationGroupNode>& newTopNavDestination,
2842 bool isPopPage, const RefPtr<NavigationTransitionProxy>& proxy,
2843 NavigationTransition navigationTransition)
2844 {
2845 // custom animation return undefined,finish this transition
2846 if (!navigationTransition.isValid) {
2847 proxy->SetIsSuccess(false);
2848 proxy->SetIsFinished(true);
2849 return false;
2850 }
2851 if (preTopNavDestination) {
2852 preTopNavDestination->SetIsOnAnimation(true);
2853 }
2854 if (newTopNavDestination) {
2855 newTopNavDestination->SetIsOnAnimation(true);
2856 }
2857 auto proxyId = proxy->GetProxyId();
2858 proxy->SetInteractive(navigationTransition.interactive);
2859 // set on transition end callback
2860 proxy->SetEndCallback(std::move(navigationTransition.endCallback));
2861 proxy->SetFinishTransitionEvent([weakNavigation = WeakClaim(this),
2862 weakPreNavDestination = WeakPtr<NavDestinationGroupNode>(preTopNavDestination),
2863 weakNewNavDestination = WeakPtr<NavDestinationGroupNode>(newTopNavDestination),
2864 isPopPage, proxyId]() {
2865 auto pattern = weakNavigation.Upgrade();
2866 CHECK_NULL_VOID(pattern);
2867 auto proxy = pattern->GetProxyById(proxyId);
2868 auto preDestination = weakPreNavDestination.Upgrade();
2869 auto topDestination = weakNewNavDestination.Upgrade();
2870 // disable render group for text node after the custom animation
2871 if (isPopPage && preDestination) {
2872 preDestination->ReleaseTextNodeList();
2873 }
2874 if (!isPopPage && topDestination) {
2875 topDestination->ReleaseTextNodeList();
2876 }
2877
2878 // to avoid call finishTransition many times
2879 if (proxy == nullptr) {
2880 TAG_LOGW(AceLogTag::ACE_NAVIGATION, "custom animation proxy is empty or is finished");
2881 return;
2882 }
2883 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "custom animation finish end");
2884 proxy->SetIsFinished(true);
2885 // update pre navigation stack
2886 ACE_SCOPED_TRACE_COMMERCIAL("navigation page custom transition end");
2887 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
2888 pattern->GetNavigationStack()->ClearRecoveryList();
2889 pattern->OnCustomAnimationFinish(preDestination, topDestination, isPopPage);
2890 pattern->RemoveProxyById(proxyId);
2891 });
2892 // add timeout callback
2893 auto timeout = navigationTransition.timeout;
2894 auto pipeline = GetHost()->GetContext();
2895 CHECK_NULL_RETURN(pipeline, false);
2896 auto taskExecutor = pipeline->GetTaskExecutor();
2897 CHECK_NULL_RETURN(taskExecutor, false);
2898 if (timeout < 0) {
2899 return true;
2900 }
2901 // deal timeout callback
2902 taskExecutor->PostDelayedTask(
2903 [weakProxy = WeakPtr<NavigationTransitionProxy>(proxy)] {
2904 auto transitionProxy = weakProxy.Upgrade();
2905 CHECK_NULL_VOID(transitionProxy);
2906 transitionProxy->FireFinishCallback();
2907 },
2908 TaskExecutor::TaskType::UI, timeout, "ArkUINavigationTransitionProxyFinish");
2909 return true;
2910 }
2911
GetIsFocusable(const RefPtr<FrameNode> & frameNode)2912 bool NavigationPattern::GetIsFocusable(const RefPtr<FrameNode>& frameNode)
2913 {
2914 CHECK_NULL_RETURN(frameNode, false);
2915 auto hostNode = AceType::DynamicCast<FrameNode>(GetHost());
2916 CHECK_NULL_RETURN(hostNode, false);
2917 auto focusHub = hostNode->GetFocusHub();
2918 CHECK_NULL_RETURN(focusHub, false);
2919 if (!focusHub->IsFocusableWholePath()) {
2920 return false;
2921 }
2922 auto currentFocusHub = frameNode->GetFocusHub();
2923 CHECK_NULL_RETURN(currentFocusHub, false);
2924 return currentFocusHub->IsFocusableNode();
2925 }
2926
IsLastStdChange()2927 bool NavigationPattern::IsLastStdChange()
2928 {
2929 // check whether last std navdestination id is changed, change return true, not change return false
2930 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2931 CHECK_NULL_RETURN(navigationNode, false);
2932 auto& navPathList = navigationStack_->GetAllNavDestinationNodes();
2933 auto& preNavPathList = navigationStack_->GetAllNavDestinationNodesPrev();
2934 auto lastStdIndex = navigationNode->GetLastStandardIndex();
2935 auto preLastStdIndex = navigationNode->GetPreLastStandardIndex();
2936 if (preLastStdIndex == -1 && lastStdIndex == -1) {
2937 return false;
2938 }
2939 if (preLastStdIndex != -1 && lastStdIndex != -1) {
2940 // check new and pre std navdestination id changed or not
2941 auto preStd = NavigationGroupNode::GetNavDestinationNode(preNavPathList[preLastStdIndex].second.Upgrade());
2942 auto newStd = NavigationGroupNode::GetNavDestinationNode(navPathList[lastStdIndex].second);
2943 if (preStd && newStd) {
2944 return preStd != newStd;
2945 }
2946 }
2947 return true;
2948 }
2949
FollowStdNavdestinationAnimation(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage)2950 void NavigationPattern::FollowStdNavdestinationAnimation(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
2951 const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage)
2952 {
2953 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2954 CHECK_NULL_VOID(navigationNode);
2955 if (preTopNavDestination && newTopNavDestination) {
2956 if (isPopPage) {
2957 navigationNode->TransitionWithDialogPop(preTopNavDestination, newTopNavDestination);
2958 } else {
2959 navigationNode->TransitionWithDialogPush(preTopNavDestination, newTopNavDestination);
2960 }
2961 return;
2962 }
2963 if (newTopNavDestination && navigationMode_ == NavigationMode::STACK) {
2964 auto navBarNode = AceType::DynamicCast<NavBarNode>(navigationNode->GetNavBarNode());
2965 CHECK_NULL_VOID(navBarNode);
2966 navigationNode->TransitionWithDialogPush(navBarNode, newTopNavDestination, true);
2967 return;
2968 }
2969 if (preTopNavDestination) {
2970 if (navigationMode_ == NavigationMode::SPLIT) {
2971 navigationNode->TransitionWithDialogPop(preTopNavDestination, nullptr);
2972 }
2973 if (navigationMode_ == NavigationMode::STACK) {
2974 auto navBarNode = AceType::DynamicCast<NavBarNode>(navigationNode->GetNavBarNode());
2975 CHECK_NULL_VOID(navBarNode);
2976 navigationNode->TransitionWithDialogPop(preTopNavDestination, navBarNode, true);
2977 }
2978 }
2979 }
2980
TransitionWithDialogAnimation(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage)2981 void NavigationPattern::TransitionWithDialogAnimation(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
2982 const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage)
2983 {
2984 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2985 CHECK_NULL_VOID(navigationNode);
2986
2987 // if last standard id is not changed and new top navdestination is standard
2988 if (!isPopPage && !IsLastStdChange() && newTopNavDestination &&
2989 newTopNavDestination->GetNavDestinationMode() == NavDestinationMode::STANDARD) {
2990 return;
2991 }
2992 auto replaceVal = navigationStack_->GetReplaceValue();
2993 if (replaceVal != 0) {
2994 ReplaceAnimation(preTopNavDestination, newTopNavDestination);
2995 return;
2996 }
2997 // last std id is not change, but new dialogs came into stack and upward animation
2998 if (!IsLastStdChange()) {
2999 if (isPopPage) {
3000 navigationNode->StartDialogtransition(preTopNavDestination, newTopNavDestination, false);
3001 } else {
3002 if (!preTopNavDestination && navigationMode_ == NavigationMode::SPLIT) {
3003 // if split mode and push one dialog at the first time, no animation
3004 return;
3005 }
3006 navigationNode->StartDialogtransition(preTopNavDestination, newTopNavDestination, true);
3007 }
3008 return;
3009 }
3010 FollowStdNavdestinationAnimation(preTopNavDestination, newTopNavDestination, isPopPage);
3011 }
3012
CreateDragBarNode(const RefPtr<NavigationGroupNode> & navigationGroupNode)3013 void NavigationPattern::CreateDragBarNode(const RefPtr<NavigationGroupNode>& navigationGroupNode)
3014 {
3015 auto dragBarNode = FrameNode::GetOrCreateFrameNode("DragBar", ElementRegister::GetInstance()->MakeUniqueId(),
3016 []() { return AceType::MakeRefPtr<NavigationDragBarPattern>(); });
3017 auto dragBarLayoutProperty = dragBarNode->GetLayoutProperty();
3018 CHECK_NULL_VOID(dragBarLayoutProperty);
3019 auto theme = NavigationGetTheme();
3020 CHECK_NULL_VOID(theme);
3021 auto renderContext = dragBarNode->GetRenderContext();
3022 CHECK_NULL_VOID(renderContext);
3023 renderContext->UpdateBackBlurRadius(DRAG_BAR_BLUR_RADIUS);
3024 renderContext->UpdateBorderRadius(BorderRadiusProperty(DRAG_BAR_RADIUS));
3025 renderContext->UpdateZIndex(1);
3026 dragBarNode->MarkModifyDone();
3027 auto dragBarItem = CreateDragBarItemNode();
3028 dragBarItem->MountToParent(dragBarNode);
3029 dragBarNode->MountToParent(navigationGroupNode);
3030 navigationGroupNode->SetDragBarNode(dragBarNode);
3031
3032 auto dragBarPattern = dragBarNode->GetPattern<NavigationDragBarPattern>();
3033 CHECK_NULL_VOID(dragBarPattern);
3034 dragBarPattern->UpdateDefaultColor();
3035 }
3036
CreateDragBarItemNode()3037 RefPtr<FrameNode> NavigationPattern::CreateDragBarItemNode()
3038 {
3039 auto dragBarItemNode = FrameNode::GetOrCreateFrameNode("DragBarItem",
3040 ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<Pattern>(); });
3041 auto dragBarItemLayoutProperty = dragBarItemNode->GetLayoutProperty();
3042 CHECK_NULL_RETURN(dragBarItemLayoutProperty, nullptr);
3043 dragBarItemLayoutProperty->UpdateAlignment(Alignment::CENTER);
3044 auto renderContext = dragBarItemNode->GetRenderContext();
3045 CHECK_NULL_RETURN(renderContext, nullptr);
3046 renderContext->UpdateZIndex(SECOND_ZINDEX_VALUE);
3047 renderContext->UpdateBorderRadius(BorderRadiusProperty(DRAG_BAR_ITEM_RADIUS));
3048 dragBarItemNode->MarkModifyDone();
3049 return dragBarItemNode;
3050 }
3051
GetProxyById(uint64_t id) const3052 RefPtr<NavigationTransitionProxy> NavigationPattern::GetProxyById(uint64_t id) const
3053 {
3054 for (auto proxy : proxyList_) {
3055 if (proxy && proxy->GetProxyId() == id) {
3056 return proxy;
3057 }
3058 }
3059 return nullptr;
3060 }
3061
RemoveProxyById(uint64_t id)3062 void NavigationPattern::RemoveProxyById(uint64_t id)
3063 {
3064 for (auto it = proxyList_.begin(); it != proxyList_.end(); ++it) {
3065 if (*it && (*it)->GetProxyId() == id) {
3066 it = proxyList_.erase(it);
3067 return;
3068 }
3069 }
3070 }
3071
InitTouchEvent(const RefPtr<GestureEventHub> & gestureHub)3072 void NavigationPattern::InitTouchEvent(const RefPtr<GestureEventHub>& gestureHub)
3073 {
3074 if (touchEvent_) {
3075 return;
3076 }
3077 auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
3078 auto pattern = weak.Upgrade();
3079 CHECK_NULL_VOID(pattern);
3080 pattern->HandleTouchEvent(info);
3081 };
3082 touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
3083 gestureHub->AddTouchEvent(touchEvent_);
3084 }
3085
HandleTouchEvent(const TouchEventInfo & info)3086 void NavigationPattern::HandleTouchEvent(const TouchEventInfo& info)
3087 {
3088 auto touchType = info.GetTouches().front().GetTouchType();
3089 if (touchType == TouchType::DOWN) {
3090 HandleTouchDown();
3091 }
3092 if (touchType == TouchType::UP || touchType == TouchType::CANCEL) {
3093 HandleTouchUp();
3094 }
3095 }
3096
HandleTouchDown()3097 void NavigationPattern::HandleTouchDown()
3098 {
3099 auto dragBarNode = GetDragBarNode();
3100 CHECK_NULL_VOID(dragBarNode);
3101 auto dragPattern = dragBarNode->GetPattern<NavigationDragBarPattern>();
3102 CHECK_NULL_VOID(dragPattern);
3103 dragPattern->UpdateActiveColor();
3104
3105 auto dividerNode = GetDividerNode();
3106 CHECK_NULL_VOID(dividerNode);
3107 auto dividerRenderContext = dividerNode->GetRenderContext();
3108 CHECK_NULL_VOID(dividerRenderContext);
3109 auto theme = NavigationGetTheme();
3110 CHECK_NULL_VOID(theme);
3111 NG::Gradient gradient;
3112 gradient.CreateGradientWithType(NG::GradientType::LINEAR);
3113 gradient.AddColor(CreatePercentGradientColor(0, theme->GetDviderLightBlueColor()));
3114 gradient.AddColor(CreatePercentGradientColor(HALF_POSITION, theme->GetDviderDarkBlueColor()));
3115 gradient.AddColor(CreatePercentGradientColor(END_POSITION, theme->GetDviderLightBlueColor()));
3116 dividerRenderContext->UpdateBackgroundColor(Color::TRANSPARENT);
3117 dividerRenderContext->UpdateLinearGradient(gradient);
3118 }
3119
HandleTouchUp()3120 void NavigationPattern::HandleTouchUp()
3121 {
3122 auto dragBarNode = GetDragBarNode();
3123 CHECK_NULL_VOID(dragBarNode);
3124 auto dragPattern = dragBarNode->GetPattern<NavigationDragBarPattern>();
3125 CHECK_NULL_VOID(dragPattern);
3126 dragPattern->UpdateDefaultColor();
3127
3128 auto theme = NavigationGetTheme();
3129 CHECK_NULL_VOID(theme);
3130 auto dividerNode = GetDividerNode();
3131 CHECK_NULL_VOID(dividerNode);
3132 NG::Gradient gradient;
3133 gradient.CreateGradientWithType(NG::GradientType::LINEAR);
3134 gradient.AddColor(CreatePercentGradientColor(0, Color::TRANSPARENT));
3135 dividerNode->GetRenderContext()->UpdateLinearGradient(gradient);
3136 dividerNode->GetRenderContext()->UpdateBackgroundColor(theme->GetNavigationDividerColor());
3137 }
3138
CheckContentNeedMeasure(const RefPtr<FrameNode> & node)3139 void NavigationPattern::CheckContentNeedMeasure(const RefPtr<FrameNode>& node)
3140 {
3141 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(node);
3142 CHECK_NULL_VOID(navigationNode);
3143 auto navigationLayoutProperty = navigationNode->GetLayoutProperty<NavigationLayoutProperty>();
3144 CHECK_NULL_VOID(navigationLayoutProperty);
3145 if (!NavigationLayoutAlgorithm::IsAutoHeight(navigationLayoutProperty)) {
3146 return;
3147 }
3148 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "Navigation height is auto, content need to measure after pushAnimation ends");
3149 auto contentNode = navigationNode->GetContentNode();
3150 CHECK_NULL_VOID(contentNode);
3151 contentNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
3152 }
3153 } // namespace OHOS::Ace::NG
3154