• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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